[tetgen] 03/15: Remove unused patch.
Anton Gladky
gladk at moszumanska.debian.org
Tue Jan 28 22:13:45 UTC 2014
This is an automated email from the git hooks/post-receive script.
gladk pushed a commit to branch master
in repository tetgen.
commit e4b48d6517aad9277d7d744d6b1f903440d3b78d
Author: Anton Gladky <gladk at debian.org>
Date: Tue Jan 28 20:20:14 2014 +0100
Remove unused patch.
---
debian/patches/quality.patch | 14927 -----------------------------------------
1 file changed, 14927 deletions(-)
diff --git a/debian/patches/quality.patch b/debian/patches/quality.patch
deleted file mode 100644
index 4150041..0000000
--- a/debian/patches/quality.patch
+++ /dev/null
@@ -1,14927 +0,0 @@
-Index: tetgen1.4.2/tetgen.cxx
-===================================================================
---- tetgen1.4.2.orig/tetgen.cxx 2008-02-16 01:32:45.022628815 +0100
-+++ tetgen1.4.2/tetgen.cxx 2008-02-16 01:33:00.862609011 +0100
-@@ -5,18 +5,16 @@
- // A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator //
- // //
- // Version 1.4 //
--// April 16, 2007 //
-+// January 14, 2006 //
- // //
--// Copyright (C) 2002--2007 //
-+// Copyright 2002, 2004, 2005, 2006 //
- // Hang Si //
--// Research Group Numerical Mathematics and Scientific Computing //
--// Weierstrass Institute for Applied Analysis and Stochastics //
--// Mohrenstr. 39, 10117 Berlin, Germany //
-+// Rathausstr. 9, 10178 Berlin, Germany //
- // si at wias-berlin.de //
- // //
--// TetGen is freely available through the website: http://tetgen.berlios.de. //
--// It may be copied, modified, and redistributed for non-commercial use. //
--// Please consult the file LICENSE for the detailed copyright notices. //
-+// You can obtain TetGen via internet: http://tetgen.berlios.de. It may be //
-+// freely copied, modified, and redistributed under the copyright notices //
-+// given in the file LICENSE. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
-@@ -24,7 +22,7 @@
- // //
- // tetgen.cxx //
- // //
--// The TetGen library and program. //
-+// The C++ implementation file of the TetGen library. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
-@@ -66,15 +64,15 @@
- {
- firstnumber = 0; // Default item index is numbered from Zero.
- mesh_dim = 3; // Default mesh dimension is 3.
-- useindex = true;
-
- pointlist = (REAL *) NULL;
- pointattributelist = (REAL *) NULL;
-- pointmtrlist = (REAL *) NULL;
-+ addpointlist = (REAL *) NULL;
-+ addpointattributelist = (REAL *) NULL;
- pointmarkerlist = (int *) NULL;
- numberofpoints = 0;
- numberofpointattributes = 0;
-- numberofpointmtrs = 0;
-+ numberofaddpoints = 0;
-
- tetrahedronlist = (int *) NULL;
- tetrahedronattributelist = (REAL *) NULL;
-@@ -107,18 +105,11 @@
- numberoffacetconstraints = 0;
- segmentconstraintlist = (REAL *) NULL;
- numberofsegmentconstraints = 0;
-+ nodeconstraintlist = (REAL *) NULL;
-+ numberofnodeconstraints = 0;
-
- pbcgrouplist = (pbcgroup *) NULL;
- numberofpbcgroups = 0;
--
-- vpointlist = (REAL *) NULL;
-- vedgelist = (voroedge *) NULL;
-- vfacetlist = (vorofacet *) NULL;
-- vcelllist = (int **) NULL;
-- numberofvpoints = 0;
-- numberofvedges = 0;
-- numberofvfacets = 0;
-- numberofvcells = 0;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
-@@ -149,8 +140,11 @@
- if (pointattributelist != (REAL *) NULL) {
- delete [] pointattributelist;
- }
-- if (pointmtrlist != (REAL *) NULL) {
-- delete [] pointmtrlist;
-+ if (addpointlist != (REAL *) NULL) {
-+ delete [] addpointlist;
-+ }
-+ if (addpointattributelist != (REAL *) NULL) {
-+ delete [] addpointattributelist;
- }
- if (pointmarkerlist != (int *) NULL) {
- delete [] pointmarkerlist;
-@@ -216,6 +210,9 @@
- if (segmentconstraintlist != (REAL *) NULL) {
- delete [] segmentconstraintlist;
- }
-+ if (nodeconstraintlist != (REAL *) NULL) {
-+ delete [] nodeconstraintlist;
-+ }
- if (pbcgrouplist != (pbcgroup *) NULL) {
- for (i = 0; i < numberofpbcgroups; i++) {
- pg = &(pbcgrouplist[i]);
-@@ -225,24 +222,6 @@
- }
- delete [] pbcgrouplist;
- }
-- if (vpointlist != (REAL *) NULL) {
-- delete [] vpointlist;
-- }
-- if (vedgelist != (voroedge *) NULL) {
-- delete [] vedgelist;
-- }
-- if (vfacetlist != (vorofacet *) NULL) {
-- for (i = 0; i < numberofvfacets; i++) {
-- delete [] vfacetlist[i].elist;
-- }
-- delete [] vfacetlist;
-- }
-- if (vcelllist != (int **) NULL) {
-- for (i = 0; i < numberofvcells; i++) {
-- delete [] vcelllist[i];
-- }
-- delete [] vcelllist;
-- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
-@@ -295,15 +274,13 @@
- attribindex = 0;
- for (i = 0; i < numberofpoints; i++) {
- stringptr = readnumberline(inputline, infile, infilename);
-- if (useindex) {
-- if (i == 0) {
-- firstnode = (int) strtol (stringptr, &stringptr, 0);
-- if ((firstnode == 0) || (firstnode == 1)) {
-- firstnumber = firstnode;
-- }
-+ if (i == 0) {
-+ firstnode = (int) strtol (stringptr, &stringptr, 0);
-+ if ((firstnode == 0) || (firstnode == 1)) {
-+ firstnumber = firstnode;
- }
-- stringptr = findnextnumber(stringptr);
-- } // if (useindex)
-+ }
-+ stringptr = findnextnumber(stringptr);
- if (*stringptr == '\0') {
- printf("Error: Point %d has no x coordinate.\n", firstnumber + i);
- break;
-@@ -395,50 +372,34 @@
- return false;
- }
- printf("Opening %s.\n", innodefilename);
-- // Read the first line of the file.
-+ // Read number of points, number of dimensions, number of point
-+ // attributes, and number of boundary markers.
- stringptr = readnumberline(inputline, infile, innodefilename);
-- // Is this list of points generated from rbox?
-- stringptr = strstr(inputline, "rbox");
-- if (stringptr == NULL) {
-- // Read number of points, number of dimensions, number of point
-- // attributes, and number of boundary markers.
-- stringptr = inputline;
-- numberofpoints = (int) strtol (stringptr, &stringptr, 0);
-- stringptr = findnextnumber(stringptr);
-- if (*stringptr == '\0') {
-- mesh_dim = 3;
-- } else {
-- mesh_dim = (int) strtol (stringptr, &stringptr, 0);
-- }
-- stringptr = findnextnumber(stringptr);
-- if (*stringptr == '\0') {
-- numberofpointattributes = 0;
-- } else {
-- numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
-- }
-- stringptr = findnextnumber(stringptr);
-- if (*stringptr == '\0') {
-- markers = 0;
-- } else {
-- markers = (int) strtol (stringptr, &stringptr, 0);
-- }
-+ numberofpoints = (int) strtol (stringptr, &stringptr, 0);
-+ stringptr = findnextnumber(stringptr);
-+ if (*stringptr == '\0') {
-+ mesh_dim = 3;
- } else {
-- // It is a rbox (qhull) input file.
-- stringptr = inputline;
-- // Get the dimension.
- mesh_dim = (int) strtol (stringptr, &stringptr, 0);
-- // Get the number of points.
-- stringptr = readnumberline(inputline, infile, innodefilename);
-- numberofpoints = (int) strtol (stringptr, &stringptr, 0);
-- // There is no index column.
-- useindex = 0;
-+ }
-+ stringptr = findnextnumber(stringptr);
-+ if (*stringptr == '\0') {
-+ numberofpointattributes = 0;
-+ } else {
-+ numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
-+ }
-+ stringptr = findnextnumber(stringptr);
-+ if (*stringptr == '\0') {
-+ markers = 0;
-+ } else {
-+ markers = (int) strtol (stringptr, &stringptr, 0);
- }
-
-- // if ((mesh_dim != 3) && (mesh_dim != 2)) {
-- // printf("Input error: TetGen only works for 2D & 3D point sets.\n");
-- // fclose(infile);
-- // return false;
-- // }
-+ if ((mesh_dim != 3) && (mesh_dim != 2)) {
-+ printf("Input error: TetGen only works for 2D & 3D point sets.\n");
-+ fclose(infile);
-+ return false;
-+ }
- if (numberofpoints < (mesh_dim + 1)) {
- printf("Input error: TetGen needs at least %d points.\n", mesh_dim + 1);
- fclose(infile);
-@@ -456,6 +417,91 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
-+// load_addnodes() Load a list of additional nodes into 'addpointlists'. //
-+// //
-+// 'filename' is the filename of the original inputfile without suffix. The //
-+// additional nodes are found in file 'filename-a.node'. //
-+// //
-+///////////////////////////////////////////////////////////////////////////////
-+
-+bool tetgenio::load_addnodes(char* filename)
-+{
-+ FILE *infile;
-+ char addnodefilename[FILENAMESIZE];
-+ char inputline[INPUTLINESIZE];
-+ char *stringptr;
-+ REAL x, y, z;
-+ int index;
-+ int i;
-+
-+ // Additional nodes are saved in file "filename-a.node".
-+ strcpy(addnodefilename, filename);
-+ strcat(addnodefilename, "-a.node");
-+ infile = fopen(addnodefilename, "r");
-+ if (infile != (FILE *) NULL) {
-+ printf("Opening %s.\n", addnodefilename);
-+ } else {
-+ // Strange! However, it is not a fatal error.
-+ printf("Warning: Can't opening %s. Skipped.\n", addnodefilename);
-+ numberofaddpoints = 0;
-+ return false;
-+ }
-+
-+ // Read the number of additional points.
-+ stringptr = readnumberline(inputline, infile, addnodefilename);
-+ numberofaddpoints = (int) strtol (stringptr, &stringptr, 0);
-+ if (numberofaddpoints == 0) {
-+ // It looks this file contains no point.
-+ fclose(infile);
-+ return false;
-+ }
-+ // Initialize 'addpointlist';
-+ addpointlist = new REAL[numberofaddpoints * mesh_dim];
-+ if (addpointlist == (REAL *) NULL) {
-+ printf("Error: Out of memory.\n");
-+ terminatetetgen(1);
-+ }
-+
-+ // Read the list of additional points.
-+ index = 0;
-+ for (i = 0; i < numberofaddpoints; i++) {
-+ stringptr = readnumberline(inputline, infile, addnodefilename);
-+ stringptr = findnextnumber(stringptr);
-+ if (*stringptr == '\0') {
-+ printf("Error: Point %d has no x coordinate.\n", firstnumber + i);
-+ break;
-+ }
-+ x = (REAL) strtod(stringptr, &stringptr);
-+ stringptr = findnextnumber(stringptr);
-+ if (*stringptr == '\0') {
-+ printf("Error: Point %d has no y coordinate.\n", firstnumber + i);
-+ break;
-+ }
-+ y = (REAL) strtod(stringptr, &stringptr);
-+ stringptr = findnextnumber(stringptr);
-+ if (*stringptr == '\0') {
-+ printf("Error: Point %d has no z coordinate.\n", firstnumber + i);
-+ break;
-+ }
-+ z = (REAL) strtod(stringptr, &stringptr);
-+ addpointlist[index++] = x;
-+ addpointlist[index++] = y;
-+ addpointlist[index++] = z;
-+ }
-+ fclose(infile);
-+
-+ if (i < numberofaddpoints) {
-+ // Failed to read to additional points due to some error.
-+ delete [] addpointlist;
-+ addpointlist = (REAL *) NULL;
-+ numberofaddpoints = 0;
-+ return false;
-+ }
-+ return true;
-+}
-+
-+///////////////////////////////////////////////////////////////////////////////
-+// //
- // load_pbc() Load a list of pbc groups into 'pbcgrouplist'. //
- // //
- // 'filename' is the filename of the original inputfile without suffix. The //
-@@ -670,6 +716,43 @@
- }
- }
-
-+ // Read the node constraint section. It is optional.
-+ stringptr = readnumberline(inputline, infile, NULL);
-+ if (stringptr != (char *) NULL && *stringptr != '\0') {
-+ numberofnodeconstraints = (int) strtol (stringptr, &stringptr, 0);
-+ } else {
-+ numberofnodeconstraints = 0;
-+ }
-+ if (numberofnodeconstraints > 0) {
-+ // Initialize 'nodeconstraintlist'.
-+ nodeconstraintlist = new REAL[numberofnodeconstraints * 2];
-+ index = 0;
-+ for (i = 0; i < numberofnodeconstraints; i++) {
-+ stringptr = readnumberline(inputline, infile, varfilename);
-+ stringptr = findnextnumber(stringptr);
-+ if (*stringptr == '\0') {
-+ printf("Error: node constraint %d has no node index.\n",
-+ firstnumber + i);
-+ break;
-+ } else {
-+ nodeconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
-+ }
-+ stringptr = findnextnumber(stringptr);
-+ if (*stringptr == '\0') {
-+ printf("Error: node constraint %d has no edge length bound.\n",
-+ firstnumber + i);
-+ break;
-+ } else {
-+ nodeconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
-+ }
-+ }
-+ if (i < numberofnodeconstraints) {
-+ // This must be caused by an error.
-+ fclose(infile);
-+ return false;
-+ }
-+ }
-+
- fclose(infile);
- return true;
- }
-@@ -689,8 +772,8 @@
- char mtrfilename[FILENAMESIZE];
- char inputline[INPUTLINESIZE];
- char *stringptr;
-- REAL mtr;
-- int mtrindex;
-+ REAL attrib;
-+ int attribindex;
- int i, j;
-
- strcpy(mtrfilename, filename);
-@@ -706,33 +789,38 @@
- // Read number of points, number of columns (1, 3, or 6).
- stringptr = readnumberline(inputline, infile, mtrfilename);
- stringptr = findnextnumber(stringptr); // Skip number of points.
-- if (*stringptr != '\0') {
-- numberofpointmtrs = (int) strtol (stringptr, &stringptr, 0);
-- }
-- if (numberofpointmtrs == 0) {
-- // Column number doesn't match. Set a default number (1).
-- numberofpointmtrs = 1;
-+ i = (int) strtol (stringptr, &stringptr, 0);
-+ if ((i != 1) && (i != 3) && (i != 6)) {
-+ // Column number doesn't match. Do nothing with this file.
-+ fclose(infile);
-+ return false;
- }
-
-- // Allocate space for pointmtrlist.
-- pointmtrlist = new REAL[numberofpoints * numberofpointmtrs];
-- if (pointmtrlist == (REAL *) NULL) {
-+ // Metric tensors are saved in pointattributelist.
-+ if (pointattributelist != (REAL *) NULL) {
-+ delete [] pointattributelist;
-+ pointattributelist = (REAL *) NULL;
-+ }
-+ numberofpointattributes = i;
-+ // Allocate space for pointattributelist.
-+ pointattributelist = new REAL[numberofpoints * numberofpointattributes];
-+ if (pointattributelist == (REAL *) NULL) {
- printf("Error: Out of memory.\n");
- terminatetetgen(1);
- }
-- mtrindex = 0;
-+ attribindex = 0;
- for (i = 0; i < numberofpoints; i++) {
- // Read metrics.
- stringptr = readnumberline(inputline, infile, mtrfilename);
-- for (j = 0; j < numberofpointmtrs; j++) {
-+ for (j = 0; j < numberofpointattributes; j++) {
-+ // stringptr = findnextnumber(stringptr);
- if (*stringptr == '\0') {
- printf("Error: Metric %d is missing value #%d in %s.\n",
- i + firstnumber, j + 1, mtrfilename);
- terminatetetgen(1);
- }
-- mtr = (REAL) strtod(stringptr, &stringptr);
-- pointmtrlist[mtrindex++] = mtr;
-- stringptr = findnextnumber(stringptr);
-+ attrib = (REAL) strtod(stringptr, &stringptr);
-+ pointattributelist[attribindex++] = attrib;
- }
- }
-
-@@ -1729,21 +1817,20 @@
- // the .mesh will be added in this case). .mesh is the file format of Medit, //
- // a user-friendly interactive mesh viewing program. //
- // //
--// This routine ONLY reads the sections containing vertices, triangles, and //
--// quadrilaters. Other sections (such as tetrahedra, edges, ...) are ignored.//
-+// This routine ONLY reads the sections containing vertices and triangles, //
-+// other sections (such as tetrahedra, edges, ...) are ignored. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
- bool tetgenio::load_medit(char* filename)
- {
- FILE *fp;
-- tetgenio::facet *tmpflist, *f;
-+ tetgenio::facet *f;
- tetgenio::polygon *p;
- char infilename[FILENAMESIZE];
- char buffer[INPUTLINESIZE];
- char *bufferp, *str;
- double *coord;
-- int *tmpfmlist;
- int dimension = 0;
- int nverts = 0;
- int nfaces = 0;
-@@ -1844,7 +1931,6 @@
- }
- if (nfaces == 0) {
- // Find if it is the keyword "Triangles" or "Quadrilaterals".
-- corners = 0;
- str = strstr(bufferp, "Triangles");
- if (!str) str = strstr(bufferp, "triangles");
- if (!str) str = strstr(bufferp, "TRIANGLES");
-@@ -1867,32 +1953,13 @@
- }
- nfaces = strtol(bufferp, &bufferp, 0);
- // Allocate memory for 'tetgenio'
-- if (nfaces > 0) {
-- if (numberoffacets > 0) {
-- // facetlist has already been allocated. Enlarge arrays.
-- tmpflist = new tetgenio::facet[numberoffacets + nfaces];
-- tmpfmlist = new int[numberoffacets + nfaces];
-- // Copy the data of old arrays into new arrays.
-- for (i = 0; i < numberoffacets; i++) {
-- f = &(tmpflist[i]);
-- tetgenio::init(f);
-- *f = facetlist[i];
-- tmpfmlist[i] = facetmarkerlist[i];
-- }
-- // Release old arrays.
-- delete [] facetlist;
-- delete [] facetmarkerlist;
-- // Remember the new arrays.
-- facetlist = tmpflist;
-- facetmarkerlist = tmpfmlist;
-- } else {
-- // This is the first time to allocate facetlist.
-- facetlist = new tetgenio::facet[nfaces];
-- facetmarkerlist = new int[nfaces];
-- }
-+ if (nfaces > 0) {
-+ numberoffacets = nfaces;
-+ facetlist = new tetgenio::facet[nfaces];
-+ facetmarkerlist = new int[nfaces];
- }
- // Read the following list of faces.
-- for (i = numberoffacets; i < numberoffacets + nfaces; i++) {
-+ for (i = 0; i < nfaces; i++) {
- bufferp = readline(buffer, fp, &line_count);
- if (bufferp == NULL) {
- printf("Unexpected end of file on line %d in file %s\n",
-@@ -1934,12 +2001,10 @@
- facetmarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
- }
- }
-- // Have read in a list of triangles/quads.
-- numberoffacets += nfaces;
-- nfaces = 0;
-+ continue;
- }
- }
-- // if (nverts > 0 && nfaces > 0) break; // Ignore other data.
-+ if (nverts > 0 && nfaces > 0) break; // Ignore other data.
- }
-
- // Close file
-@@ -2027,43 +2092,38 @@
- printf("File I/O Error: Cannot access file %s.\n", infilename);
- return false;
- }
-- // Read the first line of the file.
-- stringptr = readnumberline(inputline, infile, infilename);
-- // Is this list of points generated from rbox?
-- stringptr = strstr(inputline, "rbox");
-- if (stringptr == NULL) {
-- // Read number of points, number of dimensions, number of point
-- // attributes, and number of boundary markers.
-- stringptr = inputline;
-- numberofpoints = (int) strtol (stringptr, &stringptr, 0);
-- stringptr = findnextnumber(stringptr);
-- if (*stringptr == '\0') {
-- mesh_dim = 3;
-- } else {
-- mesh_dim = (int) strtol (stringptr, &stringptr, 0);
-- }
-- stringptr = findnextnumber(stringptr);
-- if (*stringptr == '\0') {
-- numberofpointattributes = 0;
-- } else {
-- numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
-- }
-- stringptr = findnextnumber(stringptr);
-- if (*stringptr == '\0') {
-- markers = 0; // Default value.
-- } else {
-- markers = (int) strtol (stringptr, &stringptr, 0);
-- }
-+ // Read number of points, number of dimensions, number of point
-+ // attributes, and number of boundary markers.
-+ stringptr = readnumberline(inputline, infile, infilename);
-+ numberofpoints = (int) strtol (stringptr, &stringptr, 0);
-+ stringptr = findnextnumber(stringptr);
-+ if (*stringptr == '\0') {
-+ mesh_dim = 3;
- } else {
-- // It is a rbox (qhull) input file.
-- stringptr = inputline;
-- // Get the dimension.
- mesh_dim = (int) strtol (stringptr, &stringptr, 0);
-- // Get the number of points.
-- stringptr = readnumberline(inputline, infile, infilename);
-- numberofpoints = (int) strtol (stringptr, &stringptr, 0);
-- // There is no index column.
-- useindex = 0;
-+ }
-+ stringptr = findnextnumber(stringptr);
-+ if (*stringptr == '\0') {
-+ numberofpointattributes = 0;
-+ } else {
-+ numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
-+ }
-+ stringptr = findnextnumber(stringptr);
-+ if (*stringptr == '\0') {
-+ markers = 0; // Default value.
-+ } else {
-+ markers = (int) strtol (stringptr, &stringptr, 0);
-+ }
-+
-+ if (mesh_dim != 3) {
-+ printf("Error: load_tetmesh() only works for 3D points.\n");
-+ fclose(infile);
-+ return false;
-+ }
-+ if (numberofpoints < 4) {
-+ printf("File I/O error: Input should has at least 4 points.\n");
-+ fclose(infile);
-+ return false;
- }
-
- // Load the list of nodes.
-@@ -2074,92 +2134,86 @@
- fclose(infile);
-
- // Read the elements from an .ele file.
-- if (mesh_dim == 3) {
-- infilename = inelefilename;
-- infile = fopen(infilename, "r");
-- if (infile != (FILE *) NULL) {
-- printf("Opening %s.\n", infilename);
-- // Read number of elements, number of corners (4 or 10), number of
-- // element attributes.
-- stringptr = readnumberline(inputline, infile, infilename);
-- numberoftetrahedra = (int) strtol (stringptr, &stringptr, 0);
-- stringptr = findnextnumber(stringptr);
-- if (*stringptr == '\0') {
-- numberofcorners = 4; // Default read 4 nodes per element.
-- } else {
-- numberofcorners = (int) strtol(stringptr, &stringptr, 0);
-- }
-- stringptr = findnextnumber(stringptr);
-- if (*stringptr == '\0') {
-- numberoftetrahedronattributes = 0; // Default no attribute.
-- } else {
-- numberoftetrahedronattributes = (int) strtol(stringptr, &stringptr, 0);
-- }
-- if (numberofcorners != 4 && numberofcorners != 10) {
-- printf("Error: Wrong number of corners %d (should be 4 or 10).\n",
-- numberofcorners);
-- fclose(infile);
-- return false;
-+ infilename = inelefilename;
-+ infile = fopen(infilename, "r");
-+ if (infile != (FILE *) NULL) {
-+ printf("Opening %s.\n", infilename);
-+ // Read number of elements, number of corners (4 or 10), number of
-+ // element attributes.
-+ stringptr = readnumberline(inputline, infile, infilename);
-+ numberoftetrahedra = (int) strtol (stringptr, &stringptr, 0);
-+ stringptr = findnextnumber(stringptr);
-+ if (*stringptr == '\0') {
-+ numberofcorners = 4; // Default read 4 nodes per element.
-+ } else {
-+ numberofcorners = (int) strtol (stringptr, &stringptr, 0);
-+ }
-+ stringptr = findnextnumber(stringptr);
-+ if (*stringptr == '\0') {
-+ numberoftetrahedronattributes = 0; // Default no attribute.
-+ } else {
-+ numberoftetrahedronattributes = (int) strtol (stringptr, &stringptr, 0);
-+ }
-+ if (numberofcorners != 4 && numberofcorners != 10) {
-+ printf("Error: Wrong number of corners %d (should be 4 or 10).\n",
-+ numberofcorners);
-+ fclose(infile);
-+ return false;
-+ }
-+ // Allocate memory for tetrahedra.
-+ if (numberoftetrahedra > 0) {
-+ tetrahedronlist = new int[numberoftetrahedra * numberofcorners];
-+ if (tetrahedronlist == (int *) NULL) {
-+ printf("Error: Out of memory.\n");
-+ terminatetetgen(1);
- }
-- // Allocate memory for tetrahedra.
-- if (numberoftetrahedra > 0) {
-- tetrahedronlist = new int[numberoftetrahedra * numberofcorners];
-- if (tetrahedronlist == (int *) NULL) {
-+ // Allocate memory for output tetrahedron attributes if necessary.
-+ if (numberoftetrahedronattributes > 0) {
-+ tetrahedronattributelist = new REAL[numberoftetrahedra *
-+ numberoftetrahedronattributes];
-+ if (tetrahedronattributelist == (REAL *) NULL) {
- printf("Error: Out of memory.\n");
- terminatetetgen(1);
- }
-- // Allocate memory for output tetrahedron attributes if necessary.
-- if (numberoftetrahedronattributes > 0) {
-- tetrahedronattributelist = new REAL[numberoftetrahedra *
-- numberoftetrahedronattributes];
-- if (tetrahedronattributelist == (REAL *) NULL) {
-- printf("Error: Out of memory.\n");
-- terminatetetgen(1);
-- }
-- }
- }
-- // Read the list of tetrahedra.
-- index = 0;
-- attribindex = 0;
-- for (i = 0; i < numberoftetrahedra; i++) {
-- // Read tetrahedron index and the tetrahedron's corners.
-- stringptr = readnumberline(inputline, infile, infilename);
-- for (j = 0; j < numberofcorners; j++) {
-- stringptr = findnextnumber(stringptr);
-- if (*stringptr == '\0') {
-- printf("Error: Tetrahedron %d is missing vertex %d in %s.\n",
-- i + firstnumber, j + 1, infilename);
-- terminatetetgen(1);
-- }
-- corner = (int) strtol(stringptr, &stringptr, 0);
-- if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
-- printf("Error: Tetrahedron %d has an invalid vertex index.\n",
-- i + firstnumber);
-- terminatetetgen(1);
-- }
-- tetrahedronlist[index++] = corner;
-+ }
-+ // Read the list of tetrahedra.
-+ index = 0;
-+ attribindex = 0;
-+ for (i = 0; i < numberoftetrahedra; i++) {
-+ // Read tetrahedron index and the tetrahedron's corners.
-+ stringptr = readnumberline(inputline, infile, infilename);
-+ for (j = 0; j < numberofcorners; j++) {
-+ stringptr = findnextnumber(stringptr);
-+ if (*stringptr == '\0') {
-+ printf("Error: Tetrahedron %d is missing vertex %d in %s.\n",
-+ i + firstnumber, j + 1, infilename);
-+ terminatetetgen(1);
- }
-- // Read the tetrahedron's attributes.
-- for (j = 0; j < numberoftetrahedronattributes; j++) {
-- stringptr = findnextnumber(stringptr);
-- if (*stringptr == '\0') {
-- attrib = 0.0;
-- } else {
-- attrib = (REAL) strtod(stringptr, &stringptr);
-- }
-- tetrahedronattributelist[attribindex++] = attrib;
-+ corner = (int) strtol(stringptr, &stringptr, 0);
-+ if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
-+ printf("Error: Tetrahedron %d has an invalid vertex index.\n",
-+ i + firstnumber);
-+ terminatetetgen(1);
- }
-+ tetrahedronlist[index++] = corner;
-+ }
-+ // Read the tetrahedron's attributes.
-+ for (j = 0; j < numberoftetrahedronattributes; j++) {
-+ stringptr = findnextnumber(stringptr);
-+ if (*stringptr == '\0') {
-+ attrib = 0.0;
-+ } else {
-+ attrib = (REAL) strtod(stringptr, &stringptr);
-+ }
-+ tetrahedronattributelist[attribindex++] = attrib;
- }
-- fclose(infile);
- }
-- } // if (meshdim == 3)
-+ fclose(infile);
-+ }
-
- // Read the hullfaces or subfaces from a .face file if it exists.
-- if (mesh_dim == 3) {
-- infilename = infacefilename;
-- } else {
-- infilename = inelefilename;
-- }
-+ infilename = infacefilename;
- infile = fopen(infilename, "r");
- if (infile != (FILE *) NULL) {
- printf("Opening %s.\n", infilename);
-@@ -2167,10 +2221,6 @@
- stringptr = readnumberline(inputline, infile, infilename);
- numberoftrifaces = (int) strtol (stringptr, &stringptr, 0);
- stringptr = findnextnumber(stringptr);
-- if (mesh_dim == 2) {
-- // Skip a number.
-- stringptr = findnextnumber(stringptr);
-- }
- if (*stringptr == '\0') {
- markers = 0; // Default there is no marker per face.
- } else {
-@@ -2307,177 +2357,16 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// load_voronoi() Load a Voronoi diagram from files. //
-+// save_nodes() Save points to a .node file. //
- // //
--// 'filename' is the inputfile without suffix. The Voronoi diagram is read //
--// from files: filename.v.node, filename.v.edge, and filename.v.face. //
-+// 'filename' is a string containing the file name without suffix. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--bool tetgenio::load_voronoi(char* filename)
--{
-- FILE *infile;
-- char innodefilename[FILENAMESIZE];
-- char inedgefilename[FILENAMESIZE];
-- char inputline[INPUTLINESIZE];
-- char *stringptr, *infilename;
-- voroedge *vedge;
-- REAL x, y, z;
-- int firstnode, corner;
-- int index;
-- int i, j;
--
-- // Assembling the actual file names we want to open.
-- strcpy(innodefilename, filename);
-- strcpy(inedgefilename, filename);
-- strcat(innodefilename, ".v.node");
-- strcat(inedgefilename, ".v.edge");
--
-- // Read the points from a .v.node file.
-- infilename = innodefilename;
-- printf("Opening %s.\n", infilename);
-- infile = fopen(infilename, "r");
-- if (infile == (FILE *) NULL) {
-- printf("File I/O Error: Cannot access file %s.\n", infilename);
-- return false;
-- }
-- // Read the first line of the file.
-- stringptr = readnumberline(inputline, infile, infilename);
-- // Is this list of points generated from rbox?
-- stringptr = strstr(inputline, "rbox");
-- if (stringptr == NULL) {
-- // Read number of points, number of dimensions, number of point
-- // attributes, and number of boundary markers.
-- stringptr = inputline;
-- numberofvpoints = (int) strtol (stringptr, &stringptr, 0);
-- stringptr = findnextnumber(stringptr);
-- if (*stringptr == '\0') {
-- mesh_dim = 3; // Default.
-- } else {
-- mesh_dim = (int) strtol (stringptr, &stringptr, 0);
-- }
-- useindex = 1; // There is an index column.
-- } else {
-- // It is a rbox (qhull) input file.
-- stringptr = inputline;
-- // Get the dimension.
-- mesh_dim = (int) strtol (stringptr, &stringptr, 0);
-- // Get the number of points.
-- stringptr = readnumberline(inputline, infile, infilename);
-- numberofvpoints = (int) strtol (stringptr, &stringptr, 0);
-- useindex = 0; // No index column.
-- }
-- // Initialize 'vpointlist'.
-- vpointlist = new REAL[numberofvpoints * 3];
-- if (vpointlist == (REAL *) NULL) {
-- printf("Error: Out of memory.\n");
-- terminatetetgen(1);
-- }
-- // Read the point section.
-- index = 0;
-- for (i = 0; i < numberofvpoints; i++) {
-- stringptr = readnumberline(inputline, infile, infilename);
-- if (useindex) {
-- if (i == 0) {
-- firstnode = (int) strtol (stringptr, &stringptr, 0);
-- if ((firstnode == 0) || (firstnode == 1)) {
-- firstnumber = firstnode;
-- }
-- }
-- stringptr = findnextnumber(stringptr);
-- } // if (useindex)
-- if (*stringptr == '\0') {
-- printf("Error: Point %d has no x coordinate.\n", firstnumber + i);
-- terminatetetgen(1);
-- }
-- x = (REAL) strtod(stringptr, &stringptr);
-- stringptr = findnextnumber(stringptr);
-- if (*stringptr == '\0') {
-- printf("Error: Point %d has no y coordinate.\n", firstnumber + i);
-- terminatetetgen(1);
-- }
-- y = (REAL) strtod(stringptr, &stringptr);
-- if (mesh_dim == 3) {
-- stringptr = findnextnumber(stringptr);
-- if (*stringptr == '\0') {
-- printf("Error: Point %d has no z coordinate.\n", firstnumber + i);
-- terminatetetgen(1);
-- }
-- z = (REAL) strtod(stringptr, &stringptr);
-- } else {
-- z = 0.0; // mesh_dim == 2;
-- }
-- vpointlist[index++] = x;
-- vpointlist[index++] = y;
-- vpointlist[index++] = z;
-- }
-- fclose(infile);
--
-- // Read the Voronoi edges from a .v.edge file if it exists.
-- infilename = inedgefilename;
-- infile = fopen(infilename, "r");
-- if (infile != (FILE *) NULL) {
-- printf("Opening %s.\n", infilename);
-- // Read number of boundary edges.
-- stringptr = readnumberline(inputline, infile, infilename);
-- numberofvedges = (int) strtol (stringptr, &stringptr, 0);
-- if (numberofvedges > 0) {
-- vedgelist = new voroedge[numberofvedges];
-- }
-- // Read the list of faces.
-- index = 0;
-- for (i = 0; i < numberofvedges; i++) {
-- // Read edge index and the edge's two endpoints.
-- stringptr = readnumberline(inputline, infile, infilename);
-- vedge = &(vedgelist[i]);
-- for (j = 0; j < 2; j++) {
-- stringptr = findnextnumber(stringptr);
-- if (*stringptr == '\0') {
-- printf("Error: Edge %d is missing vertex %d in %s.\n",
-- i + firstnumber, j + 1, infilename);
-- terminatetetgen(1);
-- }
-- corner = (int) strtol(stringptr, &stringptr, 0);
-- j == 0 ? vedge->v1 = corner : vedge->v2 = corner;
-- }
-- if (vedge->v2 < 0) {
-- for (j = 0; j < mesh_dim; j++) {
-- stringptr = findnextnumber(stringptr);
-- if (*stringptr == '\0') {
-- printf("Error: Edge %d is missing normal in %s.\n",
-- i + firstnumber, infilename);
-- terminatetetgen(1);
-- }
-- vedge->vnormal[j] = (REAL) strtod(stringptr, &stringptr);
-- }
-- if (mesh_dim == 2) {
-- vedge->vnormal[2] = 0.0;
-- }
-- } else {
-- vedge->vnormal[0] = 0.0;
-- vedge->vnormal[1] = 0.0;
-- vedge->vnormal[2] = 0.0;
-- }
-- }
-- fclose(infile);
-- }
--
-- return true;
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
--// save_nodes() Save points to a .node file. //
--// //
--// 'filename' is a string containing the file name without suffix. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--void tetgenio::save_nodes(char* filename)
-+void tetgenio::save_nodes(char* filename)
- {
- FILE *fout;
- char outnodefilename[FILENAMESIZE];
-- char outmtrfilename[FILENAMESIZE];
- int i, j;
-
- sprintf(outnodefilename, "%s.node", filename);
-@@ -2502,22 +2391,8 @@
- }
- fprintf(fout, "\n");
- }
-- fclose(fout);
-
-- // If the point metrics exist, output them to a .mtr file.
-- if ((numberofpointmtrs > 0) && (pointmtrlist != (REAL *) NULL)) {
-- sprintf(outmtrfilename, "%s.mtr", filename);
-- printf("Saving metrics to %s\n", outmtrfilename);
-- fout = fopen(outmtrfilename, "w");
-- fprintf(fout, "%d %d\n", numberofpoints, numberofpointmtrs);
-- for (i = 0; i < numberofpoints; i++) {
-- for (j = 0; j < numberofpointmtrs; j++) {
-- fprintf(fout, "%.16g ", pointmtrlist[i * numberofpointmtrs + j]);
-- }
-- fprintf(fout, "\n");
-- }
-- fclose(fout);
-- }
-+ fclose(fout);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
-@@ -2897,16 +2772,16 @@
- {
- // Initialize command line switches.
- plc = 0;
-- quality = 0;
- refine = 0;
-- coarse = 0;
-+ quality = 0;
-+ smooth = 1;
- metric = 0;
-+ bgmesh = 0;
- minratio = 2.0;
- goodratio = 0.0;
- minangle = 20.0;
- goodangle = 0.0;
-- maxdihedral = 165.0;
-- mindihedral = 5.0;
-+ maxdihedral = 170.0;
- varvolume = 0;
- fixedvolume = 0;
- maxvolume = -1.0;
-@@ -2916,18 +2791,15 @@
- offcenter = 0;
- conformdel = 0;
- alpha1 = sqrt(2.0);
-- alpha2 = 1.0;
-+ alpha2 = 0.5;
- alpha3 = 0.6;
- zeroindex = 0;
- facesout = 0;
- edgesout = 0;
- neighout = 0;
-- voroout = 0;
- meditview = 0;
- gidview = 0;
- geomview = 0;
-- optlevel = 3;
-- optpasses = 3;
- order = 1;
- nojettison = 0;
- nobound = 0;
-@@ -2943,6 +2815,7 @@
- docheck = 0;
- quiet = 0;
- verbose = 0;
-+ tol = 0;
- useshelles = 0;
- epsilon = 1.0e-8;
- epsilon2 = 1.0e-5;
-@@ -2951,7 +2824,6 @@
- commandline[0] = '\0';
- infilename[0] = '\0';
- outfilename[0] = '\0';
-- addinfilename[0] = '\0';
- bgmeshfilename[0] = '\0';
- }
-
-@@ -2963,12 +2835,7 @@
-
- void tetgenbehavior::versioninfo()
- {
-- printf("Version 1.4.2 (April 16, 2007).\n");
-- printf("\n");
-- printf("Copyright (C) 2002 - 2007\n");
-- printf("Hang Si\n");
-- printf("Mohrenstr. 39, 10117 Berlin, Germany\n");
-- printf("si at wias-berlin.de\n");
-+ printf("Version 1.4.1 (July 06, 2006).\n");
- }
-
- ///////////////////////////////////////////////////////////////////////////////
-@@ -2979,28 +2846,27 @@
-
- void tetgenbehavior::syntax()
- {
-- printf(" tetgen [-prq_Ra_AiMYS_T_dzo_fenvgGOJBNEFICQVh] input_file\n");
-- printf(" -p Tetrahedralizes a piecewise linear complex (PLC).\n");
-- printf(" -r Reconstructs a previously generated mesh.\n");
-- printf(" -q Quality mesh generation (adding new mesh points to ");
-- printf("improve mesh quality).\n");
-- printf(" -R Mesh coarsening (deleting redundant mesh points).\n");
-+ printf(" tetgen [-pq__a__AriMYS__T__dzjo_fengGOJBNEFICQVvh] input_file\n");
-+ printf(" -p Tetrahedralizes a piecewise linear complex.\n");
-+ printf(" -q Quality mesh generation. A minimum radius-edge ratio may\n");
-+ printf(" be specified (default 2.0).\n");
- printf(" -a Applies a maximum tetrahedron volume constraint.\n");
- printf(" -A Assigns attributes to identify tetrahedra in different ");
- printf("regions.\n");
-+ printf(" -r Reconstructs and Refines a previously generated mesh.\n");
- printf(" -i Inserts a list of additional points into mesh.\n");
- printf(" -M Does not merge coplanar facets.\n");
- printf(" -Y Suppresses boundary facets/segments splitting.\n");
-- printf(" -S Specifies maximum number of added points.\n");
-- printf(" -T Sets a tolerance for coplanar test (default 1e-8).\n");
-- printf(" -d Detects self-intersections of facets of the PLC.\n");
-+ printf(" -S Specifies maximum number of added Steiner points.\n");
-+ printf(" -T Set a tolerance for coplanar test (default 1e-8).\n");
-+ printf(" -d Diagnoses the validation of the input PLC.\n");
- printf(" -z Numbers all output items starting from zero.\n");
- printf(" -o2 Generates second-order subparametric elements.\n");
-- printf(" -f Outputs all faces to .face file.");
-+ printf(" -P Outputs triangulated PLC facets to .smesh file.\n");
-+ printf(" -f Outputs all faces (instead of boundary faces) to .face ");
- printf("file.\n");
-- printf(" -e Outputs all edges to .edge file.\n");
-+ printf(" -e Outputs subsegments to .edge file.\n");
- printf(" -n Outputs tetrahedra neighbors to .neigh file.\n");
-- printf(" -v Outputs Voronoi diagram to files.\n");
- printf(" -g Outputs mesh to .mesh file for viewing by Medit.\n");
- printf(" -G Outputs mesh to .msh file for viewing by Gid.\n");
- printf(" -O Outputs mesh to .off file for viewing by Geomview.\n");
-@@ -3013,6 +2879,7 @@
- printf(" -C Checks the consistency of the final mesh.\n");
- printf(" -Q Quiet: No terminal output except errors.\n");
- printf(" -V Verbose: Detailed information, more terminal output.\n");
-+ printf(" -v Prints the version information.\n");
- printf(" -h Help: A brief instruction for using TetGen.\n");
- }
-
-@@ -3029,6 +2896,11 @@
- printf("Triangulator\n");
- versioninfo();
- printf("\n");
-+ printf("Copyright 2002, 2004, 2005, 2006\n");
-+ printf("Hang Si\n");
-+ printf("Rathausstr. 9, 10178 Berlin, Germany\n");
-+ printf("si at wias-berlin.de\n");
-+ printf("\n");
- printf("What Can TetGen Do?\n");
- printf("\n");
- printf(" TetGen generates exact Delaunay tetrahedralizations, exact\n");
-@@ -3102,7 +2974,7 @@
- int startindex;
- int increment;
- int meshnumber;
-- int scount;
-+ int Rcount;
- int i, j, k;
- char workstring[1024];
-
-@@ -3118,7 +2990,7 @@
- }
-
- // Rcount used to count the number of '-R' be used.
-- scount = 0;
-+ Rcount = 0;
-
- for (i = startindex; i < argc; i++) {
- // Remember the command line switches.
-@@ -3139,34 +3011,12 @@
- plc = 1;
- } else if (argv[i][j] == 'r') {
- refine = 1;
-- } else if (argv[i][j] == 'R') {
-- coarse = 1;
-- } else if (argv[i][j] == 'q') {
-- quality++;
-- if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
-- (argv[i][j + 1] == '.')) {
-- k = 0;
-- while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
-- (argv[i][j + 1] == '.')) {
-- j++;
-- workstring[k] = argv[i][j];
-- k++;
-- }
-- workstring[k] = '\0';
-- if (quality == 1) {
-- minratio = (REAL) strtod(workstring, (char **) NULL);
-- } else if (quality == 2) {
-- mindihedral = (REAL) strtod(workstring, (char **) NULL);
-- } else if (quality == 3) {
-- maxdihedral = (REAL) strtod(workstring, (char **) NULL);
-- } else if (quality == 4) {
-- alpha2 = (REAL) strtod(workstring, (char **) NULL);
-- } else if (quality == 5) {
-- alpha1 = (REAL) strtod(workstring, (char **) NULL);
-- }
-- }
- } else if (argv[i][j] == 'm') {
-- metric++;
-+ metric = 1;
-+ } else if (argv[i][j] == 'b') {
-+ bgmesh = 1;
-+ } else if (argv[i][j] == 'q') {
-+ quality = 1;
- if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
- (argv[i][j + 1] == '.')) {
- k = 0;
-@@ -3177,13 +3027,10 @@
- k++;
- }
- workstring[k] = '\0';
-- if (metric == 1) {
-- alpha1 = (REAL) strtod(workstring, (char **) NULL);
-- } else if (metric == 2) {
-- alpha2 = (REAL) strtod(workstring, (char **) NULL);
-- }
-- }
-+ minratio = (REAL) strtod(workstring, (char **) NULL);
-+ }
- } else if (argv[i][j] == 'a') {
-+ quality = 1;
- if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
- (argv[i][j + 1] == '.')) {
- fixedvolume = 1;
-@@ -3211,11 +3058,9 @@
- } else if (argv[i][j] == 'f') {
- facesout = 1;
- } else if (argv[i][j] == 'e') {
-- edgesout++;
-+ edgesout = 1;
- } else if (argv[i][j] == 'n') {
- neighout++;
-- } else if (argv[i][j] == 'v') {
-- voroout = 1;
- } else if (argv[i][j] == 'g') {
- meditview = 1;
- } else if (argv[i][j] == 'G') {
-@@ -3258,7 +3103,6 @@
- steiner = (int) strtol(workstring, (char **) NULL, 0);
- }
- } else if (argv[i][j] == 's') {
-- scount++;
- if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
- (argv[i][j + 1] == '.')) {
- k = 0;
-@@ -3270,15 +3114,34 @@
- k++;
- }
- workstring[k] = '\0';
-- if (scount == 1) {
-- optlevel = (int) strtol(workstring, (char **) NULL, 0);
-- } else if (scount == 2) {
-- optpasses = (int) strtol(workstring, (char **) NULL, 0);
-+ maxdihedral = (REAL) strtod(workstring, (char **) NULL);
-+ if (maxdihedral >= 180.0) smooth = 0;
-+ }
-+ } else if (argv[i][j] == 'R') {
-+ Rcount++;
-+ if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
-+ (argv[i][j + 1] == '.')) {
-+ k = 0;
-+ while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
-+ (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
-+ (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
-+ j++;
-+ workstring[k] = argv[i][j];
-+ k++;
- }
-+ workstring[k] = '\0';
-+ if (Rcount == 1) {
-+ alpha1 = (REAL) strtod(workstring, (char **) NULL);
-+ } else if (Rcount == 2) {
-+ alpha2 = (REAL) strtod(workstring, (char **) NULL);
-+ } else if (Rcount == 3) {
-+ alpha3 = (REAL) strtod(workstring, (char **) NULL);
-+ }
- }
- } else if (argv[i][j] == 'D') {
- conformdel++;
- } else if (argv[i][j] == 'T') {
-+ tol++;
- if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
- (argv[i][j + 1] == '.')) {
- k = 0;
-@@ -3290,7 +3153,11 @@
- k++;
- }
- workstring[k] = '\0';
-- epsilon = (REAL) strtod(workstring, (char **) NULL);
-+ if (tol == 1) {
-+ epsilon = (REAL) strtod(workstring, (char **) NULL);
-+ } else if (tol == 2) {
-+ epsilon2 = (REAL) strtod(workstring, (char **) NULL);
-+ }
- }
- } else if (argv[i][j] == 'C') {
- docheck++;
-@@ -3300,9 +3167,9 @@
- quiet = 1;
- } else if (argv[i][j] == 'V') {
- verbose++;
-- // } else if (argv[i][j] == 'v') {
-- // versioninfo();
-- // terminatetetgen(0);
-+ } else if (argv[i][j] == 'v') {
-+ versioninfo();
-+ terminatetetgen(0);
- } else if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
- (argv[i][j] == '?')) {
- usage();
-@@ -3357,7 +3224,7 @@
- }
- }
- plc = plc || diagnose;
-- useshelles = plc || refine || coarse || quality;
-+ useshelles = plc || refine || quality;
- goodratio = minratio;
- goodratio *= goodratio;
-
-@@ -3368,7 +3235,7 @@
- }
- if (refine && (plc || noiterationnum)) {
- printf("Error: Switches %s cannot use together with -r.\n",
-- "-p, -d, and -I");
-+ "-p, -d, -c, and -I");
- return false;
- }
- if (diagnose && (quality || insertaddpoints || (order == 2) || neighout
-@@ -3388,12 +3255,6 @@
- if (refine || !plc) {
- regionattrib = 0;
- }
-- // If '-a' or '-aa' is in use, enable '-q' option too.
-- if (fixedvolume || varvolume) {
-- if (quality == 0) {
-- quality = 1;
-- }
-- }
- // Calculate the goodangle for testing bad subfaces.
- goodangle = cos(minangle * PI / 180.0);
- goodangle *= goodangle;
-@@ -3430,9 +3291,6 @@
- workstring[increment + 2] = '\0';
- sprintf(outfilename, workstring, meshnumber + 1);
- }
-- // Additional input file name has the end ".a".
-- strcpy(addinfilename, infilename);
-- strcat(addinfilename, ".a");
- // Background filename has the form "*.b.ele", "*.b.node", ...
- strcpy(bgmeshfilename, infilename);
- strcat(bgmeshfilename, ".b");
-@@ -4188,15 +4046,18 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// del() Delete a node. //
-+// del() Delete a node containing the given pointer. //
- // //
- // Returns a pointer of the deleted data. If you try to delete a non-existed //
- // node (e.g. link is empty or a wrong index is given) return NULL. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--void* tetgenmesh::link::deletenode(void** deadnode)
-+void* tetgenmesh::link::del(void* delitem)
- {
-+ void **deadnode = (void **) ((void **) delitem - 2);
-+
-+ // now delete the nownode
- void **nextnode = (void **) *deadnode;
- void **prevnode = (void **) *(deadnode + 1);
- *prevnode = (void *) nextnode;
-@@ -4224,7 +4085,7 @@
- if (!locate(pos) || (linkitems == 0)) {
- return (void *) NULL;
- }
-- return deletenode((void **) nextlinkitem);
-+ return del((void *) ((void **) nextlinkitem + 2));
- }
-
- ///////////////////////////////////////////////////////////////////////////////
-@@ -4359,26 +4220,6 @@
- { {2, 3}, {-1, -1}, {1, 1}, {-1, -1}, {0, 5}, {-1, -1} }
- };
-
--// The edge number (from 0 to 5) of a tet is defined as follows:
--// 0 - (v0, v1), 1 - (v1, v2), 2 - (v2, v0)
--// 3 - (v3, v0), 4 - (v3, v1), 5 - (v3, v2).
--
--int tetgenmesh::locver2edge[4][6] = {
-- {0, 0, 1, 1, 2, 2},
-- {3, 3, 4, 4, 0, 0},
-- {4, 4, 5, 5, 1, 1},
-- {5, 5, 3, 3, 2, 2}
--};
--
--int tetgenmesh::edge2locver[6][2] = {
-- {0, 0}, // 0 v0 -> v1
-- {0, 2}, // 1 v1 -> v2
-- {0, 4}, // 2 v2 -> v1
-- {1, 0}, // 3 v0 -> v3
-- {1, 2}, // 4 v1 -> v3
-- {2, 2} // 5 v2 -> v3
--};
--
- //
- // End of tables initialization.
- //
-@@ -4528,67 +4369,12 @@
- // If f1 exists, return true. Otherwise, return false, i.e., f0 is a
- // boundary or hull face.
-
--inline bool tetgenmesh::fnext(triface& t1, triface& t2)
--{
-- // Get the next face.
-- t2.loc = locver2nextf[t1.loc][t1.ver][0];
-- // Is the next face in the same tet?
-- if (t2.loc != -1) {
-- // It's in the same tet. Get the edge version.
-- t2.ver = locver2nextf[t1.loc][t1.ver][1];
-- t2.tet = t1.tet;
-- } else {
-- // The next face is in the neigbhour of 't1'.
-- sym(t1, t2);
-- if (t2.tet != dummytet) {
-- // Find the corresponding edge in t2.
-- point torg;
-- int tloc, tver, i;
-- t2.ver = 0;
-- torg = org(t1);
-- for (i = 0; (i < 3) && (org(t2) != torg); i++) {
-- enextself(t2);
-- }
-- // Go to the next face in t2.
-- tloc = t2.loc;
-- tver = t2.ver;
-- t2.loc = locver2nextf[tloc][tver][0];
-- t2.ver = locver2nextf[tloc][tver][1];
-- }
-- }
-- return t2.tet != dummytet;
--}
--
--inline bool tetgenmesh::fnextself(triface& t1)
--{
-- triface t2;
--
-- // Get the next face.
-- t2.loc = locver2nextf[t1.loc][t1.ver][0];
-- // Is the next face in the same tet?
-- if (t2.loc != -1) {
-- // It's in the same tet. Get the edge version.
-- t2.ver = locver2nextf[t1.loc][t1.ver][1];
-- t1.loc = t2.loc;
-- t1.ver = t2.ver;
-- } else {
-- // The next face is in the neigbhour of 't1'.
-- sym(t1, t2);
-- if (t2.tet != dummytet) {
-- // Find the corresponding edge in t2.
-- point torg;
-- int i;
-- t2.ver = 0;
-- torg = org(t1);
-- for (i = 0; (i < 3) && (org(t2) != torg); i++) {
-- enextself(t2);
-- }
-- t1.loc = locver2nextf[t2.loc][t2.ver][0];
-- t1.ver = locver2nextf[t2.loc][t2.ver][1];
-- t1.tet = t2.tet;
-- }
-- }
-- return t2.tet != dummytet;
-+inline bool tetgenmesh::fnext(triface& t1, triface& t2) {
-+ return getnextface(&t1, &t2);
-+}
-+
-+inline bool tetgenmesh::fnextself(triface& t) {
-+ return getnextface(&t, NULL);
- }
-
- // enextfnext() and enext2fnext() are combination primitives of enext(),
-@@ -4923,32 +4709,6 @@
- //
-
- //
--// Begin of primitives for interacting between tet and subsegs.
--//
--
--inline void tetgenmesh::tsspivot1(triface& t, face& seg)
--{
-- shellface sptr = (shellface) t.tet[8 + locver2edge[t.loc][t.ver]];
-- sdecode(sptr, seg);
--}
--
--// Only bond/dissolve at tet's side, but not vice versa.
--
--inline void tetgenmesh::tssbond1(triface& t, face& seg)
--{
-- t.tet[8 + locver2edge[t.loc][t.ver]] = (tetrahedron) sencode(seg);
--}
--
--inline void tetgenmesh::tssdissolve1(triface& t)
--{
-- t.tet[8 + locver2edge[t.loc][t.ver]] = (tetrahedron) dummysh;
--}
--
--//
--// End of primitives for interacting between tet and subsegs.
--//
--
--//
- // Begin of primitives for points
- //
-
-@@ -5082,6 +4842,64 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
-+// getnextface() Get the successor of 'tface1' in the face ring. //
-+// //
-+// If 'tface1' is not a boundary (or hull) face, then its successor in the //
-+// face ring exists. The successor is returned in 'tface2' if it is not a //
-+// NULL, or the 'tface1' itself is used to return this face. On finish, the //
-+// function returns TRUE. //
-+// //
-+// If 'tface1' is a boundary (or hull) face, its successor does not exist. //
-+// This case, return FALSE and 'tface1' remains unchanged. //
-+// //
-+///////////////////////////////////////////////////////////////////////////////
-+
-+bool tetgenmesh::getnextface(triface* tface1, triface* tface2)
-+{
-+ point torg, tdest;
-+ int tloc, tver;
-+
-+ // Where the next face locates, in 'tface1' or in its neigbhour? It can be
-+ // quickly determined by checking the edge ring of 'tface1'.
-+ // if (EdgeRing(tface1->ver) == CW) {
-+ if ((tface1->ver & 01) == CW) {
-+ // The next face is in the neigbhour of 'tface1'.
-+ if (!issymexist(tface1)) {
-+ // Hit outer space - The next face does not exist.
-+ return false;
-+ }
-+ torg = org(*tface1);
-+ tdest = dest(*tface1);
-+ if (tface2) {
-+ sym(*tface1, *tface2);
-+ findedge(tface2, torg, tdest);
-+ } else {
-+ symself(*tface1);
-+ findedge(tface1, torg, tdest);
-+ }
-+ } else {
-+ // The next face is in 'tface1'.
-+ if (tface2) {
-+ *tface2 = *tface1;
-+ }
-+ }
-+
-+ if (tface2) {
-+ tloc = tface2->loc;
-+ tver = tface2->ver;
-+ tface2->loc = locver2nextf[tloc][tver][0];
-+ tface2->ver = locver2nextf[tloc][tver][1];
-+ } else {
-+ tloc = tface1->loc;
-+ tver = tface1->ver;
-+ tface1->loc = locver2nextf[tloc][tver][0];
-+ tface1->ver = locver2nextf[tloc][tver][1];
-+ }
-+ return true;
-+}
-+
-+///////////////////////////////////////////////////////////////////////////////
-+// //
- // getnextsface() Finds the next subface in the face ring. //
- // //
- // For saving space in the data structure of subface, there only exists one //
-@@ -5149,13 +4967,13 @@
- do {
- tspivot(spintet, parentsh);
- // Does spintet have a (non-fake) subface attached?
-- if ((parentsh.sh != dummysh) && (sapex(parentsh) != NULL)) {
-- // Find a subface! Find the edge in it.
-+ if (parentsh.sh != dummysh && !isdead(&parentsh)) {
-+ // Find a subface!
- findedge(&parentsh, org(*checkedge), dest(*checkedge));
- sspivot(parentsh, *checkseg);
- if (checkseg->sh != dummysh) {
- // Find a subsegment! Correct its edge direction before return.
-- if (sorg(*checkseg) != org(*checkedge)) {
-+ if (sorg(*checkseg) != sorg(parentsh)) {
- sesymself(*checkseg);
- }
- }
-@@ -5659,7 +5477,7 @@
- if (b->useshelles) {
- tmpface = *tface;
- facecount = 0;
-- while(facecount < 6) {
-+ while(facecount < 4) {
- tmpface.loc = facecount;
- tspivot(tmpface, tmpsh);
- if(tmpsh.sh != dummysh) {
-@@ -5705,6 +5523,8 @@
- if (sapex(*sface) != NULL) {
- if (shelltype(*sface) == SHARP) {
- printf(" (sharp)");
-+ } else if (shelltype(*sface) == SKINNY) {
-+ printf(" (skinny)");
- }
- } else {
- if (shelltype(*sface) == SHARP) {
-@@ -7547,72 +7367,6 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// tetaspectratio() Calculate the aspect ratio of the tetrahedron. //
--// //
--// The aspect ratio of a tet is R/h, where R is the circumradius and h is //
--// the shortest height of the tet. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--REAL tetgenmesh::tetaspectratio(point pa, point pb, point pc, point pd)
--{
-- REAL vda[3], vdb[3], vdc[3];
-- REAL N[4][3], A[4][4], rhs[4], D;
-- REAL H[4], volume, radius2, minheightinv;
-- int indx[4];
-- int i, j;
--
-- // Set the matrix A = [vda, vdb, vdc]^T.
-- for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
-- for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
-- for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
-- // Lu-decompose the matrix A.
-- lu_decmp(A, 3, indx, &D, 0);
-- // Get the volume of abcd.
-- volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
-- // Check if it is zero.
-- if (volume == 0.0) return 1.0e+200; // A degenerate tet.
-- // if (volume < 0.0) volume = -volume;
-- // Check the radiu-edge ratio of the tet.
-- rhs[0] = 0.5 * dot(vda, vda);
-- rhs[1] = 0.5 * dot(vdb, vdb);
-- rhs[2] = 0.5 * dot(vdc, vdc);
-- lu_solve(A, 3, indx, rhs, 0);
-- // Get the circumcenter.
-- // for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i];
-- // Get the square of the circumradius.
-- radius2 = dot(rhs, rhs);
--
-- // Compute the 4 face normals (N[0], ..., N[3]).
-- for (j = 0; j < 3; j++) {
-- for (i = 0; i < 3; i++) rhs[i] = 0.0;
-- rhs[j] = 1.0; // Positive means the inside direction
-- lu_solve(A, 3, indx, rhs, 0);
-- for (i = 0; i < 3; i++) N[j][i] = rhs[i];
-- }
-- // Get the fourth normal by summing up the first three.
-- for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
-- // Normalized the normals.
-- for (i = 0; i < 4; i++) {
-- // H[i] is the inverse of the height of its corresponding face.
-- H[i] = sqrt(dot(N[i], N[i]));
-- // if (H[i] > 0.0) {
-- // for (j = 0; j < 3; j++) N[i][j] /= H[i];
-- // }
-- }
-- // Get the radius of the inscribed sphere.
-- // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
-- // Get the biggest H[i] (corresponding to the smallest height).
-- minheightinv = H[0];
-- for (i = 1; i < 3; i++) {
-- if (H[i] > minheightinv) minheightinv = H[i];
-- }
--
-- return sqrt(radius2) * minheightinv;
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
- // circumsphere() Calculate the smallest circumsphere (center and radius) //
- // of the given three or four points. //
- // //
-@@ -8137,41 +7891,29 @@
- varconstraint = 1;
- }
-
-- // The index within each point at which its metric tensor is found. It is
-- // saved directly after the list of point attributes.
-- pointmtrindex = 3 + in->numberofpointattributes;
-- // Decide the size (1, 3, or 6) of the metric tensor.
-- if (b->metric) {
-- // For '-m' option. A tensor field is provided (*.mtr or *.b.mtr file).
-- if (bgm != (tetgenmesh *) NULL) {
-- // A background mesh is allocated. It may not exist though.
-- sizeoftensor = (bgm->in != (tetgenio *) NULL) ?
-- bgm->in->numberofpointmtrs : in->numberofpointmtrs;
-- } else {
-- // No given background mesh - Itself is a background mesh.
-- sizeoftensor = in->numberofpointmtrs;
-- }
-- // Make sure sizeoftensor is at least 1.
-- sizeoftensor = (sizeoftensor > 0) ? sizeoftensor : 1;
-+ // The index within each point at which its local feature size is found.
-+ // It is saved directly after the list of point attributes.
-+ if (b->bgmesh && (bgm != (tetgenmesh *) NULL)) {
-+ // A background mesh is in use. That point attributes should be the
-+ // same as that of the background mesh.
-+ pointlfsindex = 3 + bgm->in->numberofpointattributes;
- } else {
-- // For '-q' option. Make sure to have space for saving a scalar value.
-- sizeoftensor = b->quality ? 1 : 0;
-+ pointlfsindex = 3 + in->numberofpointattributes;
- }
-- // The index within each point at which an element pointer is found, where
-+ // The index within each point at which a element pointer is found, where
- // the index is measured in pointers. Ensure the index is aligned to a
- // sizeof(tetrahedron)-byte address.
-- point2simindex = ((pointmtrindex + sizeoftensor) * sizeof(REAL)
-+ point2simindex = ((pointlfsindex + b->quality) * sizeof(REAL)
- + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
- if (b->plc || b->refine) {
- // Increase the point size by three pointers, which are:
- // - a pointer to a tet, read by point2tet();
- // - a pointer to a subface/subsegment , read by point2sh();
- // - a pointer to a parent point, read by point2ppt()).
-- if (b->metric) {
-- // Increase one pointer to a tet of the background mesh.
-+ pointsize = (point2simindex + 3) * sizeof(tetrahedron);
-+ if (bgm != (tetgenmesh *) NULL) {
-+ // Increase the size by one pointer to a tet of the background mesh.
- pointsize = (point2simindex + 4) * sizeof(tetrahedron);
-- } else {
-- pointsize = (point2simindex + 3) * sizeof(tetrahedron);
- }
- // The index within each point at which a pbc point is found.
- point2pbcptindex = (pointsize + sizeof(tetrahedron) - 1)
-@@ -8199,11 +7941,7 @@
- // The number of bytes occupied by a tetrahedron. There are four pointers
- // to other tetrahedra, four pointers to corners, and possibly four
- // pointers to subfaces.
-- elesize = (8 + b->useshelles * 6) * sizeof(tetrahedron);
-- // If Voronoi diagram is wanted, make sure we have additional space.
-- if (b->voroout && (b->useshelles == 0)) {
-- elesize = (8 + 4) * sizeof(tetrahedron);
-- }
-+ elesize = (8 + b->useshelles * 4) * sizeof(tetrahedron);
- // The index within each element at which its attributes are found, where
- // the index is measured in REALs.
- elemattribindex = (elesize + sizeof(REAL) - 1) / sizeof(REAL);
-@@ -8220,15 +7958,15 @@
- elesize = volumeboundindex * sizeof(REAL);
- }
- // If element neighbor graph is requested (-n switch), an additional
-- // integer is allocated for each element.
-- elemmarkerindex = (elesize + sizeof(int) - 1) / sizeof(int);
-- if (b->neighout || b->voroout) {
-+ // integer is allocated for each element.
-+ if (b->neighout) {
-+ elemmarkerindex = (elesize + sizeof(int) - 1) / sizeof(int);
- elesize = (elemmarkerindex + 1) * sizeof(int);
- }
- // If -o2 switch is used, an additional pointer pointed to the list of
- // higher order nodes is allocated for each element.
-- highorderindex = (elesize + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
- if (b->order == 2) {
-+ highorderindex = (elesize + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
- elesize = (highorderindex + 1) * sizeof(tetrahedron);
- }
- // Having determined the memory size of an element, initialize the pool.
-@@ -8434,8 +8172,6 @@
- newtet->tet[9 ] = (tetrahedron) dummysh;
- newtet->tet[10] = (tetrahedron) dummysh;
- newtet->tet[11] = (tetrahedron) dummysh;
-- newtet->tet[12] = (tetrahedron) dummysh;
-- newtet->tet[13] = (tetrahedron) dummysh;
- }
- for (int i = 0; i < in->numberoftetrahedronattributes; i++) {
- setelemattribute(newtet->tet, i, 0.0);
-@@ -8483,7 +8219,7 @@
- // Set the boundary marker to zero.
- setshellmark(*newface, 0);
- // Set the type.
-- setshelltype(*newface, NSHARP);
-+ setshelltype(*newface, NSHARPNSKINNY);
- if (checkpbcs) {
- // Set the pbcgroup be ivalid.
- setshellpbcgroup(*newface, -1);
-@@ -8508,19 +8244,21 @@
- (*pnewpoint)[1] = 0.0;
- (*pnewpoint)[2] = 0.0;
- // Initialize the list of user-defined attributes.
-- for (i = 0; i < in->numberofpointattributes; i++) {
-- (*pnewpoint)[3 + i] = 0.0;
-- }
-- // Initialize the metric tensor.
-- for (i = 0; i < sizeoftensor; i++) {
-- (*pnewpoint)[pointmtrindex + i] = 0.0;
-+ if (bgm != (tetgenmesh *) NULL) {
-+ for (i = 0; i < bgm->in->numberofpointattributes; i++) {
-+ (*pnewpoint)[3 + i] = 0.0;
-+ }
-+ } else {
-+ for (i = 0; i < in->numberofpointattributes; i++) {
-+ (*pnewpoint)[3 + i] = 0.0;
-+ }
- }
- if (b->plc || b->refine) {
- // Initialize the point-to-simplex filed.
- setpoint2tet(*pnewpoint, NULL);
- setpoint2sh(*pnewpoint, NULL);
- setpoint2ppt(*pnewpoint, NULL);
-- if (b->metric) {
-+ if (bgm != (tetgenmesh *) NULL) {
- setpoint2bgmtet(*pnewpoint, NULL);
- }
- if (checkpbcs) {
-@@ -8531,7 +8269,7 @@
- // Initialize the point marker (starting from in->firstnumber).
- ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1);
- setpointmark(*pnewpoint, ptmark);
-- // Initialize the point type.
-+ // Initialize the point type be UNUSEDVERTEX.
- setpointtype(*pnewpoint, UNUSEDVERTEX);
- }
-
-@@ -8551,24 +8289,8 @@
-
- unsigned long tetgenmesh::randomnation(unsigned int choices)
- {
-- unsigned long newrandom;
--
-- if (choices >= 714025l) {
-- newrandom = (randomseed * 1366l + 150889l) % 714025l;
-- randomseed = (newrandom * 1366l + 150889l) % 714025l;
-- newrandom = newrandom * (choices / 714025l) + randomseed;
-- if (newrandom >= choices) {
-- return newrandom - choices;
-- } else {
-- return newrandom;
-- }
-- } else {
-- randomseed = (randomseed * 1366l + 150889l) % 714025l;
-- return randomseed % choices;
-- }
-- // Old function.
-- // randomseed = (randomseed * 1366l + 150889l) % 714025l;
-- // return randomseed / (714025l / choices + 1);
-+ randomseed = (randomseed * 1366l + 150889l) % 714025l;
-+ return randomseed / (714025l / choices + 1);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
-@@ -8641,12 +8363,8 @@
- }
- // 'searchtet' should be a valid tetrahedron now.
- #ifdef SELF_CHECK
-- // assert(!isdead(searchtet) && (searchtet->tet != dummytet));
-+ assert(!isdead(searchtet) && (searchtet->tet != dummytet));
- #endif
-- if (isdead(searchtet)) {
-- printf("Warning: Point location failed.\n");
-- return OUTSIDE;
-- }
-
- searchtet->ver = 0; // Keep in CCW edge ring.
- // Find a face of 'searchtet' such that the 'searchpt' lies strictly
-@@ -8781,8 +8499,8 @@
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--enum tetgenmesh::locateresult tetgenmesh::locate(point searchpt,
-- triface *searchtet)
-+enum tetgenmesh::locateresult tetgenmesh::
-+locate(point searchpt, triface *searchtet)
- {
- tetrahedron *firsttet, *tetptr;
- void **sampleblock;
-@@ -8801,12 +8519,8 @@
- symself(*searchtet);
- }
- #ifdef SELF_CHECK
-- // assert(!isdead(searchtet));
-+ assert(!isdead(searchtet));
- #endif
-- if (isdead(searchtet)) {
-- printf("Warning: Point location failed.\n");
-- return OUTSIDE;
-- }
-
- // Get the distance from the suggested starting tet to the point we seek.
- searchdist = distance2(searchtet->tet, searchpt);
-@@ -8888,8 +8602,9 @@
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--enum tetgenmesh::locateresult tetgenmesh::adjustlocate(point searchpt,
-- triface* searchtet, enum locateresult precise, REAL epspp)
-+enum tetgenmesh::locateresult tetgenmesh::
-+adjustlocate(point searchpt, triface* searchtet, enum locateresult precise,
-+ REAL epspp)
- {
- point torg, tdest, tapex, toppo;
- REAL s1, s2, s3, s4;
-@@ -9040,77 +8755,6 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// hullwalk() Find a tetrahedron on the hull to continue search. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--enum tetgenmesh::locateresult tetgenmesh::hullwalk(point searchpt,
-- triface *hulltet)
--{
-- list* travtetlist;
-- triface travtet, neightet;
-- point pa, pb, pc;
-- enum locateresult loc;
-- REAL ori;
-- int i;
--
-- travtetlist = new list(sizeof(triface), NULL, 256);
-- travtet = *hulltet;
-- infect(travtet);
-- travtetlist->append(&travtet);
--
-- loc = OUTSIDE;
-- for (i = 0; i < travtetlist->len(); i++) {
-- travtet = * (triface *)(* travtetlist)[i];
-- // Choose the CCW-edgering in face.
-- travtet.ver = 0;
-- // Look for a side where pt lies below it.
-- for (travtet.loc = 0; travtet.loc < 4; travtet.loc++) {
-- pa = org(travtet);
-- pb = dest(travtet);
-- pc = apex(travtet);
-- ori = orient3d(pa, pb, pc, searchpt);
-- if (ori > 0.0) break;
-- }
-- // Is pt above all (or coplanar with some of) the four sides?
-- if (travtet.loc == 4) {
-- hulltet->tet = travtet.tet;
-- loc = adjustlocate(searchpt, hulltet, INTETRAHEDRON, b->epsilon);
-- assert(loc != OUTSIDE);
-- } else { // ori > 0.0
-- // pt is below (behind) this side. We want to walk through it.
-- sym(travtet, neightet);
-- if (neightet.tet == dummytet) {
-- // This is a hull side. Is p approximately on this side.
-- loc = adjustlocate(searchpt, &travtet, OUTSIDE, b->epsilon);
-- }
-- if (loc == OUTSIDE) {
-- // Let's collect all the neighbors for next searching.
-- for (travtet.loc = 0; travtet.loc < 4; travtet.loc++) {
-- sym(travtet, neightet);
-- if ((neightet.tet != dummytet) && !infected(neightet)) {
-- // Neighbor exists and not visited.
-- infect(neightet);
-- travtetlist->append(&neightet);
-- }
-- } // for (travtet.loc = 0;
-- } // if (loc == OUTSIDE)
-- } // if (travtet.loc == 4)
-- if (loc != OUTSIDE) break;
-- } // for (i = 0; i < travtetlist->len(); i++)
--
-- // Uninfect traversed tets.
-- for (i = 0; i < travtetlist->len(); i++) {
-- travtet = * (triface *)(* travtetlist)[i];
-- uninfect(travtet);
-- }
--
-- delete travtetlist;
-- return loc;
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
- // locatesub() Find a point in the surface mesh of a facet. //
- // //
- // Searching begins from the input 'searchsh', it should be a handle on the //
-@@ -9535,21 +9179,26 @@
- // //
- // categorizeface() Determine the flip type of a given face. //
- // //
--// On input, 'horiz' represents the face abc we want to flip (imagine it is //
--// parallel to the horizon). Let the tet above it be abcd. //
-+// On input, 'horiz' represents the face we want to flip (you can imagine it //
-+// is parallel to the horizon). Let the tetrahedron above it be abcd, where //
-+// abc is 'horiz'. //
- // //
- // This routine determines the suitable type of flip operation for 'horiz'. //
- // - Returns T23 if a 2-to-3 flip is applicable. 'horiz' is same as input. //
--// - Returns T32 if a 3-to-2 flip is applicable. 'horiz' returns the edge //
--// of abc which is the flipable. //
--// - Returns T22 if a 2-to-2 or 4-to-4 flip is applicable. 'horiz' returns //
--// the edge of abc which is flipable. //
--// - Returns N32 indicates it is unflipable due to the absence of a tet. //
--// 'horize' returns the unflipable edge. //
--// - Returns N40 indicates it is unflipable and is locally Delaunay. //
--// - Returns FORBIDDENFACE indicates abc is a subface. //
--// - Returns FORBIDDENEDGE indicates the flipable edge of abc is a segment.//
--// 'horize' returns the flipable edge. //
-+// - Returns T32 if a 3-to-2 flip is applicable. 'horiz' is adjusted so //
-+// that the primary edge of 'horiz' is the flipable edge. //
-+// - Returns T22 if a 2-to-2 or 4-to-4 flip is applicable. 'horiz' is //
-+// adjusted so that the primary edge of 'horiz' is the flipable edge. //
-+// - Returns FORBIDDENFACE indicates although a 2-to-3 flip is applicable, //
-+// but it is a subface and should not be flipped away. //
-+// - Returns FORBIDDENEDGE indicates although a 3-to-2, or 2-to-2, or //
-+// 4-to-4 flip is applicable, but the flipable edge is a subsegment and //
-+// should not be flipped away. 'horiz' is adjusted so that the primary //
-+// edge of 'horiz' is the flipable edge. //
-+// - Returns UNFLIPABLE indicates it is unflipable due to the absence of //
-+// a tetrahedron. 'horiz' is adjusted so that the primary edge of 'horiz'//
-+// is the unflipable edge. Possibly, It is a subsegment. //
-+// - Returns NONCONVEX indicates it is unflipable and is locally Delaunay. //
- // //
- // Given a face abc, with two adjoining tetrahedra abcd and bace. If abc is //
- // flipable, i.e., T23, T32, T22 or T44, its flip type can be determined by //
-@@ -9575,7 +9224,7 @@
- sym(horiz, symhoriz);
- if (symhoriz.tet == dummytet) {
- // A hull face is unflipable and locally Delaunay.
-- return N40;
-+ return NONCONVEX;
- }
-
- adjustedgering(horiz, CCW);
-@@ -9660,7 +9309,7 @@
- return FORBIDDENEDGE;
- }
- }
-- return N32;
-+ return UNFLIPABLE;
- }
- ori2 = orient3d(pb, pc, pd, pe);
- if (checksubfaces && ori2 != 0.0) {
-@@ -9707,7 +9356,7 @@
- return FORBIDDENEDGE;
- }
- }
-- return N32;
-+ return UNFLIPABLE;
- }
- ori3 = orient3d(pc, pa, pd, pe);
- if (checksubfaces && ori3 != 0.0) {
-@@ -9757,7 +9406,7 @@
- return FORBIDDENEDGE;
- }
- }
-- return N32;
-+ return UNFLIPABLE;
- }
- if (ori1 == 0.0) {
- // e is coplanar with abd.
-@@ -9766,7 +9415,7 @@
- // assert(!(ori2 == 0.0 && ori3 == 0.0));
- // Three points (d, e, and a or b) are collinear, abc is unflipable
- // and locally Delaunay.
-- return N40;
-+ return NONCONVEX;
- }
- } else if (ori2 == 0.0) {
- // e is coplanar with bcd.
-@@ -9775,7 +9424,7 @@
- // assert(!(ori1 == 0.0 && ori3 == 0.0));
- // Three points (d, e, and b or c) are collinear, abc is unflipable
- // and locally Delaunay.
-- return N40;
-+ return NONCONVEX;
- }
- // Adjust 'horiz' and 'symhoriz' be the edge bc.
- enextself(horiz);
-@@ -9787,7 +9436,7 @@
- // assert(!(ori1 == 0.0 && ori2 == 0.0));
- // Three points (d, e, and c or a) are collinear, abc is unflipable
- // and locally Delaunay.
-- return N40;
-+ return NONCONVEX;
- }
- // Adjust 'horiz' and 'symhoriz' be the edge ca.
- enext2self(horiz);
-@@ -9840,14 +9489,14 @@
- pc = apex(horiz);
- // Be careful not to create an inverted tetrahedron. Check the case.
- ori1 = orient3d(pc, pd, pe, pa);
-- if (ori1 <= 0) return N40;
-+ if (ori1 <= 0) return NONCONVEX;
- ori1 = orient3d(pd, pc, pe, pb);
-- if (ori1 <= 0) return N40;
-+ if (ori1 <= 0) return NONCONVEX;
- if (pf != (point) NULL) {
- ori1 = orient3d(pd, pf, pe, pa);
-- if (ori1 <= 0) return N40;
-+ if (ori1 <= 0) return NONCONVEX;
- ori1 = orient3d(pf, pd, pe, pb);
-- if (ori1 <= 0) return N40;
-+ if (ori1 <= 0) return NONCONVEX;
- }
- }
- if (pf == (point) NULL) {
-@@ -9862,7 +9511,7 @@
- }
- } else {
- // ab has more than four faces around it, unflipable.
-- return N32;
-+ return UNFLIPABLE;
- }
- } else if (adjtet == 1) {
- // One of its three edges is locally non-convex. Type T32 is possible.
-@@ -9917,7 +9566,7 @@
- }
- if (ori1 <= 0.0) {
- // a lies above or is coplanar cde, abc is locally Delaunay.
-- return N40;
-+ return NONCONVEX;
- }
- ori2 = orient3d(pd, pc, pe, pb);
- if (checksubfaces && ori2 != 0.0) {
-@@ -9948,7 +9597,7 @@
- }
- if (ori2 <= 0.0) {
- // b lies above dce, unflipable, and abc is locally Delaunay.
-- return N40;
-+ return NONCONVEX;
- }
- // Edge ab crosses face cde properly.
- if (checksubfaces) {
-@@ -9973,14 +9622,14 @@
- printf("Warning: A tetrahedron spans two subfaces of a facet.\n");
- }
- // Temporarily, let it be there.
-- return N32;
-+ return UNFLIPABLE;
- }
- }
- return T32;
- } else {
- // The convex hull of {a, b, c, d, e} has only four vertices, abc is
- // unflipable, furthermore, it is locally Delaunay.
-- return N40;
-+ return NONCONVEX;
- }
- }
-
-@@ -9998,14 +9647,12 @@
- void tetgenmesh::enqueueflipface(triface& checkface, queue* flipqueue)
- {
- badface *queface;
-- triface symface;
-
-- sym(checkface, symface);
-- if (symface.tet != dummytet) {
-- queface = (badface *) flipqueue->push((void *) NULL);
-- queface->tt = checkface;
-- queface->foppo = oppo(symface);
-- }
-+ queface = (badface *) flipqueue->push((void *) NULL);
-+ queface->tt = checkface;
-+ queface->forg = org(checkface);
-+ queface->fdest = dest(checkface);
-+ queface->fapex = apex(checkface);
- }
-
- void tetgenmesh::enqueueflipedge(face& checkedge, queue* flipqueue)
-@@ -10039,14 +9686,10 @@
- triface abcd, bace; // Old configuration.
- triface oldabd, oldbcd, oldcad;
- triface abdcasing, bcdcasing, cadcasing;
-+ face abdsh, bcdsh, cadsh;
- triface oldbae, oldcbe, oldace;
- triface baecasing, cbecasing, acecasing;
-- triface worktet;
-- face abdsh, bcdsh, cadsh; // The six subfaces on the CH.
- face baesh, cbesh, acesh;
-- face abseg, bcseg, caseg; // The nine segs on the CH.
-- face adseg, bdseg, cdseg;
-- face aeseg, beseg, ceseg;
- triface edab, edbc, edca; // New configuration.
- point pa, pb, pc, pd, pe;
- REAL attrib, volume;
-@@ -10054,25 +9697,27 @@
-
- abcd = *flipface;
- adjustedgering(abcd, CCW); // abcd represents edge ab.
-+ sym(abcd, bace);
-+ findedge(&bace, dest(abcd), org(abcd)); // bace represents edge ba.
- pa = org(abcd);
- pb = dest(abcd);
- pc = apex(abcd);
- pd = oppo(abcd);
-- // sym(abcd, bace);
-- // findedge(&bace, dest(abcd), org(abcd)); // bace represents edge ba.
-- sym(abcd, bace);
-- bace.ver = 0; // CCW.
-- for (i = 0; (i < 3) && (org(bace) != pb); i++) {
-- enextself(bace);
-- }
- pe = oppo(bace);
-
- if (b->verbose > 2) {
-- printf(" Do T23 on face (%d, %d, %d) %d, %d.\n", pointmark(pa),
-- pointmark(pb), pointmark(pc), pointmark(pd), pointmark(pe));
-+ printf(" Do T23 on face (%d, %d, %d, %d).\n", pointmark(pa),
-+ pointmark(pb), pointmark(pc), pointmark(pd));
- }
- flip23s++;
-
-+#ifdef SELF_CHECK
-+ // Edge de must cross face abc properly.
-+ assert(orient3d(pa, pb, pd, pe) >= 0.0);
-+ assert(orient3d(pb, pc, pd, pe) >= 0.0);
-+ assert(orient3d(pc, pa, pd, pe) >= 0.0);
-+#endif
-+
- // Storing the old configuration outside the convex hull.
- fnext(abcd, oldabd);
- enextfnext(abcd, oldbcd);
-@@ -10093,24 +9738,6 @@
- tspivot(oldbae, baesh);
- tspivot(oldcbe, cbesh);
- tspivot(oldace, acesh);
-- } else if (checksubsegs) {
-- tsspivot1(abcd, abseg);
-- enext(abcd, worktet);
-- tsspivot1(worktet, bcseg);
-- enext2(abcd, worktet);
-- tsspivot1(worktet, caseg);
-- enext2(oldabd, worktet);
-- tsspivot1(worktet, adseg);
-- enext2(oldbcd, worktet);
-- tsspivot1(worktet, bdseg);
-- enext2(oldcad, worktet);
-- tsspivot1(worktet, cdseg);
-- enext(oldbae, worktet);
-- tsspivot1(worktet, aeseg);
-- enext(oldcbe, worktet);
-- tsspivot1(worktet, beseg);
-- enext(oldace, worktet);
-- tsspivot1(worktet, ceseg);
- }
-
- // Creating the new configuration inside the convex hull.
-@@ -10144,10 +9771,10 @@
-
- // Clear old bonds in edab(was abcd) and edbc(was bace).
- for (i = 0; i < 4; i ++) {
-- edab.tet[i] = (tetrahedron) dummytet;
-- }
-- for (i = 0; i < 4; i ++) {
-- edbc.tet[i] = (tetrahedron) dummytet;
-+ edab.loc = i;
-+ dissolve(edab);
-+ edbc.loc = i;
-+ dissolve(edbc);
- }
- // Bond the faces inside the convex hull.
- edab.loc = 0;
-@@ -10171,7 +9798,7 @@
- edca.loc = 2;
- bond(edca, cadcasing);
- edca.loc = 3;
-- bond(edca, acecasing);
-+ bond(edca, acecasing);
- // There may exist subfaces that need to be bonded to new configuarton.
- if (checksubfaces) {
- // Clear old flags in edab(was abcd) and edbc(was bace).
-@@ -10205,55 +9832,6 @@
- edca.loc = 3;
- tsbond(edca, acesh);
- }
-- } else if (checksubsegs) {
-- for (i = 0; i < 6; i++) {
-- edab.tet[8 + i] = (tetrahedron) dummysh;
-- }
-- for (i = 0; i < 6; i++) {
-- edbc.tet[8 + i] = (tetrahedron) dummysh;
-- }
-- edab.loc = edab.ver = 0;
-- edbc.loc = edab.ver = 0;
-- edca.loc = edab.ver = 0;
-- // Operate in tet edab (5 edges).
-- enext(edab, worktet);
-- tssbond1(worktet, adseg);
-- enext2(edab, worktet);
-- tssbond1(worktet, aeseg);
-- fnext(edab, worktet);
-- enextself(worktet);
-- tssbond1(worktet, bdseg);
-- enextself(worktet);
-- tssbond1(worktet, beseg);
-- enextfnext(edab, worktet);
-- enextself(worktet);
-- tssbond1(worktet, abseg);
-- // Operate in tet edbc (5 edges)
-- enext(edbc, worktet);
-- tssbond1(worktet, bdseg);
-- enext2(edbc, worktet);
-- tssbond1(worktet, beseg);
-- fnext(edbc, worktet);
-- enextself(worktet);
-- tssbond1(worktet, cdseg);
-- enextself(worktet);
-- tssbond1(worktet, ceseg);
-- enextfnext(edbc, worktet);
-- enextself(worktet);
-- tssbond1(worktet, bcseg);
-- // Operate in tet edca (5 edges)
-- enext(edca, worktet);
-- tssbond1(worktet, cdseg);
-- enext2(edca, worktet);
-- tssbond1(worktet, ceseg);
-- fnext(edca, worktet);
-- enextself(worktet);
-- tssbond1(worktet, adseg);
-- enextself(worktet);
-- tssbond1(worktet, aeseg);
-- enextfnext(edca, worktet);
-- enextself(worktet);
-- tssbond1(worktet, caseg);
- }
-
- edab.loc = 0;
-@@ -10311,44 +9889,40 @@
- triface edab, edbc, edca; // Old configuration.
- triface oldabd, oldbcd, oldcad;
- triface abdcasing, bcdcasing, cadcasing;
-+ face abdsh, bcdsh, cadsh;
- triface oldbae, oldcbe, oldace;
- triface baecasing, cbecasing, acecasing;
-- triface worktet;
-- face abdsh, bcdsh, cadsh;
- face baesh, cbesh, acesh;
-- face abseg, bcseg, caseg; // The nine segs on the CH.
-- face adseg, bdseg, cdseg;
-- face aeseg, beseg, ceseg;
- triface abcd, bace; // New configuration.
- point pa, pb, pc, pd, pe;
- int i;
-
- edab = *flipface;
- adjustedgering(edab, CCW);
-- pa = apex(edab);
-- pb = oppo(edab);
-- pd = dest(edab);
-- pe = org(edab);
- fnext(edab, edbc);
- symself(edbc);
-- edbc.ver = 0;
-- for (i = 0; (i < 3) && (org(edbc) != pe); i++) {
-- enextself(edbc);
-- }
-- pc = oppo(edbc);
-+ findedge(&edbc, org(edab), dest(edab));
- fnext(edbc, edca);
- symself(edca);
-- edca.ver = 0;
-- for (i = 0; (i < 3) && (org(edca) != pe); i++) {
-- enextself(edca);
-- }
-+ findedge(&edca, org(edab), dest(edab));
-+ pa = apex(edab);
-+ pb = oppo(edab);
-+ pc = oppo(edbc);
-+ pd = dest(edab);
-+ pe = org(edab);
-
- if (b->verbose > 2) {
-- printf(" Do T32 on edge (%d, %d) %d, %d, %d.\n", pointmark(pe),
-- pointmark(pd), pointmark(pa), pointmark(pb), pointmark(pc));
-+ printf(" Do T32 on face (%d, %d, %d, %d).\n",
-+ pointmark(pe), pointmark(pd), pointmark(pa), pointmark(pb));
- }
- flip32s++;
-
-+#ifdef SELF_CHECK
-+ // Edge de must cross face abc properly.
-+ // assert(orient3d(pa, pb, pc, pd) <= 0.0);
-+ // assert(orient3d(pb, pa, pc, pe) <= 0.0);
-+#endif
-+
- // Storing the old configuration outside the convex hull.
- enextfnext(edab, oldabd);
- enext2fnext(edab, oldbae);
-@@ -10369,28 +9943,6 @@
- tspivot(oldbae, baesh);
- tspivot(oldcbe, cbesh);
- tspivot(oldace, acesh);
-- } else if (checksubsegs) {
-- enext(edab, worktet);
-- tsspivot1(worktet, adseg);
-- enext2(edab, worktet);
-- tsspivot1(worktet, aeseg);
-- enext(edbc, worktet);
-- tsspivot1(worktet, bdseg);
-- enext2(edbc, worktet);
-- tsspivot1(worktet, beseg);
-- enext(edca, worktet);
-- tsspivot1(worktet, cdseg);
-- enext2(edca, worktet);
-- tsspivot1(worktet, ceseg);
-- enextfnext(edab, worktet);
-- enextself(worktet);
-- tsspivot1(worktet, abseg);
-- enextfnext(edbc, worktet);
-- enextself(worktet);
-- tsspivot1(worktet, bcseg);
-- enextfnext(edca, worktet);
-- enextself(worktet);
-- tsspivot1(worktet, caseg);
- }
-
- // Creating the new configuration inside the convex hull.
-@@ -10409,10 +9961,10 @@
-
- // Clear the old bonds in abcd (was edab) and bace (was edbc).
- for (i = 0; i < 4; i ++) {
-- abcd.tet[i] = (tetrahedron) dummytet;
-- }
-- for (i = 0; i < 4; i ++) {
-- bace.tet[i] = (tetrahedron) dummytet;
-+ abcd.loc = i;
-+ dissolve(abcd);
-+ bace.loc = i;
-+ dissolve(bace);
- }
- // Bond the inside face of the convex hull.
- abcd.loc = 0;
-@@ -10434,72 +9986,35 @@
- if (checksubfaces) {
- // Clear old bonds in abcd(was edab) and bace(was edbc).
- for (i = 0; i < 4; i ++) {
-- abcd.tet[8 + i] = (tetrahedron) dummysh;
-- }
-- for (i = 0; i < 4; i ++) {
-- bace.tet[8 + i] = (tetrahedron) dummysh;
-+ abcd.loc = i;
-+ tsdissolve(abcd);
-+ bace.loc = i;
-+ tsdissolve(bace);
- }
- if (abdsh.sh != dummysh) {
- abcd.loc = 1;
- tsbond(abcd, abdsh);
- }
-- if (bcdsh.sh != dummysh) {
-- abcd.loc = 2;
-- tsbond(abcd, bcdsh);
-- }
-- if (cadsh.sh != dummysh) {
-- abcd.loc = 3;
-- tsbond(abcd, cadsh);
-- }
- if (baesh.sh != dummysh) {
- bace.loc = 1;
- tsbond(bace, baesh);
- }
-+ if (bcdsh.sh != dummysh) {
-+ abcd.loc = 2;
-+ tsbond(abcd, bcdsh);
-+ }
- if (cbesh.sh != dummysh) {
- bace.loc = 3;
- tsbond(bace, cbesh);
- }
-+ if (cadsh.sh != dummysh) {
-+ abcd.loc = 3;
-+ tsbond(abcd, cadsh);
-+ }
- if (acesh.sh != dummysh) {
- bace.loc = 2;
- tsbond(bace, acesh);
- }
-- } else if (checksubsegs) {
-- for (i = 0; i < 6; i++) {
-- abcd.tet[8 + i] = (tetrahedron) dummysh;
-- }
-- for (i = 0; i < 6; i++) {
-- bace.tet[8 + i] = (tetrahedron) dummysh;
-- }
-- abcd.loc = abcd.ver = 0;
-- bace.loc = bace.ver = 0;
-- tssbond1(abcd, abseg); // 1
-- enext(abcd, worktet);
-- tssbond1(worktet, bcseg); // 2
-- enext2(abcd, worktet);
-- tssbond1(worktet, caseg); // 3
-- fnext(abcd, worktet);
-- enext2self(worktet);
-- tssbond1(worktet, adseg); // 4
-- enextfnext(abcd, worktet);
-- enext2self(worktet);
-- tssbond1(worktet, bdseg); // 5
-- enext2fnext(abcd, worktet);
-- enext2self(worktet);
-- tssbond1(worktet, cdseg); // 6
-- tssbond1(bace, abseg);
-- enext2(bace, worktet);
-- tssbond1(worktet, bcseg);
-- enext(bace, worktet);
-- tssbond1(worktet, caseg);
-- fnext(bace, worktet);
-- enextself(worktet);
-- tssbond1(worktet, aeseg); // 7
-- enext2fnext(bace, worktet);
-- enextself(worktet);
-- tssbond1(worktet, beseg); // 8
-- enextfnext(bace, worktet);
-- enextself(worktet);
-- tssbond1(worktet, ceseg); // 9
- }
-
- abcd.loc = 0;
-@@ -10569,14 +10084,10 @@
- triface bacf, abdf;
- triface oldacf, oldcbf, oldbdf, olddaf;
- triface acfcasing, cbfcasing, bdfcasing, dafcasing;
-- triface worktet;
- face acfsh, cbfsh, bdfsh, dafsh;
- face abc, bad;
-- face adseg, dbseg, bcseg, caseg; // Coplanar segs.
-- face aeseg, deseg, beseg, ceseg; // Above segs.
-- face afseg, dfseg, bfseg, cfseg; // Below segs.
- point pa, pb, pc, pd, pe, pf;
-- int mirrorflag, i;
-+ int mirrorflag;
-
- adjustedgering(*flipface, CCW); // 'flipface' is bae.
- fnext(*flipface, abce);
-@@ -10598,20 +10109,12 @@
- sym(abce, bacf);
- mirrorflag = bacf.tet != dummytet;
- if (mirrorflag) {
-- // findedge(&bacf, pb, pa);
-- bacf.ver = 0;
-- for (i = 0; (i < 3) && (org(bacf) != pb); i++) {
-- enextself(bacf);
-- }
-+ findedge(&bacf, pb, pa);
- sym(bade, abdf);
- #ifdef SELF_CHECK
- assert(abdf.tet != dummytet);
- #endif
-- // findedge(&abdf, pa, pb);
-- abdf.ver = 0;
-- for (i = 0; (i < 3) && (org(abdf) != pa); i++) {
-- enextself(abdf);
-- }
-+ findedge(&abdf, pa, pb);
- pf = oppo(bacf);
- #ifdef SELF_CHECK
- assert(oppo(abdf) == pf);
-@@ -10624,6 +10127,12 @@
- }
- mirrorflag ? flip44s++ : flip22s++;
-
-+#ifdef SELF_CHECK
-+ // The quadrilateral formed by a, b, c, and d must be convex.
-+ assert(orient3d(pc, pd, pe, pa) <= 0.0);
-+ assert(orient3d(pd, pc, pe, pb) <= 0.0);
-+#endif
-+
- // Save the old configuration at the convex hull.
- enextfnext(abce, oldbce);
- enext2fnext(abce, oldcae);
-@@ -10640,29 +10149,6 @@
- tspivot(olddbe, dbesh);
- tspivot(abce, abc);
- tspivot(bade, bad);
-- } else if (checksubsegs) {
-- // Coplanar segs: a->d->b->c.
-- enext(bade, worktet);
-- tsspivot1(worktet, adseg);
-- enext2(bade, worktet);
-- tsspivot1(worktet, dbseg);
-- enext(abce, worktet);
-- tsspivot1(worktet, bcseg);
-- enext2(abce, worktet);
-- tsspivot1(worktet, caseg);
-- // Above segs: a->e, d->e, b->e, c->e.
-- fnext(bade, worktet);
-- enextself(worktet);
-- tsspivot1(worktet, aeseg);
-- enextfnext(bade, worktet);
-- enextself(worktet);
-- tsspivot1(worktet, deseg);
-- enext2fnext(bade, worktet);
-- enextself(worktet);
-- tsspivot1(worktet, beseg);
-- enextfnext(abce, worktet);
-- enextself(worktet);
-- tsspivot1(worktet, ceseg);
- }
- if (mirrorflag) {
- enextfnext(bacf, oldacf);
-@@ -10678,20 +10164,6 @@
- tspivot(oldcbf, cbfsh);
- tspivot(oldbdf, bdfsh);
- tspivot(olddaf, dafsh);
-- } else if (checksubsegs) {
-- // Below segs: a->f, d->f, b->f, c->f.
-- fnext(abdf, worktet);
-- enext2self(worktet);
-- tsspivot1(worktet, afseg);
-- enext2fnext(abdf, worktet);
-- enext2self(worktet);
-- tsspivot1(worktet, dfseg);
-- enextfnext(abdf, worktet);
-- enext2self(worktet);
-- tsspivot1(worktet, bfseg);
-- enextfnext(bacf, worktet);
-- enextself(worktet);
-- tsspivot1(worktet, cfseg);
- }
- }
-
-@@ -10722,75 +10194,6 @@
- } else {
- tsbond(olddbe, bcesh);
- }
-- } else if (checksubsegs) {
-- // 5 edges in abce are changed.
-- enext(abce, worktet); // fit b->c into c->a.
-- if (caseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, caseg);
-- }
-- enext2(abce, worktet); // fit c->a into a->d.
-- if (adseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, adseg);
-- }
-- fnext(abce, worktet); // fit b->e into c->e.
-- enextself(worktet);
-- if (ceseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, ceseg);
-- }
-- enextfnext(abce, worktet); // fit c->e into a->e.
-- enextself(worktet);
-- if (aeseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, aeseg);
-- }
-- enext2fnext(abce, worktet); // fit a->e into d->e.
-- enextself(worktet);
-- if (deseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, deseg);
-- }
-- // 5 edges in bade are changed.
-- enext(bade, worktet); // fit a->d into d->b.
-- if (dbseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, dbseg);
-- }
-- enext2(bade, worktet); // fit d->b into b->c.
-- if (bcseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, bcseg);
-- }
-- fnext(bade, worktet); // fit a->e into d->e.
-- enextself(worktet);
-- if (deseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, deseg);
-- }
-- enextfnext(bade, worktet); // fit d->e into b->e.
-- enextself(worktet);
-- if (beseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, beseg);
-- }
-- enext2fnext(bade, worktet); // fit b->e into c->e.
-- enextself(worktet);
-- if (ceseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, ceseg);
-- }
- }
- if (mirrorflag) {
- // Rotate bacf, abdf one-quarter turn counterclockwise.
-@@ -10820,75 +10223,6 @@
- } else {
- tsbond(oldbdf, cbfsh);
- }
-- } else if (checksubsegs) {
-- // 5 edges in bacf are changed.
-- enext2(bacf, worktet); // fit b->c into c->a.
-- if (caseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, caseg);
-- }
-- enext(bacf, worktet); // fit c->a into a->d.
-- if (adseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, adseg);
-- }
-- fnext(bacf, worktet); // fit b->f into c->f.
-- enext2self(worktet);
-- if (cfseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, cfseg);
-- }
-- enext2fnext(bacf, worktet); // fit c->f into a->f.
-- enext2self(worktet);
-- if (afseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, afseg);
-- }
-- enextfnext(bacf, worktet); // fit a->f into d->f.
-- enext2self(worktet);
-- if (dfseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, dfseg);
-- }
-- // 5 edges in abdf are changed.
-- enext2(abdf, worktet); // fit a->d into d->b.
-- if (dbseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, dbseg);
-- }
-- enext(abdf, worktet); // fit d->b into b->c.
-- if (bcseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, bcseg);
-- }
-- fnext(abdf, worktet); // fit a->f into d->f.
-- enext2self(worktet);
-- if (dfseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, dfseg);
-- }
-- enext2fnext(abdf, worktet); // fit d->f into b->f.
-- enext2self(worktet);
-- if (bfseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, bfseg);
-- }
-- enextfnext(abdf, worktet); // fit b->f into c->f.
-- enext2self(worktet);
-- if (cfseg.sh == dummysh) {
-- tssdissolve1(worktet);
-- } else {
-- tssbond1(worktet, cfseg);
-- }
- }
- }
-
-@@ -11219,10 +10553,15 @@
- while (!flipqueue->empty()) {
- qface = (badface *) flipqueue->pop();
- flipface = qface->tt;
-- if (isdead(&flipface)) continue;
-+ // Check the validity of this face.
-+ if (isdead(&flipface) || flipface.tet == dummytet ||
-+ (org(flipface) != qface->forg) ||
-+ (dest(flipface) != qface->fdest) ||
-+ (apex(flipface) != qface->fapex) ||
-+ (oppo(flipface) == (point) NULL)) continue;
- sym(flipface, symface);
- // Only do check when the adjacent tet exists and it's not a "fake" tet.
-- if ((symface.tet != dummytet) && (oppo(symface) == qface->foppo)) {
-+ if (symface.tet != dummytet && oppo(symface) != (point) NULL) {
- // For positive orientation that insphere() test requires.
- adjustedgering(flipface, CW);
- pa = org(flipface);
-@@ -11230,7 +10569,7 @@
- pc = apex(flipface);
- pd = oppo(flipface);
- pe = oppo(symface);
-- if (symbolic) {
-+ // if (symbolic) {
- ia = pointmark(pa);
- ib = pointmark(pb);
- ic = pointmark(pc);
-@@ -11238,9 +10577,9 @@
- ie = pointmark(pe);
- sign = insphere_sos(pa, pb, pc, pd, pe, ia, ib, ic, id, ie);
- assert(sign != 0.0);
-- } else {
-- sign = insphere(pa, pb, pc, pd, pe);
-- }
-+ // } else {
-+ // sign = insphere(pa, pb, pc, pd, pe);
-+ // }
- } else {
- sign = -1.0; // A hull face is locally Delaunay.
- }
-@@ -11252,7 +10591,7 @@
- epscount = 0;
- while (epscount < 32) {
- fc = categorizeface(flipface);
-- if (fc == N40) {
-+ if (fc == NONCONVEX) {
- b->epsilon *= 1e-1;
- epscount++;
- continue;
-@@ -11264,12 +10603,12 @@
- if (b->verbose > 0) {
- printf("Warning: Can't flip a degenerate tetrahedron.\n");
- }
-- fc = N40;
-+ fc = NONCONVEX;
- }
- } else {
- fc = categorizeface(flipface);
- #ifdef SELF_CHECK
-- assert(fc != N40);
-+ assert(fc != NONCONVEX);
- #endif
- }
- switch (fc) {
-@@ -11285,14 +10624,14 @@
- flip32(&flipface, flipqueue);
- break;
- // The following face types are unflipable.
-- case N32:
-+ case UNFLIPABLE:
- break;
- case FORBIDDENFACE:
- break;
- case FORBIDDENEDGE:
- break;
- // This case is only possible when the domain is nonconvex.
-- case N40:
-+ case NONCONVEX:
- // assert(nonconvex);
- break;
- }
-@@ -11322,233 +10661,6 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// lawson() Flip locally non-Delaunay faces by Lawson's algorithm. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--long tetgenmesh::lawson(list *misseglist, queue* flipqueue)
--{
-- badface *qface, *misseg;
-- triface flipface, symface;
-- triface starttet, spintet;
-- face checksh, checkseg;
-- point pa, pb, pc, pd, pe;
-- point swappt;
-- REAL sign, ori;
-- long flipcount;
-- int ia, ib, ic, id, ie;
-- int hitbdry, i;
--
-- if (b->verbose > 1) {
-- printf(" Do flipface queue: %ld faces.\n", flipqueue->len());
-- }
-- flipcount = flip23s + flip32s + flip22s + flip44s;
--
-- // Go through the stack of possible flips and decide whether to do them.
-- // Note that during the loop new possible flips will be pushed onto
-- // this stack, while they popped in this loop.
-- while (!flipqueue->empty()) {
-- qface = (badface *) flipqueue->pop();
-- flipface = qface->tt;
-- // Check if tet has already been flipped out of existence.
-- if (!isdead(&flipface)) {
-- sym(flipface, symface);
-- // Check if this tet is the same as the one which was stacked.
-- if ((symface.tet != dummytet) && (oppo(symface) == qface->foppo)) {
-- flipface.ver = 0; // Select the CCW ring.
-- pa = org(flipface);
-- pb = dest(flipface);
-- pc = apex(flipface);
-- pd = oppo(flipface);
-- pe = oppo(symface);
-- if (symbolic) {
-- ia = pointmark(pa);
-- ib = pointmark(pb);
-- ic = pointmark(pc);
-- id = pointmark(pd);
-- ie = pointmark(pe);
-- sign = insphere_sos(pb, pa, pc, pd, pe, ib, ia, ic, id, ie);
-- } else {
-- sign = insphere(pb, pa, pc, pd, pe);
-- }
-- if (sign > 0.0) {
-- for (i = 0; i < 3; i++) {
-- ori = orient3d(pa, pb, pd, pe);
-- if (ori > 0.0) {
-- // Goto and check the next edge.
-- swappt = pa;
-- pa = pb;
-- pb = pc;
-- pc = swappt;
-- enextself(flipface);
-- } else {
-- break; // either (ori < 0.0) or (ori == 0.0)
-- }
-- } // for (i = 0; ....)
-- if (ori > 0.0) {
-- // All three edges are convex, a 2-3 flip is possible.
-- if (checksubfaces) {
-- tspivot(flipface, checksh);
-- if (checksh.sh != dummysh) {
-- // A subface is not flipable.
-- continue;
-- }
-- }
-- flip23(&flipface, flipqueue);
-- } else if (ori < 0.0) {
-- // The edge (a, b) is non-convex, check for a 3-2 flip.
-- fnext(flipface, symface);
-- symself(symface);
-- if (oppo(symface) == pe) {
-- // Only three tets adjoining this edge.
-- if (checksubfaces) {
-- tsspivot(&flipface, &checkseg);
-- if (checkseg.sh != dummysh) {
-- // A subsegment is not flipable.
-- continue;
-- }
-- } else if (checksubsegs) {
-- tsspivot1(flipface, checkseg);
-- if (checkseg.sh != dummysh) {
-- if (b->verbose > 2) {
-- printf(" Queuing missing segment (%d, %d).\n",
-- pointmark(org(flipface)), pointmark(dest(flipface)));
-- }
-- misseg = (badface *) misseglist->append(NULL);
-- misseg->ss = checkseg;
-- misseg->forg = sorg(checkseg);
-- misseg->fdest = sdest(checkseg);
-- // Detach all tets having this seg.
-- starttet = flipface;
-- adjustedgering(starttet, CCW);
-- fnextself(starttet);
-- spintet = starttet;
-- hitbdry = 0;
-- do {
-- tssdissolve1(spintet);
-- if (!fnextself(spintet)) {
-- hitbdry++;
-- if (hitbdry < 2) {
-- esym(starttet, spintet);
-- if (!fnextself(spintet)) {
-- hitbdry++;
-- }
-- }
-- }
-- } while ((apex(spintet) != apex(starttet)) && (hitbdry < 2));
-- }
-- } // if (checksubfaces)
-- flip32(&flipface, flipqueue);
-- }
-- } else {
-- // Four points (a, b, d, e) are coplanar.
-- fnext(flipface, symface);
-- if (fnextself(symface)) {
-- // Check for a 4-4 flip.
-- fnextself(symface);
-- if (apex(symface) == pe) {
-- if (checksubfaces) {
-- tsspivot(&flipface, &checkseg);
-- if (checkseg.sh != dummysh) {
-- // A subsegment is not flippable.
-- continue;
-- }
-- } else if (checksubsegs) {
-- tsspivot1(flipface, checkseg);
-- if (checkseg.sh != dummysh) {
-- if (b->verbose > 2) {
-- printf(" Queuing missing segment (%d, %d).\n",
-- pointmark(org(flipface)), pointmark(dest(flipface)));
-- }
-- misseg = (badface *) misseglist->append(NULL);
-- misseg->ss = checkseg;
-- misseg->forg = sorg(checkseg);
-- misseg->fdest = sdest(checkseg);
-- // Detach all tets having this seg.
-- starttet = flipface;
-- adjustedgering(starttet, CCW);
-- fnextself(starttet);
-- spintet = starttet;
-- hitbdry = 0;
-- do {
-- tssdissolve1(spintet);
-- if (!fnextself(spintet)) {
-- hitbdry++;
-- if (hitbdry < 2) {
-- esym(starttet, spintet);
-- if (!fnextself(spintet)) {
-- hitbdry++;
-- }
-- }
-- }
-- } while ((apex(spintet) != apex(starttet)) &&
-- (hitbdry < 2));
-- }
-- } // if (checksubfaces)
-- flip22(&flipface, flipqueue);
-- }
-- } else {
-- // Check for a 2-2 flip.
-- esym(flipface, symface);
-- fnextself(symface);
-- symself(symface);
-- if (symface.tet == dummytet) {
-- if (checksubfaces) {
-- tsspivot(&flipface, &checkseg);
-- if (checkseg.sh != dummysh) {
-- // A subsegment is not flipable.
-- continue;
-- }
-- } else if (checksubsegs) {
-- tsspivot1(flipface, checkseg);
-- if (checkseg.sh != dummysh) {
-- if (b->verbose > 2) {
-- printf(" Queuing missing segment (%d, %d).\n",
-- pointmark(org(flipface)), pointmark(dest(flipface)));
-- }
-- misseg = (badface *) misseglist->append(NULL);
-- misseg->ss = checkseg;
-- misseg->forg = sorg(checkseg);
-- misseg->fdest = sdest(checkseg);
-- // Detach all tets having this seg.
-- starttet = flipface;
-- adjustedgering(starttet, CCW);
-- fnextself(starttet);
-- spintet = starttet;
-- hitbdry = 0;
-- do {
-- tssdissolve1(spintet);
-- if (!fnextself(spintet)) {
-- hitbdry++;
-- if (hitbdry < 2) {
-- esym(starttet, spintet);
-- if (!fnextself(spintet)) {
-- hitbdry++;
-- }
-- }
-- }
-- } while ((apex(spintet) != apex(starttet)) &&
-- (hitbdry < 2));
-- }
-- } // if (checksubfaces)
-- flip22(&flipface, flipqueue);
-- }
-- }
-- } // if (ori > 0.0)
-- } // if (sign > 0.0)
-- }
-- } // !isdead(&qface->tt)
-- } // while (!flipqueue->empty())
--
-- flipcount = flip23s + flip32s + flip22s + flip44s - flipcount;
-- if (b->verbose > 1) {
-- printf(" %ld flips.\n", flipcount);
-- }
-- return flipcount;
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
- // undoflip() Undo the most recent flip sequence induced by flip(). //
- // //
- // 'lastflip' is the stack of recently flipped faces. Walks through the list //
-@@ -11615,8 +10727,7 @@
-
- edgeflips = 0;
-
-- while (!flipqueue->empty()) {
-- qedge = (badface *) flipqueue->pop();
-+ while ((qedge = (badface *) flipqueue->pop()) != NULL) {
- flipedge = qedge->ss;
- if (flipedge.sh == dummysh) continue;
- if ((sorg(flipedge) != qedge->forg) ||
-@@ -11675,1128 +10786,43 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// removetetbypeeloff() Remove a boundary tet by peeling it off. //
-+// splittetrahedron() Insert a point into a tetrahedron, split it into //
-+// four tetrahedra. //
- // //
--// 'striptet' (abcd) is on boundary and can be removed by stripping it off. //
--// Let abc and bad are the external boundary faces. //
-+// The tetrahedron is given by 'splittet'. Let it is abcd. The inserting //
-+// point 'newpoint' v should lie strictly inside abcd. //
- // //
--// To strip 'abcd' from the mesh is to detach its two interal faces (dca and //
--// cdb) from their adjoining tets together with a 2-to-2 flip to transform //
--// two subfaces (abc and bad) into another two (dca and cdb). //
-+// Splitting a tetrahedron is to shrink abcd to abcv, and create three new //
-+// tetrahedra badv, cbdv, and acdv. //
- // //
--// In mesh optimization. It is possible that ab is a segment and abcd is a //
--// sliver on the hull. Strip abcd will also delete the segment ab. //
-+// On completion, 'splittet' returns abcv. If 'flipqueue' is not NULL, it //
-+// contains all possibly non-locally Delaunay faces. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--bool tetgenmesh::removetetbypeeloff(triface *striptet)
-+void tetgenmesh::
-+splittetrahedron(point newpoint, triface* splittet, queue* flipqueue)
- {
-- triface abcd, badc;
-- triface dcacasing, cdbcasing;
-- face abc, bad;
-- face abseg;
-- REAL ang;
--
-- abcd = *striptet;
-- adjustedgering(abcd, CCW);
-- // Get the casing tets at the internal sides.
-- enextfnext(abcd, cdbcasing);
-- enext2fnext(abcd, dcacasing);
-- symself(cdbcasing);
-- symself(dcacasing);
-- // Do the neighboring tets exist? During optimization. It is possible
-- // that the neighboring tets are already dead.
-- if ((cdbcasing.tet == dummytet) || (dcacasing.tet == dummytet)) {
-- // Do not strip this tet.
-- return false;
-- }
--
-- // Are there subfaces?
-- if (checksubfaces) {
-- // Get the external subfaces abc, bad.
-- fnext(abcd, badc);
-- esymself(badc);
-- tspivot(abcd, abc);
-- tspivot(badc, bad);
-- if (abc.sh != dummysh) {
-- assert(bad.sh != dummysh);
-- findedge(&abc, org(abcd), dest(abcd));
-- findedge(&bad, org(badc), dest(badc));
-- // Is ab a segment?
-- sspivot(abc, abseg);
-- if (abseg.sh != dummysh) {
-- // Does a segment allow to be removed?
-- if ((b->optlevel > 3) && (b->nobisect == 0)) {
-- // Only remove this segment if the dihedal angle at ab is between
-- // [b->maxdihedral-9, 180] (deg). This avoids mistakely fliping
-- // ab when it has actually no big dihedral angle while cd has.
-- ang = facedihedral(org(abcd), dest(abcd), apex(abcd), oppo(abcd));
-- ang = ang * 180.0 / PI;
-- if ((ang + 9.0) > b->maxdihedral) {
-- if (b->verbose > 1) {
-- printf(" Remove a segment during peeling.\n");
-- }
-- face prevseg, nextseg;
-- // It is only shared by abc and bad (abcd is a tet).
-- ssdissolve(abc);
-- ssdissolve(bad);
-- abseg.shver = 0;
-- senext(abseg, nextseg);
-- spivotself(nextseg);
-- if (nextseg.sh != dummysh) {
-- ssdissolve(nextseg);
-- }
-- senext2(abseg, prevseg);
-- spivotself(prevseg);
-- if (prevseg.sh != dummysh) {
-- ssdissolve(prevseg);
-- }
-- shellfacedealloc(subsegs, abseg.sh);
-- optcount[1]++;
-- } else {
-- return false;
-- }
-- } else {
-- return false;
-- }
-- }
-- // Do a 2-to-2 flip on abc and bad, transform abc->dca, bad->cdb.
-- flip22sub(&abc, NULL);
-- // The two internal faces become boundary faces.
-- tsbond(cdbcasing, bad);
-- tsbond(dcacasing, abc);
-- }
-- }
--
-- // Detach abcd from the two internal faces.
-- dissolve(cdbcasing);
-- dissolve(dcacasing);
-- // Delete abcd.
-- tetrahedrondealloc(abcd.tet);
-- return true;
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
--// removeedgebyflip22() Remove an edge by a 2-to-2 (or 4-to-4) flip. //
--// //
--// 'abtetlist' contains n tets (n is 2 or 4) sharing edge ab, abtetlist[0] //
--// and abtetlist[1] are tets abec and abde, respectively (NOTE, both are in //
--// CW edge ring), where a, b, c, and d are coplanar. If n = 4, abtetlist[2] //
--// and abtetlist[3] are tets abfd and abcf, respectively. This routine uses //
--// flip22() to replace edge ab with cd, the surrounding tets are rotated. //
--// //
--// If 'key' != NULL. The old tets are replaced by the new tets only if the //
--// local mesh quality is improved. Current 'key' = cos(\theta), where \theta //
--// is the maximum dihedral angle in the old tets. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--bool tetgenmesh::removeedgebyflip22(REAL *key, int n, triface *abtetlist,
-- queue *flipque)
--{
-- point pa, pb, pc, pd, pe, pf;
-- REAL cosmaxd, d1, d2, d3;
-- bool doflip;
--
-- doflip = true;
-- adjustedgering(abtetlist[0], CW);
-- pa = org(abtetlist[0]);
-- pb = dest(abtetlist[0]);
-- pe = apex(abtetlist[0]);
-- pc = oppo(abtetlist[0]);
-- pd = apex(abtetlist[1]);
-- if (n == 4) {
-- pf = apex(abtetlist[2]);
-- }
-- if (key && (*key > -1.0)) {
-- tetalldihedral(pc, pd, pe, pa, NULL, &d1, NULL);
-- tetalldihedral(pd, pc, pe, pb, NULL, &d2, NULL);
-- cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle.
-- if (n == 4) {
-- tetalldihedral(pd, pc, pf, pa, NULL, &d1, NULL);
-- tetalldihedral(pc, pd, pf, pb, NULL, &d2, NULL);
-- d3 = d1 < d2 ? d1 : d2; // Choose the bigger angle.
-- cosmaxd = cosmaxd < d3 ? cosmaxd : d3; // Choose the bigger angle.
-- }
-- doflip = (*key < cosmaxd); // Can local quality be improved?
-- }
--
-- if (doflip) {
-- flip22(&abtetlist[0], NULL);
-- // Return the improved quality value.
-- if (key) *key = cosmaxd;
-- }
--
-- return doflip;
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
--// removefacebyflip23() Remove a face by a 2-to-3 flip. //
--// //
--// 'abctetlist' contains 2 tets sharing abc, which are [0]abcd and [1]bace. //
--// This routine forms three new tets that abc is not a face anymore. Save //
--// them in 'newtetlist': [0]edab, [1]edbc, and [2]edca. Note that the new //
--// tets may not valid if one of them get inverted. return false if so. //
--// //
--// If 'key' != NULL. The old tets are replaced by the new tets only if the //
--// local mesh quality is improved. Current 'key' = cos(\theta), where \theta //
--// is the maximum dihedral angle in the old tets. //
--// //
--// If the face is flipped, 'newtetlist' returns the three new tets. The two //
--// tets in 'abctetlist' are NOT deleted. The caller has the right to either //
--// delete them or reverse the operation. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--bool tetgenmesh::removefacebyflip23(REAL *key, triface *abctetlist,
-- triface *newtetlist, queue *flipque)
--{
-- triface edab, edbc, edca; // new configuration.
-- triface newfront, oldfront, adjfront;
-- face checksh;
-- point pa, pb, pc, pd, pe;
-- REAL ori, cosmaxd, d1, d2, d3;
-- REAL attrib, volume;
-- bool doflip;
-- int i;
--
-- adjustedgering(abctetlist[0], CCW);
-- pa = org(abctetlist[0]);
-- pb = dest(abctetlist[0]);
-- pc = apex(abctetlist[0]);
-- pd = oppo(abctetlist[0]);
-- pe = oppo(abctetlist[1]);
--
-- // Check if the flip creates valid new tets.
-- ori = orient3d(pe, pd, pa, pb);
-- if (ori < 0.0) {
-- ori = orient3d(pe, pd, pb, pc);
-- if (ori < 0.0) {
-- ori = orient3d(pe, pd, pc, pa);
-- }
-- }
-- doflip = (ori < 0.0); // Can abc be flipped away?
-- if (doflip && (key != (REAL *) NULL)) {
-- if (*key > -1.0) {
-- // Test if the new tets reduce the maximal dihedral angle.
-- tetalldihedral(pe, pd, pa, pb, NULL, &d1, NULL);
-- tetalldihedral(pe, pd, pb, pc, NULL, &d2, NULL);
-- tetalldihedral(pe, pd, pc, pa, NULL, &d3, NULL);
-- cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle.
-- cosmaxd = cosmaxd < d3 ? cosmaxd : d3; // Choose the bigger angle.
-- doflip = (*key < cosmaxd); // Can local quality be improved?
-- }
-- }
--
-- if (doflip) {
-- // A valid (2-to-3) flip is found.
-- flip23s++;
-- // Create the new tets.
-- maketetrahedron(&edab);
-- setorg(edab, pe);
-- setdest(edab, pd);
-- setapex(edab, pa);
-- setoppo(edab, pb);
-- maketetrahedron(&edbc);
-- setorg(edbc, pe);
-- setdest(edbc, pd);
-- setapex(edbc, pb);
-- setoppo(edbc, pc);
-- maketetrahedron(&edca);
-- setorg(edca, pe);
-- setdest(edca, pd);
-- setapex(edca, pc);
-- setoppo(edca, pa);
-- // Transfer the element attributes.
-- for (i = 0; i < in->numberoftetrahedronattributes; i++) {
-- attrib = elemattribute(abctetlist[0].tet, i);
-- setelemattribute(edab.tet, i, attrib);
-- setelemattribute(edbc.tet, i, attrib);
-- setelemattribute(edca.tet, i, attrib);
-- }
-- // Transfer the volume constraints.
-- if (b->varvolume && !b->refine) {
-- volume = volumebound(abctetlist[0].tet);
-- setvolumebound(edab.tet, volume);
-- setvolumebound(edbc.tet, volume);
-- setvolumebound(edca.tet, volume);
-- }
-- // Return two new tets.
-- newtetlist[0] = edab;
-- newtetlist[1] = edbc;
-- newtetlist[2] = edca;
-- // Glue the three new tets.
-- for (i = 0; i < 3; i++) {
-- fnext(newtetlist[i], newfront);
-- bond(newfront, newtetlist[(i + 1) % 3]);
-- }
-- // Substitute the three new tets into the old cavity.
-- for (i = 0; i < 3; i++) {
-- fnext(abctetlist[0], oldfront);
-- sym(oldfront, adjfront); // may be outside.
-- enextfnext(newtetlist[i], newfront);
-- bond(newfront, adjfront);
-- if (checksubfaces) {
-- tspivot(oldfront, checksh);
-- if (checksh.sh != dummysh) {
-- tsbond(newfront, checksh);
-- }
-- }
-- if (flipque != (queue *) NULL) {
-- enqueueflipface(newfront, flipque);
-- }
-- enextself(abctetlist[0]);
-- }
-- findedge(&(abctetlist[1]), pb, pa);
-- for (i = 0; i < 3; i++) {
-- fnext(abctetlist[1], oldfront);
-- sym(oldfront, adjfront); // may be outside.
-- enext2fnext(newtetlist[i], newfront);
-- bond(newfront, adjfront);
-- if (checksubfaces) {
-- tspivot(oldfront, checksh);
-- if (checksh.sh != dummysh) {
-- tsbond(newfront, checksh);
-- }
-- }
-- if (flipque != (queue *) NULL) {
-- enqueueflipface(newfront, flipque);
-- }
-- enext2self(abctetlist[1]);
-- }
-- // Do not delete the old tets.
-- // for (i = 0; i < 2; i++) {
-- // tetrahedrondealloc(abctetlist[i].tet);
-- // }
-- // Return the improved quality value.
-- if (key != (REAL *) NULL) *key = cosmaxd;
-- return true;
-- }
--
-- return false;
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
--// removeedgebyflip32() Remove an edge by a 3-to-2 flip. //
--// //
--// 'abtetlist' contains 3 tets sharing ab. Imaging that ab is perpendicular //
--// to the screen, where a lies in front of and b lies behind it. The 3 tets //
--// of the list are: [0]abce, [1]abdc, and [2]abed, respectively. //
--// //
--// This routine forms two new tets that ab is not an edge of them. Save them //
--// in 'newtetlist', [0]dcea, [1]cdeb. Note that the new tets may not valid //
--// if one of them get inverted. return false if so. //
--// //
--// If 'key' != NULL. The old tets are replaced by the new tets only if the //
--// local mesh quality is improved. Current 'key' = cos(\theta), where \theta //
--// is the maximum dihedral angle in the old tets. //
--// //
--// If the edge is flipped, 'newtetlist' returns the two new tets. The three //
--// tets in 'abtetlist' are NOT deleted. The caller has the right to either //
--// delete them or reverse the operation. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--bool tetgenmesh::removeedgebyflip32(REAL *key, triface *abtetlist,
-- triface *newtetlist, queue *flipque)
--{
-- triface dcea, cdeb; // new configuration.
-- triface newfront, oldfront, adjfront;
-- face checksh;
-- point pa, pb, pc, pd, pe;
-- REAL ori, cosmaxd, d1, d2;
-- REAL attrib, volume;
-- bool doflip;
-- int i;
--
-- pa = org(abtetlist[0]);
-- pb = dest(abtetlist[0]);
-- pc = apex(abtetlist[0]);
-- pd = apex(abtetlist[1]);
-- pe = apex(abtetlist[2]);
--
-- ori = orient3d(pd, pc, pe, pa);
-- if (ori < 0.0) {
-- ori = orient3d(pc, pd, pe, pb);
-- }
-- doflip = (ori < 0.0); // Can ab be flipped away?
--
-- // Does the caller ensure a valid configuration?
-- if (doflip && (key != (REAL *) NULL)) {
-- if (*key > -1.0) {
-- // Test if the new tets reduce the maximal dihedral angle.
-- tetalldihedral(pd, pc, pe, pa, NULL, &d1, NULL);
-- tetalldihedral(pc, pd, pe, pb, NULL, &d2, NULL);
-- cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle.
-- doflip = (*key < cosmaxd); // Can local quality be improved?
-- // Return the key
-- *key = cosmaxd;
-- }
-- }
--
-- if (doflip) {
-- // Create the new tets.
-- maketetrahedron(&dcea);
-- setorg(dcea, pd);
-- setdest(dcea, pc);
-- setapex(dcea, pe);
-- setoppo(dcea, pa);
-- maketetrahedron(&cdeb);
-- setorg(cdeb, pc);
-- setdest(cdeb, pd);
-- setapex(cdeb, pe);
-- setoppo(cdeb, pb);
-- // Transfer the element attributes.
-- for (i = 0; i < in->numberoftetrahedronattributes; i++) {
-- attrib = elemattribute(abtetlist[0].tet, i);
-- setelemattribute(dcea.tet, i, attrib);
-- setelemattribute(cdeb.tet, i, attrib);
-- }
-- // Transfer the volume constraints.
-- if (b->varvolume && !b->refine) {
-- volume = volumebound(abtetlist[0].tet);
-- setvolumebound(dcea.tet, volume);
-- setvolumebound(cdeb.tet, volume);
-- }
-- // Return two new tets.
-- newtetlist[0] = dcea;
-- newtetlist[1] = cdeb;
-- // Glue the two new tets.
-- bond(dcea, cdeb);
-- // Substitute the two new tets into the old three-tets cavity.
-- for (i = 0; i < 3; i++) {
-- fnext(dcea, newfront); // face dca, cea, eda.
-- esym(abtetlist[(i + 1) % 3], oldfront);
-- enextfnextself(oldfront);
-- // Get the adjacent tet at the face (may be a dummytet).
-- sym(oldfront, adjfront);
-- bond(newfront, adjfront);
-- if (checksubfaces) {
-- tspivot(oldfront, checksh);
-- if (checksh.sh != dummysh) {
-- tsbond(newfront, checksh);
-- }
-- }
-- if (flipque != (queue *) NULL) {
-- enqueueflipface(newfront, flipque);
-- }
-- enext2self(dcea);
-- }
-- for (i = 0; i < 3; i++) {
-- fnext(cdeb, newfront); // face cdb, deb, ecb.
-- esym(abtetlist[(i + 1) % 3], oldfront);
-- enext2fnextself(oldfront);
-- // Get the adjacent tet at the face (may be a dummytet).
-- sym(oldfront, adjfront);
-- bond(newfront, adjfront);
-- if (checksubfaces) {
-- tspivot(oldfront, checksh);
-- if (checksh.sh != dummysh) {
-- tsbond(newfront, checksh);
-- }
-- }
-- if (flipque != (queue *) NULL) {
-- enqueueflipface(newfront, flipque);
-- }
-- enextself(cdeb);
-- }
-- // Do not delete the old tets.
-- // for (i = 0; i < 3; i++) {
-- // tetrahedrondealloc(abtetlist[i].tet);
-- // }
-- return true;
-- } // if (doflip)
--
-- return false;
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
--// removeedgebytranNM() Remove an edge by transforming n-to-m tets. //
--// //
--// This routine attempts to remove a given edge (ab) by transforming the set //
--// T of tets surrounding ab into another set T' of tets. T and T' have the //
--// same outer faces and ab is not an edge of T' anymore. Let |T|=n, and |T'| //
--// =m, it is actually a n-to-m flip for n > 3. The relation between n and m //
--// depends on the method, ours is found below. //
--// //
--// 'abtetlist' contains n tets sharing ab. Imaging that ab is perpendicular //
--// to the screen, where a lies in front of and b lies behind it. Let the //
--// projections of the n apexes onto screen in clockwise order are: p_0, ... //
--// p_n-1, respectively. The tets in the list are: [0]abp_0p_n-1,[1]abp_1p_0, //
--// ..., [n-1]abp_n-1p_n-2, respectively. //
--// //
--// The principle of the approach is: Recursively reduce the link of ab by //
--// using flip23 until only three faces remain, hence a flip32 can be applied //
--// to remove ab. For a given face a.b.p_0, check a flip23 can be applied on //
--// it, i.e, edge p_1.p_n-1 crosses it. NOTE*** We do the flip even p_1.p_n-1 //
--// intersects with a.b (they are coplanar). If so, a degenerate tet (a.b.p_1.//
--// p_n-1) is temporarily created, but it will be eventually removed by the //
--// final flip32. This relaxation splits a flip44 into flip23 + flip32. *NOTE //
--// Now suppose a.b.p_0 gets flipped, p_0 is not on the link of ab anymore. //
--// The link is then reduced (by 1). 2 of the 3 new tets, p_n-1.p_1.p_0.a and //
--// p_1.p_n-1.p_0.b, will be part of the new configuration. The left new tet,//
--// a.b.p_1.p_n-1, goes into the new link of ab. A recurrence can be applied. //
--// //
--// If 'e1' and 'e2' are not NULLs, they specify an wanted edge to appear in //
--// the new tet configuration. In such case, only do flip23 if edge e1<->e2 //
--// can be recovered. It is used in removeedgebycombNM(). //
--// //
--// If ab gets removed. 'newtetlist' contains m new tets. By using the above //
--// approach, the pairs (n, m) can be easily enumerated. For example, (3, 2),//
--// (4, 4), (5, 6), (6, 8), (7, 10), (8, 12), (9, 14), (10, 16), and so on. //
--// It is easy to deduce, that m = (n - 2) * 2, when n >= 3. The n tets in //
--// 'abtetlist' are NOT deleted in this routine. The caller has the right to //
--// either delete them or reverse this operation. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--bool tetgenmesh::removeedgebytranNM(REAL *key, int n, triface *abtetlist,
-- triface *newtetlist, point e1, point e2, queue *flipque)
--{
-- triface tmpabtetlist[9]; // Temporary max 9 tets configuration.
-- triface newfront, oldfront, adjfront;
-- face checksh;
-- point pa, pb, p[10];
-- REAL ori, cosmaxd, d1, d2;
-- REAL tmpkey;
-- REAL attrib, volume;
-- bool doflip, copflag, success;
-- int i, j, k;
--
-- // Maximum 10 tets.
-- assert(n <= 10);
-- // Two points a and b are fixed.
-- pa = org(abtetlist[0]);
-- pb = dest(abtetlist[0]);
-- // The points p_0, p_1, ..., p_n-1 are permuted in each new configuration.
-- // These permutations can be easily done in the following loop.
-- // Loop through all the possible new tets configurations. Stop on finding
-- // a valid new tet configuration which also immproves the quality value.
-- for (i = 0; i < n; i++) {
-- // Get other n points for the current configuration.
-- for (j = 0; j < n; j++) {
-- p[j] = apex(abtetlist[(i + j) % n]);
-- }
-- // Is there a wanted edge?
-- if ((e1 != (point) NULL) && (e2 != (point) NULL)) {
-- // Yes. Skip this face if p[1]<->p[n-1] is not the edge.
-- if (!(((p[1] == e1) && (p[n - 1] == e2)) ||
-- ((p[1] == e2) && (p[n - 1] == e1)))) continue;
-- }
-- // Test if face a.b.p_0 can be flipped (by flip23), ie, to check if the
-- // edge p_n-1.p_1 crosses face a.b.p_0 properly.
-- // Note. It is possible that face a.b.p_0 has type flip44, ie, a,b,p_1,
-- // and p_n-1 are coplanar. A trick is to split the flip44 into two
-- // steps: frist a flip23, then a flip32. The first step creates a
-- // degenerate tet (vol=0) which will be removed by the second flip.
-- ori = orient3d(pa, pb, p[1], p[n - 1]);
-- copflag = (ori == 0.0); // Are they coplanar?
-- if (ori >= 0.0) {
-- // Accept the coplanar case which supports flip44.
-- ori = orient3d(pb, p[0], p[1], p[n - 1]);
-- if (ori > 0.0) {
-- ori = orient3d(p[0], pa, p[1], p[n - 1]);
-- }
-- }
-- // Is face abc flipable?
-- if (ori > 0.0) {
-- // A valid (2-to-3) flip (or 4-to-4 flip) is found.
-- copflag ? flip44s++ : flip23s++;
-- doflip = true;
-- if (key != (REAL *) NULL) {
-- if (*key > -1.0) {
-- // Test if the new tets reduce the maximal dihedral angle. Only 2
-- // tets, p_n-1.p_1.p_0.a and p_1.p_n-1.p_0.b, need to be tested
-- // The left one a.b.p_n-1.p_1 goes into the new link of ab.
-- tetalldihedral(p[n - 1], p[1], p[0], pa, NULL, &d1, NULL);
-- tetalldihedral(p[1], p[n - 1], p[0], pb, NULL, &d2, NULL);
-- cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle.
-- doflip = *key < cosmaxd; // Can the local quality be improved?
-- }
-- }
-- if (doflip) {
-- tmpkey = key != NULL ? *key : -1.0;
-- // Create the two new tets.
-- maketetrahedron(&(newtetlist[0]));
-- setorg(newtetlist[0], p[n - 1]);
-- setdest(newtetlist[0], p[1]);
-- setapex(newtetlist[0], p[0]);
-- setoppo(newtetlist[0], pa);
-- maketetrahedron(&(newtetlist[1]));
-- setorg(newtetlist[1], p[1]);
-- setdest(newtetlist[1], p[n - 1]);
-- setapex(newtetlist[1], p[0]);
-- setoppo(newtetlist[1], pb);
-- // Create the n - 1 temporary new tets (the new Star(ab)).
-- maketetrahedron(&(tmpabtetlist[0]));
-- setorg(tmpabtetlist[0], pa);
-- setdest(tmpabtetlist[0], pb);
-- setapex(tmpabtetlist[0], p[n - 1]);
-- setoppo(tmpabtetlist[0], p[1]);
-- for (j = 1; j < n - 1; j++) {
-- maketetrahedron(&(tmpabtetlist[j]));
-- setorg(tmpabtetlist[j], pa);
-- setdest(tmpabtetlist[j], pb);
-- setapex(tmpabtetlist[j], p[j]);
-- setoppo(tmpabtetlist[j], p[j + 1]);
-- }
-- // Transfer the element attributes.
-- for (j = 0; j < in->numberoftetrahedronattributes; j++) {
-- attrib = elemattribute(abtetlist[0].tet, j);
-- setelemattribute(newtetlist[0].tet, j, attrib);
-- setelemattribute(newtetlist[1].tet, j, attrib);
-- for (k = 0; k < n - 1; k++) {
-- setelemattribute(tmpabtetlist[k].tet, j, attrib);
-- }
-- }
-- // Transfer the volume constraints.
-- if (b->varvolume && !b->refine) {
-- volume = volumebound(abtetlist[0].tet);
-- setvolumebound(newtetlist[0].tet, volume);
-- setvolumebound(newtetlist[1].tet, volume);
-- for (k = 0; k < n - 1; k++) {
-- setvolumebound(tmpabtetlist[k].tet, volume);
-- }
-- }
-- // Glue the new tets at their internal faces: 2 + (n - 1).
-- bond(newtetlist[0], newtetlist[1]); // p_n-1.p_1.p_0.
-- fnext(newtetlist[0], newfront);
-- enext2fnext(tmpabtetlist[0], adjfront);
-- bond(newfront, adjfront); // p_n-1.p_1.a.
-- fnext(newtetlist[1], newfront);
-- enextfnext(tmpabtetlist[0], adjfront);
-- bond(newfront, adjfront); // p_n-1.p_1.b.
-- // Glue n - 1 internal faces around ab.
-- for (j = 0; j < n - 1; j++) {
-- fnext(tmpabtetlist[j], newfront);
-- bond(newfront, tmpabtetlist[(j + 1) % (n - 1)]); // a.b.p_j+1
-- }
-- // Substitute the old tets with the new tets by connecting the new
-- // tets to the adjacent tets in the mesh. There are n * 2 (outer)
-- // faces of the new tets need to be operated.
-- // Note, after the substitution, the old tets still have pointers to
-- // their adjacent tets in the mesh. These pointers can be re-used
-- // to inverse the substitution.
-- for (j = 0; j < n; j++) {
-- // Get an old tet: [0]a.b.p_0.p_n-1 or [j]a.b.p_j.p_j-1, (j > 0).
-- oldfront = abtetlist[(i + j) % n];
-- esymself(oldfront);
-- enextfnextself(oldfront);
-- // Get an adjacent tet at face: [0]a.p_0.p_n-1 or [j]a.p_j.p_j-1.
-- sym(oldfront, adjfront); // adjfront may be dummy.
-- // Get the corresponding face from the new tets.
-- if (j == 0) {
-- enext2fnext(newtetlist[0], newfront); // a.p_0.n_n-1
-- } else if (j == 1) {
-- enextfnext(newtetlist[0], newfront); // a.p_1.p_0
-- } else { // j >= 2.
-- enext2fnext(tmpabtetlist[j - 1], newfront); // a.p_j.p_j-1
-- }
-- bond(newfront, adjfront);
-- if (checksubfaces) {
-- tspivot(oldfront, checksh);
-- if (checksh.sh != dummysh) {
-- tsbond(newfront, checksh);
-- }
-- }
-- if (flipque != (queue *) NULL) {
-- // Only queue the faces of the two new tets.
-- if (j < 2) enqueueflipface(newfront, flipque);
-- }
-- }
-- for (j = 0; j < n; j++) {
-- // Get an old tet: [0]a.b.p_0.p_n-1 or [j]a.b.p_j.p_j-1, (j > 0).
-- oldfront = abtetlist[(i + j) % n];
-- esymself(oldfront);
-- enext2fnextself(oldfront);
-- // Get an adjacent tet at face: [0]b.p_0.p_n-1 or [j]b.p_j.p_j-1.
-- sym(oldfront, adjfront); // adjfront may be dummy.
-- // Get the corresponding face from the new tets.
-- if (j == 0) {
-- enextfnext(newtetlist[1], newfront); // b.p_0.n_n-1
-- } else if (j == 1) {
-- enext2fnext(newtetlist[1], newfront); // b.p_1.p_0
-- } else { // j >= 2.
-- enextfnext(tmpabtetlist[j - 1], newfront); // b.p_j.p_j-1
-- }
-- bond(newfront, adjfront);
-- if (checksubfaces) {
-- tspivot(oldfront, checksh);
-- if (checksh.sh != dummysh) {
-- tsbond(newfront, checksh);
-- }
-- }
-- if (flipque != (queue *) NULL) {
-- // Only queue the faces of the two new tets.
-- if (j < 2) enqueueflipface(newfront, flipque);
-- }
-- }
-- // Adjust the faces in the temporary new tets at ab for recursively
-- // processing on the n-1 tets.(See the description at beginning)
-- for (j = 0; j < n - 1; j++) {
-- fnextself(tmpabtetlist[j]);
-- }
-- if (n > 4) {
-- success = removeedgebytranNM(&tmpkey, n-1, tmpabtetlist,
-- &(newtetlist[2]), NULL, NULL, flipque);
-- } else { // assert(n == 4);
-- success = removeedgebyflip32(&tmpkey, tmpabtetlist,
-- &(newtetlist[2]), flipque);
-- }
-- // No matter it was success or not, delete the temporary tets.
-- for (j = 0; j < n - 1; j++) {
-- tetrahedrondealloc(tmpabtetlist[j].tet);
-- }
-- if (success) {
-- // The new configuration is good.
-- // Do not delete the old tets.
-- // for (j = 0; j < n; j++) {
-- // tetrahedrondealloc(abtetlist[j].tet);
-- // }
-- // Save the minimal improved quality value.
-- if (key != (REAL *) NULL) {
-- *key = (tmpkey < cosmaxd ? tmpkey : cosmaxd);
-- }
-- return true;
-- } else {
-- // The new configuration is bad, substitue back the old tets.
-- for (j = 0; j < n; j++) {
-- oldfront = abtetlist[(i + j) % n];
-- esymself(oldfront);
-- enextfnextself(oldfront); // [0]a.p_0.p_n-1, [j]a.p_j.p_j-1.
-- sym(oldfront, adjfront); // adjfront may be dummy.
-- bond(oldfront, adjfront);
-- if (checksubfaces) {
-- tspivot(oldfront, checksh);
-- if (checksh.sh != dummysh) {
-- tsbond(oldfront, checksh);
-- }
-- }
-- }
-- for (j = 0; j < n; j++) {
-- oldfront = abtetlist[(i + j) % n];
-- esymself(oldfront);
-- enext2fnextself(oldfront); // [0]b.p_0.p_n-1, [j]b.p_j.p_j-1.
-- sym(oldfront, adjfront); // adjfront may be dummy
-- bond(oldfront, adjfront);
-- if (checksubfaces) {
-- tspivot(oldfront, checksh);
-- if (checksh.sh != dummysh) {
-- tsbond(oldfront, checksh);
-- }
-- }
-- }
-- // Delete the new tets.
-- tetrahedrondealloc(newtetlist[0].tet);
-- tetrahedrondealloc(newtetlist[1].tet);
-- // If tmpkey has been modified, then the failure was not due to
-- // unflipable configuration, but the non-improvement.
-- if (key && (tmpkey < *key)) {
-- *key = tmpkey;
-- return false;
-- }
-- } // if (success)
-- } // if (doflip)
-- } // if (ori > 0.0)
-- } // for (i = 0; i < n; i++)
--
-- return false;
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
--// removeedgebycombNM() Remove an edge by combining two flipNMs. //
--// //
--// Given a set T of tets surrounding edge ab. The premise is that ab can not //
--// be removed by a flipNM. This routine attempts to remove ab by two flipNMs,//
--// i.e., first find and flip an edge af (or bf) by flipNM, then flip ab by //
--// flipNM. If it succeeds, two sets T(ab) and T(af) of tets are replaced by //
--// a new set T' and both ab and af are not edges in T' anymore. //
--// //
--// 'abtetlist' contains n tets sharing ab. Imaging that ab is perpendicular //
--// to the screen, such that a lies in front of and b lies behind it. Let the //
--// projections of the n apexes on the screen in clockwise order are: p_0,...,//
--// p_n-1, respectively. So the list of tets are: [0]abp_0p_n-1, [1]abp_1p_0, //
--// ..., [n-1]abp_n-1p_n-2, respectively. //
--// //
--// The principle of the approach is: for a face a.b.p_0, check if edge b.p_0 //
--// is of type N32 (or N44). If it is, then try to do a flipNM on it. If the //
--// flip is successful, then try to do another flipNM on a.b. If one of the //
--// two flipNMs fails, restore the old tets as they have never been flipped. //
--// Then try the next face a.b.p_1. The process can be looped for all faces //
--// having ab. Stop if ab is removed or all faces have been visited. Note in //
--// the above description only b.p_0 is considered, a.p_0 is done by swapping //
--// the position of a and b. //
--// //
--// Similar operations have been described in [Joe,1995]. My approach checks //
--// more cases for finding flips than Joe's. For instance, the cases (1)-(7) //
--// of Joe only consider abf for finding a flip (T23/T32). My approach looks //
--// all faces at ab for finding flips. Moreover, the flipNM can flip an edge //
--// whose star may have more than 3 tets while Joe's only works on 3-tet case.//
--// //
--// If ab is removed, 'newtetlist' contains the new tets. Two sets 'abtetlist'//
--// (n tets) and 'bftetlist' (n1 tets) have been replaced. The number of new //
--// tets can be calculated by follows: the 1st flip transforms n1 tets into //
--// (n1 - 2) * 2 new tets, however,one of the new tets goes into the new link //
--// of ab, i.e., the reduced tet number in Star(ab) is n - 1; the 2nd flip //
--// transforms n - 1 tets into (n - 3) * 2 new tets. Hence the number of new //
--// tets are: m = ((n1 - 2) * 2 - 1) + (n - 3) * 2. The old tets are NOT del-//
--// eted. The caller has the right to delete them or reverse the operation. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--bool tetgenmesh::removeedgebycombNM(REAL *key, int n, triface *abtetlist,
-- int *n1, triface *bftetlist, triface *newtetlist, queue *flipque)
--{
-- triface tmpabtetlist[11];
-- triface newfront, oldfront, adjfront;
-- face checksh;
-- point pa, pb, p[10];
-- REAL ori, tmpkey, tmpkey2;
-- REAL attrib, volume;
-- bool doflip, success;
-- int twice, count;
-- int i, j, k, m;
--
-- // Maximal 10 tets in Star(ab).
-- assert(n <= 10);
--
-- // Do the following procedure twice, one for flipping edge b.p_0 and the
-- // other for p_0.a which is symmetric to the first.
-- twice = 0;
-- do {
-- // Two points a and b are fixed.
-- pa = org(abtetlist[0]);
-- pb = dest(abtetlist[0]);
-- // The points p_0, ..., p_n-1 are permuted in the following loop.
-- for (i = 0; i < n; i++) {
-- // Get the n points for the current configuration.
-- for (j = 0; j < n; j++) {
-- p[j] = apex(abtetlist[(i + j) % n]);
-- }
-- // Check if b.p_0 is of type N32 or N44.
-- ori = orient3d(pb, p[0], p[1], p[n - 1]);
-- if ((ori > 0) && (key != (REAL *) NULL)) {
-- // b.p_0 is not N32. However, it is possible that the tet b.p_0.p_1.
-- // p_n-1 has worse quality value than the key. In such case, also
-- // try to flip b.p_0.
-- tetalldihedral(pb, p[0], p[n - 1], p[1], NULL, &tmpkey, NULL);
-- if (tmpkey < *key) ori = 0.0;
-- }
-- if (ori <= 0.0) {
-- // b.p_0 is either N32 or N44. Try the 1st flipNM.
-- bftetlist[0] = abtetlist[i];
-- enextself(bftetlist[0]);// go to edge b.p_0.
-- adjustedgering(bftetlist[0], CW); // edge p_0.b.
-- assert(apex(bftetlist[0]) == pa);
-- // Form Star(b.p_0).
-- doflip = true;
-- *n1 = 0;
-- do {
-- // Is the list full?
-- if (*n1 == 10) break;
-- if (checksubfaces) {
-- // Stop if a subface appears.
-- tspivot(bftetlist[*n1], checksh);
-- if (checksh.sh != dummysh) {
-- doflip = false; break;
-- }
-- }
-- // Get the next tet at p_0.b.
-- fnext(bftetlist[*n1], bftetlist[(*n1) + 1]);
-- (*n1)++;
-- } while (apex(bftetlist[*n1]) != pa);
-- // 2 <= n1 <= 10.
-- if (doflip) {
-- success = false;
-- tmpkey = -1.0; // = acos(pi).
-- if (key != (REAL *) NULL) tmpkey = *key;
-- m = 0;
-- if (*n1 == 3) {
-- // Three tets case. Try flip32.
-- success = removeedgebyflip32(&tmpkey,bftetlist,newtetlist,flipque);
-- m = 2;
-- } else if ((*n1 > 3) && (*n1 < 7)) {
-- // Four or more tets case. Try flipNM.
-- success = removeedgebytranNM(&tmpkey, *n1, bftetlist, newtetlist,
-- p[1], p[n - 1], flipque);
-- // If success, the number of new tets.
-- m = ((*n1) - 2) * 2;
-- } else {
-- if (b->verbose > 1) {
-- printf(" !! Unhandled case: n1 = %d.\n", *n1);
-- }
-- }
-- if (success) {
-- // b.p_0 is flipped. The link of ab is reduced (by 1), i.e., p_0
-- // is not on the link of ab. Two old tets a.b.p_0.p_n-1 and
-- // a.b.p_1.p_0 have been removed from the Star(ab) and one new
-- // tet t = a.b.p_1.p_n-1 belongs to Star(ab).
-- // Find t in the 'newtetlist' and remove it from the list.
-- setpointmark(pa, -pointmark(pa) - 1);
-- setpointmark(pb, -pointmark(pb) - 1);
-- assert(m > 0);
-- for (j = 0; j < m; j++) {
-- tmpabtetlist[0] = newtetlist[j];
-- // Does it has ab?
-- count = 0;
-- for (k = 0; k < 4; k++) {
-- if (pointmark((point)(tmpabtetlist[0].tet[4+k])) < 0) count++;
-- }
-- if (count == 2) {
-- // It is. Adjust t to be the edge ab.
-- for (tmpabtetlist[0].loc = 0; tmpabtetlist[0].loc < 4;
-- tmpabtetlist[0].loc++) {
-- if ((oppo(tmpabtetlist[0]) != pa) &&
-- (oppo(tmpabtetlist[0]) != pb)) break;
-- }
-- // The face of t must contain ab.
-- assert(tmpabtetlist[0].loc < 4);
-- findedge(&(tmpabtetlist[0]), pa, pb);
-- break;
-- }
-- }
-- assert(j < m); // The tet must exist.
-- // Remove t from list. Fill t's position by the last tet.
-- newtetlist[j] = newtetlist[m - 1];
-- setpointmark(pa, -(pointmark(pa) + 1));
-- setpointmark(pb, -(pointmark(pb) + 1));
-- // Create the temporary Star(ab) for the next flipNM.
-- adjustedgering(tmpabtetlist[0], CCW);
-- if (org(tmpabtetlist[0]) != pa) {
-- fnextself(tmpabtetlist[0]);
-- esymself(tmpabtetlist[0]);
-- }
--#ifdef SELF_CHECK
-- // Make sure current edge is a->b.
-- assert(org(tmpabtetlist[0]) == pa);
-- assert(dest(tmpabtetlist[0]) == pb);
-- assert(apex(tmpabtetlist[0]) == p[n - 1]);
-- assert(oppo(tmpabtetlist[0]) == p[1]);
--#endif // SELF_CHECK
-- // There are n - 2 left temporary tets.
-- for (j = 1; j < n - 1; j++) {
-- maketetrahedron(&(tmpabtetlist[j]));
-- setorg(tmpabtetlist[j], pa);
-- setdest(tmpabtetlist[j], pb);
-- setapex(tmpabtetlist[j], p[j]);
-- setoppo(tmpabtetlist[j], p[j + 1]);
-- }
-- // Transfer the element attributes.
-- for (j = 0; j < in->numberoftetrahedronattributes; j++) {
-- attrib = elemattribute(abtetlist[0].tet, j);
-- for (k = 0; k < n - 1; k++) {
-- setelemattribute(tmpabtetlist[k].tet, j, attrib);
-- }
-- }
-- // Transfer the volume constraints.
-- if (b->varvolume && !b->refine) {
-- volume = volumebound(abtetlist[0].tet);
-- for (k = 0; k < n - 1; k++) {
-- setvolumebound(tmpabtetlist[k].tet, volume);
-- }
-- }
-- // Glue n - 1 internal faces of Star(ab).
-- for (j = 0; j < n - 1; j++) {
-- fnext(tmpabtetlist[j], newfront);
-- bond(newfront, tmpabtetlist[(j + 1) % (n - 1)]); // a.b.p_j+1
-- }
-- // Substitute the old tets with the new tets by connecting the
-- // new tets to the adjacent tets in the mesh. There are (n-2)
-- // * 2 (outer) faces of the new tets need to be operated.
-- // Note that the old tets still have the pointers to their
-- // adjacent tets in the mesh. These pointers can be re-used
-- // to inverse the substitution.
-- for (j = 2; j < n; j++) {
-- // Get an old tet: [j]a.b.p_j.p_j-1, (j > 1).
-- oldfront = abtetlist[(i + j) % n];
-- esymself(oldfront);
-- enextfnextself(oldfront);
-- // Get an adjacent tet at face: [j]a.p_j.p_j-1.
-- sym(oldfront, adjfront); // adjfront may be dummy.
-- // Get the corresponding face from the new tets.
-- // j >= 2.
-- enext2fnext(tmpabtetlist[j - 1], newfront); // a.p_j.p_j-1
-- bond(newfront, adjfront);
-- if (checksubfaces) {
-- tspivot(oldfront, checksh);
-- if (checksh.sh != dummysh) {
-- tsbond(newfront, checksh);
-- }
-- }
-- }
-- for (j = 2; j < n; j++) {
-- // Get an old tet: [j]a.b.p_j.p_j-1, (j > 2).
-- oldfront = abtetlist[(i + j) % n];
-- esymself(oldfront);
-- enext2fnextself(oldfront);
-- // Get an adjacent tet at face: [j]b.p_j.p_j-1.
-- sym(oldfront, adjfront); // adjfront may be dummy.
-- // Get the corresponding face from the new tets.
-- // j >= 2.
-- enextfnext(tmpabtetlist[j - 1], newfront); // b.p_j.p_j-1
-- bond(newfront, adjfront);
-- if (checksubfaces) {
-- tspivot(oldfront, checksh);
-- if (checksh.sh != dummysh) {
-- tsbond(newfront, checksh);
-- }
-- }
-- }
-- // Adjust the faces in the temporary new tets at ab for
-- // recursively processing on the n-1 tets.
-- for (j = 0; j < n - 1; j++) {
-- fnextself(tmpabtetlist[j]);
-- }
-- tmpkey2 = -1;
-- if (key) tmpkey2 = *key;
-- if ((n - 1) == 3) {
-- success = removeedgebyflip32(&tmpkey2, tmpabtetlist,
-- &(newtetlist[m - 1]), flipque);
-- } else { // assert((n - 1) >= 4);
-- success = removeedgebytranNM(&tmpkey2, n - 1, tmpabtetlist,
-- &(newtetlist[m - 1]), NULL, NULL, flipque);
-- }
-- // No matter it was success or not, delete the temporary tets.
-- for (j = 0; j < n - 1; j++) {
-- tetrahedrondealloc(tmpabtetlist[j].tet);
-- }
-- if (success) {
-- // The new configuration is good.
-- // Do not delete the old tets.
-- // for (j = 0; j < n; j++) {
-- // tetrahedrondealloc(abtetlist[j].tet);
-- // }
-- // Return the bigger dihedral in the two sets of new tets.
-- if (key != (REAL *) NULL) {
-- *key = tmpkey2 < tmpkey ? tmpkey2 : tmpkey;
-- }
-- return true;
-- } else {
-- // The new configuration is bad, substitue back the old tets.
-- for (j = 0; j < n; j++) {
-- oldfront = abtetlist[(i + j) % n];
-- esymself(oldfront);
-- enextfnextself(oldfront); // [0]a.p_0.p_n-1, [j]a.p_j.p_j-1.
-- sym(oldfront, adjfront); // adjfront may be dummy.
-- bond(oldfront, adjfront);
-- if (checksubfaces) {
-- tspivot(oldfront, checksh);
-- if (checksh.sh != dummysh) {
-- tsbond(oldfront, checksh);
-- }
-- }
-- }
-- for (j = 0; j < n; j++) {
-- oldfront = abtetlist[(i + j) % n];
-- esymself(oldfront);
-- enext2fnextself(oldfront); // [0]b.p_0.p_n-1, [j]b.p_j.p_j-1.
-- sym(oldfront, adjfront); // adjfront may be dummy
-- bond(oldfront, adjfront);
-- if (checksubfaces) {
-- tspivot(oldfront, checksh);
-- if (checksh.sh != dummysh) {
-- tsbond(oldfront, checksh);
-- }
-- }
-- }
-- // Substitute back the old tets of the first flip.
-- for (j = 0; j < *n1; j++) {
-- oldfront = bftetlist[j];
-- esymself(oldfront);
-- enextfnextself(oldfront);
-- sym(oldfront, adjfront); // adjfront may be dummy.
-- bond(oldfront, adjfront);
-- if (checksubfaces) {
-- tspivot(oldfront, checksh);
-- if (checksh.sh != dummysh) {
-- tsbond(oldfront, checksh);
-- }
-- }
-- }
-- for (j = 0; j < *n1; j++) {
-- oldfront = bftetlist[j];
-- esymself(oldfront);
-- enext2fnextself(oldfront); // [0]b.p_0.p_n-1, [j]b.p_j.p_j-1.
-- sym(oldfront, adjfront); // adjfront may be dummy
-- bond(oldfront, adjfront);
-- if (checksubfaces) {
-- tspivot(oldfront, checksh);
-- if (checksh.sh != dummysh) {
-- tsbond(oldfront, checksh);
-- }
-- }
-- }
-- // Delete the new tets of the first flip. Note that one new
-- // tet has already been removed from the list.
-- for (j = 0; j < m - 1; j++) {
-- tetrahedrondealloc(newtetlist[j].tet);
-- }
-- } // if (success)
-- } // if (success)
-- } // if (doflip)
-- } // if (ori <= 0.0)
-- } // for (i = 0; i < n; i++)
-- // Inverse a and b and the tets configuration.
-- for (i = 0; i < n; i++) newtetlist[i] = abtetlist[i];
-- for (i = 0; i < n; i++) {
-- oldfront = newtetlist[n - i - 1];
-- esymself(oldfront);
-- fnextself(oldfront);
-- abtetlist[i] = oldfront;
-- }
-- twice++;
-- } while (twice < 2);
--
-- return false;
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
--// splittetrahedron() Insert a point into a tetrahedron, split it into //
--// four tetrahedra. //
--// //
--// The tetrahedron is given by 'splittet'. Let it is abcd. The inserting //
--// point 'newpoint' v should lie strictly inside abcd. //
--// //
--// Splitting a tetrahedron is to shrink abcd to abcv, and create three new //
--// tetrahedra badv, cbdv, and acdv. //
--// //
--// On completion, 'splittet' returns abcv. If 'flipqueue' is not NULL, it //
--// contains all possibly non-locally Delaunay faces. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--void tetgenmesh::splittetrahedron(point newpoint, triface* splittet,
-- queue* flipqueue)
--{
-- triface oldabd, oldbcd, oldcad; // Old configuration.
-- triface abdcasing, bcdcasing, cadcasing;
-- face abdsh, bcdsh, cadsh;
-- triface abcv, badv, cbdv, acdv; // New configuration.
-- triface worktet;
-- face abseg, bcseg, caseg;
-- face adseg, bdseg, cdseg;
-- point pa, pb, pc, pd;
-- REAL attrib, volume;
-- int i;
--
-- abcv = *splittet;
-- abcv.ver = 0;
-- // Set the changed vertices and new tetrahedron.
-- pa = org(abcv);
-- pb = dest(abcv);
-- pc = apex(abcv);
-- pd = oppo(abcv);
--
-- if (b->verbose > 1) {
-- printf(" Inserting point %d in tetrahedron (%d, %d, %d, %d).\n",
-- pointmark(newpoint), pointmark(pa), pointmark(pb), pointmark(pc),
-- pointmark(pd));
-+ triface oldabd, oldbcd, oldcad; // Old configuration.
-+ triface abdcasing, bcdcasing, cadcasing;
-+ face abdsh, bcdsh, cadsh;
-+ triface abcv, badv, cbdv, acdv; // New configuration.
-+ point pa, pb, pc, pd;
-+ REAL attrib, volume;
-+ int i;
-+
-+ abcv = *splittet;
-+ abcv.ver = 0;
-+ // Set the changed vertices and new tetrahedron.
-+ pa = org(abcv);
-+ pb = dest(abcv);
-+ pc = apex(abcv);
-+ pd = oppo(abcv);
-+
-+ if (b->verbose > 1) {
-+ printf(" Inserting point %d in tetrahedron (%d, %d, %d, %d).\n",
-+ pointmark(newpoint), pointmark(pa), pointmark(pb), pointmark(pc),
-+ pointmark(pd));
- }
-
- fnext(abcv, oldabd);
-@@ -12863,51 +10889,6 @@
- tsdissolve(oldcad);
- tsbond(acdv, cadsh);
- }
-- } else if (checksubsegs) {
-- tsspivot1(abcv, abseg);
-- if (abseg.sh != dummysh) {
-- tssbond1(badv, abseg);
-- }
-- enext(abcv, worktet);
-- tsspivot1(worktet, bcseg);
-- if (bcseg.sh != dummysh) {
-- tssbond1(cbdv, bcseg);
-- }
-- enext2(abcv, worktet);
-- tsspivot1(worktet, caseg);
-- if (caseg.sh != dummysh) {
-- tssbond1(acdv, caseg);
-- }
-- fnext(abcv, worktet);
-- enext2self(worktet);
-- tsspivot1(worktet, adseg);
-- if (adseg.sh != dummysh) {
-- tssdissolve1(worktet);
-- enext(badv, worktet);
-- tssbond1(worktet, adseg);
-- enext2(acdv, worktet);
-- tssbond1(worktet, adseg);
-- }
-- enextfnext(abcv, worktet);
-- enext2self(worktet);
-- tsspivot1(worktet, bdseg);
-- if (bdseg.sh != dummysh) {
-- tssdissolve1(worktet);
-- enext(cbdv, worktet);
-- tssbond1(worktet, bdseg);
-- enext2(badv, worktet);
-- tssbond1(worktet, bdseg);
-- }
-- enext2fnext(abcv, worktet);
-- enext2self(worktet);
-- tsspivot1(worktet, cdseg);
-- if (cdseg.sh != dummysh) {
-- tssdissolve1(worktet);
-- enext(acdv, worktet);
-- tssbond1(worktet, cdseg);
-- enext2(cbdv, worktet);
-- tssbond1(worktet, cdseg);
-- }
- }
- badv.loc = 3;
- cbdv.loc = 2;
-@@ -13041,18 +11022,14 @@
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--void tetgenmesh::splittetface(point newpoint, triface* splittet,
-- queue* flipqueue)
-+void tetgenmesh::
-+splittetface(point newpoint, triface* splittet, queue* flipqueue)
- {
- triface abcd, bace; // Old configuration.
- triface oldbcd, oldcad, oldace, oldcbe;
- triface bcdcasing, cadcasing, acecasing, cbecasing;
- face abcsh, bcdsh, cadsh, acesh, cbesh;
- triface abvd, bcvd, cavd, bave, cbve, acve; // New configuration.
-- triface worktet;
-- face bcseg, caseg;
-- face adseg, bdseg, cdseg;
-- face aeseg, beseg, ceseg;
- point pa, pb, pc, pd, pe;
- REAL attrib, volume;
- bool mirrorflag;
-@@ -13088,6 +11065,13 @@
- pointmark(pa), pointmark(pb), pointmark(pc));
- }
-
-+#ifdef SELF_CHECK
-+ // Make sure no inversed tetrahedron has been created.
-+ assert(orient3d(pa, pb, pd, newpoint) >= 0.0);
-+ assert(orient3d(pb, pc, pd, newpoint) >= 0.0);
-+ assert(orient3d(pc, pa, pd, newpoint) >= 0.0);
-+#endif
-+
- // Save the old configuration at faces bcd and cad.
- enextfnext(abcd, oldbcd);
- enext2fnext(abcd, oldcad);
-@@ -13224,95 +11208,6 @@
- // Split this subface 'abc' into three i.e, abv, bcv, cav.
- splitsubface(newpoint, &abcsh, (queue *) NULL);
- }
-- } else if (checksubsegs) {
-- // abvd.loc = abvd.ver = 0;
-- bcvd.loc = bcvd.ver = 0;
-- cavd.loc = cavd.ver = 0;
-- if (mirrorflag) {
-- // bave.loc = bave.ver = 0;
-- cbve.loc = cbve.ver = 0;
-- acve.loc = acve.ver = 0;
-- }
-- enext(abvd, worktet);
-- tsspivot1(worktet, bcseg);
-- if (bcseg.sh != dummysh) {
-- tssdissolve1(worktet);
-- tssbond1(bcvd, bcseg);
-- if (mirrorflag) {
-- enext2(bave, worktet);
-- tssdissolve1(worktet);
-- tssbond1(cbve, bcseg);
-- }
-- }
-- enext2(abvd, worktet);
-- tsspivot1(worktet, caseg);
-- if (caseg.sh != dummysh) {
-- tssdissolve1(worktet);
-- tssbond1(cavd, caseg);
-- if (mirrorflag) {
-- enext(bave, worktet);
-- tssdissolve1(worktet);
-- tssbond1(acve, caseg);
-- }
-- }
-- fnext(abvd, worktet);
-- enext2self(worktet);
-- tsspivot1(worktet, adseg);
-- if (adseg.sh != dummysh) {
-- fnext(cavd, worktet);
-- enextself(worktet);
-- tssbond1(worktet, adseg);
-- }
-- fnext(abvd, worktet);
-- enextself(worktet);
-- tsspivot1(worktet, bdseg);
-- if (bdseg.sh != dummysh) {
-- fnext(bcvd, worktet);
-- enext2self(worktet);
-- tssbond1(worktet, bdseg);
-- }
-- enextfnext(abvd, worktet);
-- enextself(worktet);
-- tsspivot1(worktet, cdseg);
-- if (cdseg.sh != dummysh) {
-- tssdissolve1(worktet);
-- fnext(bcvd, worktet);
-- enextself(worktet);
-- tssbond1(worktet, cdseg);
-- fnext(cavd, worktet);
-- enext2self(worktet);
-- tssbond1(worktet, cdseg);
-- }
-- if (mirrorflag) {
-- fnext(bave, worktet);
-- enextself(worktet);
-- tsspivot1(worktet, aeseg);
-- if (aeseg.sh != dummysh) {
-- fnext(acve, worktet);
-- enext2self(worktet);
-- tssbond1(worktet, aeseg);
-- }
-- fnext(bave, worktet);
-- enext2self(worktet);
-- tsspivot1(worktet, beseg);
-- if (beseg.sh != dummysh) {
-- fnext(cbve, worktet);
-- enextself(worktet);
-- tssbond1(worktet, beseg);
-- }
-- enextfnext(bave, worktet);
-- enextself(worktet);
-- tsspivot1(worktet, ceseg);
-- if (ceseg.sh != dummysh) {
-- tssdissolve1(worktet);
-- fnext(cbve, worktet);
-- enext2self(worktet);
-- tssbond1(worktet, ceseg);
-- fnext(acve, worktet);
-- enextself(worktet);
-- tssbond1(worktet, ceseg);
-- }
-- }
- }
-
- // Save a handle for quick point location.
-@@ -13505,8 +11400,8 @@
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--void tetgenmesh::splitsubface(point newpoint, face* splitface,
-- queue* flipqueue)
-+void tetgenmesh::
-+splitsubface(point newpoint, face* splitface, queue* flipqueue)
- {
- triface abvd, bcvd, cavd, bave, cbve, acve;
- face abc, oldbc, oldca, bc, ca, spinsh;
-@@ -13811,15 +11706,13 @@
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--void tetgenmesh::splittetedge(point newpoint, triface* splittet,
-- queue* flipqueue)
-+void tetgenmesh::
-+splittetedge(point newpoint, triface* splittet, queue* flipqueue)
- {
- triface *bots, *newtops;
- triface oldtop, topcasing;
- triface spintet, tmpbond0, tmpbond1;
- face abseg, splitsh, topsh, spinsh;
-- triface worktet;
-- face n1n2seg, n2vseg, n1vseg;
- point pa, pb, n1, n2;
- REAL attrib, volume;
- int wrapcount, hitbdry;
-@@ -13962,14 +11855,14 @@
- }
- #ifdef SELF_CHECK
- // Make sure no inversed tetrahedron has been created.
-- // volume = orient3d(pa, n1, n2, newpoint);
-- // if (volume >= 0.0) {
-- // printf("Internal error in splittetedge(): volume = %.12g.\n", volume);
-- // }
-- // volume = orient3d(pb, n2, n1, newpoint);
-- // if (volume >= 0.0) {
-- // printf("Internal error in splittetedge(): volume = %.12g.\n", volume);
-- // }
-+ volume = orient3d(pa, n1, n2, newpoint);
-+ if (volume >= 0.0) {
-+ printf("Internal error in splittetedge(): volume = %.12g.\n", volume);
-+ }
-+ volume = orient3d(pb, n2, n1, newpoint);
-+ if (volume >= 0.0) {
-+ printf("Internal error in splittetedge(): volume = %.12g.\n", volume);
-+ }
- #endif
- }
-
-@@ -14005,29 +11898,6 @@
- enext2fnext(newtops[0], tmpbond1);
- bond(tmpbond0, tmpbond1);
- }
-- if (checksubsegs) {
-- for (i = 0; i < wrapcount; i++) {
-- enextfnext(bots[i], worktet); // edge n1->n2.
-- tsspivot1(worktet, n1n2seg);
-- if (n1n2seg.sh != dummysh) {
-- enext(newtops[i], tmpbond0);
-- tssbond1(tmpbond0, n1n2seg);
-- }
-- enextself(worktet); // edge n2->v ==> n2->b
-- tsspivot1(worktet, n2vseg);
-- if (n2vseg.sh != dummysh) {
-- tssdissolve1(worktet);
-- tssbond1(newtops[i], n2vseg);
-- }
-- enextself(worktet); // edge v->n1 ==> b->n1
-- tsspivot1(worktet, n1vseg);
-- if (n1vseg.sh != dummysh) {
-- tssdissolve1(worktet);
-- enext2(newtops[i], tmpbond0);
-- tssbond1(tmpbond0, n1vseg);
-- }
-- }
-- }
-
- // Is there exist subfaces and subsegment need to be split?
- if (checksubfaces) {
-@@ -14438,7 +12308,6 @@
- // There is a subsegment connecting with ab at b. It will connect
- // to vb at b after splitting.
- bccasout.shver = 0;
-- if (sorg(bccasout) != pb) sesymself(bccasout);
- #ifdef SELF_CHECK
- assert(sorg(bccasout) == pb);
- #endif
-@@ -14715,8 +12584,8 @@
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--enum tetgenmesh::insertsiteresult tetgenmesh::insertsite(point newpoint,
-- triface* searchtet, bool approx, queue* flipqueue)
-+enum tetgenmesh::insertsiteresult tetgenmesh::
-+insertsite(point newpoint, triface* searchtet, bool approx, queue* flipqueue)
- {
- enum locateresult intersect, exactloc;
- point checkpt;
-@@ -14808,8 +12677,9 @@
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--void tetgenmesh::undosite(enum insertsiteresult insresult, triface* splittet,
-- point torg, point tdest, point tapex, point toppo)
-+void tetgenmesh::
-+undosite(enum insertsiteresult insresult, triface* splittet, point torg,
-+ point tdest, point tapex, point toppo)
- {
- // Set the four corners of 'splittet' exactly be 'torg', ... 'toppo'.
- findface(splittet, torg, tdest, tapex);
-@@ -14844,145 +12714,6 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// closeopenface() Close "open" faces recursively. //
--// //
--// This is the support routine of inserthullsite(). A point p which lies out-//
--// side of CH(T). p is inserted to T by forming a tet t from p and a visible //
--// CH face f. The three sides of f which have p as a vertex is called "open" //
--// face. Each open face will be closed by either creating a tet on top of it //
--// or become a new CH face. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--void tetgenmesh::closeopenface(triface* openface, queue* flipque)
--{
-- triface newtet, oldhull;
-- triface newopenface, closeface;
-- point inspoint, pa, pb, pc;
-- REAL attrib, volume;
-- int i;
--
-- // Get the new point p.
-- inspoint = apex(*openface);
-- // Find the old CH face f_o (f and f_o share the same edge).
-- esym(*openface, oldhull);
-- while (fnextself(oldhull)) ;
-- if (apex(oldhull) != inspoint) {
-- // Is f_o visible by p?
-- pa = org(oldhull);
-- pb = dest(oldhull);
-- pc = apex(oldhull);
-- if (orient3d(pa, pb, pc, inspoint) < 0.0) {
-- // Yes. Create a new tet t above f_o.
-- maketetrahedron(&newtet);
-- setorg(newtet, pa);
-- setdest(newtet, pb);
-- setapex(newtet, pc);
-- setoppo(newtet, inspoint);
-- for (i = 0; i < in->numberoftetrahedronattributes; i++) {
-- attrib = elemattribute(oldhull.tet, i);
-- setelemattribute(newtet.tet, i, attrib);
-- }
-- if (b->varvolume) {
-- volume = volumebound(oldhull.tet);
-- setvolumebound(newtet.tet, volume);
-- }
-- // Connect t to T.
-- bond(newtet, oldhull);
-- // Close f.
-- fnext(newtet, newopenface);
-- bond(newopenface, *openface);
-- // f_o becomes an interior face.
-- enqueueflipface(oldhull, flipque);
-- // Hull face number decreases.
-- hullsize--;
-- // Two faces of t become open face.
-- enextself(newtet);
-- for (i = 0; i < 2; i++) {
-- fnext(newtet, newopenface);
-- sym(newopenface, closeface);
-- if (closeface.tet == dummytet) {
-- closeopenface(&newopenface, flipque);
-- }
-- enextself(newtet);
-- }
-- } else {
-- // Inivisible. f becomes a new CH face.
-- hullsize++;
-- // Let 'dummytet' holds f for the next point location.
-- dummytet[0] = encode(*openface);
-- }
-- } else {
-- // f_o is co-incident with f --> f is closed by f_o.
-- bond(*openface, oldhull);
-- // f is an interior face.
-- enqueueflipface(*openface, flipque);
-- }
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
--// inserthullsite() Insert a point which lies outside the convex hull. //
--// //
--// The 'inspoint' p lies outside the tetrahedralization T. The 'horiz' f is //
--// on the convex hull of T, CH(T), which is visible by p (Imagine f is para- //
--// llel to the horizon). To insert p into T we have to enlarge the CH(T) and //
--// update T so that p is on the new CH(T). //
--// //
--// To enlarge the CH(T). We need to find the set F of faces which are on CH //
--// (T) and visible by p (F can be formed by a depth-first search from f). p //
--// is then inserted into T by mounting new tets formed by p and these faces. //
--// Faces of F become interior faces and may non-locally Delaunay. They are //
--// queued in 'flipqueue' for flip tests. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--void tetgenmesh::inserthullsite(point inspoint, triface* horiz, queue* flipque)
--{
-- triface firstnewtet;
-- triface openface, closeface;
-- REAL attrib, volume;
-- int i;
--
-- // Let f face to p.
-- adjustedgering(*horiz, CW);
-- // Create the first tet t (from f and p).
-- maketetrahedron(&firstnewtet);
-- setorg (firstnewtet, org(*horiz));
-- setdest(firstnewtet, dest(*horiz));
-- setapex(firstnewtet, apex(*horiz));
-- setoppo(firstnewtet, inspoint);
-- for (i = 0; i < in->numberoftetrahedronattributes; i++) {
-- attrib = elemattribute(horiz->tet, i);
-- setelemattribute(firstnewtet.tet, i, attrib);
-- }
-- if (b->varvolume) {
-- volume = volumebound(horiz->tet);
-- setvolumebound(firstnewtet.tet, volume);
-- }
-- // Connect t to T.
-- bond(firstnewtet, *horiz);
-- // f is not on CH(T) anymore.
-- enqueueflipface(*horiz, flipque);
-- // Hull face number decreases.
-- hullsize--;
--
-- // Call the faces of t which have p as a vertex "open" face.
-- for (i = 0; i < 3; i++) {
-- // Get an open face f_i of t.
-- fnext(firstnewtet, openface);
-- // Close f_i if it is still open.
-- sym(openface, closeface);
-- if (closeface.tet == dummytet) {
-- closeopenface(&openface, flipque);
-- }
-- // Go to the next open face of t.
-- enextself(firstnewtet);
-- }
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
- // Terminology: BC(p) and CBC(p), B(p) and C(p). //
- // //
- // Given an arbitrary point p, the Bowyer-Watson cavity BC(p) is formed by //
-@@ -16194,7 +13925,17 @@
- if (chkencseg) {
- // Check if a->p and p->b are encroached by other vertices.
- checkseg4encroach(&apseg, NULL, NULL, true);
-+ if (!shell2badface(apseg)) {
-+ if (varconstraint && (areabound(apseg) > 0.0)) {
-+ checkseg4badqual(&apseg, true);
-+ }
-+ }
- checkseg4encroach(&pbseg, NULL, NULL, true);
-+ if (!shell2badface(pbseg)) {
-+ if (varconstraint && (areabound(pbseg) > 0.0)) {
-+ checkseg4badqual(&pbseg, true);
-+ }
-+ }
- // Check if the adjacent segments are encroached by p.
- tallencsegs(bp, n, ceillists);
- }
-@@ -16221,6 +13962,11 @@
- for (i = 0; i < subceillist->len(); i++) {
- newsh = * (face *)(* subceillist)[i];
- checksub4encroach(&newsh, NULL, true);
-+ if (!shell2badface(newsh)) {
-+ if (varconstraint && (areabound(newsh) > 0.0)) {
-+ checksub4badqual(&newsh, true);
-+ }
-+ }
- }
- // Only do once if p is on a facet.
- if (splitseg == (face *) NULL) break;
-@@ -16300,17 +14046,15 @@
- // Add t into T.
- * (triface *)(* tetlist)[0] = starttet;
- infect(starttet);
-- if (verlist != (list *) NULL) {
-- // Add three verts of t into V.
-- ver[0] = org(starttet);
-- ver[1] = dest(starttet);
-- ver[2] = apex(starttet);
-- for (i = 0; i < 3; i++) {
-- // Mark the vert by inversing the index of the vert.
-- idx = pointmark(ver[i]);
-- setpointmark(ver[i], -idx - 1); // -1 to distinguish the zero.
-- verlist->append(&(ver[i]));
-- }
-+ // Add three verts of t into V.
-+ ver[0] = org(starttet);
-+ ver[1] = dest(starttet);
-+ ver[2] = apex(starttet);
-+ for (i = 0; i < 3; i++) {
-+ // Mark the vert by inversing the index of the vert.
-+ idx = pointmark(ver[i]);
-+ setpointmark(ver[i], -idx - 1); // -1 to distinguish the zero.
-+ verlist->append(&(ver[i]));
- }
-
- // Find other tets by a broadth-first search.
-@@ -16333,17 +14077,14 @@
- // Add n into T.
- infect(neightet);
- tetlist->append(&neightet);
-- if (verlist != (list *) NULL) {
-- // Add the apex vertex in n into V.
-- ver[0] = org(starttet);
-- ver[1] = dest(starttet);
-- findedge(&neightet, ver[0], ver[1]);
-- ver[2] = apex(neightet);
-- idx = pointmark(ver[2]);
-- if (idx >= 0) {
-- setpointmark(ver[2], -idx - 1);
-- verlist->append(&(ver[2]));
-- }
-+ ver[0] = org(starttet);
-+ ver[1] = dest(starttet);
-+ findedge(&neightet, ver[0], ver[1]);
-+ ver[2] = apex(neightet);
-+ idx = pointmark(ver[2]);
-+ if (idx >= 0) {
-+ setpointmark(ver[2], -idx - 1);
-+ verlist->append(&(ver[2]));
- }
- }
- }
-@@ -16356,13 +14097,11 @@
- starttet = * (triface *)(* tetlist)[i];
- uninfect(starttet);
- }
-- if (verlist != (list *) NULL) {
-- // Uninfect vertices.
-- for (i = 0; i < verlist->len(); i++) {
-- ver[0] = * (point *)(* verlist)[i];
-- idx = pointmark(ver[0]);
-- setpointmark(ver[0], -(idx + 1));
-- }
-+ // Uninfect vertices.
-+ for (i = 0; i < verlist->len(); i++) {
-+ ver[0] = * (point *)(* verlist)[i];
-+ idx = pointmark(ver[0]);
-+ setpointmark(ver[0], -(idx + 1));
- }
- }
-
-@@ -16441,24 +14180,163 @@
- }
- }
- }
-- } while ((apex(spintet) != tapex) && (hitbdry < 2));
-+ } while ((apex(spintet) != tapex) && (hitbdry < 2));
-+ }
-+ }
-+ if (merged) {
-+ if (b->object != tetgenbehavior::STL) {
-+ if (!b->quiet) {
-+ printf("Warning: Point %d is unified to point %d.\n",
-+ pointmark(testpt), pointmark(checkpt));
-+ }
-+ // Count the number of duplicated points.
-+ dupverts++;
-+ }
-+ // Remember it is a duplicated point.
-+ setpointtype(testpt, DUPLICATEDVERTEX);
-+ // Set a pointer to the point it duplicates.
-+ setpoint2ppt(testpt, checkpt);
-+ }
-+ return merged;
-+}
-+
-+///////////////////////////////////////////////////////////////////////////////
-+// //
-+// closeopenface() Close "open" faces recursively. //
-+// //
-+// This is the support routine of inserthullsite(). A point p which lies out-//
-+// side of CH(T). p is inserted to T by forming a tet t from p and a visible //
-+// CH face f. The three sides of f which have p as a vertex is called "open" //
-+// face. Each open face will be closed by either creating a tet on top of it //
-+// or become a new CH face. //
-+// //
-+///////////////////////////////////////////////////////////////////////////////
-+
-+void tetgenmesh::closeopenface(triface* openface, queue* flipque)
-+{
-+ triface newtet, oldhull;
-+ triface newopenface, closeface;
-+ point inspoint, pa, pb, pc;
-+ REAL attrib, volume;
-+ int i;
-+
-+ // Get the new point p.
-+ inspoint = apex(*openface);
-+ // Find the old CH face f_o (f and f_o share the same edge).
-+ esym(*openface, oldhull);
-+ while (fnextself(oldhull)) ;
-+ if (apex(oldhull) != inspoint) {
-+ // Is f_o visible by p?
-+ pa = org(oldhull);
-+ pb = dest(oldhull);
-+ pc = apex(oldhull);
-+ if (orient3d(pa, pb, pc, inspoint) < 0.0) {
-+ // Yes. Create a new tet t above f_o.
-+ maketetrahedron(&newtet);
-+ setorg(newtet, pa);
-+ setdest(newtet, pb);
-+ setapex(newtet, pc);
-+ setoppo(newtet, inspoint);
-+ for (i = 0; i < in->numberoftetrahedronattributes; i++) {
-+ attrib = elemattribute(oldhull.tet, i);
-+ setelemattribute(newtet.tet, i, attrib);
-+ }
-+ if (b->varvolume) {
-+ volume = volumebound(oldhull.tet);
-+ setvolumebound(newtet.tet, volume);
-+ }
-+ // Connect t to T.
-+ bond(newtet, oldhull);
-+ // Close f.
-+ fnext(newtet, newopenface);
-+ bond(newopenface, *openface);
-+ // f_o becomes an interior face.
-+ enqueueflipface(oldhull, flipque);
-+ // Hull face number decreases.
-+ hullsize--;
-+ // Two faces of t become open face.
-+ enextself(newtet);
-+ for (i = 0; i < 2; i++) {
-+ fnext(newtet, newopenface);
-+ sym(newopenface, closeface);
-+ if (closeface.tet == dummytet) {
-+ closeopenface(&newopenface, flipque);
-+ }
-+ enextself(newtet);
-+ }
-+ } else {
-+ // Inivisible. f becomes a new CH face.
-+ hullsize++;
-+ // Let 'dummytet' holds f for the next point location.
-+ dummytet[0] = encode(*openface);
- }
-+ } else {
-+ // f_o is co-incident with f --> f is closed by f_o.
-+ bond(*openface, oldhull);
-+ // f is an interior face.
-+ enqueueflipface(*openface, flipque);
- }
-- if (merged) {
-- if (b->object != tetgenbehavior::STL) {
-- if (!b->quiet) {
-- printf("Warning: Point %d is unified to point %d.\n",
-- pointmark(testpt), pointmark(checkpt));
-- }
-- // Count the number of duplicated points.
-- dupverts++;
-+}
-+
-+///////////////////////////////////////////////////////////////////////////////
-+// //
-+// inserthullsite() Insert a point which lies outside the convex hull. //
-+// //
-+// The 'inspoint' p lies outside the tetrahedralization T. The 'horiz' f is //
-+// on the convex hull of T, CH(T), which is visible by p (Imagine f is para- //
-+// llel to the horizon). To insert p into T we have to enlarge the CH(T) and //
-+// update T so that p is on the new CH(T). //
-+// //
-+// To enlarge the CH(T). We need to find the set F of faces which are on CH //
-+// (T) and visible by p (F can be formed by a depth-first search from f). p //
-+// is then inserted into T by mounting new tets formed by p and these faces. //
-+// Faces of F become interior faces and may non-locally Delaunay. They are //
-+// queued in 'flipqueue' for flip tests. //
-+// //
-+///////////////////////////////////////////////////////////////////////////////
-+
-+void tetgenmesh::inserthullsite(point inspoint, triface* horiz, queue* flipque)
-+{
-+ triface firstnewtet;
-+ triface openface, closeface;
-+ REAL attrib, volume;
-+ int i;
-+
-+ // Let f face to p.
-+ adjustedgering(*horiz, CW);
-+ // Create the first tet t (from f and p).
-+ maketetrahedron(&firstnewtet);
-+ setorg (firstnewtet, org(*horiz));
-+ setdest(firstnewtet, dest(*horiz));
-+ setapex(firstnewtet, apex(*horiz));
-+ setoppo(firstnewtet, inspoint);
-+ for (i = 0; i < in->numberoftetrahedronattributes; i++) {
-+ attrib = elemattribute(horiz->tet, i);
-+ setelemattribute(firstnewtet.tet, i, attrib);
-+ }
-+ if (b->varvolume) {
-+ volume = volumebound(horiz->tet);
-+ setvolumebound(firstnewtet.tet, volume);
-+ }
-+ // Connect t to T.
-+ bond(firstnewtet, *horiz);
-+ // f is not on CH(T) anymore.
-+ enqueueflipface(*horiz, flipque);
-+ // Hull face number decreases.
-+ hullsize--;
-+
-+ // Call the faces of t which have p as a vertex "open" face.
-+ for (i = 0; i < 3; i++) {
-+ // Get an open face f_i of t.
-+ fnext(firstnewtet, openface);
-+ // Close f_i if it is still open.
-+ sym(openface, closeface);
-+ if (closeface.tet == dummytet) {
-+ closeopenface(&openface, flipque);
- }
-- // Remember it is a duplicated point.
-- setpointtype(testpt, DUPLICATEDVERTEX);
-- // Set a pointer to the point it duplicates.
-- setpoint2ppt(testpt, checkpt);
-+ // Go to the next open face of t.
-+ enextself(firstnewtet);
- }
-- return merged;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
-@@ -16489,7 +14367,6 @@
- REAL det, n[3];
- REAL attrib, volume;
- int i, j;
-- clock_t loc_start, loc_end;
-
- if (b->verbose > 0) {
- printf(" Creating initial tetrahedralization.\n");
-@@ -16574,11 +14451,6 @@
- insertarray[0] = insertarray[1];
- insertarray[1] = swappt;
- }
-- if (b->verbose > 2) {
-- printf(" Create the first tet (%d, %d, %d, %d).\n",
-- pointmark(insertarray[0]), pointmark(insertarray[1]),
-- pointmark(insertarray[2]), pointmark(lastpt));
-- }
- setorg(newtet, insertarray[0]);
- setdest(newtet, insertarray[1]);
- setapex(newtet, insertarray[2]);
-@@ -16593,18 +14465,18 @@
- setvolumebound(newtet.tet, volume);
- }
- }
-- // Set vertex type be FREEVOLVERTEX if it has no type yet.
-+ // Set vertex type be VOLVERTEX if it has no type yet.
- if (pointtype(insertarray[0]) == UNUSEDVERTEX) {
-- setpointtype(insertarray[0], FREEVOLVERTEX);
-+ setpointtype(insertarray[0], VOLVERTEX);
- }
- if (pointtype(insertarray[1]) == UNUSEDVERTEX) {
-- setpointtype(insertarray[1], FREEVOLVERTEX);
-+ setpointtype(insertarray[1], VOLVERTEX);
- }
- if (pointtype(insertarray[2]) == UNUSEDVERTEX) {
-- setpointtype(insertarray[2], FREEVOLVERTEX);
-+ setpointtype(insertarray[2], VOLVERTEX);
- }
- if (pointtype(lastpt) == UNUSEDVERTEX) {
-- setpointtype(lastpt, FREEVOLVERTEX);
-+ setpointtype(lastpt, VOLVERTEX);
- }
- // Bond to 'dummytet' for point location.
- dummytet[0] = encode(newtet);
-@@ -16625,18 +14497,11 @@
- // Insert the rest of points, one by one.
- for (; i < arraysize; i++) {
- // Locate p_i in T.
--#ifdef SELF_CHECK
-- loc_start = clock();
--#endif
- if (jump) {
- loc = locate(insertarray[i], &searchtet);
- } else {
- loc = preciselocate(insertarray[i], &searchtet, tetrahedrons->items);
- }
--#ifdef SELF_CHECK
-- loc_end = clock();
-- tloctime += ((REAL) (loc_end - loc_start)) / CLOCKS_PER_SEC;
--#endif
- // Keep current search state for next searching.
- recenttet = searchtet;
- if (loc == ONVERTEX) {
-@@ -16684,26 +14549,18 @@
- }
- if (pointtype(insertarray[i]) == UNUSEDVERTEX) {
- // p_i becomes a (volume) vertex of T.
-- setpointtype(insertarray[i], FREEVOLVERTEX);
-+ setpointtype(insertarray[i], VOLVERTEX);
- }
--#ifdef SELF_CHECK
-- loc_start = clock();
--#endif
- if (!b->noflip) {
- // Recover Delaunayness of T by flipping.
- flip(flipque, NULL);
- } else {
-- lawson(NULL, flipque);
- // T remains regular.
-- // flipque->clear();
-+ flipque->clear();
- }
--#ifdef SELF_CHECK
-- loc_end = clock();
-- tfliptime += ((REAL) (loc_end - loc_start)) / CLOCKS_PER_SEC;
--#endif
- }
-
-- if (b->verbose > 0) {
-+ if (!b->noflip && b->verbose > 0) {
- printf(" %ld Flips (T23 %ld, T32 %ld, T22 %ld, T44 %ld)\n",
- flip23s+flip32s+flip22s+flip44s, flip23s, flip32s, flip22s, flip44s);
- }
-@@ -16734,29 +14591,23 @@
- }
- }
-
-- flipque = new queue(sizeof(badface));
- // Prepare the array of points for inserting.
- arraysize = points->items;
-- insertarray = new point[arraysize];
-- points->traversalinit();
--
-+ insertarray = new point[arraysize];
- // Randomize the point order.
- // randomseed = b->srandseed;
-+ points->traversalinit();
- for (i = 0; i < arraysize; i++) {
- j = (int) randomnation(i + 1); // 0 <= j <= i;
- insertarray[i] = insertarray[j];
- insertarray[j] = pointtraverse();
- }
--
-- // Use lawson flip.
-- b->noflip = 1;
-+ flipque = new queue(sizeof(badface));
-
- // Form the DT by incremental flip Delaunay algorithm.
- incrflipdelaunay(NULL, insertarray, arraysize, true, b->plc, b->epsilon,
- flipque);
-
-- b->noflip = 0;
--
- delete [] insertarray;
- delete flipque;
- return hullsize;
-@@ -16799,15 +14650,12 @@
- senextself(steinsh);
- }
- assert(i < 3);
-- // Add the edge f into list.
- * (face *)(* trilist)[0] = steinsh;
-+ // Add two verts a, b and one edge ab of f into lists,
- pa = sorg(steinsh);
- pb = sdest(steinsh);
-- if (vertlist != (list *) NULL) {
-- // Add two verts a, b into V,
-- vertlist->append(&pa);
-- vertlist->append(&pb);
-- }
-+ vertlist->append(&pa);
-+ vertlist->append(&pb);
-
- // Rotate edge pa to the left (CW) until meet pb or a segment.
- lnextsh = steinsh;
-@@ -16829,10 +14677,8 @@
- // Add edge ca to E.
- pc = sorg(lnextsh);
- if (pc == pb) break; // Rotate back.
-- if (vertlist != (list *) NULL) {
-- // Add vert c into V.
-- vertlist->append(&pc);
-- }
-+ // Add vert c to V.
-+ vertlist->append(&pc);
- } while (true);
-
- if (pc != pb) {
-@@ -16855,10 +14701,8 @@
- // Add edge bd to E.
- pd = sdest(rnextsh);
- if (pd == pa) break; // Rotate back.
-- if (vertlist != (list *) NULL) {
-- // Add vert d into V.
-- vertlist->append(&pd);
-- }
-+ // Add vert d to V.
-+ vertlist->append(&pd);
- } while (true);
- }
- }
-@@ -16885,7 +14729,7 @@
- // //
- // getfacetabovepoint() Get a point above a plane pass through a facet. //
- // //
--// The calculcated point is saved in 'facetabovepointarray'. The 'abovepoint'//
-+// The calulcated point is saved in 'facetabovepointarray'. The 'abovepoint' //
- // is set on return. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-@@ -16893,6 +14737,7 @@
- void tetgenmesh::getfacetabovepoint(face* facetsh)
- {
- list *verlist, *trilist, *tetlist;
-+ tetrahedron tetptr;
- triface adjtet;
- face symsh;
- point p1, p2, p3, pa;
-@@ -16959,22 +14804,17 @@
- stpivot(symsh, adjtet);
- }
- if (adjtet.tet == dummytet) {
-- decode(point2tet(p1), adjtet);
-- if (isdead(&adjtet)) {
-- adjtet.tet = dummytet;
-- } else {
-- if (!findorg(&adjtet, p1)) {
-+ tetptr = point2tet(p1);
-+ if (tetptr != (tetrahedron) NULL) {
-+ decode(tetptr, adjtet);
-+ if (isdead(&adjtet)) {
- adjtet.tet = dummytet;
- }
- }
- }
- if (adjtet.tet == dummytet) {
- loc = locate(p1, &adjtet);
-- if (loc == ONVERTEX) {
-- setpoint2tet(p1, encode(adjtet));
-- } else {
-- adjtet.tet = dummytet;
-- }
-+ if (loc != ONVERTEX) adjtet.tet = dummytet;
- }
- if (adjtet.tet != dummytet) {
- // Get the star polyhedron of p1.
-@@ -17248,7 +15088,6 @@
- REAL det, area;
- bool aboveflag;
- int arraysize;
-- int epscount;
- int fmarker;
- int idx, i, j, k;
-
-@@ -17264,8 +15103,6 @@
- // cillinear points of the set V = 'insertarray'. The first point:
- // a = insertarray[0].
-
-- epscount = 0;
-- while (true) {
- for (i = 1; i < arraysize; i++) {
- det = distance(insertarray[0], insertarray[i]);
- if (det > (longest * eps)) break;
-@@ -17291,23 +15128,22 @@
- // The set of vertices is not good (or nearly degenerate). However,
- // a trivial triangulation can be formed (using 3 vertices). It may
- // be corrected (or deleted) by mergefacet().
-- if ((eps == 0.0) || (epscount > 16)) {
-- printf("Error: Invalid PLC.\n");
-- printf(" Facet (%d, %d, %d", pointmark(insertarray[0]),
-- pointmark(insertarray[1]), pointmark(insertarray[2]));
-- if (ptlist->len() > 3) {
-- printf(", ...");
-+ if (eps == 0.0) {
-+ if (!b->quiet) {
-+ printf("Warning: Facet %d (%d, %d, %d", shmark,
-+ pointmark(insertarray[0]), pointmark(insertarray[1]),
-+ pointmark(insertarray[2]));
-+ if (ptlist->len() > 3) {
-+ printf(", ...");
-+ }
-+ printf(") is not a valid polygon.\n");
- }
-- printf(") (%d) is not a valid polygon.\n", shmark);
-- terminatetetgen(1);
- }
-- // Decrease the eps, and continue to try.
-- eps *= 1e-2;
-- epscount++;
-- continue;
-+ // Only use the first three points.
-+ i = arraysize;
-+ // Don't do calculation of abovepoint.
-+ aboveflag = false;
- }
-- break;
-- } // while (true);
-
- // Create the initial triangle.
- makeshellface(subfaces, &newsh);
-@@ -17316,15 +15152,15 @@
- setsapex(newsh, insertarray[2]);
- // Remeber the facet it belongs to.
- setshellmark(newsh, shmark);
-- // Set vertex type be FREESUBVERTEX if it has no type yet.
-- if (pointtype(insertarray[0]) == FREEVOLVERTEX) {
-- setpointtype(insertarray[0], FREESUBVERTEX);
-+ // Set vertex type be FACETVERTEX if it has no type yet.
-+ if (pointtype(insertarray[0]) == VOLVERTEX) {
-+ setpointtype(insertarray[0], FACETVERTEX);
- }
-- if (pointtype(insertarray[1]) == FREEVOLVERTEX) {
-- setpointtype(insertarray[1], FREESUBVERTEX);
-+ if (pointtype(insertarray[1]) == VOLVERTEX) {
-+ setpointtype(insertarray[1], FACETVERTEX);
- }
-- if (pointtype(insertarray[2]) == FREEVOLVERTEX) {
-- setpointtype(insertarray[2], FREESUBVERTEX);
-+ if (pointtype(insertarray[2]) == VOLVERTEX) {
-+ setpointtype(insertarray[2], FACETVERTEX);
- }
- // Let 'dummysh' point to it (for point location).
- dummysh[0] = sencode(newsh);
-@@ -17388,9 +15224,9 @@
- } else if (loc == ONVERTEX) {
- // !should not happen!
- }
-- // Set p_i's type FREESUBVERTEX if it has no type yet.
-- if (pointtype(insertarray[i]) == FREEVOLVERTEX) {
-- setpointtype(insertarray[i], FREESUBVERTEX);
-+ // Set p_i's type FACETVERTEX if it has no type yet.
-+ if (pointtype(insertarray[i]) == VOLVERTEX) {
-+ setpointtype(insertarray[i], FACETVERTEX);
- }
- flipsub(flipque);
- }
-@@ -18011,14 +15847,6 @@
- insertsubseg(&newsh);
- senextself(newsh);
- }
-- } else if (ptlist->len() == 2) {
-- // This facet is actually a segment. It is not support by the mesh data
-- // strcuture. Hence the segment will not be maintained in the mesh.
-- // However, during segment recovery, the segment can be processed.
-- cons = (point *)(* conlist)[0];
-- makeshellface(subsegs, &newsh);
-- setsorg(newsh, cons[0]);
-- setsdest(newsh, cons[1]);
- }
- }
-
-@@ -18240,8 +16068,8 @@
- // //
- // Segments between two merged facets will be removed from the mesh. If all //
- // segments around a vertex have been removed, change its vertex type to be //
--// FREESUBVERTEX. Edge flips will be performed to ensure the Delaunayness of //
--// the triangulation of merged facets. //
-+// FACETVERTEX. Edge flips will be performed to ensure the Delaunay criteria //
-+// of the triangulation of merged facets. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
-@@ -18318,12 +16146,12 @@
- j = pointmark(eorg);
- segspernodelist[j]--;
- if (segspernodelist[j] == 0) {
-- setpointtype(eorg, FREESUBVERTEX);
-+ setpointtype(eorg, FACETVERTEX);
- }
- j = pointmark(edest);
- segspernodelist[j]--;
- if (segspernodelist[j] == 0) {
-- setpointtype(edest, FREESUBVERTEX);
-+ setpointtype(edest, FACETVERTEX);
- }
- // Add 'parentsh' to queue checking for flip.
- enqueueflipedge(parentsh, flipqueue);
-@@ -18517,8 +16345,6 @@
- // Unify segments in 'subsegs', remove redundant segments. Face links
- // of segments are also built.
- unifysegments();
-- // Remember the number of input segments (for output).
-- insegments = subsegs->items;
-
- if (checkpbcs) {
- // Create the global array 'segpbcgrouptable'.
-@@ -18530,7 +16356,7 @@
- jettisonnodes();
- }
-
-- if (!b->nomerge && !b->nobisect && !checkpbcs) {
-+ if (!b->nomerge && !checkpbcs) {
- // No '-M' switch - merge adjacent facets if they are coplanar.
- mergefacets(flipqueue);
- }
-@@ -19009,15 +16835,13 @@
-
- void tetgenmesh::createsegpbcgrouptable()
- {
-- shellface** segsperverlist;
-- pbcdata *pd, *ppd, pd1, pd2;
-+ pbcdata *pd, *pd1, *pd2;
- face segloop, symseg;
- face startsh, spinsh, symsh;
-- point pa, pb, syma, symb;
-+ point pa, pb;
- enum locateresult symloc;
- REAL testpt[3], sympt[3];
- bool inflag;
-- int *idx2seglist;
- int segid1, segid2;
- int f1, f2;
- int i, j, k, l;
-@@ -19025,11 +16849,6 @@
- // Allocate memory for 'subpbcgrouptable'.
- segpbcgrouptable = new list(sizeof(pbcdata), NULL, 256);
-
-- if (b->refine) {
-- // Create a point-to-seg map for quickly finding PBC seg pairs.
-- makesegmentmap(idx2seglist, segsperverlist);
-- }
--
- // Loop through the segment list.
- subsegs->traversalinit();
- segloop.sh = shellfacetraverse(subsegs);
-@@ -19048,52 +16867,13 @@
- // Does spinsh belong to a pbcgroup?
- if (shellpbcgroup(spinsh) != -1) {
- // Yes! There exists a segment cd. ab and cd form a pbcgroup.
-- if (b->refine) {
-- getsubpbcgroup(&spinsh, &pd, &f1, &f2);
-- // Transform pa from f1 -> f2.
-- for (i = 0; i < 3; i++) {
-- sympt[i] = pd->transmat[f1][i][0] * pa[0]
-- + pd->transmat[f1][i][1] * pa[1]
-- + pd->transmat[f1][i][2] * pa[2]
-- + pd->transmat[f1][i][3] * 1.0;
-- }
-- syma = point2pbcpt(pa);
-- // Is 'sympt == syma'?
-- if (distance(sympt, syma) > (longest * b->epsilon)) {
-- // No. Search the symmetric vertex of pa.
-- symloc = getsubpbcsympoint(pa, &spinsh, sympt, &symsh);
-- syma = sorg(symsh);
-- if (symloc != ONVERTEX) {
-- // Do a brute force search. Not done yet.
-- assert(0);
-- }
-- }
-- // Transform pb from f1 -> f2.
-- for (i = 0; i < 3; i++) {
-- sympt[i] = pd->transmat[f1][i][0] * pb[0]
-- + pd->transmat[f1][i][1] * pb[1]
-- + pd->transmat[f1][i][2] * pb[2]
-- + pd->transmat[f1][i][3] * 1.0;
-- }
-- // Search sym subface from the point-to-subface map.
-- symseg.shver = 0;
-- j = pointmark(syma) - in->firstnumber;
-- for (i = idx2seglist[j]; i < idx2seglist[j + 1]; i++) {
-- symseg.sh = segsperverlist[i];
-- if (sorg(symseg) == syma) symb = sdest(symseg);
-- else symb = sorg(symseg);
-- if (distance(sympt, symb) <= (longest * b->epsilon)) break;
-- }
-- assert(i < idx2seglist[j + 1]);
-- } else {
-- // 'testpt' is the midpoint of ab used to find cd.
-- for (i = 0; i < 3; i++) testpt[i] = 0.5 * (pa[i] + pb[i]);
-- symloc = getsubpbcsympoint(testpt, &spinsh, sympt, &symsh);
-+ // 'testpt' is the midpoint of ab used to find cd.
-+ for (i = 0; i < 3; i++) testpt[i] = 0.5 * (pa[i] + pb[i]);
-+ symloc = getsubpbcsympoint(testpt, &spinsh, sympt, &symsh);
- #ifdef SELF_CHECK
-- assert(symloc == ONEDGE);
-+ assert(symloc == ONEDGE);
- #endif
-- sspivot(symsh, symseg);
-- }
-+ sspivot(symsh, symseg);
- #ifdef SELF_CHECK
- assert(symseg.sh != dummysh);
- #endif
-@@ -19118,19 +16898,19 @@
- pd->ss[0] = segloop;
- pd->ss[1] = symseg;
- // Find the map from ab to cd.
-- getsubpbcgroup(&spinsh, &ppd, &f1, &f2);
-- pd->fmark[0] = ppd->fmark[f1];
-- pd->fmark[1] = ppd->fmark[f2];
-+ getsubpbcgroup(&spinsh, &pd1, &f1, &f2);
-+ pd->fmark[0] = pd1->fmark[f1];
-+ pd->fmark[1] = pd1->fmark[f2];
- // Set the map from ab to cd.
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++) {
-- pd->transmat[0][i][j] = ppd->transmat[f1][i][j];
-+ pd->transmat[0][i][j] = pd1->transmat[f1][i][j];
- }
- }
- // Set the map from cd to ab.
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++) {
-- pd->transmat[1][i][j] = ppd->transmat[f2][i][j];
-+ pd->transmat[1][i][j] = pd1->transmat[f2][i][j];
- }
- }
- }
-@@ -19140,35 +16920,27 @@
- } while (spinsh.sh != startsh.sh);
- segloop.sh = shellfacetraverse(subsegs);
- }
--
-- if (b->refine) {
-- delete [] segsperverlist;
-- delete [] idx2seglist;
-- }
-
- // Create the indirect segment pbcgroups.
-- // Bug-fixed (08 Sept. 2006). The total size of 'segpbcgrouptable' may get
-- // increased. Do not use pointers for 'pd1' and 'pd2'. The addresses may
-- // be invaild after realloc().
- for (i = 0; i < segpbcgrouptable->len(); i++) {
-- pd1 = * (pbcdata *)(* segpbcgrouptable)[i];
-+ pd1 = (pbcdata *)(* segpbcgrouptable)[i];
- for (f1 = 0; f1 < 2; f1++) {
-- // Search for a group (except i) contains pd1.segid[f1].
-+ // Search for a group (except i) contains pd1->segid[f1].
- for (j = 0; j < segpbcgrouptable->len(); j++) {
- if (j == i) continue;
-- pd2 = * (pbcdata *)(* segpbcgrouptable)[j];
-+ pd2 = (pbcdata *)(* segpbcgrouptable)[j];
- f2 = -1;
-- if (pd1.segid[f1] == pd2.segid[0]) {
-+ if (pd1->segid[f1] == pd2->segid[0]) {
- f2 = 0;
-- } else if (pd1.segid[f1] == pd2.segid[1]) {
-+ } else if (pd1->segid[f1] == pd2->segid[1]) {
- f2 = 1;
- }
- if (f2 != -1) {
- #ifdef SELF_CHECK
-- assert(pd1.segid[f1] == pd2.segid[f2]);
-+ assert(pd1->segid[f1] == pd2->segid[f2]);
- #endif
-- segid1 = pd1.segid[1 - f1];
-- segid2 = pd2.segid[1 - f2];
-+ segid1 = pd1->segid[1 - f1];
-+ segid2 = pd2->segid[1 - f2];
- // Search for the existence of segment pbcgroup (segid1, segid2).
- inflag = false;
- for (k = 0; k < segpbcgrouptable->len() && !inflag; k++) {
-@@ -19181,28 +16953,28 @@
- }
- if (!inflag) {
- pd = (pbcdata *) segpbcgrouptable->append(NULL);
-- pd->segid[0] = pd1.segid[1 - f1];
-- pd->segid[1] = pd2.segid[1 - f2];
-- pd->ss[0] = pd1.ss[1 - f1];
-- pd->ss[1] = pd2.ss[1 - f2];
-+ pd->segid[0] = pd1->segid[1 - f1];
-+ pd->segid[1] = pd2->segid[1 - f2];
-+ pd->ss[0] = pd1->ss[1 - f1];
-+ pd->ss[1] = pd2->ss[1 - f2];
- // Invalid the fmark[0] == fmark[1].
- pd->fmark[0] = pd->fmark[1] = 0;
- // Translate matrix pd->transmat[0] = m2 * m1, where m1 =
-- // pd1.transmat[1 - f1], m2 = pd2.transmat[f2].
-+ // pd1->transmat[1 - f1], m2 = pd2->transmat[f2].
- for (k = 0; k < 4; k++) {
- for (l = 0; l < 4; l++) {
-- pd->transmat[0][k][l] = pd2.transmat[f2][k][l];
-+ pd->transmat[0][k][l] = pd2->transmat[f2][k][l];
- }
- }
-- m4xm4(pd->transmat[0], pd1.transmat[1 - f1]);
-+ m4xm4(pd->transmat[0], pd1->transmat[1 - f1]);
- // Translate matrix pd->transmat[1] = m4 * m3, where m3 =
-- // pd2.transmat[1 - f2], m4 = pd1.transmat[f1].
-+ // pd2->transmat[1 - f2], m4 = pd1->transmat[f1].
- for (k = 0; k < 4; k++) {
- for (l = 0; l < 4; l++) {
-- pd->transmat[1][k][l] = pd1.transmat[f1][k][l];
-+ pd->transmat[1][k][l] = pd1->transmat[f1][k][l];
- }
- }
-- m4xm4(pd->transmat[1], pd2.transmat[1 - f2]);
-+ m4xm4(pd->transmat[1], pd2->transmat[1 - f2]);
- }
- }
- }
-@@ -20040,93 +17812,92 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// markacutevertices() Mark acute vertices. //
-+// markacutevertices() Mark each vertex to be ACUTE or NACUTE. //
- // //
--// A vertex v is called acute if there are two segments sharing at v forming //
--// an acute angle (i.e. smaller than 90 degree). //
--// //
--// This routine finds all acute vertices in the PLC and marks them as point- //
--// type ACUTEVERTEX. The other vertices of segments which are non-acute will //
--// be marked as NACUTEVERTEX. Vertices which are not endpoints of segments //
--// (such as DUPLICATEDVERTEX, UNUSEDVERTEX, etc) are not infected. //
--// //
--// NOTE: This routine should be called before Steiner points are introduced. //
--// That is, no point has type like FREESEGVERTEX, etc. //
-+// A vertex is acute if at least two segments incident at it with an angle //
-+// smaller than a given angle bound (e.g. 90 degree). //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
- void tetgenmesh::markacutevertices(REAL acuteangle)
- {
- shellface **segsperverlist;
-- face segloop, nextseg;
-- point pointloop, edest, eapex;
-+ face segloop, workseg, inciseg;
-+ point eorg, edest, eapex;
- REAL cosbound, anglearc;
- REAL v1[3], v2[3], L, D;
- bool isacute;
- int *idx2seglist;
-- int acutecount;
- int idx, i, j, k;
-
- if (b->verbose > 0) {
-- printf(" Marking acute vertices.\n");
-+ printf(" Marking segments have acute corners.\n");
- }
-
- anglearc = acuteangle * PI / 180.0;
- cosbound = cos(anglearc);
-- acutecount = 0;
- // Constructing a map from vertex to segments.
- makesegmentmap(idx2seglist, segsperverlist);
--
-- // Loop over the set of vertices.
-- points->traversalinit();
-- pointloop = pointtraverse();
-- while (pointloop != (point) NULL) {
-- idx = pointmark(pointloop) - in->firstnumber;
-- // Only do test if p is an endpoint of some segments.
-- if (idx2seglist[idx + 1] > idx2seglist[idx]) {
-- // Init p to be non-acute.
-- setpointtype(pointloop, NACUTEVERTEX);
-- isacute = false;
-- // Loop through all segments sharing at p.
-- for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isacute; i++) {
-- segloop.sh = segsperverlist[i];
-- // segloop.shver = 0;
-- if (sorg(segloop) != pointloop) sesymself(segloop);
-- edest = sdest(segloop);
-- for (j = i + 1; j < idx2seglist[idx + 1] && !isacute; j++) {
-- nextseg.sh = segsperverlist[j];
-- // nextseg.shver = 0;
-- if (sorg(nextseg) != pointloop) sesymself(nextseg);
-- eapex = sdest(nextseg);
-- // Check the angle formed by segs (p, edest) and (p, eapex).
-- for (k = 0; k < 3; k++) {
-- v1[k] = edest[k] - pointloop[k];
-- v2[k] = eapex[k] - pointloop[k];
-- }
-- L = sqrt(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]);
-- for (k = 0; k < 3; k++) v1[k] /= L;
-- L = sqrt(v2[0] * v2[0] + v2[1] * v2[1] + v2[2] * v2[2]);
-- for (k = 0; k < 3; k++) v2[k] /= L;
-- D = v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
-- // Is D acute?
-- isacute = (D >= cosbound);
-- }
-- }
-- if (isacute) {
-- // Mark p to be acute.
-- setpointtype(pointloop, ACUTEVERTEX);
-- acutecount++;
-+
-+ // Loop over the set of subsegments.
-+ subsegs->traversalinit();
-+ segloop.sh = shellfacetraverse(subsegs);
-+ while (segloop.sh != (shellface *) NULL) {
-+ // Check and set types for the two ends of this segment.
-+ for (segloop.shver = 0; segloop.shver < 2; segloop.shver++) {
-+ eorg = sorg(segloop);
-+ if ((pointtype(eorg) != ACUTEVERTEX) &&
-+ (pointtype(eorg) != NACUTEVERTEX) &&
-+ (pointtype(eorg) != FREESEGVERTEX)) {
-+ // This vertex has no type be set yet.
-+ idx = pointmark(eorg) - in->firstnumber;
-+ isacute = false;
-+ for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isacute; i++) {
-+ workseg.sh = segsperverlist[i];
-+ workseg.shver = 0;
-+ if (sorg(workseg) != eorg) sesymself(workseg);
-+#ifdef SELF_CHECK
-+ assert(sorg(workseg) == eorg);
-+#endif
-+ edest = sdest(workseg);
-+ for (j = i + 1; j < idx2seglist[idx + 1] && !isacute; j++) {
-+ inciseg.sh = segsperverlist[j];
-+ inciseg.shver = 0;
-+#ifdef SELF_CHECK
-+ assert(inciseg.sh != workseg.sh);
-+#endif
-+ if (sorg(inciseg) != eorg) sesymself(inciseg);
-+#ifdef SELF_CHECK
-+ assert(sorg(inciseg) == eorg);
-+#endif
-+ eapex = sdest(inciseg);
-+ // Check angles between segs (eorg, edest) and (eorg, eapex).
-+ for (k = 0; k < 3; k++) {
-+ v1[k] = edest[k] - eorg[k];
-+ v2[k] = eapex[k] - eorg[k];
-+ }
-+ L = sqrt(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]);
-+ for (k = 0; k < 3; k++) v1[k] /= L;
-+ L = sqrt(v2[0] * v2[0] + v2[1] * v2[1] + v2[2] * v2[2]);
-+ for (k = 0; k < 3; k++) v2[k] /= L;
-+ D = v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
-+ if (D >= cosbound) {
-+ isacute = true;
-+ }
-+ }
-+ }
-+ if (isacute) {
-+ setpointtype(eorg, ACUTEVERTEX);
-+ } else {
-+ setpointtype(eorg, NACUTEVERTEX);
-+ }
- }
- }
-- pointloop = pointtraverse();
-+ segloop.sh = shellfacetraverse(subsegs);
- }
-
- delete [] idx2seglist;
- delete [] segsperverlist;
--
-- if ((b->verbose > 0) && (acutecount > 0)) {
-- printf(" %d acute vertices.\n", acutecount);
-- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
-@@ -20655,7 +18426,7 @@
- point farorg, fardest;
- point ei, ej, ek, c;
- REAL v[3], r, split;
-- REAL d1, d2, ps, rs;
-+ REAL d1, ps, rs;
- bool acuteorg, acutedest;
- int stype, rule;
- int i;
-@@ -20765,6 +18536,7 @@
- if (rule == 1) r1count++;
- else if (rule == 2) r2count++;
- else if (rule == 3) r3count++;
-+ else if (rule == 4) r4count++;
-
- if (b->verbose > 1) {
- if (stype == 2) {
-@@ -20778,13 +18550,12 @@
- makepoint(&splitpoint);
- // Add a random perturbation on splitpoint.
- d1 = distance(c, v);
-- d2 = distance(refpoint, v);
- if (stype == 1 || stype == 3) {
- ps = randgenerator(d1 * 1.0e-3);
- } else {
- // For type-2 segment, add a smaller perturbation.
- // ps = randgenerator(d1 * 1.0e-5);
-- // REAL d2 = distance(refpoint, v);
-+ REAL d2 = distance(refpoint, v);
- ps = randgenerator(d2 * 1.0e-5);
- }
- rs = ps / d1;
-@@ -20809,100 +18580,6 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// insertsegment() Insert segment into DT. Queue it if it does not exist. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--bool tetgenmesh::insertsegment(face *insseg, list *misseglist)
--{
-- badface *misseg;
-- triface searchtet, spintet;
-- point tend, checkpoint;
-- point p1, p2;
-- enum finddirectionresult collinear;
-- int hitbdry;
--
-- // Search segment ab in DT.
-- p1 = (point) insseg->sh[3];
-- p2 = (point) insseg->sh[4];
-- getsearchtet(p1, p2, &searchtet, &tend);
-- collinear = finddirection(&searchtet, tend, tetrahedrons->items);
-- if (collinear == LEFTCOLLINEAR) {
-- checkpoint = apex(searchtet);
-- enext2self(searchtet);
-- esymself(searchtet);
-- } else if (collinear == RIGHTCOLLINEAR) {
-- checkpoint = dest(searchtet);
-- } else if (collinear == TOPCOLLINEAR) {
-- checkpoint = oppo(searchtet);
-- fnextself(searchtet);
-- enext2self(searchtet);
-- esymself(searchtet);
-- } else {
-- // assert(collinear == ACROSSFACE || collinear == ACROSSEDGE);
-- checkpoint = (point) NULL;
-- }
-- if (checkpoint == tend) {
-- // Segment exist. Bond it to all tets containing it.
-- hitbdry = 0;
-- adjustedgering(searchtet, CCW);
-- fnextself(searchtet);
-- spintet = searchtet;
-- do {
-- tssbond1(spintet, *insseg);
-- if (!fnextself(spintet)) {
-- hitbdry++;
-- if (hitbdry < 2) {
-- esym(searchtet, spintet);
-- if (!fnextself(spintet)) {
-- hitbdry++;
-- }
-- }
-- }
-- } while ((apex(spintet) != apex(searchtet)) && (hitbdry < 2));
-- return true;
-- } else {
-- // Segment is missing.
-- if (misseglist != (list *) NULL) {
-- if (b->verbose > 2) {
-- printf(" Queuing missing segment (%d, %d).\n", pointmark(p1),
-- pointmark(p2));
-- }
-- misseg = (badface *) misseglist->append(NULL);
-- misseg->ss = *insseg;
-- misseg->forg = p1;
-- misseg->fdest = p2;
-- misseg->foppo = (point) NULL; // Not used.
-- // setshell2badface(misseg->ss, misseg);
-- }
-- return false;
-- }
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
--// tallmissegs() Find and queue all missing segments in DT. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--void tetgenmesh::tallmissegs(list *misseglist)
--{
-- face segloop;
--
-- if (b->verbose) {
-- printf(" Queuing missing segments.\n");
-- }
--
-- subsegs->traversalinit();
-- segloop.sh = shellfacetraverse(subsegs);
-- while (segloop.sh != (shellface *) NULL) {
-- insertsegment(&segloop, misseglist);
-- segloop.sh = shellfacetraverse(subsegs);
-- }
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
- // delaunizesegments() Split segments repeatedly until they appear in a //
- // Delaunay tetrahedralization. //
- // //
-@@ -20940,20 +18617,19 @@
-
- void tetgenmesh::delaunizesegments()
- {
-- list *misseglist;
- queue *flipqueue;
-- badface *misloop;
- tetrahedron encodedtet;
- triface searchtet, splittet;
- face splitsh, symsplitsub;
- face segloop, symsplitseg;
-+ face lastsplit;
- point refpoint, splitpoint, sympoint;
- point tend, checkpoint;
- point p1, p2, pa;
- enum finddirectionresult collinear;
- enum insertsiteresult success;
- enum locateresult symloc;
-- bool coll;
-+ bool finish, coll;
- long vertcount;
- int i, j;
-
-@@ -20961,35 +18637,30 @@
- printf("Delaunizing segments.\n");
- }
-
-- // Construct a map from points to tets for speeding point location.
-- makepoint2tetmap();
-- // Initialize a flipqueue.
-+ // Mark segment vertices (acute or not) for determining segment types.
-+ markacutevertices(89.0);
-+ // Construct a map from points to tetrahedra for speeding point location.
-+ // makepoint2tetmap(); // This is done in above routine.
-+ // Initialize a queue for returning non-Delaunay faces and edges.
- flipqueue = new queue(sizeof(badface));
-- // Initialize the pool of missing segments.
-- misseglist = new list(sizeof(badface), NULL, SUBPERBLOCK);
-- // Looking for missing segments.
-- tallmissegs(misseglist);
-- // The DT contains segments now.
-- checksubsegs = 1;
-+ // 'lastsplit' is the last segment be split in one loop, all segments
-+ // after it are existing. At first, set it be NULL;
-+ lastsplit.sh = (shellface *) NULL;
- // Remember the current number of points.
- vertcount = points->items;
- // Initialize the counters.
-- r1count = r2count = r3count = 0l;
-+ r1count = r2count = r3count = r4count = 0l;
-
-- // Loop until 'misseglist' is empty.
-- while (misseglist->items > 0) {
-- // Randomly pick a missing segment to recover.
-- i = randomnation(misseglist->items);
-- misloop = (badface *)(* misseglist)[i];
-- segloop = misloop->ss;
-- // Fill the "hole" in the list by filling the last one.
-- *misloop = *(badface *)(* misseglist)[misseglist->items - 1];
-- misseglist->items--;
-- // Now recover the segment.
-- p1 = (point) segloop.sh[3];
-- p2 = (point) segloop.sh[4];
-- if (b->verbose > 1) {
-- printf(" Recover segment (%d, %d).\n", pointmark(p1), pointmark(p2));
-+ finish = false;
-+ while (!finish && (steinerleft != 0)) {
-+ subsegs->traversalinit();
-+ segloop.sh = shellfacetraverse(subsegs);
-+ while ((segloop.sh != (shellface *) NULL) && (steinerleft != 0)) {
-+ // Search segment ab in DT.
-+ p1 = sorg(segloop); // p1 = a;
-+ p2 = sdest(segloop); // p2 = b;
-+ if (b->verbose > 2) {
-+ printf(" Checking segment (%d, %d).\n", pointmark(p1), pointmark(p2));
- }
- getsearchtet(p1, p2, &searchtet, &tend);
- collinear = finddirection(&searchtet, tend, tetrahedrons->items);
-@@ -21013,7 +18684,7 @@
- // ab is defined by a long segment with c inside it. Use c to
- // split ab. No new point is created.
- splitpoint = checkpoint;
-- if (pointtype(checkpoint) == FREEVOLVERTEX) {
-+ if (pointtype(checkpoint) == VOLVERTEX) {
- // c is not a segment vertex yet. It becomes NACUTEVERTEX.
- setpointtype(splitpoint, NACUTEVERTEX);
- } else if (pointtype(checkpoint) == ACUTEVERTEX) {
-@@ -21026,7 +18697,7 @@
- } else {
- // Find a reference point p of ab.
- refpoint = scoutrefpoint(&searchtet, tend);
-- if (pointtype(refpoint) == FREEVOLVERTEX) {
-+ if (pointtype(refpoint) == VOLVERTEX) {
- // p is an input point, check if it is nearly collinear with ab.
- coll = iscollinear(p1, p2, refpoint, b->epsilon);
- if (coll) {
-@@ -21080,7 +18751,7 @@
- // Let sympoint remember splittet.
- setpoint2tet(sympoint, encode(splittet));
- // Do flip in DT.
-- lawson(misseglist, flipqueue);
-+ flip(flipqueue, NULL);
- // Insert sympoint into F.
- symsplitseg.shver = 0;
- spivot(symsplitseg, symsplitsub);
-@@ -21088,13 +18759,6 @@
- splitsubedge(sympoint, &symsplitsub, flipqueue);
- // Do flip in facet.
- flipsub(flipqueue);
-- // Insert the two subsegments.
-- symsplitseg.shver = 0;
-- insertsegment(&symsplitseg, misseglist);
-- senextself(symsplitseg);
-- spivotself(symsplitseg);
-- symsplitseg.shver = 0;
-- insertsegment(&symsplitseg, misseglist);
- } else { // if (symloc == ONVERTEX) {
- // The sympoint already exists. It is possible when two
- // pbc groups are exactly the same. Omit this point.
-@@ -21117,42 +18781,35 @@
- // consequent point location.
- setpoint2tet(splitpoint, encode(searchtet));
- // Maintain Delaunayness in DT.
-- lawson(misseglist, flipqueue);
-+ flip(flipqueue, NULL);
- }
- }
- // Insert 'splitpoint' into F.
- spivot(segloop, splitsh);
- splitsubedge(splitpoint, &splitsh, flipqueue);
- flipsub(flipqueue);
-- // Insert the two subsegments.
-- segloop.shver = 0;
-- insertsegment(&segloop, misseglist);
-- senextself(segloop);
-- spivotself(segloop);
-- segloop.shver = 0;
-- insertsegment(&segloop, misseglist);
-+ // Remember 'segloop'.
-+ lastsplit = segloop;
-+ } else {
-+ // ab exists. Is it the last one we've checked?
-+ if (segloop.sh == lastsplit.sh) {
-+ finish = true;
-+ break;
-+ }
- }
-- }
--
-- // Detach all segments from tets.
-- tetrahedrons->traversalinit();
-- searchtet.tet = tetrahedrontraverse();
-- while (searchtet.tet != (tetrahedron *) NULL) {
-- for (i = 0; i < 6; i++) {
-- searchtet.tet[8 + i] = (tetrahedron) dummysh;
-+ segloop.sh = shellfacetraverse(subsegs);
-+ }
-+ if (lastsplit.sh == (shellface *) NULL) {
-+ // No missing segment!
-+ finish = true;
- }
-- searchtet.tet = tetrahedrontraverse();
- }
-- // No segments now.
-- checksubsegs = 0;
-
- if (b->verbose > 0) {
- printf(" %ld protect points.\n", points->items - vertcount);
-- printf(" R1: %ld, R2: %ld, R3: %ld.\n", r1count, r2count, r3count);
- }
-
- delete flipqueue;
-- delete misseglist;
- }
-
- //
-@@ -23453,8 +21110,6 @@
- if (shellmark(neighsh) == 0) {
- setshellmark(neighsh, 1);
- }
-- // This side becomes hull. Update the handle in dummytet.
-- dummytet[0] = encode(neighbor);
- }
- }
- }
-@@ -23605,8 +21260,9 @@
- j = pointmark(checkpt);
- tetspernodelist[j]--;
- if (tetspernodelist[j] == 0) {
-- // If it is added volume vertex or '-j' is not used, delete it.
-- if ((pointtype(checkpt) == FREEVOLVERTEX) || !b->nojettison) {
-+ // If it is a volume vertex, mark to delete it.
-+ if ((pointtype(checkpt) == VOLVERTEX) ||
-+ (pointtype(checkpt) == FREEVOLVERTEX)) {
- setpointtype(checkpt, UNUSEDVERTEX);
- unuverts++;
- }
-@@ -24175,7 +21831,7 @@
- flip22(flipface, flipque);
- return true;
- }
-- } else if (fc == N32) {
-+ } else if (fc == UNFLIPABLE) {
- // Is f a crossface?
- if (front != (triface *) NULL) {
- // (6) Is any obstacle face (abd, or abe, ...) flipable?
-@@ -24613,7 +22269,7 @@
- floorlist->len(), ceillist->len(), ptlist->len());
- }
-
-- // symbolic = 1;
-+ symbolic = 1;
-
- // Initialize the cavity C.
- initializecavity(floorlist, ceillist, frontlist);
-@@ -24654,7 +22310,7 @@
- retrievenewtets(newtetlist);
- }
-
-- // symbolic = 0;
-+ symbolic = 0;
-
- if (misfrontlist->len() == 0) {
- // All fronts have identified in D. Get the shape of C by removing out
-@@ -25199,8 +22855,8 @@
-
- // Loop in B(p), replace p with np, queue dead tets, uninfect old tets.
- for (i = 0; i < oldtetlist->len(); i++) {
-- oldtet = * (triface *)(* oldtetlist)[i]; // assert(infected(oldtet));
-- uninfect(oldtet);
-+ oldtet = * (triface *)(* oldtetlist)[i];
-+ assert(!infected(oldtet));
- pa = org(oldtet);
- pb = dest(oldtet);
- pc = apex(oldtet);
-@@ -25289,12 +22945,8 @@
- }
- // Dealloc the 'fake' tet.
- tetrahedrondealloc(front.tet);
-- // If 'neightet' is a hull face, let 'dummytet' bond to it. It is
-- // a 'dummytet' when this front was created from a new subface.
-- // In such case, it should not be bounded.
-- if (neightet.tet != dummytet) {
-- dummytet[0] = encode(neightet);
-- }
-+ // This side (neightet) is a boundary face, let 'dummytet' bond to it.
-+ dummytet[0] = encode(neightet);
- }
- }
- }
-@@ -25360,14 +23012,11 @@
- // 'supsh' is a subface f of F, and p = sapex(f); the other parameters are //
- // working lists which are empty at the beginning and the end. //
- // //
--// 'optflag' is used for mesh optimization. If it is set, after removing p, //
--// test the object function on each new tet, queue bad tets. //
--// //
- ///////////////////////////////////////////////////////////////////////////////
-
- bool tetgenmesh::suppressfacetpoint(face* supsh, list* frontlist,
- list* misfrontlist, list* ptlist, list* conlist, memorypool* viri,
-- queue* flipque, bool noreloc, bool optflag)
-+ queue* flipque)
- {
- list *oldtetlist[2], *newtetlist[2];
- list *oldshlist, *newshlist;
-@@ -25441,17 +23090,12 @@
- // Preparation for re-tetrahedralzing old B_i(p).
- orientnewsubs(newshlist, supsh, norm);
- // Tetrahedralize old B_i(p).
-- success = constrainedcavity(&oldtet, newshlist, oldtetlist[i], ptlist,
-- frontlist, misfrontlist, newtetlist[i], flipque);
-- // If p is not suppressed, do relocation if 'noreloc' is not set.
-- if (!success && !noreloc) {
-- // Try to relocate p into the old B_i(p).
-+ if (!constrainedcavity(&oldtet, newshlist, oldtetlist[i], ptlist,
-+ frontlist, misfrontlist, newtetlist[i], flipque)) {
-+ // Unable to mesh old B_i(p), try to relocate p into it.
- makepoint(&(newpt[i]));
- success = findrelocatepoint(suppt, newpt[i], norm, frontlist,
- oldtetlist[i]);
-- // Initialize newpt = suppt.
-- // for (j = 0; j < 3; j++) newpt[i][j] = suppt[j];
-- // success = smoothvolpoint(newpt[i], frontlist, true);
- if (success) {
- // p is relocated by newpt[i]. Now insert it. Don't do flip since
- // the new tets may get deleted again.
-@@ -25466,10 +23110,6 @@
- assert(newtetlist[i]->len() == 0);
- }
- }
-- if (!success && noreloc) {
-- // Failed and no point relocation. Clean fake tets.
-- deallocfaketets(frontlist);
-- }
- // Clear work lists.
- ptlist->clear();
- frontlist->clear();
-@@ -25511,17 +23151,6 @@
- }
- }
- }
-- if (optflag) {
-- // Check for new bad-quality tets.
-- for (i = 0; i < 2; i++) {
-- if (newtetlist[i] != (list *) NULL) {
-- for (j = 0; j < newtetlist[i]->len(); j++) {
-- newtet = * (triface *)(* (newtetlist[i]))[j];
-- if (!isdead(&newtet)) checktet4opt(&newtet, true);
-- }
-- }
-- }
-- }
- } else {
- // p is not suppressed. Recover the original state.
- unsupverts++;
-@@ -25590,7 +23219,7 @@
-
- bool tetgenmesh::suppresssegpoint(face* supseg, list* spinshlist,
- list* newsegshlist, list* frontlist, list* misfrontlist, list* ptlist,
-- list* conlist, memorypool* viri, queue* flipque, bool noreloc, bool optflag)
-+ list* conlist, memorypool* viri, queue* flipque)
- {
- list **oldtetlist, **newtetlist;
- list **oldshlist, **newshlist;
-@@ -25601,20 +23230,19 @@
- face nsupseg, newseg, prevseg, nextseg;
- point suppt, *newpt;
- point pa, pb, *cons;
-- REAL pnorm[2][3], norm[3];
-+ REAL norm[3], pnorm[2][3];
- bool success;
- int shmark;
- int n, i, j, k;
-
- // Get the Steiner point p.
-- assert(supseg->shver < 2);
-+ assert(supseg->shver == 0);
- suppt = sdest(*supseg);
- // Find the segment ab split by p.
- senext(*supseg, nsupseg);
- spivotself(nsupseg);
- assert(nsupseg.sh != dummysh);
- nsupseg.shver = 0;
-- if (sorg(nsupseg) != suppt) sesymself(nsupseg);
- assert(sorg(nsupseg) == suppt);
- pa = sorg(*supseg);
- pb = sdest(nsupseg);
-@@ -25672,7 +23300,6 @@
- spivotself(prevseg);
- if (prevseg.sh != dummysh) {
- prevseg.shver = 0;
-- if (sdest(prevseg) != pa) sesymself(prevseg);
- assert(sdest(prevseg) == pa);
- senextself(prevseg);
- senext2self(newseg);
-@@ -25684,7 +23311,6 @@
- spivotself(nextseg);
- if (nextseg.sh != dummysh) {
- nextseg.shver = 0;
-- if (sorg(nextseg) != pb) sesymself(nextseg);
- assert(sorg(nextseg) == pb);
- senext2self(nextseg);
- senextself(newseg);
-@@ -25801,16 +23427,13 @@
- }
- }
- // Tetrahedralize B_i(p).
-- success = constrainedcavity(&oldtet, dnewshlist, oldtetlist[i], ptlist,
-- frontlist, misfrontlist, newtetlist[i], flipque);
-- if (!success && !noreloc) {
-+ if (!constrainedcavity(&oldtet, dnewshlist, oldtetlist[i], ptlist,
-+ frontlist, misfrontlist, newtetlist[i], flipque)) {
- // C must be finished by re-locating the steiner point.
- makepoint(&(newpt[i]));
- for (j = 0; j < 3; j++) norm[j] = 0.5 * (pnorm[0][j] + pnorm[1][j]);
- success = findrelocatepoint(suppt, newpt[i], norm, frontlist,
- oldtetlist[i]);
-- // for (j = 0; j < 3; j++) newpt[i][j] = suppt[j];
-- // success = smoothvolpoint(newpt[i], frontlist, true);
- if (success) {
- // p is relocated by newpt[i]. Now insert it. Don't do flip since
- // the new tets may get deleted again.
-@@ -25825,10 +23448,6 @@
- assert(newtetlist[i]->len() == 0);
- }
- }
-- if (!success && noreloc) {
-- // Failed and no point relocation. Clean fake tets.
-- deallocfaketets(frontlist);
-- }
- // Clear work lists.
- dnewshlist->clear();
- ptlist->clear();
-@@ -25841,9 +23460,6 @@
- // p has been suppressed. (Still in the pool).
- setpointtype(suppt, UNUSEDVERTEX);
- unuverts++;
-- // Update the segmnet pointers saved in a and b.
-- setpoint2sh(pa, sencode(newseg));
-- setpoint2sh(pb, sencode(newseg));
- // Delete old segments ap, pb.
- shellfacedealloc(subsegs, supseg->sh);
- shellfacedealloc(subsegs, nsupseg.sh);
-@@ -25879,17 +23495,6 @@
- }
- }
- }
-- if (optflag) {
-- for (i = 0; i < spinshlist->len(); i++) {
-- // Check for new bad-quality tets.
-- if (newtetlist[i] != (list *) NULL) {
-- for (j = 0; j < newtetlist[i]->len(); j++) {
-- newtet = * (triface *)(* (newtetlist[i]))[j];
-- if (!isdead(&newtet)) checktet4opt(&newtet, true);
-- }
-- }
-- }
-- }
- } else {
- // p is not suppressed. Recover the original state.
- unsupverts++;
-@@ -25898,27 +23503,22 @@
- spivotself(prevseg);
- if (prevseg.sh != dummysh) {
- prevseg.shver = 0;
-- if (sdest(prevseg) != pa) sesymself(prevseg);
- assert(sdest(prevseg) == pa);
- senextself(prevseg);
- senext2self(*supseg);
- sbond(*supseg, prevseg);
-- senextself(*supseg); // Restore original state.
-- assert(supseg->shver < 2);
-+ supseg->shver = 0;
- }
- // Restore old connection at b.
- senext(nsupseg, nextseg);
- spivotself(nextseg);
- if (nextseg.sh != dummysh) {
- nextseg.shver = 0;
-- if (sorg(nextseg) != pb) sesymself(nextseg);
- assert(sorg(nextseg) == pb);
- senext2self(nextseg);
- senextself(nsupseg);
- sbond(nsupseg, nextseg);
-- // nsupseg.shver = 0;
-- senext2self(nsupseg); // Restore original state
-- assert(nsupseg.shver < 2);
-+ nsupseg.shver = 0;
- }
- // Delete the new segment ab.
- shellfacedealloc(subsegs, newseg.sh);
-@@ -25989,52 +23589,52 @@
- // //
- // suppressvolpoint() Suppress a point inside mesh. //
- // //
--// The point p = org(suptet) is inside the mesh and will be suppressed from //
--// the mesh. Note that p may not be suppressed. //
--// //
--// 'optflag' is used for mesh optimization. If it is set, after removing p, //
--// test the object function on each new tet, queue bad tets. //
-+// The point p inside the mesh will be suppressed by being deleted from the //
-+// mesh. p may not be suppressed. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--bool tetgenmesh::suppressvolpoint(triface* suptet, list* frontlist,
-- list* misfrontlist, list* ptlist, queue* flipque, bool optflag)
-+bool tetgenmesh::suppressvolpoint(point suppt, list* frontlist,
-+ list* misfrontlist, list* ptlist, queue* flipque)
- {
-- list *myfrontlist, *mymisfrontlist, *myptlist;
- list *oldtetlist, *newtetlist;
- list *newshlist; // a dummy list.
-- queue *myflipque;
-+ tetrahedron tetptr;
- triface oldtet, newtet;
-- point suppt, conpt;
- bool success;
- int j;
-
-+ if (b->verbose > 1) {
-+ printf(" Remove point %d in mesh.\n", pointmark(suppt));
-+ }
-+
-+ // Get a tet with p as a vertex.
-+ oldtet.tet = (tetrahedron *) NULL;
-+ tetptr = point2tet(suppt);
-+ if (tetptr != (tetrahedron) NULL) {
-+ decode(tetptr, oldtet);
-+ }
-+ // Make sure oldtet contains p.
-+ if (isdead(&oldtet) || !findorg(&oldtet, suppt)) {
-+ // The pointer is invalid. Recreate the map.
-+ makepoint2tetmap();
-+ tetptr = point2tet(suppt);
-+ decode(tetptr, oldtet);
-+ if (isdead(&oldtet)) {
-+ // There is no tet contain p, it is indeed an unused point.
-+ // expandsteinercavity() deleted all tets of p.
-+ setpointtype(suppt, UNUSEDVERTEX);
-+ unuverts++;
-+ return true;
-+ }
-+ }
-+
- // Allocate spaces for storing (old and new) B(p).
- oldtetlist = new list(sizeof(triface), NULL, 256);
- newtetlist = new list(sizeof(triface), NULL, 256);
- newshlist = new list(sizeof(face), NULL, 256);
-- // Allocate work lists if user doesn't supply them.
-- myfrontlist = mymisfrontlist = myptlist = (list *) NULL;
-- myflipque = (queue *) NULL;
-- if (frontlist == (list *) NULL) {
-- myfrontlist = new list(sizeof(triface), NULL, 256);
-- frontlist = myfrontlist;
-- mymisfrontlist = new list(sizeof(triface), NULL, 256);
-- misfrontlist = mymisfrontlist;
-- myptlist = new list(sizeof(point *), NULL, 256);
-- ptlist = myptlist;
-- myflipque = new queue(sizeof(badface));
-- flipque = myflipque;
-- }
--
-- suppt = org(*suptet);
-- oldtet = *suptet;
- success = true; // Assume p can be suppressed.
-
-- if (b->verbose > 1) {
-- printf(" Remove point %d in mesh.\n", pointmark(suppt));
-- }
--
- // Form old B(p) in oldtetlist.
- oldtetlist->append(&oldtet);
- formstarpolyhedron(suppt, oldtetlist, ptlist, false);
-@@ -26044,30 +23644,20 @@
- infect(oldtet);
- }
- // Tetrahedralize old B(p).
-- success = constrainedcavity(&oldtet, newshlist, oldtetlist, ptlist,
-- frontlist, misfrontlist, newtetlist, flipque);
-- if (!success) {
-- // Unable to suppress p.
-+ if (!constrainedcavity(&oldtet, newshlist, oldtetlist, ptlist, frontlist,
-+ misfrontlist, newtetlist, flipque)) {
-+ // Unable to suppress p.
-+ success = false;
-+ // Clean fake tets and quit this option.
- deallocfaketets(frontlist);
-- // Try to collapse an edge at p.
-- conpt = (point) NULL;
- assert(newtetlist->len() == 0);
-- if (findcollapseedge(suppt, &conpt, oldtetlist, ptlist)) {
-- // Collapse the edge suppt->conpt. Re-use newtetlist.
-- collapseedge(suppt, conpt, oldtetlist, newtetlist);
-- // The oldtetlist contains newtetlist.
-- if (optflag) {
-- assert(newtetlist->len() == 0);
-- for (j = 0; j < oldtetlist->len(); j++) {
-- newtet = * (triface *)(* oldtetlist)[j];
-- newtetlist->append(&newtet);
-- }
-- }
-- oldtetlist->clear(); // Do not delete them.
-- collapverts++;
-- success = true;
-- }
- }
-+ // Clear work lists.
-+ ptlist->clear();
-+ frontlist->clear();
-+ misfrontlist->clear();
-+ flipque->clear();
-+
- if (success) {
- // p has been removed! (Still in the pool).
- setpointtype(suppt, UNUSEDVERTEX);
-@@ -26079,13 +23669,6 @@
- assert(!isdead(&oldtet));
- tetrahedrondealloc(oldtet.tet);
- }
-- if (optflag) {
-- // Check for new bad tets.
-- for (j = 0; j < newtetlist->len(); j++) {
-- newtet = * (triface *)(* newtetlist)[j];
-- if (!isdead(&newtet)) checktet4opt(&newtet, true);
-- }
-- }
- } else {
- // p is not suppressed. Recover the original state.
- // Uninfect tets of old B(p).
-@@ -26096,18 +23679,6 @@
- }
- }
-
-- // Clear work lists.
-- ptlist->clear();
-- frontlist->clear();
-- misfrontlist->clear();
-- flipque->clear();
-- // Deallocate work lists.
-- if (myfrontlist != (list *) NULL) {
-- delete myfrontlist;
-- delete mymisfrontlist;
-- delete myptlist;
-- delete myflipque;
-- }
- delete oldtetlist;
- delete newtetlist;
- delete newshlist;
-@@ -26117,177 +23688,61 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// smoothpoint() Smooth a volume/segment point. //
--// //
--// 'smthpt' (p) is inside the polyhedron (C) bounded by faces in 'starlist'. //
--// This routine moves p inside C until an object function is maximized. //
--// //
--// Default, the CCW edge ring of the faces on C points to p. If 'invtori' is //
--// TRUE, the orientation is inversed. //
--// //
--// If 'key' != NULL, it contains an object value to be improved. Current it //
--// means the cosine of the largest dihedral angle. In such case, the point //
--// is smoothed only if the final configuration improves the object value, it //
--// is returned by the 'key'. //
-+// collapseedgepoint() Delete a point by edge collapse. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--bool tetgenmesh::smoothpoint(point smthpt, point e1, point e2, list *starlist,
-- bool invtori, REAL *key)
-+bool tetgenmesh::collapseedgepoint(point colpt, list *oldtetlist,
-+ list* deadtetlist, list *ptlist)
- {
-- triface starttet;
-- point pa, pb, pc;
-- REAL fcent[3], startpt[3], nextpt[3], bestpt[3];
-- REAL iniTmax, oldTmax, newTmax;
-- REAL ori, aspT, aspTmax, imprate;
-- REAL cosd, maxcosd;
-- bool segflag, randflag; //, subflag;
-- int numdirs;
-- int iter, i, j;
--
-- // Is p a segment vertex?
-- segflag = (e1 != (point) NULL);
-- // Decide the number of moving directions.
-- numdirs = segflag ? 2 : starlist->len();
-- randflag = numdirs > 10;
-- if (randflag) {
-- numdirs = 10; // Maximum 10 directions.
-- }
--
-- // Calculate the initial object value (the largest aspect ratio).
-- for (i = 0; i < starlist->len(); i++) {
-- starttet = * (triface *)(* starlist)[i];
-- adjustedgering(starttet, !invtori ? CCW : CW);
-- pa = org(starttet);
-- pb = dest(starttet);
-- pc = apex(starttet);
-- aspT = tetaspectratio(pa, pb, pc, smthpt);
-- if (i == 0) {
-- aspTmax = aspT;
-- } else {
-- aspTmax = aspT > aspTmax ? aspT : aspTmax;
-- }
-- }
-- iniTmax = aspTmax;
-+ tetrahedron tetptr;
-+ triface oldtet, newtet;
-+ point conpt;
-+ bool success;
-
- if (b->verbose > 1) {
-- printf(" Smooth %s point %d (%g, %g, %g).\n", segflag ? "seg" : "vol",
-- pointmark(smthpt), smthpt[0], smthpt[1], smthpt[2]);
-- printf(" Initial max L/h = %g.\n", iniTmax);
-- }
-- for (i = 0; i < 3; i++) {
-- bestpt[i] = startpt[i] = smthpt[i];
-+ printf(" Collapse point %d.\n", pointmark(colpt));
- }
-
-- // Do iteration until the new aspTmax does not decrease.
-- newTmax = iniTmax;
-- iter = 0;
-- while (true) {
-- // Find the best next location.
-- oldTmax = newTmax;
-- for (i = 0; i < numdirs; i++) {
-- // Calculate the moved point (saved in 'nextpt').
-- if (!segflag) {
-- if (randflag) {
-- // Randomly pick a direction.
-- j = (int) randomnation(starlist->len());
-- } else {
-- j = i;
-- }
-- starttet = * (triface *)(* starlist)[j];
-- adjustedgering(starttet, !invtori ? CCW : CW);
-- pa = org(starttet);
-- pb = dest(starttet);
-- pc = apex(starttet);
-- for (j = 0; j < 3; j++) {
-- fcent[j] = (pa[j] + pb[j] + pc[j]) / 3.0;
-- }
-- } else {
-- for (j = 0; j < 3; j++) {
-- fcent[j] = (i == 0 ? e1[j] : e2[j]);
-- }
-- }
-- for (j = 0; j < 3; j++) {
-- nextpt[j] = startpt[j] + 0.01 * (fcent[j] - startpt[j]);
-- }
-- // Get the largest object value for the new location.
-- for (j = 0; j < starlist->len(); j++) {
-- starttet = * (triface *)(* starlist)[j];
-- adjustedgering(starttet, !invtori ? CCW : CW);
-- pa = org(starttet);
-- pb = dest(starttet);
-- pc = apex(starttet);
-- ori = orient3d(pa, pb, pc, nextpt);
-- if (ori < 0.0) {
-- aspT = tetaspectratio(pa, pb, pc, nextpt);
-- if (j == 0) {
-- aspTmax = aspT;
-- } else {
-- aspTmax = aspT > aspTmax ? aspT : aspTmax;
-- }
-- } else {
-- // An invalid new tet. Discard this point.
-- aspTmax = newTmax;
-- } // if (ori < 0.0)
-- // Stop looping when the object value is bigger than before.
-- if (aspTmax >= newTmax) break;
-- } // for (j = 0; j < starlist->len(); j++)
-- if (aspTmax < newTmax) {
-- // Save the improved object value and the location.
-- newTmax = aspTmax;
-- for (j = 0; j < 3; j++) bestpt[j] = nextpt[j];
-- }
-- } // for (i = 0; i < starlist->len(); i++)
-- // Does the object value improved much?
-- imprate = fabs(oldTmax - newTmax) / oldTmax;
-- if (imprate < 1e-3) break;
-- // Yes, move p to the new location and continue.
-- for (j = 0; j < 3; j++) startpt[j] = bestpt[j];
-- iter++;
-- } // while (true)
--
-- if (iter > 0) {
-- // The point is moved.
-- if (key) {
-- // Check if the quality is improved by the smoothed point.
-- maxcosd = 0.0; // = cos(90).
-- for (j = 0; j < starlist->len(); j++) {
-- starttet = * (triface *)(* starlist)[j];
-- adjustedgering(starttet, !invtori ? CCW : CW);
-- pa = org(starttet);
-- pb = dest(starttet);
-- pc = apex(starttet);
-- tetalldihedral(pa, pb, pc, startpt, NULL, &cosd, NULL);
-- if (cosd < *key) {
-- // This quality will not be improved. Stop.
-- iter = 0; break;
-- } else {
-- // Remeber the worst quality value (of the new configuration).
-- maxcosd = maxcosd < cosd ? maxcosd : cosd;
-- }
-- }
-- if (iter > 0) *key = maxcosd;
-+ // Get a tet with p as a vertex.
-+ oldtet.tet = (tetrahedron *) NULL;
-+ tetptr = point2tet(colpt);
-+ if (tetptr != (tetrahedron) NULL) {
-+ decode(tetptr, oldtet);
-+ }
-+ // Make sure oldtet contains p.
-+ if (isdead(&oldtet) || !findorg(&oldtet, colpt)) {
-+ // The pointer is invalid. Recreate the map.
-+ makepoint2tetmap();
-+ tetptr = point2tet(colpt);
-+ decode(tetptr, oldtet);
-+ if (isdead(&oldtet)) {
-+ // There is no tet contain p, it is indeed an unused point.
-+ // expandsteinercavity() deleted all tets of p.
-+ setpointtype(colpt, UNUSEDVERTEX);
-+ unuverts++;
-+ return true;
- }
- }
-
-- if (iter > 0) {
-- segflag ? smoothsegverts++ : smoothvolverts++;
-- for (i = 0; i < 3; i++) smthpt[i] = startpt[i];
-- if (b->verbose > 1) {
-- printf(" Move to new location (%g, %g, %g).\n", smthpt[0], smthpt[1],
-- smthpt[2]);
-- printf(" Final max L/h = %g. (%d iterations)\n", newTmax, iter);
-- if (key) {
-- printf(" Max. dihed = %g (degree).\n", acos(*key) / PI * 180.0);
-- }
-- }
-- return true;
-- } else {
-- if (b->verbose > 1) {
-- printf(" Not smoothed.\n");
-- }
-- return false;
-+ // Form old B(p) in oldtetlist.
-+ oldtetlist->append(&oldtet);
-+ formstarpolyhedron(colpt, oldtetlist, ptlist, false);
-+ // Try to collapse p.
-+ success = findcollapseedge(colpt, &conpt, oldtetlist, ptlist);
-+ if (success) {
-+ // Collapse p by edge contraction.
-+ collapseedge(colpt, conpt, oldtetlist, deadtetlist);
-+ collapverts++;
-+ // p has been removed! (Still in the pool).
-+ setpointtype(colpt, UNUSEDVERTEX);
-+ unuverts++;
-+ deadtetlist->clear();
- }
-+ oldtetlist->clear();
-+ ptlist->clear();
-+
-+ return success;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
-@@ -26296,7 +23751,7 @@
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--void tetgenmesh::removesteiners(bool coarseflag)
-+void tetgenmesh::removesteiners()
- {
- list *frontlist, *misfrontlist;
- list *spinshlist, *newsegshlist;
-@@ -26306,22 +23761,12 @@
- triface checktet;
- face shloop;
- face segloop, nextseg;
-- point pa, neipt;
-- REAL len;
-+ point pa;
- bool remflag;
-- int *worklist;
- int oldnum, rmstein;
-- int i, j;
--
-- if (!b->quiet) {
-- if (!coarseflag) {
-- printf("Removing Steiner points.\n");
-- } else {
-- printf("Coarsening mesh.\n");
-- }
-- }
-+ int i;
-
-- // Initialize work lists.
-+ // Initiliaze work lists.
- frontlist = new list(sizeof(triface), NULL);
- misfrontlist = new list(sizeof(triface), NULL);
- spinshlist = new list(sizeof(face), NULL);
-@@ -26331,10 +23776,13 @@
- flipque = new queue(sizeof(badface));
- viri = new memorypool(sizeof(shellface *), 1024, POINTER, 0);
- oldnum = unuverts;
-- relverts = suprelverts = collapverts = unsupverts;
-- smoothvolverts = 0;
-+ relverts = suprelverts = collapverts = unsupverts = 0;
- expcavcount = 0;
-
-+ if (!b->quiet) {
-+ printf("Removing Steiner points.\n");
-+ }
-+
- // Suppress Steiner points inside facets.
- do {
- rmstein = unuverts;
-@@ -26347,115 +23795,32 @@
- for (i = 0; i < 3; i++) {
- pa = sapex(shloop);
- if (pointtype(pa) == FREESUBVERTEX) {
-- if (!coarseflag) {
-- // Remove it if it is not an input point.
-- j = pointmark(pa) - in->firstnumber;
-- if (j >= in->numberofpoints) {
-- if (b->nobisect == 1) {
-- // '-Y'. Remove p if s is a hull face.
-- stpivot(shloop, checktet);
-- if (checktet.tet != dummytet) {
-- sesymself(shloop);
-- stpivot(shloop, checktet);
-- }
-- remflag = (checktet.tet == dummytet);
-- } else {
-- // '-YY'. Remove p whatever s is a hull face or not.
-- remflag = true;
-- }
-+ // Find a Steiner point p.
-+ if (b->nobisect == 1) {
-+ // '-Y'. Remove p if s is a hull face.
-+ stpivot(shloop, checktet);
-+ if (checktet.tet != dummytet) {
-+ sesymself(shloop);
-+ stpivot(shloop, checktet);
- }
-+ remflag = (checktet.tet == dummytet);
- } else {
-- // Check if this vertex can be coarsed.
-- if (b->nobisect == 0) {
-- // Is a background mesh available?
-- if (b->metric) {
-- // assert(pa[pointmtrindex] > 0.0);
-- // Form the star of pa.
-- spinshlist->append(&shloop);
-- formstarpolygon(pa, spinshlist, ptlist);
-- len = 0.0;
-- for (j = 0; j < ptlist->len(); j++) {
-- neipt = * (point *)(* ptlist)[j];
-- len += distance(pa, neipt);
-- }
-- len /= ptlist->len();
-- // Carse it if the average edge length is small.
-- remflag = len < pa[pointmtrindex];
-- spinshlist->clear();
-- ptlist->clear();
-- } else {
-- // Coarse it if (1) it is an input point and its pointmarker
-- // is zero, or (2) it is a Steiner point.
-- remflag = true;
-- j = pointmark(pa) - in->firstnumber;
-- if (j < in->numberofpoints) {
-- remflag = (in->pointmarkerlist[j] == 0);
-- }
-- } // if (b->metric)
-- } // if (b->nobisect == 0)
-- } // if (!coarseflag)
-- if (remflag) break;
-- } // if (pointtype(pa) == FREESUBVERTEX)
-+ // '-YY'. Remove p whatever s is a hull face or not.
-+ remflag = true;
-+ }
-+ break;
-+ }
- senextself(shloop);
-- } // for (i = 0; i < 3; i++)
-+ }
- if (remflag) {
- suppressfacetpoint(&shloop, frontlist, misfrontlist, ptlist, conlist,
-- viri, flipque, coarseflag, false);
-+ viri, flipque);
- }
- shloop.sh = shellfacetraverse(subfaces);
- }
- // Continue if any Steiner point has been removed.
- } while (unuverts > rmstein);
-
-- if (coarseflag) {
-- shellface **segsperverlist;
-- int *idx2seglist;
-- face seg1, seg2;
-- point e1, e2;
-- // Connecting collinear segments. Hence the segment vertices may be
-- // removed. In fact, this should be done by reconstructmesh().
-- makesegmentmap(idx2seglist, segsperverlist);
-- subsegs->traversalinit();
-- segloop.sh = shellfacetraverse(subsegs);
-- while (segloop.sh != (shellface *) NULL) {
-- for (i = 0; i < 2; i++) {
-- segloop.shver = i;
-- senext(segloop, nextseg);
-- spivotself(nextseg);
-- if ((nextseg.sh == dummysh) || (nextseg.sh > segloop.sh)) {
-- // No neighbor segment connection or haven't been processed yet.
-- pa = sdest(segloop);
-- j = pointmark(pa) - in->firstnumber;
-- if (idx2seglist[j + 1] - idx2seglist[j] == 2) {
-- // pa is shared by only two segments. Get the other one.
-- nextseg.sh = segsperverlist[idx2seglist[j]];
-- if (nextseg.sh == segloop.sh) {
-- nextseg.sh = segsperverlist[idx2seglist[j] + 1];
-- }
-- nextseg.shver = 0;
-- if (sorg(nextseg) != pa) sesymself(nextseg);
-- // Check if the two segments are collinear.
-- e1 = sorg(segloop);
-- e2 = sdest(nextseg);
-- if (iscollinear(e1, pa, e2, b->epsilon)) {
-- // Connect the two segments together.
-- if (b->verbose > 1) {
-- printf(" Glue two insegs (%d, %d) at %d.\n", pointmark(e1),
-- pointmark(e2), pointmark(pa));
-- }
-- senext(segloop, seg1);
-- senext2(nextseg, seg2);
-- sbond(seg1, seg2);
-- }
-- }
-- } // if (nextseg.sh == dummysh)
-- } // for (i = 0;
-- segloop.sh = shellfacetraverse(subsegs);
-- }
-- delete [] segsperverlist;
-- delete [] idx2seglist;
-- }
--
- // Suppress Steiner points on segments.
- do {
- rmstein = unuverts;
-@@ -26463,202 +23828,95 @@
- segloop.sh = shellfacetraverse(subsegs);
- while (segloop.sh != (shellface *) NULL) {
- remflag = false;
-- // for (i = 0; i < 2; i++) {
-- // Don't check the poinytype of pa, it may be a Steiner point but
-- // has type NACUTEVERTEX due to splitting a type-3 segment.
-- segloop.shver = 0; // segloop.shver = i;
-- senext(segloop, nextseg);
-- spivotself(nextseg);
-- if (nextseg.sh != dummysh) {
-- pa = sdest(segloop); // p is going to be checked for removal.
-- nextseg.shver = 0;
-- if (sorg(nextseg) != pa) sesymself(nextseg);
-- assert(sorg(nextseg) == pa);
-- if (!coarseflag) {
-- // try to remove it if it is not an input point.
-- j = pointmark(pa) - in->firstnumber;
-- if (j >= in->numberofpoints) {
-- if (b->nobisect == 1) {
-- // '-Y'. Remove p if it is on the hull.
-- sstpivot(&segloop, &checktet);
-- assert(checktet.tet != dummytet);
-- pa = apex(checktet);
-- do {
-- if (!fnextself(checktet)) {
-- // Meet a boundary face - p is on the hull.
-- remflag = true; break;
-- }
-- } while (pa != apex(checktet));
-- } else {
-- // '-YY'. Remove p whatever it is on the hull or not.
-- remflag = true;
-- }
-+ // Don't check the poinytype of pa, it may be a Steiner point but has
-+ // type NACUTEVERTEX due to splitting a type-3 segment.
-+ // if (pointtype(pa) == FREESEGVERTEX) {
-+ segloop.shver = 0;
-+ senext(segloop, nextseg);
-+ spivotself(nextseg);
-+ if (nextseg.sh != dummysh) {
-+ // Find a Steiner point p.
-+ pa = sdest(segloop); // For checking.
-+ nextseg.shver = 0;
-+ assert(sorg(nextseg) == pa);
-+ if (b->nobisect == 1) {
-+ // '-Y'. Remove p if it is on the hull.
-+ sstpivot(&segloop, &checktet);
-+ assert(checktet.tet != dummytet);
-+ pa = apex(checktet);
-+ do {
-+ if (!fnextself(checktet)) {
-+ // Meet a boundary face - p is on the hull.
-+ remflag = true; break;
- }
-- } else {
-- // Check if this vertex can be coarsed.
-- if (b->nobisect == 0) {
-- if (b->metric) {
-- // assert(pa[pointmtrindex] > 0.0);
-- len = 0.0;
-- neipt = sorg(segloop);
-- for (j = 0; j < 2; j++) {
-- len += distance(pa, neipt);
-- /*// Is neipt inside the sparse ball of pa?
-- if (len < pa[pointmtrindex]) {
-- // Yes, the local of pa is too dense, corse it.
-- remflag = true; break;
-- } */
-- neipt = sdest(nextseg);
-- }
-- len /= 2.0;
-- // Carse it if the average edge lengh is small.
-- remflag = len < pa[pointmtrindex];
-- } else {
-- // Coarse it if (1) it is an input point and its pointmarker
-- // is zero, or (2) it is a Steiner point.
-- remflag = true;
-- j = pointmark(pa) - in->firstnumber;
-- if (j < in->numberofpoints) {
-- remflag = (in->pointmarkerlist[j] == 0);
-- }
-- } // if (b->metric)
-- } // if (b->nobisect == 0)
-- } // if (!coarseflag)
-- } // if (nextseg.sh != dummysh)
-- // if (remflag) break;
-- // } // for (i = 0; i < 2; i++)
-+ } while (pa != apex(checktet));
-+ } else {
-+ // '-YY'. Remove p whatever it is on the hull or not.
-+ remflag = true;
-+ }
-+ }
- if (remflag) {
- suppresssegpoint(&segloop, spinshlist, newsegshlist, frontlist,
-- misfrontlist, ptlist, conlist, viri, flipque, coarseflag, false);
-+ misfrontlist, ptlist, conlist, viri, flipque);
- }
- segloop.sh = shellfacetraverse(subsegs);
- }
- // Continue if any Steiner point has been removed.
- } while (unuverts > rmstein);
-
-- if ((relverts > 0) || coarseflag) {
-- worklist = new int[points->items + 1];
-- // Suppress relocated points & coarse free mesh points.
-+ if (relverts > 0) {
-+ // Suppress relocated points.
- do {
-- // Initialize the work list. Each entry of the list counts how many
-- // times the point has been processed.
-- for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
- rmstein = unuverts;
-- tetrahedrons->traversalinit();
-- checktet.tet = tetrahedrontraverse();
-- while (checktet.tet != (tetrahedron *) NULL) {
-- remflag = false;
-- for (i = 0; i < 4; i++) {
-- pa = (point) checktet.tet[4 + i];
-- if (pointtype(pa) == FREEVOLVERTEX) {
-- // NOTE. Chenge the number 3 will change the number n of removed
-- // Steiner points. In my test, n is larger when it is 1. 3
-- // reduces n in a reasonable way (see example, mech_part,
-- // thepart), 5 results a larger n than 3 does. While the best
-- // result is no limit of this number, but it makes the code
-- // extremely slow.
-- if (worklist[pointmark(pa)] < 3) {
-- worklist[pointmark(pa)]++;
-- if (!coarseflag) {
-- // Remove p if it is a Steiner point.
-- if (pointmark(pa) >= (in->numberofpoints + in->firstnumber)) {
-- remflag = true;
-- }
-- } else {
-- if (b->metric) {
-- // assert(pa[pointmtrindex] > 0.0);
-- // Form the star of pa.
-- frontlist->append(&checktet);
-- formstarpolyhedron(pa, frontlist, ptlist, true);
-- len = 0.0;
-- for (j = 0; j < ptlist->len(); j++) {
-- neipt = * (point *)(* ptlist)[j];
-- len += distance(pa, neipt);
-- }
-- len /= ptlist->len();
-- // Carse it if the average edge length is small.
-- remflag = len < pa[pointmtrindex];
-- frontlist->clear();
-- ptlist->clear();
-- } else {
-- // Coarse it if (1) it is an input point and its pointmarker
-- // is zero, or (2) it is a Steiner point.
-- remflag = true;
-- j = pointmark(pa) - in->firstnumber;
-- if (j < in->numberofpoints) {
-- remflag = (in->pointmarkerlist[j] == 0);
-- }
-- } // if (b->metric)
-- } // if (!coarseflag)
-- if (remflag) break;
-- } // if (worklist[pointmark(pa)] == 0)
-- } // if (pointtype(pa) == FREEVOLVERTEX)
-- } // for (i = 0; i < 4; i++)
-+ points->traversalinit();
-+ pa = pointtraverse();
-+ while (pa != (point) NULL) {
-+ remflag = (pointtype(pa) == FREEVOLVERTEX);
- if (remflag) {
-- findorg(&checktet, pa);
-- assert(org(checktet) == pa);
-- suppressvolpoint(&checktet, frontlist, misfrontlist, ptlist, flipque,
-- false);
-+ suppressvolpoint(pa, frontlist, misfrontlist, ptlist, flipque);
- }
-- checktet.tet = tetrahedrontraverse();
-+ pa = pointtraverse();
- }
- // Continue if any relocated point has been suppressed.
- } while (unuverts > rmstein);
--
--
-- // Smooth the unsuppressed points if it is not coarse mesh.
-- if (!coarseflag && (relverts > suprelverts)) {
-- if (b->verbose) {
-- printf(" Smoothing relocated points.\n");
-- }
-- for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
-- tetrahedrons->traversalinit();
-- checktet.tet = tetrahedrontraverse();
-- while (checktet.tet != (tetrahedron *) NULL) {
-- for (i = 0; i < 4; i++) {
-- pa = (point) checktet.tet[4 + i];
-- if (pointtype(pa) == FREEVOLVERTEX) {
-- if (worklist[pointmark(pa)] == 0) {
-- worklist[pointmark(pa)] = 1;
-- if (pointmark(pa) >= (in->numberofpoints + in->firstnumber)) {
-- // Smooth pa.
-- findorg(&checktet, pa);
-- frontlist->append(&checktet);
-- formstarpolyhedron(pa, frontlist, NULL, false);
-- smoothpoint(pa, NULL, NULL, frontlist, false, NULL);
-- frontlist->clear();
-- }
-- } // if (worklist[pointmark(pa)] == 0)
-- } // if (pointtype(pa) == FREEVOLVERTEX)
-- } // for (i = 0; i < 4; i++)
-- checktet.tet = tetrahedrontraverse();
-- }
-- }
-- delete [] worklist;
- }
-
-- if (b->verbose > 0) {
-- if (!coarseflag) {
-- printf(" %d points removed from boundary", unuverts - oldnum);
-- if (expcavcount > 0) {
-- printf(" (%d cavity corrections)", expcavcount);
-- }
-- printf("\n");
-- if (relverts > 0) {
-- printf(" %d points relocated (%d suppressed, %d collapsed).\n",
-- relverts, suprelverts - collapverts, collapverts);
-- if (smoothvolverts > 0) {
-- printf(" %d points are smoothed.\n", smoothvolverts);
-+ /* if ((relverts - suprelverts) > 0) {
-+ // Try to collapse relocated points.
-+ do {
-+ rmstein = unuverts;
-+ points->traversalinit();
-+ pa = pointtraverse();
-+ while (pa != (point) NULL) {
-+ remflag = (pointtype(pa) == FREEVOLVERTEX);
-+ if (remflag) {
-+ collapseedgepoint(pa, frontlist, misfrontlist, ptlist);
- }
-+ pa = pointtraverse();
- }
-- if (unsupverts > 0) {
-- printf(" !! %d points are unsuppressed.\n", unsupverts);
-- }
-- } else {
-- printf(" %d points are removed.\n", unuverts - oldnum);
-+ // Continue if any relocated point has been suppressed.
-+ } while (unuverts > rmstein);
-+ } */
-+
-+ if (b->verbose > 0) {
-+ printf(" %d points removed from boundary.\n", unuverts - oldnum);
-+ if (relverts > 0) {
-+ printf(" %d points relocated into volume.\n", relverts);
-+ }
-+ if (suprelverts > 0) {
-+ printf(" %d relocated points are suppressed.\n", suprelverts);
-+ }
-+ if (collapverts > 0) {
-+ printf(" %d relocated points are collapsed.\n", collapverts);
-+ }
-+ if (unsupverts > 0) {
-+ printf(" %d points are unsuppressed.\n", unsupverts);
-+ }
-+ if (expcavcount > 0) {
-+ printf(" %d cavity corrections.\n", expcavcount);
- }
- }
--
-+
- // Delete work lists.
- delete frontlist;
- delete misfrontlist;
-@@ -26674,6 +23932,10 @@
- // End of boundary Steiner points removing routines
- //
-
-+//
-+// Begin of mesh reconstruction routines
-+//
-+
- ///////////////////////////////////////////////////////////////////////////////
- // //
- // reconstructmesh() Reconstruct a tetrahedral mesh from a list of //
-@@ -26767,12 +24029,12 @@
- setdest(tetloop, tdest);
- setapex(tetloop, tapex);
- setoppo(tetloop, toppo);
-- // Temporarily set the vertices be type FREEVOLVERTEX, to indicate that
-+ // Temporarily set the vertices be type VOLVERTEX, to indicate that
- // they belong to the mesh. These types may be changed later.
-- setpointtype(torg, FREEVOLVERTEX);
-- setpointtype(tdest, FREEVOLVERTEX);
-- setpointtype(tapex, FREEVOLVERTEX);
-- setpointtype(toppo, FREEVOLVERTEX);
-+ setpointtype(torg, VOLVERTEX);
-+ setpointtype(tdest, VOLVERTEX);
-+ setpointtype(tapex, VOLVERTEX);
-+ setpointtype(toppo, VOLVERTEX);
- // Set element attributes if they exist.
- for (j = 0; j < in->numberoftetrahedronattributes; j++) {
- index = i * in->numberoftetrahedronattributes;
-@@ -26844,7 +24106,7 @@
- hullsize++; // It's a hull face.
- // Bond this side to outer space.
- dummytet[0] = encode(tetloop);
-- if ((in->pointmarkerlist != (int *) NULL) && !b->coarse) {
-+ if (in->pointmarkerlist != (int *) NULL) {
- // Set its three corners's markers be boundary (hull) vertices.
- if (in->pointmarkerlist[iorg] == 0) {
- in->pointmarkerlist[iorg] = 1;
-@@ -26969,11 +24231,11 @@
- setsorg(subloop, torg);
- setsdest(subloop, tdest);
- setsapex(subloop, tapex);
-- // Set the vertices be FREESUBVERTEX to indicate they belong to a
-+ // Set the vertices be FACETVERTEX to indicate they belong to a
- // facet of the domain. They may be changed later.
-- setpointtype(torg, FREESUBVERTEX);
-- setpointtype(tdest, FREESUBVERTEX);
-- setpointtype(tapex, FREESUBVERTEX);
-+ setpointtype(torg, FACETVERTEX);
-+ setpointtype(tdest, FACETVERTEX);
-+ setpointtype(tapex, FACETVERTEX);
- tsbond(tetloop, subloop);
- if (neightet.tet != dummytet) {
- sesymself(subloop);
-@@ -27091,10 +24353,11 @@
- makeshellface(subsegs, &subseg);
- setsorg(subseg, torg);
- setsdest(subseg, tdest);
-- // The two vertices have been marked as FREESUBVERTEX. Now mark
-- // them as NACUTEVERTEX.
-- setpointtype(torg, NACUTEVERTEX);
-- setpointtype(tdest, NACUTEVERTEX);
-+ // At the moment, all segment vertices have type FACETVERTEX.
-+ // They will be set to type ACUTEVERTEX or NACUTEVERTEX by
-+ // routine markacutevertices() later.
-+ // setpointtype(torg, SEGMENTVERTEX);
-+ // setpointtype(tdest, SEGMENTVERTEX);
- setshellmark(subseg, marker);
- marker++;
- // Bond all subfaces to this subsegment.
-@@ -27220,6 +24483,24 @@
- createsegpbcgrouptable();
- }
-
-+ // if (b->quality && varconstraint) {
-+ // // Assign constraints on facets, segments, and nodes.
-+ // assignvarconstraints(idx2verlist);
-+ // }
-+
-+ /*
-+ if (b->quality) {
-+ // Check and recover the Delaunay property.
-+ queue* flipqueue = new queue(sizeof(badface));
-+ checkdelaunay(0.0, flipqueue);
-+ if (!flipqueue->empty()) {
-+ // Call flip algorithm to recover Delaunayness.
-+ flip(flipqueue, NULL);
-+ }
-+ delete flipqueue;
-+ }
-+ */
-+
- delete markerlist;
- delete neighshlist;
- delete [] worklist;
-@@ -27234,11 +24515,54 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// insertconstrainedpoints() Insert a list of constrained points. //
-+// intettest() Test if a point is inside (or on) a tetrahedron. //
-+// //
-+// Return TRUE if the point p and the tet t has one of the relations: (1) p //
-+// is inside t; (2) p is on a faces of t; (3) p is on an edge of t; (4) p is //
-+// a vertex of t. Otherwise, return FALSE. //
-+// //
-+// An relative tolerance is used to determine coplanar case when a face of t //
-+// is on the hull. To bring back a boundary point inside the mesh. //
-+// //
-+///////////////////////////////////////////////////////////////////////////////
-+
-+bool tetgenmesh::intettest(point testpt, triface* testtet, REAL eps)
-+{
-+ triface checktet;
-+ point p1, p2, p3;
-+ REAL ori;
-+
-+ testtet->ver = 0;
-+ for (testtet->loc = 0; testtet->loc < 4; testtet->loc++) {
-+ // Get points of the side f.
-+ p1 = org(*testtet);
-+ p2 = dest(*testtet);
-+ p3 = apex(*testtet);
-+ ori = orient3d(p1, p2, p3, testpt);
-+ if (ori > 0.0) {
-+ if (eps > 0.0) {
-+ // Is f on the hull.
-+ sym(*testtet, checktet);
-+ if (checktet.tet == dummytet) {
-+ if (iscoplanar(p1, p2, p3, testpt, ori, eps)) continue;
-+ }
-+ }
-+ // p is below f. outside.
-+ return false;
-+ }
-+ }
-+ testtet->loc = 0;
-+
-+ return true;
-+}
-+
-+///////////////////////////////////////////////////////////////////////////////
-+// //
-+// insertaddpoints() Insert additional points in 'in->addpointlist'. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--void tetgenmesh::insertconstrainedpoints(tetgenio *addio)
-+void tetgenmesh::insertaddpoints()
- {
- queue *flipqueue;
- triface searchtet;
-@@ -27246,8 +24570,6 @@
- point newpoint;
- enum locateresult loc;
- REAL *attr;
-- bool insertflag;
-- int covertices, outvertices;
- int index;
- int i, j;
-
-@@ -27257,134 +24579,117 @@
- // Initialize 'flipqueue'.
- flipqueue = new queue(sizeof(badface));
- recenttet.tet = dummytet;
-- covertices = outvertices = 0;
-
- index = 0;
-- for (i = 0; i < addio->numberofpoints; i++) {
-+ for (i = 0; i < in->numberofaddpoints; i++) {
- // Create a newpoint.
- makepoint(&newpoint);
-- newpoint[0] = addio->pointlist[index++];
-- newpoint[1] = addio->pointlist[index++];
-- newpoint[2] = addio->pointlist[index++];
-- // Read the add point attributes if current points have attributes.
-- if ((addio->numberofpointattributes > 0) &&
-- (in->numberofpointattributes > 0)) {
-- attr = addio->pointattributelist + addio->numberofpointattributes * i;
-- for (j = 0; j < in->numberofpointattributes; j++) {
-- if (j < addio->numberofpointattributes) {
-- newpoint[3 + j] = attr[j];
-- }
-- }
-+ newpoint[0] = in->addpointlist[index++];
-+ newpoint[1] = in->addpointlist[index++];
-+ newpoint[2] = in->addpointlist[index++];
-+ // Copy new attributes (if available).
-+ if(in->addpointattributelist != (REAL *) NULL) {
-+ attr = in->addpointattributelist + in->numberofpointattributes * i;
-+ for (j = 0; j < in->numberofpointattributes; j++)
-+ newpoint[3 + j] = attr[j];
- }
- // Find the location of the inserted point.
- searchtet = recenttet;
- loc = locate(newpoint, &searchtet);
-- if (loc != ONVERTEX) {
-- loc = adjustlocate(newpoint, &searchtet, loc, b->epsilon2);
-+ if (loc != OUTSIDE) {
-+ if (loc != ONVERTEX) {
-+ loc = adjustlocate(newpoint, &searchtet, loc, b->epsilon);
-+ }
- }
- if (loc == OUTSIDE) {
-- loc = hullwalk(newpoint, &searchtet);
-- if (loc == OUTSIDE) {
-- // Perform a brute-force search.
-- tetrahedrons->traversalinit();
-- searchtet.tet = tetrahedrontraverse();
-- while (searchtet.tet != (tetrahedron *) NULL) {
-- loc = adjustlocate(newpoint, &searchtet, OUTSIDE, b->epsilon2);
-- if (loc != OUTSIDE) break;
-- searchtet.tet = tetrahedrontraverse();
-+ // Perform a brute-force search.
-+ tetrahedrons->traversalinit();
-+ searchtet.tet = tetrahedrontraverse();
-+ while (searchtet.tet != (tetrahedron *) NULL) {
-+ if (intettest(newpoint, &searchtet, b->epsilon)) {
-+ loc = adjustlocate(newpoint, &searchtet, OUTSIDE, b->epsilon);
-+ assert(loc != OUTSIDE);
-+ break;
- }
-+ searchtet.tet = tetrahedrontraverse();
- }
- }
- // Insert the point if it not lies outside or on a vertex.
-- insertflag = true;
- switch (loc) {
- case INTETRAHEDRON:
-- setpointtype(newpoint, FREEVOLVERTEX);
-+ setpointtype(newpoint, VOLVERTEX);
- splittetrahedron(newpoint, &searchtet, flipqueue);
- break;
- case ONFACE:
- tspivot(searchtet, checksh);
- if (checksh.sh != dummysh) {
-- // It is a boundary face. Don't insert it if -Y option is used.
-- if (b->nobisect) {
-- insertflag = false;
-- } else {
-- setpointtype(newpoint, FREESUBVERTEX);
-- }
-+ setpointtype(newpoint, FREESUBVERTEX);
- } else {
- setpointtype(newpoint, FREEVOLVERTEX);
- }
-- if (insertflag) {
-- splittetface(newpoint, &searchtet, flipqueue);
-- }
-+ splittetface(newpoint, &searchtet, flipqueue);
- break;
- case ONEDGE:
- tsspivot(&searchtet, &checkseg);
- if (checkseg.sh != dummysh) {
-- if (b->nobisect) {
-- insertflag = false;
-- } else {
-- setpointtype(newpoint, FREESEGVERTEX);
-- setpoint2sh(newpoint, sencode(checkseg));
-- }
-+ setpointtype(newpoint, FREESEGVERTEX);
-+ setpoint2sh(newpoint, sencode(checkseg));
- } else {
- tspivot(searchtet, checksh);
- if (checksh.sh != dummysh) {
-- if (b->nobisect) {
-- insertflag = false;
-- } else {
-- setpointtype(newpoint, FREESUBVERTEX);
-- }
-+ setpointtype(newpoint, FREESUBVERTEX);
- } else {
-- setpointtype(newpoint, FREEVOLVERTEX);
-+ setpointtype(newpoint, VOLVERTEX);
- }
- }
-- if (insertflag) {
-- splittetedge(newpoint, &searchtet, flipqueue);
-- }
-+ splittetedge(newpoint, &searchtet, flipqueue);
- break;
- case ONVERTEX:
-- insertflag = false;
-- covertices++;
-+ if (!b->quiet) {
-+ printf("Warning: Point (%.17g, %.17g, %.17g) falls on a vertex.\n",
-+ newpoint[0], newpoint[1], newpoint[2]);
-+ }
- break;
- case OUTSIDE:
-- insertflag = false;
-- outvertices++;
-+ if (!b->quiet) {
-+ printf("Warning: Point (%.17g, %.17g, %.17g) lies outside the mesh.\n",
-+ newpoint[0], newpoint[1], newpoint[2]);
-+ }
- break;
- }
- // Remember the tetrahedron for next point searching.
- recenttet = searchtet;
-- if (!insertflag) {
-+ if (loc == ONVERTEX || loc == OUTSIDE) {
- pointdealloc(newpoint);
- } else {
- flip(flipqueue, NULL);
- }
- }
-
-- if (b->verbose) {
-- if (covertices > 0) {
-- printf(" %d constrained points already exist.\n", covertices);
-- }
-- if (outvertices > 0) {
-- printf(" %d constrained points lie outside the mesh.\n", outvertices);
-- }
-- printf(" %d constrained points have been inserted.\n",
-- addio->numberofpoints - covertices - outvertices);
-- }
--
- delete flipqueue;
- }
-
-+//
-+// End of mesh reconstruction routines
-+//
-+
-+//
-+// Begin of background mesh routines
-+//
-+
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// p1interpolatebgm() Set pt size by p^1 interpolation in background mesh.//
-+// interpolatepointsize() Set a point size by interpolating in bgmesh. //
- // //
--// On input, 'bgmtet' is a suggesting tet in background mesh for searching //
--// 'pt'. It returns the tet containing 'pt'. //
-+// This function first finds the tet t in background mesh contains 'pt, then //
-+// set the size of 'pt' by interpolating the sizes of the corners of t. //
-+// //
-+// 'bgmtet' is a suggesting tet in background mesh for locating 'pt' in it. //
-+// It returns the tet containing 'pt'. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--bool tetgenmesh::p1interpolatebgm(point pt, triface* bgmtet, long *scount)
-+bool tetgenmesh::interpolatepointsize(point pt, triface* bgmtet, long *scount)
- {
- point bgmpt[4];
- enum locateresult loc;
-@@ -27393,25 +24698,23 @@
-
- loc = bgm->preciselocate(pt, bgmtet, bgm->tetrahedrons->items);
- if (loc == OUTSIDE) {
-- loc = bgm->hullwalk(pt, bgmtet);
-- if (loc == OUTSIDE) {
-- // Perform a brute-force search.
-- if (b->verbose) {
-- printf("Warning: Global point location.\n");
-- }
-- if (scount) (*scount)++;
-- bgm->tetrahedrons->traversalinit(); // in bgm
-- bgmtet->tet = bgm->tetrahedrontraverse(); // in bgm
-- while (bgmtet->tet != (tetrahedron *) NULL) {
-+ // Perform a brute-force search.
-+ if (scount) (*scount)++;
-+ bgm->tetrahedrons->traversalinit(); // in bgm
-+ bgmtet->tet = bgm->tetrahedrontraverse(); // in bgm
-+ while (bgmtet->tet != (tetrahedron *) NULL) {
-+ if (bgm->intettest(pt, bgmtet, b->epsilon)) {
- loc = bgm->adjustlocate(pt, bgmtet, OUTSIDE, b->epsilon);
-- if (loc != OUTSIDE) break;
-- bgmtet->tet = bgm->tetrahedrontraverse(); // in bgm
-+ assert(loc != OUTSIDE);
-+ break;
- }
-+ bgmtet->tet = bgm->tetrahedrontraverse(); // in bgm
- }
- }
- if (loc != OUTSIDE) {
- // Let p remember t.
- setpoint2bgmtet(pt, encode(*bgmtet)); // in m
-+ // Interpolate the point size.
- // get the corners of t.
- for (i = 0; i < 4; i++) bgmpt[i] = (point) bgmtet->tet[4 + i];
- // Calculate the weighted coordinates of p in t.
-@@ -27422,11 +24725,11 @@
- volpt[3] = orient3d(bgmpt[0], bgmpt[1], bgmpt[2], pt);
- for (i = 0; i < 4; i++) weights[i] = fabs(volpt[i] / vol);
- // Interpolate the solution for p.
-- for (i = 0; i < bgm->in->numberofpointmtrs; i++) {
-- pt[pointmtrindex + i] = weights[0] * bgmpt[0][bgm->pointmtrindex + i]
-- + weights[1] * bgmpt[1][bgm->pointmtrindex + i]
-- + weights[2] * bgmpt[2][bgm->pointmtrindex + i]
-- + weights[3] * bgmpt[3][bgm->pointmtrindex + i];
-+ for (i = 0; i < bgm->in->numberofpointattributes; i++) {
-+ pt[3 + i] = weights[0] * bgmpt[0][3 + i]
-+ + weights[1] * bgmpt[1][3 + i]
-+ + weights[2] * bgmpt[2][3 + i]
-+ + weights[3] * bgmpt[3][3 + i];
- }
- } else {
- setpoint2bgmtet(pt, (tetrahedron) NULL); // in m
-@@ -27436,6 +24739,45 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
-+// searchpointrecursive() Search point in background mesh recursively. //
-+// //
-+///////////////////////////////////////////////////////////////////////////////
-+
-+void tetgenmesh::searchpointrecursive(triface *curtet, long *scount)
-+{
-+ triface searchtet, bgmtet;
-+ point searchpt;
-+ int idx, i;
-+
-+ // Mark t as proceed.
-+ infect(*curtet);
-+ // Get the opposite point of t.
-+ searchpt = oppo(*curtet);
-+ // Has p already been processed?
-+ if (pointmark(searchpt) >= 0) {
-+ // Find the location of p.
-+ bgmtet = bgm->recenttet;
-+ if (interpolatepointsize(searchpt, &bgmtet, scount)) {
-+ bgm->recenttet = bgmtet; // in bgm
-+ }
-+ // Mark p as processed.
-+ idx = pointmark(searchpt);
-+ setpointmark(searchpt, -idx - 1);
-+ }
-+ // Recursively do the above searching.
-+ adjustedgering(*curtet, CCW);
-+ for (i = 0; i < 3; i++) {
-+ fnext(*curtet, searchtet);
-+ symself(searchtet);
-+ if ((searchtet.tet != dummytet) && (!infected(searchtet))) {
-+ searchpointrecursive(&searchtet, scount);
-+ }
-+ enextself(*curtet);
-+ }
-+}
-+
-+///////////////////////////////////////////////////////////////////////////////
-+// //
- // interpolatesizemap() Interpolate the point sizes in the given size map.//
- // //
- // The size map is specified on each node of the background mesh. The points //
-@@ -27449,78 +24791,46 @@
-
- void tetgenmesh::interpolatesizemap()
- {
-- list *adjtetlist;
-- triface tetloop, neightet, bgmtet;
-+ triface tetloop, bgmtet;
- point searchpt;
- long scount;
-- int *worklist;
-- int sepcount;
-- int i;
-+ int idx, i;
-
- if (b->verbose) {
- printf(" Interpolating size map.\n");
- }
--
-- worklist = new int[points->items + 1];
-- for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
-- sepcount = 0;
- scount = 0l;
-
- tetrahedrons->traversalinit();
- tetloop.tet = tetrahedrontraverse();
- while (tetloop.tet != (tetrahedron *) NULL) {
- if (!infected(tetloop)) {
-- // Find a new subdomain.
-- adjtetlist = new list(sizeof(triface), NULL, 1024);
-- infect(tetloop);
-- // Search the four corners in background mesh.
-- for (i = 0; i < 4; i++) {
-- searchpt = (point) tetloop.tet[4 + i];
-- // Mark the point for avoiding multiple searchings.
-- // assert(worklist[pointmark(searchpt)] == 0);
-- worklist[pointmark(searchpt)] = 1;
-- // Does it contain a pointer to bgm tet?
-- bgm->decode(point2bgmtet(searchpt), bgmtet);
-- if (bgm->isdead(&bgmtet)) {
-+ // Found an traversed tet t.
-+ tetloop.loc = 0;
-+ tetloop.ver = 0;
-+ // Locate the three vertices of current face of t.
-+ for (i = 0; i < 3; i++) {
-+ searchpt = org(tetloop);
-+ // Has p already been processed?
-+ if (pointmark(searchpt) >= 0) {
-+ // Interpolate p in background mesh.
- bgmtet = bgm->recenttet;
-- }
-- if (p1interpolatebgm(searchpt, &bgmtet, &scount)) {
-- bgm->recenttet = bgmtet;
-- }
-- } // for (i = 0; i < 4; i++)
-- // Collect all tets in this region.
-- adjtetlist->append(&tetloop);
-- // Collect the tets in the subdomain.
-- for (i = 0; i < adjtetlist->len(); i++) {
-- tetloop = * (triface *)(* adjtetlist)[i];
-- for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
-- sym(tetloop, neightet);
-- if ((neightet.tet != dummytet) && !infected(neightet)) {
-- // Only need to search for the opposite point.
-- searchpt = oppo(neightet);
-- if (worklist[pointmark(searchpt)] == 0) {
-- worklist[pointmark(searchpt)] = 1;
-- decode(point2bgmtet(searchpt), bgmtet);
-- if (bgm->isdead(&bgmtet)) {
-- bgmtet = bgm->recenttet;
-- }
-- if (p1interpolatebgm(searchpt, &bgmtet, &scount)) {
-- bgm->recenttet = bgmtet;
-- }
-- }
-- infect(neightet);
-- adjtetlist->append(&neightet);
-+ if (interpolatepointsize(searchpt, &bgmtet, &scount)) {
-+ bgm->recenttet = bgmtet;
- }
-+ // Mark p as processed.
-+ idx = pointmark(searchpt);
-+ setpointmark(searchpt, -idx - 1);
- }
-+ enextself(tetloop);
- }
-- // Increase the number of separated domains.
-- sepcount++;
-- delete adjtetlist;
-- } // if (!infect())
-+ // Recursively do the above searching in the neighbring tets of t.
-+ searchpointrecursive(&tetloop, &scount);
-+ }
- tetloop.tet = tetrahedrontraverse();
- }
-
-- // Unmark all tets.
-+ // Have searched all points. Unmark tets.
- tetrahedrons->traversalinit();
- tetloop.tet = tetrahedrontraverse();
- while (tetloop.tet != (tetrahedron *) NULL) {
-@@ -27528,201 +24838,192 @@
- uninfect(tetloop);
- tetloop.tet = tetrahedrontraverse();
- }
-- delete [] worklist;
-+ // Unmark points.
-+ points->traversalinit(); // in m
-+ searchpt = pointtraverse(); // in m
-+ while (searchpt != (point) NULL) {
-+ idx = pointmark(searchpt);
-+ assert(idx < 0);
-+ setpointmark(searchpt, -(idx + 1));
-+ searchpt = pointtraverse(); // in m
-+ }
-
- #ifdef SELF_CHECK
-- if (b->verbose && scount > 0l) {
-+ if (b->verbose) {
- printf(" %ld brute-force searches.\n", scount);
- }
-- if (b->verbose && sepcount > 0) {
-- printf(" %d separate domains.\n", sepcount);
-- }
- #endif
- }
-
-+//
-+// End of of background mesh routines
-+//
-+
-+//
-+// Begin of Delaunay refinement routines
-+//
-+
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// duplicatebgmesh() Duplicate current mesh to background mesh. //
-+// calclocalfeaturesizes() Calculate local feature sizes of all points. //
- // //
--// Current mesh 'this' is copied into 'this->bgm'.Both meshes share the same //
--// input tetgenio object, 'this->in', same tetgenbehavior object 'this->b'. //
-+// Given a PLC X, the local feature size, lfs_d(x), of any point x in X is //
-+// defined as the distance from x to two features of X which are of dim no //
-+// large than d. For example, lfs_0(x) is the distance from x to the second //
-+// nearest point of X. Let lfs(x) = lfs_2(x). //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--void tetgenmesh::duplicatebgmesh()
-+void tetgenmesh::calclocalfeaturesizes()
- {
-- triface tetloop, btetloop;
-- triface symtet, bsymtet;
-- face bhullsh, bneighsh;
-- point *idx2bplist, *tetptbaklist;
-- point ploop, bploop;
-- int idx, i;
-+ list *tetlist, *verlist;
-+ tetrahedron tetptr;
-+ triface starttet;
-+ face checksh, checkseg;
-+ point ploop, ver[3];
-+ point ptlfslarge, ptlfssmall;
-+ enum locateresult loc;
-+ REAL prj[3], lfs[3], len;
-+ REAL lfslarge, lfssmall;
-+ int i, j;
-
-- if (!b->quiet) {
-- printf("Duplicating background mesh.\n");
-+ if (b->verbose > 0) {
-+ printf(" Calculating local feature sizes.\n");
- }
-
-- // The background mesh itself has no background mesh.
-- // assert(bgm->bgm == (tetgenmesh *) NULL);
-- // The space for metric tensor should be allocated.
-- // assert(bgm->sizeoftensor > 0);
-+ // Construct a map from points to tetrahedra.
-+ makepoint2tetmap();
-+ // Initialize working lists.
-+ tetlist = new list(sizeof(triface), NULL, 256);
-+ verlist = new list(sizeof(point *), NULL, 256);
-+ // Initialize bookkeeping variables.
-+ ptlfslarge = ptlfssmall = (point) NULL;
-+ lfslarge = lfssmall = 0.0;
-
-- // Copy point list.
-- idx2bplist = new point[points->items + 1];
-- idx = in->firstnumber;
- points->traversalinit();
- ploop = pointtraverse();
- while (ploop != (point) NULL) {
-- bgm->makepoint(&bploop);
-- // Copy coordinates, attributes.
-- for (i = 0; i < 3 + in->numberofpointattributes; i++) {
-- bploop[i] = ploop[i];
-- }
-- // Transfer the metric tensor.
-- for (i = 0; i < bgm->sizeoftensor; i++) {
-- bploop[bgm->pointmtrindex + i] = ploop[pointmtrindex + i];
-- // Metric tensor should have a positive value.
-- if (bploop[bgm->pointmtrindex + i] <= 0.0) {
-- printf("Error: Point %d has non-positive size %g (-m option).\n",
-- bgm->pointmark(bploop), bploop[bgm->pointmtrindex + i]);
-- terminatetetgen(1);
-+ tetptr = point2tet(ploop);
-+ // Only calculate lfs(p) if it is in the mesh.
-+ if (tetptr != (tetrahedron) NULL) {
-+ decode(tetptr, starttet);
-+ tetlist->append(&starttet);
-+ formstarpolyhedron(ploop, tetlist, verlist, true); // Form star(p).
-+ lfs[0] = lfs[1] = lfs[2] = longest;
-+ // Calculate lfs_0(p).
-+ for (i = 0; i < verlist->len(); i++) {
-+ ver[0] = * (point *)(* verlist)[i];
-+ len = distance(ploop, ver[0]);
-+ if (lfs[0] > len) lfs[0] = len;
-+ }
-+ // Claculate lfs_1(p).
-+ for (i = 0; i < tetlist->len(); i++) {
-+ starttet = * (triface *)(* tetlist)[i];
-+ starttet.ver = 0;
-+ for (j = 0; j < 3; j++) {
-+ tsspivot(&starttet, &checkseg);
-+ if (checkseg.sh != dummysh) {
-+ checkseg.shver = 0;
-+ ver[0] = sorg(checkseg);
-+ ver[1] = sdest(checkseg);
-+ projpt2edge(ploop, ver[0], ver[1], prj);
-+ loc = locateseg(prj, &checkseg);
-+ if (loc != OUTSIDE) {
-+ len = distance(ploop, prj);
-+ if (lfs[1] > len) lfs[1] = len;
-+ }
-+ }
-+ enextself(starttet);
-+ }
-+ }
-+ // Claculate lfs_2(p).
-+ for (i = 0; i < tetlist->len(); i++) {
-+ starttet = * (triface *)(* tetlist)[i];
-+ tspivot(starttet, checksh);
-+ if (checksh.sh != dummysh) {
-+ ver[0] = sorg(checksh);
-+ ver[1] = sdest(checksh);
-+ ver[2] = sapex(checksh);
-+ projpt2face(ploop, ver[0], ver[1], ver[2], prj);
-+ abovepoint = facetabovepointarray[shellmark(checksh)];
-+ if (abovepoint == (point) NULL) {
-+ getfacetabovepoint(&checksh);
-+ }
-+ loc = locatesub(prj, &checksh, 1, b->epsilon);
-+ if (loc != OUTSIDE) {
-+ len = distance(ploop, prj);
-+ if (lfs[2] > len) lfs[2] = len;
-+ }
-+ }
- }
-+ // Decide lfs(p).
-+ ploop[pointlfsindex] = lfs[0];
-+ if (ploop[pointlfsindex] > lfs[1]) ploop[pointlfsindex] = lfs[1];
-+ if (ploop[pointlfsindex] > lfs[2]) ploop[pointlfsindex] = lfs[2];
-+ // Update statistics.
-+ if (ptlfslarge == (point) NULL) {
-+ ptlfslarge = ptlfssmall = ploop;
-+ lfslarge = lfssmall = ploop[pointlfsindex];
-+ } else {
-+ if (lfslarge < ploop[pointlfsindex]) {
-+ lfslarge = ploop[pointlfsindex];
-+ ptlfslarge = ploop;
-+ }
-+ if (lfssmall > ploop[pointlfsindex]) {
-+ lfssmall = ploop[pointlfsindex];
-+ ptlfssmall = ploop;
-+ }
-+ }
-+ // Clear working lists.
-+ tetlist->clear();
-+ verlist->clear();
- }
-- // Remember the point for searching.
-- idx2bplist[idx++] = bploop;
- ploop = pointtraverse();
- }
-
-- // Copy tetrahedra list.
-- tetptbaklist = new point[tetrahedrons->items + 1];
-- idx = in->firstnumber;
-- tetrahedrons->traversalinit();
-- tetloop.tet = tetrahedrontraverse();
-- while (tetloop.tet != (tetrahedron *) NULL) {
-- bgm->maketetrahedron(&btetloop);
-- // Set the four corners.
-- for (i = 0; i < 4; i++) {
-- ploop = (point) tetloop.tet[4 + i];
-- bploop = idx2bplist[pointmark(ploop)];
-- btetloop.tet[4 + i] = (tetrahedron) bploop;
-- }
-- // Remember the tet for setting neighbor connections.
-- tetptbaklist[idx++] = (point) tetloop.tet[4];
-- tetloop.tet[4] = (tetrahedron) btetloop.tet;
-- tetloop.tet = tetrahedrontraverse();
-- }
--
-- // Set the connections between background tetrahedra. Create background
-- // hull subfaces. Create the map of point-to-bgmtet.
-- idx = in->firstnumber;
-- tetrahedrons->traversalinit();
-- tetloop.tet = tetrahedrontraverse();
-- while (tetloop.tet != (tetrahedron *) NULL) {
-- // Get the corresponding background tet.
-- btetloop.tet = (tetrahedron *) tetloop.tet[4];
-- // Set the four neighbors.
-- for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
-- btetloop.loc = tetloop.loc;
-- sym(tetloop, symtet);
-- if ((symtet.tet != dummytet) && (symtet.tet > tetloop.tet)) {
-- // Operate on the un-connected interior face.
-- bsymtet.tet = (tetrahedron *) symtet.tet[4]; // The saved bgm tet.
-- bsymtet.loc = symtet.loc;
-- bgm->bond(btetloop, bsymtet);
-- } else if (symtet.tet == dummytet) {
-- // Create a subface in background mesh.
-- bgm->makeshellface(bgm->subfaces, &bhullsh);
-- bgm->adjustedgering(btetloop, CCW); // face to inside.
-- bgm->setsorg(bhullsh, bgm->org(btetloop));
-- bgm->setsdest(bhullsh, bgm->dest(btetloop));
-- bgm->setsapex(bhullsh, bgm->apex(btetloop));
-- bgm->tsbond(btetloop, bhullsh);
-- // Remember a hull face for point location.
-- bgm->dummytet[0] = bgm->encode(btetloop);
-- }
-- }
-- // Restore the backup tet point.
-- tetloop.tet[4] = (tetrahedron) tetptbaklist[idx++];
-- // Make the point-to-bgmtet map for size interpolation.
-- btetloop.loc = 0;
-- for (i = 0; i < 4; i++) {
-- ploop = (point) tetloop.tet[4 + i];
-- setpoint2bgmtet(ploop, bgm->encode(btetloop));
-- }
-- // Go to the next tet, btet.
-- tetloop.tet = tetrahedrontraverse();
-- }
--
-- // Connect bgm hull subfaces. Note: all hull subfaces form a 2-manifold.
-- bgm->subfaces->traversalinit();
-- bhullsh.sh = bgm->shellfacetraverse(bgm->subfaces);
-- while (bhullsh.sh != (shellface *) NULL) {
-- bhullsh.shver = 0;
-- bgm->stpivot(bhullsh, btetloop);
-- assert(btetloop.tet != bgm->dummytet);
-- bgm->adjustedgering(btetloop, CCW);
-- for (i = 0; i < 3; i++) {
-- bgm->spivot(bhullsh, bneighsh);
-- if (bneighsh.sh == bgm->dummysh) {
-- // This side is open, operate on it.
-- bsymtet = btetloop;
-- while (bgm->fnextself(bsymtet));
-- bgm->tspivot(bsymtet, bneighsh);
-- bgm->findedge(&bneighsh, bgm->sdest(bhullsh), bgm->sorg(bhullsh));
-- bgm->sbond(bhullsh, bneighsh);
-- }
-- bgm->enextself(btetloop);
-- bgm->senextself(bhullsh);
-- }
-- bhullsh.sh = bgm->shellfacetraverse(bgm->subfaces);
-+ if (b->verbose > 1) {
-+ printf(" smallest lfs = %g (%d).\n", lfssmall, pointmark(ptlfssmall));
-+ printf(" largest lfs = %g (%d).\n", lfslarge, pointmark(ptlfslarge));
- }
-
-- delete [] tetptbaklist;
-- delete [] idx2bplist;
-+ delete tetlist;
-+ delete verlist;
- }
-
--//
--// Begin of Delaunay refinement routines
--//
--
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// marksharpsegments() Mark sharp segments. //
--// //
--// A segment s is called sharp if it is in one of the two cases: //
--// (1) There is a segment s' intersecting with s. The internal angle (*) //
--// between s and s' is acute. //
--// (2) There are two facets f1 and f2 intersecting at s. The internal //
--// dihedral angle (*) between f1 and f2 is acute. //
--// This routine finds the sharp segments and marked them as type SHARP. //
--// The minimum angle between segments (minfaceang) and the minimum dihedral //
--// angle between facets (minfacetdihed) are calulcated. //
-+// marksharpsubsegs() Mark all sharp subsegments. //
- // //
--// (*) The internal angle (or dihedral) bewteen two features means the angle //
--// inside the mesh domain. //
-+// A segment is sharp if it is between two facets that form a small dihedral //
-+// angle (< 'dihedbound', given in degrees). It is marked as SHARP. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--void tetgenmesh::marksharpsegments(REAL sharpangle)
-+void tetgenmesh::marksharpsubsegs(REAL dihedbound)
- {
-+ list *spinshlist;
- triface adjtet;
- face startsh, spinsh, neighsh;
- face segloop, prevseg, nextseg;
- point eorg, edest;
-- REAL ang, smallang;
-+ enum shestype stype;
-+ REAL angle, smallang;
- bool issharp;
-- int sharpsegcount;
-+ int scount;
-+ int i;
-
- if (b->verbose > 0) {
-- printf(" Marking sharp segments.\n");
-+ printf(" Marking sharp subsegments.\n");
- }
-
-- smallang = sharpangle * PI / 180.;
-- sharpsegcount = 0;
-- eorg = edest = (point) NULL; // To avoid compiler warnings.
--
-- // A segment s may have been split into many subsegments. Operate the one
-- // which contains the origin of s. Then mark the rest of subsegments.
-+ smallang = dihedbound * PI / 180.;
-+ scount = 0;
-+ eorg = edest = (point) NULL; // avoid compilation warnings.
-+ // Initial working list.
-+ spinshlist = new list(sizeof(face), NULL, 256);
-+
-+ // A segment s may be split into many subsegments. Operate the one which
-+ // contains the origin of s. Then mark the rest of subsegments.
- subsegs->traversalinit();
- segloop.sh = shellfacetraverse(subsegs);
- while (segloop.sh != (shellface *) NULL) {
-@@ -27730,512 +25031,148 @@
- senext2(segloop, prevseg);
- spivotself(prevseg);
- if (prevseg.sh == dummysh) {
-- // Operate on this seg s.
-- assert(shelltype(segloop) != SHARP); // It should be unmarked.
-+ // Operate on this seg.
- issharp = false;
-+ segloop.shver = 0;
- spivot(segloop, startsh);
- if (startsh.sh != dummysh) {
-- // First check if two facets form an acute dihedral angle at s.
-- eorg = sorg(segloop);
-- edest = sdest(segloop);
-- spinsh = startsh;
-- do {
-- if (sorg(spinsh) != eorg) {
-- sesymself(spinsh);
-- }
-- // Only do test when the spinsh is faceing inward.
-- stpivot(spinsh, adjtet);
-- if (adjtet.tet != dummytet) {
-- // Get the subface on the adjacent facet.
-- spivot(spinsh, neighsh);
-- // Do not calculate if it is self-bonded.
-- if (neighsh.sh != spinsh.sh) {
-- // Calculate the dihedral angle between the two subfaces.
-- ang = facedihedral(eorg, edest, sapex(spinsh), sapex(neighsh));
-- // Only do check if a sharp angle has not been found.
-- if (!issharp) issharp = (ang < smallang);
-- // Remember the smallest facet dihedral angle.
-- minfacetdihed = minfacetdihed < ang ? minfacetdihed : ang;
-- }
-- }
-- // Go to the next facet.
-- spivotself(spinsh);
-- } while (spinsh.sh != startsh.sh);
-- // if (!issharp) {
-- // Second check if s forms an acute angle with another seg.
-+ spivot(startsh, spinsh);
-+ if (spinsh.sh != startsh.sh) {
-+ // This subface is not self-bonded.
-+ eorg = sorg(segloop);
-+ edest = sdest(segloop);
-+ // Get all incident subfaces around the seg.
- spinsh = startsh;
- do {
- if (sorg(spinsh) != eorg) {
- sesymself(spinsh);
- }
-- // Calculate the angle between s and s' of this facet.
-- neighsh = spinsh;
-- // Rotate edges around 'eorg' until meeting another seg s'. Such
-- // seg (s') must exist since the facet is segment-bounded.
-- // The sum of the angles of faces at 'eorg' gives the internal
-- // angle between the two segments.
-- ang = 0.0;
-- do {
-- ang += interiorangle(eorg, sdest(neighsh), sapex(neighsh), NULL);
-- senext2self(neighsh);
-- sspivot(neighsh, nextseg);
-- if (nextseg.sh != dummysh) break;
-- // Go to the next coplanar subface.
-- spivotself(neighsh);
-- assert(neighsh.sh != dummysh);
-- if (sorg(neighsh) != eorg) {
-- sesymself(neighsh);
-- }
-- } while (true);
-- // Only do check if a sharp angle has not been found.
-- if (!issharp) issharp = (ang < smallang);
-- // Remember the smallest input face angle.
-- minfaceang = minfaceang < ang ? minfaceang : ang;
-- // Go to the next facet.
-+ spinshlist->append(&spinsh);
- spivotself(spinsh);
- } while (spinsh.sh != startsh.sh);
-- // }
-- }
-- if (issharp) {
-- setshelltype(segloop, SHARP);
-- // Set the type for all subsegments at forwards.
-- senext(segloop, nextseg);
-- spivotself(nextseg);
-- while (nextseg.sh != dummysh) {
-- nextseg.shver = 0;
-- setshelltype(nextseg, SHARP);
-- senextself(nextseg);
-- spivotself(nextseg);
- }
-- sharpsegcount++;
-- }
-- }
-- segloop.sh = shellfacetraverse(subsegs);
-- }
--
-- // So far we have marked all segments which have an acute dihedral angle
-- // or whose ORIGINs have an acute angle. In the un-marked subsegments,
-- // there are possible ones whose DESTINATIONs have an acute angle.
-- subsegs->traversalinit();
-- segloop.sh = shellfacetraverse(subsegs);
-- while (segloop.sh != (shellface *) NULL) {
-- // Only operate if s is non-sharp and contains the dest.
-- segloop.shver = 0;
-- senext(segloop, nextseg);
-- spivotself(nextseg);
-- // if ((nextseg.sh == dummysh) && (shelltype(segloop) != SHARP)) {
-- if (nextseg.sh == dummysh) {
-- // issharp = false;
-- issharp = (shelltype(segloop) == SHARP);
-- spivot(segloop, startsh);
-- if (startsh.sh != dummysh) {
-- // Check if s forms an acute angle with another seg.
-- eorg = sdest(segloop);
-- spinsh = startsh;
-- do {
-- if (sorg(spinsh) != eorg) {
-- sesymself(spinsh);
-+ // Check the pair of adjacent subfaces for small angle.
-+ spinsh = * (face *)(* spinshlist)[0];
-+ for (i = 1; i <= spinshlist->len() && !issharp; i++) {
-+ if (i == spinshlist->len()) {
-+ neighsh = * (face *)(* spinshlist)[0];
-+ } else {
-+ neighsh = * (face *)(* spinshlist)[i];
- }
-- // Calculate the angle between s and s' of this facet.
-- neighsh = spinsh;
-- ang = 0.0;
-- do {
-- ang += interiorangle(eorg, sdest(neighsh), sapex(neighsh), NULL);
-- senext2self(neighsh);
-- sspivot(neighsh, nextseg);
-- if (nextseg.sh != dummysh) break;
-- // Go to the next coplanar subface.
-- spivotself(neighsh);
-- assert(neighsh.sh != dummysh);
-- if (sorg(neighsh) != eorg) {
-- sesymself(neighsh);
-- }
-- } while (true);
-- // Only do check if a sharp angle has not been found.
-- if (!issharp) issharp = (ang < smallang);
-- // Remember the smallest input face angle.
-- minfaceang = minfaceang < ang ? minfaceang : ang;
-- // Go to the next facet.
-- spivotself(spinsh);
-- } while (spinsh.sh != startsh.sh);
-- }
-- if (issharp) {
-- setshelltype(segloop, SHARP);
-- // Set the type for all subsegments at backwards.
-- senext2(segloop, prevseg);
-- spivotself(prevseg);
-- while (prevseg.sh != dummysh) {
-- prevseg.shver = 0;
-- setshelltype(prevseg, SHARP);
-- senext2self(prevseg);
-- spivotself(prevseg);
-+ // Only do test when the spinsh is faceing inward.
-+ stpivot(spinsh, adjtet);
-+ if (adjtet.tet != dummytet) {
-+ angle = facedihedral(eorg, edest, sapex(spinsh), sapex(neighsh));
-+ issharp = angle < smallang;
-+ }
-+ spinsh = neighsh;
- }
-- sharpsegcount++;
-+ spinshlist->clear();
- }
-- }
-- segloop.sh = shellfacetraverse(subsegs);
-- }
--
-- if ((b->verbose > 0) && (sharpsegcount > 0)) {
-- printf(" %d sharp segments.\n", sharpsegcount);
-- }
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
--// decidefeaturepointsizes() Decide the sizes for all feature points. //
--// //
--// A feature point is a point on a sharp segment. Every feature point p will //
--// be assigned a positive size which is the radius of the protecting ball. //
--// //
--// The size of a feature point may be specified by one of the following ways://
--// (1) directly specifying on an input vertex (by using .mtr file); //
--// (2) imposing a fixed maximal volume constraint ('-a__' option); //
--// (3) imposing a maximal volume constraint in a region ('-a' option); //
--// (4) imposing a maximal area constraint on a facet (in .var file); //
--// (5) imposing a maximal length constraint on a segment (in .var file); //
--// (6) combining (1) - (5). //
--// (7) automatically deriving a size if none of (1) - (6) is available. //
--// In case (7),the size of p is set to be the smallest edge length among all //
--// edges connecting at p. The final size of p is the minimum of (1) - (7). //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--void tetgenmesh::decidefeaturepointsizes()
--{
-- list *tetlist, *verlist;
-- shellface **segsperverlist;
-- triface starttet;
-- face shloop;
-- face checkseg, prevseg, nextseg, testseg;
-- point ploop, adjpt, e1, e2;
-- REAL lfs_0, len, vol, maxlen, varlen;
-- bool isfeature;
-- int *idx2seglist;
-- int featurecount;
-- int idx, i, j;
--
-- if (b->verbose > 0) {
-- printf(" Deciding feature-point sizes.\n");
-- }
--
-- // Constructing a map from vertices to segments.
-- makesegmentmap(idx2seglist, segsperverlist);
-- // Initialize working lists.
-- tetlist = new list(sizeof(triface), NULL, 256);
-- verlist = new list(sizeof(point *), NULL, 256);
--
-- if (b->fixedvolume) {
-- // A fixed volume constraint is imposed. This gives an upper bound of
-- // the maximal radius of the protect ball of a vertex.
-- maxlen = pow(6.0 * b->maxvolume, 1.0/3.0);
-- }
--
-- if (!b->refine) {
-- // Initially correct types for Steiner points.
-- featurecount = 0;
-- points->traversalinit();
-- ploop = pointtraverse();
-- while (ploop != (point) NULL) {
-- if (pointtype(ploop) == NACUTEVERTEX) {
-- if (point2sh(ploop) != (shellface) NULL) {
-- setpointtype(ploop, FREESEGVERTEX);
-- featurecount++;
-- }
-+ // Set type for this segment (inclusing subsegments).
-+ stype = issharp ? SHARP : NSHARPNSKINNY;
-+ scount += issharp ? 1 : 0;
-+ setshelltype(segloop, stype);
-+ senext(segloop, nextseg);
-+ spivotself(nextseg);
-+ while (nextseg.sh != dummysh) {
-+ nextseg.shver = 0;
-+ setshelltype(nextseg, stype);
-+ senextself(nextseg);
-+ spivotself(nextseg);
- }
-- ploop = pointtraverse();
- }
--#ifdef SELF_CHECK
-- if ((b->verbose > 0) && (featurecount > 0)) {
-- printf(" %d Steiner points correction.\n", featurecount);
-- }
--#endif
-- }
--
-- // First only assign a size of p if p is not a Steiner point. The size of
-- // a Steiner point will be interpolated later from the endpoints of the
-- // segment on which it lies.
-- featurecount = 0;
-- points->traversalinit();
-- ploop = pointtraverse();
-- while (ploop != (point) NULL) {
-- if (pointtype(ploop) != FREESEGVERTEX) {
-- // Is p a feature point?
-- isfeature = false;
-- idx = pointmark(ploop) - in->firstnumber;
-- for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isfeature; i++) {
-- checkseg.sh = segsperverlist[i];
-- isfeature = (shelltype(checkseg) == SHARP);
-- }
-- // Decide the size of p if it is on a sharp segment.
-- if (isfeature) {
-- // Find a tet containing p (checkseg is a sharp seg which contains p).
-- sstpivot(&checkseg, &starttet);
-- // Form star(p).
-- tetlist->append(&starttet);
-- formstarpolyhedron(ploop, tetlist, verlist, true);
-- // Decide the size for p if no input size is given on input.
-- if (ploop[pointmtrindex] == 0.0) {
-- // Calculate lfs_0(p).
-- lfs_0 = longest;
-- for (i = 0; i < verlist->len(); i++) {
-- adjpt = * (point *)(* verlist)[i];
-- if (pointtype(adjpt) == FREESEGVERTEX) {
-- // A Steiner point q. Find the seg it lies on.
-- sdecode(point2sh(adjpt), checkseg);
-- assert(checkseg.sh != dummysh);
-- checkseg.shver = 0;
-- // Find the origin of this seg.
-- prevseg = checkseg;
-- do {
-- senext2(prevseg, testseg);
-- spivotself(testseg);
-- if (testseg.sh == dummysh) break;
-- prevseg = testseg; // Go to the previous subseg.
-- prevseg.shver = 0;
-- } while (true);
-- // Find the dest of this seg.
-- nextseg = checkseg;
-- do {
-- senext(nextseg, testseg);
-- spivotself(testseg);
-- if (testseg.sh == dummysh) break;
-- nextseg = testseg; // Go to the next subseg.
-- nextseg.shver = 0;
-- } while (true);
-- e1 = sorg(prevseg);
-- e2 = sdest(nextseg);
-- // Check if p is the origin or the dest of this seg.
-- if (ploop == e1) {
-- // Set q to be the dest of this seg.
-- adjpt = e2;
-- } else if (ploop == e2) {
-- // Set q to be the org of this seg.
-- adjpt = e1;
-- }
-- }
-- len = distance(ploop, adjpt);
-- if (lfs_0 > len) lfs_0 = len;
-- }
-- ploop[pointmtrindex] = lfs_0;
-- }
-- if (b->fixedvolume) {
-- // A fixed volume constraint is imposed. Adjust H(p) <= maxlen.
-- if (ploop[pointmtrindex] > maxlen) {
-- ploop[pointmtrindex] = maxlen;
-- }
-- }
-- if (b->varvolume) {
-- // Variant volume constraints are imposed. Adjust H(p) <= varlen.
-- for (i = 0; i < tetlist->len(); i++) {
-- starttet = * (triface *)(* tetlist)[i];
-- vol = volumebound(starttet.tet);
-- if (vol > 0.0) {
-- varlen = pow(6 * vol, 1.0/3.0);
-- if (ploop[pointmtrindex] > varlen) {
-- ploop[pointmtrindex] = varlen;
-- }
-- }
-- }
-- }
-- // Clear working lists.
-- tetlist->clear();
-- verlist->clear();
-- featurecount++;
-- } else {
-- // NO feature point, set the size of p be zero.
-- ploop[pointmtrindex] = 0.0;
-- }
-- } // if (pointtype(ploop) != FREESEGVERTEX) {
-- ploop = pointtraverse();
-+ segloop.sh = shellfacetraverse(subsegs);
- }
-
- if (b->verbose > 0) {
-- printf(" %d feature points.\n", featurecount);
-- }
--
-- if (!b->refine) {
-- // Second only assign sizes for all Steiner points. A Steiner point p
-- // inserted on a sharp segment s is assigned a size by interpolating
-- // the sizes of the original endpoints of s.
-- featurecount = 0;
-- points->traversalinit();
-- ploop = pointtraverse();
-- while (ploop != (point) NULL) {
-- if (pointtype(ploop) == FREESEGVERTEX) {
-- if (ploop[pointmtrindex] == 0.0) {
-- sdecode(point2sh(ploop), checkseg);
-- assert(checkseg.sh != dummysh);
-- if (shelltype(checkseg) == SHARP) {
-- checkseg.shver = 0;
-- // Find the origin of this seg.
-- prevseg = checkseg;
-- do {
-- senext2(prevseg, testseg);
-- spivotself(testseg);
-- if (testseg.sh == dummysh) break;
-- prevseg = testseg; // Go the previous subseg.
-- prevseg.shver = 0;
-- } while (true);
-- // Find the dest of this seg.
-- nextseg = checkseg;
-- do {
-- senext(nextseg, testseg);
-- spivotself(testseg);
-- if (testseg.sh == dummysh) break;
-- nextseg = testseg; // Go the next subseg.
-- nextseg.shver = 0;
-- } while (true);
-- e1 = sorg(prevseg);
-- e2 = sdest(nextseg);
-- len = distance(e1, e2);
-- lfs_0 = distance(e1, ploop);
-- // The following assert() happens when -Y option is used.
-- if (b->nobisect == 0) {
-- assert(lfs_0 < len);
-- }
-- ploop[pointmtrindex] = e1[pointmtrindex]
-- + (lfs_0 / len) * (e2[pointmtrindex] - e1[pointmtrindex]);
-- featurecount++;
-- } else {
-- // NO feature point, set the size of p be zero.
-- ploop[pointmtrindex] = 0.0;
-- } // if (shelltype(checkseg) == SHARP)
-- } // if (ploop[pointmtrindex] == 0.0)
-- } // if (pointtype(ploop) != FREESEGVERTEX)
-- ploop = pointtraverse();
-- }
-- if ((b->verbose > 0) && (featurecount > 0)) {
-- printf(" %d Steiner feature points.\n", featurecount);
-- }
-+ printf(" %d sharp segments.\n", scount);
- }
--
-- if (varconstraint) {
-- // A .var file exists. Adjust feature sizes.
-- if (in->facetconstraintlist) {
-- // Have facet area constrains.
-- subfaces->traversalinit();
-- shloop.sh = shellfacetraverse(subfaces);
-- while (shloop.sh != (shellface *) NULL) {
-- varlen = areabound(shloop);
-- if (varlen > 0.0) {
-- // Check if the three corners are feature points.
-- varlen = sqrt(varlen);
-- for (j = 0; j < 3; j++) {
-- ploop = (point) shloop.sh[3 + j];
-- isfeature = false;
-- idx = pointmark(ploop) - in->firstnumber;
-- for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isfeature;
-- i++) {
-- checkseg.sh = segsperverlist[i];
-- isfeature = (shelltype(checkseg) == SHARP);
-- }
-- if (isfeature) {
-- assert(ploop[pointmtrindex] > 0.0);
-- if (ploop[pointmtrindex] > varlen) {
-- ploop[pointmtrindex] = varlen;
-- }
-- }
-- } // for (j = 0; j < 3; j++)
-- }
-- shloop.sh = shellfacetraverse(subfaces);
-- }
-- }
-- if (in->segmentconstraintlist) {
-- // Have facet area constrains.
-- subsegs->traversalinit();
-- shloop.sh = shellfacetraverse(subsegs);
-- while (shloop.sh != (shellface *) NULL) {
-- varlen = areabound(shloop);
-- if (varlen > 0.0) {
-- // Check if the two endpoints are feature points.
-- for (j = 0; j < 2; j++) {
-- ploop = (point) shloop.sh[3 + j];
-- isfeature = false;
-- idx = pointmark(ploop) - in->firstnumber;
-- for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isfeature;
-- i++) {
-- checkseg.sh = segsperverlist[i];
-- isfeature = (shelltype(checkseg) == SHARP);
-- }
-- if (isfeature) {
-- assert(ploop[pointmtrindex] > 0.0);
-- if (ploop[pointmtrindex] > varlen) {
-- ploop[pointmtrindex] = varlen;
-- }
-- }
-- } // for (j = 0; j < 2; j++)
-- }
-- shloop.sh = shellfacetraverse(subsegs);
-- }
-- }
-- } // if (varconstraint)
--
-- delete [] segsperverlist;
-- delete [] idx2seglist;
-- delete tetlist;
-- delete verlist;
-+ delete spinshlist;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// enqueueencsub() Add an encroached subface into the queue. //
-+// markskinnysubfaces() Mark all skinny subfaces. //
- // //
--///////////////////////////////////////////////////////////////////////////////
--
--void tetgenmesh::enqueueencsub(face* testsub, point encpt, int quenumber,
-- REAL* cent)
--{
-- badface *encsub;
-- int i;
--
-- encsub = (badface *) badsubfaces->alloc();
-- encsub->ss = *testsub;
-- encsub->forg = sorg(*testsub);
-- encsub->fdest = sdest(*testsub);
-- encsub->fapex = sapex(*testsub);
-- encsub->foppo = (point) encpt;
-- for (i = 0; i < 3; i++) encsub->cent[i] = cent[i];
-- encsub->nextitem = (badface *) NULL;
-- // Set the pointer of 'encsubseg' into 'testsub'. It has two purposes:
-- // (1) We can regonize it is encroached; (2) It is uniquely queued.
-- setshell2badface(encsub->ss, encsub);
-- // Add the subface to the end of a queue (quenumber = 2, high priority).
-- *subquetail[quenumber] = encsub;
-- // Maintain a pointer to the NULL pointer at the end of the queue.
-- subquetail[quenumber] = &encsub->nextitem;
-- if (b->verbose > 2) {
-- printf(" Queuing subface (%d, %d, %d) [%d].\n", pointmark(encsub->forg),
-- pointmark(encsub->fdest), pointmark(encsub->fapex), quenumber);
-- }
--}
--
--///////////////////////////////////////////////////////////////////////////////
-+// A subface is skinny if it has an angle smaller than 'anglebound' and the //
-+// two edges form the angle are both segments. Such subface is not be able //
-+// to refine. It will be marked as type SKINNY. //
- // //
--// dequeueencsub() Remove an enc-subface from the front of the queue. //
-+// This procedure operates in two phases. The first phase finds some skinny //
-+// subfaces by checking the angles of subfaces. The second phase finds all //
-+// skinny subfaces by a neighbor-first search. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--tetgenmesh::badface* tetgenmesh::dequeueencsub(int* pquenumber)
--{
-- badface *result;
-- int quenumber;
-+void tetgenmesh::markskinnysubfaces(REAL anglebound)
-+{
-+ list *skinnyshlist;
-+ face subloop, checksub;
-+ face startsh, neighsh;
-+ face seg1, seg2, checkseg;
-+ point pa, pb, pc;
-+ enum shestype shty;
-+ REAL smallang, angle;
-+ int i, j;
-+
-+ if (b->verbose > 0) {
-+ printf(" Marking skinny subfaces.\n");
-+ }
-
-- // Look for a nonempty queue.
-- for (quenumber = 2; quenumber >= 0; quenumber--) {
-- result = subquefront[quenumber];
-- if (result != (badface *) NULL) {
-- // Remove the badface from the queue.
-- subquefront[quenumber] = result->nextitem;
-- // Maintain a pointer to the NULL pointer at the end of the queue.
-- if (subquefront[quenumber] == (badface *) NULL) {
-- subquetail[quenumber] = &subquefront[quenumber];
-+ smallang = anglebound * PI / 180.;
-+ // Initial working list.
-+ skinnyshlist = new list(sizeof(face), NULL, subfaces->items);
-+
-+ // Loop the set of subfaces, collect some skinny ones.
-+ subfaces->traversalinit();
-+ subloop.sh = shellfacetraverse(subfaces);
-+ while (subloop.sh != (shellface *) NULL) {
-+ // Check the three angles of subloop;
-+ for (i = 0; i < 3; i++) {
-+ sspivot(subloop, seg1);
-+ if (seg1.sh != dummysh) {
-+ senext2(subloop, checksub);
-+ sspivot(checksub, seg2);
-+ if (seg2.sh != dummysh) {
-+ pa = sorg(subloop);
-+ pb = sdest(subloop);
-+ pc = sapex(subloop);
-+ angle = interiorangle(pa, pb, pc, NULL);
-+ if (angle < smallang) {
-+ // It is skinny!
-+ setshelltype(subloop, SKINNY);
-+ skinnyshlist->append(&subloop);
-+ break;
-+ }
-+ }
- }
-- *pquenumber = quenumber;
-- return result;
-+ senextself(subloop);
- }
-+ subloop.sh = shellfacetraverse(subfaces);
- }
-- return (badface *) NULL;
-+
-+ // Next finds all skinny subfaces.
-+ for (i = 0; i < skinnyshlist->len(); i++) {
-+ startsh = * (face *)(* skinnyshlist)[i];
-+ shty = shelltype(startsh);
-+ for (j = 0; j < 3; j++) {
-+ sspivot(startsh, checkseg);
-+ if (checkseg.sh == dummysh) {
-+ spivot(startsh, neighsh);
-+ if (shelltype(neighsh) != shty) {
-+ setshelltype(neighsh, shty);
-+ skinnyshlist->append(&neighsh);
-+ }
-+ }
-+ senextself(startsh);
-+ }
-+ }
-+
-+ if (b->verbose > 0) {
-+ printf(" %d skinny subfaces.\n", skinnyshlist->len());
-+ }
-+ delete skinnyshlist;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
-@@ -28266,8 +25203,7 @@
- newbadtet->nextitem = (badface *) NULL;
- // Determine the appropriate queue to put the bad tetrahedron into.
- if (ratio2 > b->goodratio) {
-- // queuenumber = (int) ((ratio2 - b->goodratio) / 0.5);
-- queuenumber = (int) (64.0 - 64.0 / ratio2);
-+ queuenumber = (int) ((ratio2 - b->goodratio) / 0.5);
- // 'queuenumber' may overflow (negative) caused by a very large ratio.
- if ((queuenumber > 63) || (queuenumber < 0)) {
- queuenumber = 63;
-@@ -28276,33 +25212,10 @@
- // It's not a bad ratio; put the tet in the lowest-priority queue.
- queuenumber = 0;
- }
--
-- // Are we inserting into an empty queue?
-- if (tetquefront[queuenumber] == (badface *) NULL) {
-- // Yes. Will this become the highest-priority queue?
-- if (queuenumber > firstnonemptyq) {
-- // Yes, this is the highest-priority queue.
-- nextnonemptyq[queuenumber] = firstnonemptyq;
-- firstnonemptyq = queuenumber;
-- } else {
-- // No. Find the queue with next higher priority.
-- i = queuenumber + 1;
-- while (tetquefront[i] == (badface *) NULL) {
-- i++;
-- }
-- // Mark the newly nonempty queue as following a higher-priority queue.
-- nextnonemptyq[queuenumber] = nextnonemptyq[i];
-- nextnonemptyq[i] = queuenumber;
-- }
-- // Put the bad tetrahedron at the beginning of the (empty) queue.
-- tetquefront[queuenumber] = newbadtet;
-- } else {
-- // Add the bad tetrahedron to the end of an already nonempty queue.
-- tetquetail[queuenumber]->nextitem = newbadtet;
-- }
-- // Maintain a pointer to the last tetrahedron of the queue.
-- tetquetail[queuenumber] = newbadtet;
--
-+ // Add the tetrahedron to the end of a queue.
-+ *tetquetail[queuenumber] = newbadtet;
-+ // Maintain a pointer to the NULL pointer at the end of the queue.
-+ tetquetail[queuenumber] = &newbadtet->nextitem;
- if (b->verbose > 2) {
- printf(" Queueing bad tet: (%d, %d, %d, %d), ratio %g, qnum %d.\n",
- pointmark(newbadtet->forg), pointmark(newbadtet->fdest),
-@@ -28313,53 +25226,94 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// dequeuebadtet() Remove a tetrahedron from the front of the queue. //
-+// enqueueencsub() Add an encroached subface into the queue. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--tetgenmesh::badface* tetgenmesh::topbadtetra()
-+void tetgenmesh::enqueueencsub(face* testsub, point encpt, int quenumber,
-+ REAL* cent)
- {
-- // Keep a record of which queue was accessed in case dequeuebadtetra()
-- // is called later.
-- recentq = firstnonemptyq;
-- // If no queues are nonempty, return NULL.
-- if (firstnonemptyq < 0) {
-- return (badface *) NULL;
-+ badface *encsub;
-+ int i;
-+
-+ encsub = (badface *) badsubfaces->alloc();
-+ encsub->ss = *testsub;
-+ encsub->forg = sorg(*testsub);
-+ encsub->fdest = sdest(*testsub);
-+ encsub->fapex = sapex(*testsub);
-+ encsub->foppo = (point) encpt;
-+ if (quenumber == 2) {
-+ for (i = 0; i < 3; i++) encsub->cent[i] = 0.0;
- } else {
-- // Return the first tetrahedron of the highest-priority queue.
-- return tetquefront[firstnonemptyq];
-+ for (i = 0; i < 3; i++) encsub->cent[i] = cent[i];
-+ }
-+ encsub->nextitem = (badface *) NULL;
-+ // Set the pointer of 'encsubseg' into 'testsub'. It has two purposes:
-+ // (1) We can regonize it is encroached; (2) It is uniquely queued.
-+ setshell2badface(encsub->ss, encsub);
-+ // Add the subface to the end of a queue (quenumber = 2, high priority).
-+ *subquetail[quenumber] = encsub;
-+ // Maintain a pointer to the NULL pointer at the end of the queue.
-+ subquetail[quenumber] = &encsub->nextitem;
-+ if (b->verbose > 2) {
-+ printf(" Queuing subface (%d, %d, %d) [%d].\n", pointmark(encsub->forg),
-+ pointmark(encsub->fdest), pointmark(encsub->fapex), quenumber);
- }
- }
-
--void tetgenmesh::dequeuebadtet()
-+///////////////////////////////////////////////////////////////////////////////
-+// //
-+// dequeuebadtet() Remove a tetrahedron from the front of the queue. //
-+// //
-+///////////////////////////////////////////////////////////////////////////////
-+
-+tetgenmesh::badface* tetgenmesh::dequeuebadtet()
- {
-- badface *deadbadtet;
-- int i;
-+ badface *result;
-+ int queuenumber;
-
-- // If queues were empty last time topbadtetra() was called, do nothing.
-- if (recentq >= 0) {
-- // Find the tetrahedron last returned by topbadtetra().
-- deadbadtet = tetquefront[recentq];
-- // Remove the tetrahedron from the queue.
-- tetquefront[recentq] = deadbadtet->nextitem;
-- // If this queue is now empty, update the list of nonempty queues.
-- if (deadbadtet == tetquetail[recentq]) {
-- // Was this the highest-priority queue?
-- if (firstnonemptyq == recentq) {
-- // Yes; find the queue with next lower priority.
-- firstnonemptyq = nextnonemptyq[firstnonemptyq];
-- } else {
-- // No; find the queue with next higher priority.
-- i = recentq + 1;
-- while (tetquefront[i] == (badface *) NULL) {
-- i++;
-- }
-- nextnonemptyq[i] = nextnonemptyq[recentq];
-+ // Look for a nonempty queue.
-+ for (queuenumber = 63; queuenumber >= 0; queuenumber--) {
-+ result = tetquefront[queuenumber];
-+ if (result != (badface *) NULL) {
-+ // Remove the tetrahedron from the queue.
-+ tetquefront[queuenumber] = result->nextitem;
-+ // Maintain a pointer to the NULL pointer at the end of the queue.
-+ if (tetquefront[queuenumber] == (badface *) NULL) {
-+ tetquetail[queuenumber] = &tetquefront[queuenumber];
-+ }
-+ return result;
-+ }
-+ }
-+ return (badface *) NULL;
-+}
-+
-+///////////////////////////////////////////////////////////////////////////////
-+// //
-+// dequeueencsub() Remove an enc-subface from the front of the queue. //
-+// //
-+///////////////////////////////////////////////////////////////////////////////
-+
-+tetgenmesh::badface* tetgenmesh::dequeueencsub(int* pquenumber)
-+{
-+ badface *result;
-+ int quenumber;
-+
-+ // Look for a nonempty queue.
-+ for (quenumber = 2; quenumber >= 0; quenumber--) {
-+ result = subquefront[quenumber];
-+ if (result != (badface *) NULL) {
-+ // Remove the badface from the queue.
-+ subquefront[quenumber] = result->nextitem;
-+ // Maintain a pointer to the NULL pointer at the end of the queue.
-+ if (subquefront[quenumber] == (badface *) NULL) {
-+ subquetail[quenumber] = &subquefront[quenumber];
- }
-+ *pquenumber = quenumber;
-+ return result;
- }
-- // Return the bad tetrahedron to the pool.
-- badfacedealloc(badtetrahedrons, deadbadtet);
- }
-+ return (badface *) NULL;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
-@@ -28389,7 +25343,6 @@
- bool enq;
- int hitbdry;
-
-- enq = false;
- eorg = sorg(*testseg);
- edest = sdest(*testseg);
- cent[0] = 0.5 * (eorg[0] + edest[0]);
-@@ -28397,55 +25350,50 @@
- cent[2] = 0.5 * (eorg[2] + edest[2]);
- radius = distance(cent, eorg);
-
-- if (varconstraint && (areabound(*testseg) > 0.0)) {
-- enq = (2.0 * radius) > areabound(*testseg);
-- }
--
-- if (!enq) {
-- maxradius = 0.0;
-- if (testpt == (point) NULL) {
-- // Check if it is encroached by traversing all faces containing it.
-- sstpivot(testseg, &starttet);
-- eapex = apex(starttet);
-- spintet = starttet;
-- hitbdry = 0;
-- do {
-- dist = distance(cent, apex(spintet));
-- diff = dist - radius;
-- if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
-- if (diff <= 0.0) {
-- // s is encroached.
-- enq = true;
-- if (prefpt != (point *) NULL) {
-- // Find the reference point.
-- encpt = apex(spintet);
-- circumsphere(eorg, edest, encpt, NULL, NULL, &dist);
-- if (dist > maxradius) {
-- // Rememebr this point.
-- *prefpt = encpt;
-- maxradius = dist;
-- }
-- } else {
-- break;
-+ enq = false;
-+ maxradius = 0.0;
-+ if (testpt == (point) NULL) {
-+ // Check if it is encroached by traversing all faces containing it.
-+ sstpivot(testseg, &starttet);
-+ eapex = apex(starttet);
-+ spintet = starttet;
-+ hitbdry = 0;
-+ do {
-+ dist = distance(cent, apex(spintet));
-+ diff = dist - radius;
-+ if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
-+ if (diff <= 0.0) {
-+ // s is encroached.
-+ enq = true;
-+ if (prefpt != (point *) NULL) {
-+ // Find the reference point.
-+ encpt = apex(spintet);
-+ circumsphere(eorg, edest, encpt, NULL, NULL, &dist);
-+ if (dist > maxradius) {
-+ // Rememebr this point.
-+ *prefpt = encpt;
-+ maxradius = dist;
- }
-+ } else {
-+ break;
- }
-- if (!fnextself(spintet)) {
-- hitbdry++;
-- if (hitbdry < 2) {
-- esym(starttet, spintet);
-- if (!fnextself(spintet)) {
-- hitbdry++;
-- }
-- }
-+ }
-+ if (!fnextself(spintet)) {
-+ hitbdry++;
-+ if (hitbdry < 2) {
-+ esym(starttet, spintet);
-+ if (!fnextself(spintet)) {
-+ hitbdry++;
-+ }
- }
-- } while (apex(spintet) != eapex && (hitbdry < 2));
-- } else {
-- // Only check if 'testseg' is encroached by 'testpt'.
-- dist = distance(cent, testpt);
-- diff = dist - radius;
-- if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
-- enq = (diff <= 0.0);
-- }
-+ }
-+ } while (apex(spintet) != eapex && (hitbdry < 2));
-+ } else {
-+ // Only check if 'testseg' is encroached by 'testpt'.
-+ dist = distance(cent, testpt);
-+ diff = dist - radius;
-+ if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
-+ enq = (diff <= 0.0);
- }
-
- if (enq && enqflag) {
-@@ -28482,57 +25430,31 @@
- bool tetgenmesh::checksub4encroach(face* testsub, point testpt, bool enqflag)
- {
- triface abuttet;
-- point pa, pb, pc, encpt;
-- REAL A[4][4], rhs[4], D;
-- REAL cent[3], area;
-+ point forg, fdest, fapex, encpt;
-+ REAL cent[3];
- REAL radius, dist, diff;
-- bool enq;
-- int indx[4];
-+ bool enq, ncollinear;
- int quenumber;
-
-- enq = false;
-- radius = 0.0;
-- encpt = (point) NULL;
--
-- pa = sorg(*testsub);
-- pb = sdest(*testsub);
-- pc = sapex(*testsub);
-+ forg = sorg(*testsub);
-+ fdest = sdest(*testsub);
-+ fapex = sapex(*testsub);
-+ ncollinear = circumsphere(forg, fdest, fapex, NULL, cent, &radius);
-+ if (!ncollinear) return false; // Not a valid subface.
-
-- // Compute the coefficient matrix A (3x3).
-- A[0][0] = pb[0] - pa[0];
-- A[0][1] = pb[1] - pa[1];
-- A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
-- A[1][0] = pc[0] - pa[0];
-- A[1][1] = pc[1] - pa[1];
-- A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
-- cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
--
-- if (varconstraint && (areabound(*testsub) > 0.0)) {
-- // Check if the subface has too big area.
-- area = 0.5 * sqrt(dot(A[2], A[2]));
-- enq = area > areabound(*testsub);
-- if (enq) {
-- quenumber = 2; // A queue of subfaces having too big area.
-+ enq = false;
-+ encpt = (point) NULL;
-+ if (testpt == (point) NULL) {
-+ stpivot(*testsub, abuttet);
-+ if (abuttet.tet != dummytet) {
-+ dist = distance(cent, oppo(abuttet));
-+ diff = dist - radius;
-+ if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
-+ enq = (diff <= 0.0);
-+ if (enq) encpt = oppo(abuttet);
- }
-- }
--
-- // Compute the right hand side vector b (3x1).
-- rhs[0] = 0.5 * dot(A[0], A[0]);
-- rhs[1] = 0.5 * dot(A[1], A[1]);
-- rhs[2] = 0.0;
-- // Solve the 3 by 3 equations use LU decomposition with partial pivoting
-- // and backward and forward substitute..
-- if (lu_decmp(A, 3, indx, &D, 0)) {
-- lu_solve(A, 3, indx, rhs, 0);
-- cent[0] = pa[0] + rhs[0];
-- cent[1] = pa[1] + rhs[1];
-- cent[2] = pa[2] + rhs[2];
-- radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
-- }
--
-- if (!enq) {
-- // Check if the subface is encroached.
-- if (testpt == (point) NULL) {
-+ if (!enq) {
-+ sesymself(*testsub);
- stpivot(*testsub, abuttet);
- if (abuttet.tet != dummytet) {
- dist = distance(cent, oppo(abuttet));
-@@ -28541,30 +25463,190 @@
- enq = (diff <= 0.0);
- if (enq) encpt = oppo(abuttet);
- }
-- if (!enq) {
-- sesymself(*testsub);
-- stpivot(*testsub, abuttet);
-- if (abuttet.tet != dummytet) {
-- dist = distance(cent, oppo(abuttet));
-- diff = dist - radius;
-- if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
-- enq = (diff <= 0.0);
-- if (enq) encpt = oppo(abuttet);
-- }
-- }
-+ }
-+ } else {
-+ dist = distance(cent, testpt);
-+ diff = dist - radius;
-+ if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
-+ enq = (diff <= 0.0);
-+ }
-+
-+ if (enq && enqflag) {
-+ /* REAL prj[3], ori1, ori2, ori3;
-+ bool inflag;
-+ // Test if encpt is inside the face.
-+ if (encpt) {
-+ projpt2face(encpt, forg, fdest, fapex, prj);
- } else {
-- dist = distance(cent, testpt);
-- diff = dist - radius;
-- if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
-- enq = (diff <= 0.0);
-+ assert(testpt);
-+ projpt2face(testpt, forg, fdest, fapex, prj);
- }
-- if (enq) {
-- quenumber = 0; // A queue of encroached subfaces.
-+ abovepoint = facetabovepointarray[shellmark(*testsub)];
-+ if (abovepoint == (point) NULL) {
-+ getfacetabovepoint(testsub);
- }
-+ ori1 = orient3d(forg, fdest, abovepoint, prj);
-+ ori2 = orient3d(fdest, fapex, abovepoint, prj);
-+ inflag = (ori1 * ori2 >= 0.0);
-+ if (inflag) {
-+ ori3 = orient3d(fapex, forg, abovepoint, prj);
-+ inflag = (ori2 * ori3 >= 0.0);
-+ }
-+ // Decide which queue (1 or 0) to put s (1 has higher priority).
-+ quenumber = (inflag ? 1 : 0); */
-+ quenumber = 0;
-+ enqueueencsub(testsub, encpt, quenumber, cent);
- }
-
-+ return enq;
-+}
-+
-+///////////////////////////////////////////////////////////////////////////////
-+// //
-+// checkseg4badqual() Check if a segment is longer than it is allowed. //
-+// //
-+///////////////////////////////////////////////////////////////////////////////
-+
-+bool tetgenmesh::checkseg4badqual(face* testseg, bool enqflag)
-+{
-+ badface *encsubseg;
-+ point eorg, edest;
-+ REAL dist;
-+ bool enq;
-+
-+ eorg = sorg(*testseg);
-+ edest = sdest(*testseg);
-+ dist = distance(eorg, edest);
-+
-+ enq = dist > areabound(*testseg);
-+
- if (enq && enqflag) {
-- enqueueencsub(testsub, encpt, quenumber, cent);
-+ if (b->verbose > 2) {
-+ printf(" Queuing badqual subsegment (%d, %d).\n",
-+ pointmark(eorg), pointmark(edest));
-+ }
-+ encsubseg = (badface *) badsubsegs->alloc();
-+ encsubseg->ss = *testseg;
-+ encsubseg->forg = eorg;
-+ encsubseg->fdest = edest;
-+ encsubseg->foppo = NULL;
-+ // Set the pointer of 'encsubseg' into 'testseg'. It has two purposes:
-+ // (1) We can regonize it is encroached; (2) It is uniquely queued.
-+ setshell2badface(encsubseg->ss, encsubseg);
-+ }
-+
-+ return enq;
-+}
-+
-+///////////////////////////////////////////////////////////////////////////////
-+// //
-+// checksub4badqual() Test if the quality of a subface is bad. //
-+// //
-+// A subface has bad quality if: (1) its minimum internal angle is smaller //
-+// than 20 degree; or (2) its area is larger than a maximum area condition. //
-+// Return TRUE if it is bad. //
-+// //
-+///////////////////////////////////////////////////////////////////////////////
-+
-+bool tetgenmesh::checksub4badqual(face* testsub, bool enqflag)
-+{
-+ face sametestsub;
-+ face subseg1, subseg2;
-+ point torg, tdest, tapex;
-+ point anglevertex;
-+ REAL dxod, dyod, dzod;
-+ REAL dxda, dyda, dzda;
-+ REAL dxao, dyao, dzao;
-+ REAL dxod2, dyod2, dzod2;
-+ REAL dxda2, dyda2, dzda2;
-+ REAL dxao2, dyao2, dzao2;
-+ REAL apexlen, orglen, destlen;
-+ REAL angle, area;
-+ bool enq;
-+
-+ enq = false;
-+ torg = sorg(*testsub);
-+ tdest = sdest(*testsub);
-+ tapex = sapex(*testsub);
-+ dxod = torg[0] - tdest[0];
-+ dyod = torg[1] - tdest[1];
-+ dzod = torg[2] - tdest[2];
-+ dxda = tdest[0] - tapex[0];
-+ dyda = tdest[1] - tapex[1];
-+ dzda = tdest[2] - tapex[2];
-+ dxao = tapex[0] - torg[0];
-+ dyao = tapex[1] - torg[1];
-+ dzao = tapex[2] - torg[2];
-+ dxod2 = dxod * dxod;
-+ dyod2 = dyod * dyod;
-+ dzod2 = dzod * dzod;
-+ dxda2 = dxda * dxda;
-+ dyda2 = dyda * dyda;
-+ dzda2 = dzda * dzda;
-+ dxao2 = dxao * dxao;
-+ dyao2 = dyao * dyao;
-+ dzao2 = dzao * dzao;
-+ // Find the lengths of the triangle's three edges.
-+ apexlen = dxod2 + dyod2 + dzod2;
-+ orglen = dxda2 + dyda2 + dzda2;
-+ destlen = dxao2 + dyao2 + dzao2;
-+ if ((apexlen < orglen) && (apexlen < destlen)) {
-+ // The edge opposite the apex is shortest.
-+ // Find the square of the cosine of the angle at the apex.
-+ angle = dxda * dxao + dyda * dyao + dzda * dzao;
-+ angle = angle * angle / (orglen * destlen);
-+ anglevertex = tapex;
-+ senext(*testsub, sametestsub);
-+ sspivot(sametestsub, subseg1);
-+ senext2(*testsub, sametestsub);
-+ sspivot(sametestsub, subseg2);
-+ } else if (orglen < destlen) {
-+ // The edge opposite the origin is shortest.
-+ // Find the square of the cosine of the angle at the origin.
-+ angle = dxod * dxao + dyod * dyao + dzod * dzao;
-+ angle = angle * angle / (apexlen * destlen);
-+ anglevertex = torg;
-+ sspivot(*testsub, subseg1);
-+ senext2(*testsub, sametestsub);
-+ sspivot(sametestsub, subseg2);
-+ } else {
-+ // The edge opposite the destination is shortest.
-+ // Find the square of the cosine of the angle at the destination.
-+ angle = dxod * dxda + dyod * dyda + dzod * dzda;
-+ angle = angle * angle / (apexlen * orglen);
-+ anglevertex = tdest;
-+ sspivot(*testsub, subseg1);
-+ senext(*testsub, sametestsub);
-+ sspivot(sametestsub, subseg2);
-+ }
-+
-+ // Check if both edges that form the angle are segments.
-+ // if ((subseg1.sh != dummysh) && (subseg2.sh != dummysh)) {
-+ if (shelltype(*testsub) == SKINNY) {
-+ // The angle is a segment intersection. Don't add this bad subface to
-+ // the list; there's nothing that can be done about a small angle
-+ // between two segments.
-+ angle = 0.0;
-+ }
-+
-+ // Check whether the angle is smaller than permitted.
-+ if (angle > b->goodangle) {
-+ enq = true;
-+ }
-+
-+ if (!enq && varconstraint && areabound(*testsub) > 0.0) {
-+ // Check whether the area is larger than desired. A variation form of
-+ // Heron's formula which only uses the squares of the edge lengthes
-+ // is used to calculated the area of a 3D triangle.
-+ area = apexlen + orglen - destlen;
-+ area = area * area;
-+ area = 4 * apexlen * orglen - area;
-+ area = 0.25 * sqrt(fabs(area));
-+ enq = area > areabound(*testsub);
-+ }
-+
-+ if (enq && enqflag) {
-+ enqueueencsub(testsub, NULL, 2, NULL);
- }
-
- return enq;
-@@ -28582,17 +25664,19 @@
-
- bool tetgenmesh::checktet4badqual(triface* testtet, bool enqflag)
- {
-+ badface *newbadtet;
- point pa, pb, pc, pd, pe1, pe2;
- REAL vda[3], vdb[3], vdc[3];
- REAL vab[3], vbc[3], vca[3];
- REAL N[4][3], A[4][4], rhs[4], D;
- REAL elen[6], circumcent[3];
- REAL bicent[3], offcent[3];
-- REAL volume, L, cosd;
-+ REAL volume, L, q, cosd;
- REAL radius2, smlen2, ratio2;
- REAL dist, sdist, split;
- bool enq;
- int indx[4];
-+ int queuenumber;
- int sidx, i, j;
-
- pa = (point) testtet->tet[4];
-@@ -28600,6 +25684,10 @@
- pc = (point) testtet->tet[6];
- pd = (point) testtet->tet[7];
-
-+ // Avoid compile warnings.
-+ pe1 = pe2 = (point) NULL;
-+ radius2 = 0.0;
-+
- // Get the edge vectors vda: d->a, vdb: d->b, vdc: d->c.
- // Set the matrix A = [vda, vdb, vdc]^T.
- for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
-@@ -28615,118 +25703,135 @@
- // Get the volume of abcd.
- volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
- if (volume < 0.0) volume = -volume;
-- // Check the radiu-edge ratio of the tet.
-- rhs[0] = 0.5 * dot(vda, vda);
-- rhs[1] = 0.5 * dot(vdb, vdb);
-- rhs[2] = 0.5 * dot(vdc, vdc);
-- lu_solve(A, 3, indx, rhs, 0);
-- // Get the circumcenter.
-- for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i];
-- // Get the square of the circumradius.
-- radius2 = dot(rhs, rhs);
-- // Find the square of the shortest edge length.
-+ // Compare the volume to average edge length of abcd.
- elen[0] = dot(vda, vda);
- elen[1] = dot(vdb, vdb);
- elen[2] = dot(vdc, vdc);
- elen[3] = dot(vab, vab);
- elen[4] = dot(vbc, vbc);
- elen[5] = dot(vca, vca);
-- smlen2 = elen[0]; sidx = 0;
-- for (i = 1; i < 6; i++) {
-- if (smlen2 > elen[i]) { smlen2 = elen[i]; sidx = i; }
-- }
-- // Calculate the square of radius-edge ratio.
-- ratio2 = radius2 / smlen2;
-- // Check whether the ratio is smaller than permitted.
-- enq = ratio2 > b->goodratio;
-+
-+ enq = false;
-+ if (b->offcenter) {
-+ // Check if the tet is very flat.
-+ L = 0.0;
-+ for (i = 0; i < 6; i++) L += sqrt(elen[i]);
-+ L /= 6.0;
-+ q = volume / (L * L * L);
-+ enq = (q < b->epsilon * 1e+2);
-+ }
-+
-+ // Is abcd very flat?
- if (!enq) {
-- // abcd has good ratio.
-- // ratio2 = 0.0;
-- // if (b->offcenter) {
-- // Test if it is a sliver.
-- // Compute the 4 face normals (N[0], ..., N[3]).
-- for (j = 0; j < 3; j++) {
-- for (i = 0; i < 3; i++) rhs[i] = 0.0;
-- rhs[j] = 1.0; // Positive means the inside direction
-- lu_solve(A, 3, indx, rhs, 0);
-- for (i = 0; i < 3; i++) N[j][i] = rhs[i];
-- }
-- // Get the fourth normal by summing up the first three.
-- for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
-- // Normalized the normals.
-- for (i = 0; i < 4; i++) {
-- L = sqrt(dot(N[i], N[i]));
-- if (L > 0.0) {
-- for (j = 0; j < 3; j++) N[i][j] /= L;
-- }
-- }
-- // N[0] is the normal of face bcd. Test the dihedral angles at edge
-- // cd, bd, and bc to see if they are too small or too big.
-- for (i = 1; i < 4 && !enq; i++) {
-- cosd = -dot(N[0], N[i]); // Edge cd, bd, bc.
-- enq = cosd > cosmindihed;
-- }
-- if (!enq) {
-- for (i = 2; i < 4 && !enq; i++) {
-- cosd = -dot(N[1], N[i]); // Edge ad, ac
-- enq = cosd > cosmindihed;
-- }
-- if (!enq) {
-- cosd = -dot(N[2], N[3]); // Edge ab
-- enq = cosd > cosmindihed;
-+ rhs[0] = 0.5 * dot(vda, vda);
-+ rhs[1] = 0.5 * dot(vdb, vdb);
-+ rhs[2] = 0.5 * dot(vdc, vdc);
-+ lu_solve(A, 3, indx, rhs, 0);
-+ // Get the circumcenter.
-+ for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i];
-+ // Get the square of the circumradius.
-+ radius2 = dot(rhs, rhs);
-+ // Find the square of the shortest edge length.
-+ smlen2 = elen[0]; sidx = 0;
-+ for (i = 1; i < 6; i++) {
-+ if (smlen2 > elen[i]) { smlen2 = elen[i]; sidx = i; }
-+ }
-+ // Calculate the square of radius-edge ratio.
-+ ratio2 = radius2 / smlen2;
-+ // Check whether the ratio is smaller than permitted.
-+ enq = ratio2 > b->goodratio;
-+ if (!enq) {
-+ // abcd has good ratio.
-+ if (b->offcenter) {
-+ // Test if it is a sliver.
-+ // Compute the 4 face normals (N[0], ..., N[3]).
-+ for (j = 0; j < 3; j++) {
-+ for (i = 0; i < 3; i++) rhs[i] = 0.0;
-+ rhs[j] = 1.0; // Positive means the inside direction
-+ lu_solve(A, 3, indx, rhs, 0);
-+ for (i = 0; i < 3; i++) N[j][i] = rhs[i];
-+ }
-+ // Get the fourth normal by summing up the first three.
-+ for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
-+ // Normalized the normals.
-+ for (i = 0; i < 4; i++) {
-+ L = sqrt(dot(N[i], N[i]));
-+ if (L > 0.0) {
-+ for (j = 0; j < 3; j++) N[i][j] /= L;
-+ }
-+ }
-+ // N[0] is the normal of face bcd. Test the dihedral angles at edge
-+ // cd, bd, and bc to see if they are too small or too big.
-+ for (i = 1; i < 4 && !enq; i++) {
-+ cosd = -dot(N[0], N[i]); // Edge cd, bd, bc.
-+ enq = ((cosd > cosmindihed) || ((cosd < cosmaxdihed)));
-+ }
-+ if (enq) {
-+ // A sliver! Split it at the barycenter.
-+ for (i = 0; i < 3; i++) {
-+ circumcent[i] = 0.25 * (pa[i] + pb[i] + pc[i] + pd[i]);
-+ }
-+ ratio2 = 0.0;
- }
- }
-- // }
-- } else if (b->offcenter) {
-- // abcd has bad-quality. Use off-center instead of circumcenter.
-- switch (sidx) {
-- case 0: // edge da.
-- pe1 = pd; pe2 = pa; break;
-- case 1: // edge db.
-- pe1 = pd; pe2 = pb; break;
-- case 2: // edge dc.
-- pe1 = pd; pe2 = pc; break;
-- case 3: // edge ab.
-- pe1 = pa; pe2 = pb; break;
-- case 4: // edge bc.
-- pe1 = pb; pe2 = pc; break;
-- case 5: // edge ca.
-- pe1 = pc; pe2 = pa; break;
-- default:
-- pe1 = pe2 = (point) NULL; // Avoid a compile warning.
-- }
-- // The shortest edge is e1->e2.
-- for (i = 0; i < 3; i++) bicent[i] = 0.5 * (pe1[i] + pe2[i]);
-- dist = distance(bicent, circumcent);
-- // sdist = sqrt(smlen2) * sin(PI / 3.0); // A icoso-triangle.
-- // The following formulae is from
-- sdist = b->alpha3 * (b->minratio+sqrt(b->goodratio-0.25))* sqrt(smlen2);
-- split = sdist / dist;
-- if (split > 1.0) split = 1.0;
-- // Get the off-center.
-+ } else if (b->offcenter) {
-+ // abcd has bad-quality. Use off-center instead of circumcenter.
-+ switch (sidx) {
-+ case 0: // edge da.
-+ pe1 = pd; pe2 = pa; break;
-+ case 1: // edge db.
-+ pe1 = pd; pe2 = pb; break;
-+ case 2: // edge dc.
-+ pe1 = pd; pe2 = pc; break;
-+ case 3: // edge ab.
-+ pe1 = pa; pe2 = pb; break;
-+ case 4: // edge bc.
-+ pe1 = pb; pe2 = pc; break;
-+ case 5: // edge ca.
-+ pe1 = pc; pe2 = pa; break;
-+ default: break;
-+ }
-+ // The shortest edge is e1->e2.
-+ for (i = 0; i < 3; i++) bicent[i] = 0.5 * (pe1[i] + pe2[i]);
-+ dist = distance(bicent, circumcent);
-+ // sdist = sqrt(smlen2) * sin(PI / 3.0); // A icoso-triangle.
-+ // The following formulae is from
-+ sdist = b->alpha3 * (b->minratio + sqrt(b->goodratio - 0.25))
-+ * sqrt(smlen2);
-+ split = sdist / dist;
-+ if (split > 1.0) split = 1.0;
-+ // Get the off-center.
-+ for (i = 0; i < 3; i++) {
-+ offcent[i] = bicent[i] + split * (circumcent[i] - bicent[i]);
-+ }
-+ }
-+ } else {
-+ // A fat tet. Split it at the centroid.
- for (i = 0; i < 3; i++) {
-- offcent[i] = bicent[i] + split * (circumcent[i] - bicent[i]);
-+ circumcent[i] = 0.25 * (pa[i] + pb[i] + pc[i] + pd[i]);
- }
-+ ratio2 = 0.0;
- }
-
- if (!enq && (b->varvolume || b->fixedvolume)) {
-- // Check if the tet has too big volume.
-+ // The tet is in good shape.
-+ ratio2 = 0.0;
- enq = b->fixedvolume && (volume > b->maxvolume);
- if (!enq && b->varvolume) {
- enq = (volume > volumebound(testtet->tet)) &&
- (volumebound(testtet->tet) > 0.0);
- }
- }
--
- if (!enq) {
-- // Check if the user-defined sizing function is satisfied.
-- if (b->metric) {
-- // assert(b->alpha1 > 0.0);
-+ // The tet is in good shape.
-+ ratio2 = 0.0;
-+ if (b->bgmesh && (b->alpha1 > 0.0)) {
- sdist = sqrt(radius2) / b->alpha1;
-+ // Check if the nodal size map is satisfied.
- for (i = 0; i < 4; i++) {
- pa = (point) testtet->tet[4 + i];
- // Get the indicated size of p.
-- dist = pa[pointmtrindex]; // dist = b->alpha1 * pa[pointmtrindex];
-+ dist = pa[3]; // dist = b->alpha1 * pa[pointlfsindex];
- enq = ((dist < sdist) && (dist > 0.0));
- if (enq) break; // It is bad wrt. a node constraint.
- // *** Experiment ! Stop test if c is inside H(a).
-@@ -28734,14 +25839,44 @@
- }
- // *** Experiment !
- // enq = (i == 4); // Does c lies outside all sparse-ball?
-- } // if (b->metric)
-+ }
- }
-
- if (enq && enqflag) {
-- if (b->offcenter && (ratio2 > b->goodratio)) {
-- for (i = 0; i < 3; i++) circumcent[i] = offcent[i];
-+ // Allocate space for the bad tetrahedron.
-+ newbadtet = (badface *) badtetrahedrons->alloc();
-+ newbadtet->tt = *testtet;
-+ newbadtet->key = ratio2;
-+ if ((ratio2 != 0) && b->offcenter) {
-+ for (i = 0; i < 3; i++) newbadtet->cent[i] = offcent[i];
-+ } else {
-+ for (i = 0; i < 3; i++) newbadtet->cent[i] = circumcent[i];
-+ }
-+ newbadtet->forg = org(*testtet);
-+ newbadtet->fdest = dest(*testtet);
-+ newbadtet->fapex = apex(*testtet);
-+ newbadtet->foppo = oppo(*testtet);
-+ newbadtet->nextitem = (badface *) NULL;
-+ // Determine the appropriate queue to put the bad tetrahedron into.
-+ if (ratio2 > b->goodratio) {
-+ queuenumber = (int) ((ratio2 - b->goodratio) / 0.5);
-+ // 'queuenumber' may overflow (negative) caused by a very large ratio.
-+ if ((queuenumber > 63) || (queuenumber < 0)) {
-+ queuenumber = 63;
-+ }
-+ } else {
-+ // It's not a bad ratio; put the tet in the lowest-priority queue.
-+ queuenumber = 0;
-+ }
-+ // Add the tetrahedron to the end of a queue.
-+ *tetquetail[queuenumber] = newbadtet;
-+ // Maintain a pointer to the NULL pointer at the end of the queue.
-+ tetquetail[queuenumber] = &newbadtet->nextitem;
-+ if (b->verbose > 2) {
-+ printf(" Queueing bad tet: (%d, %d, %d, %d), ratio %g, qnum %d.\n",
-+ pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd),
-+ sqrt(ratio2), queuenumber);
- }
-- enqueuebadtet(testtet, ratio2, circumcent);
- }
-
- return enq;
-@@ -28757,23 +25892,28 @@
- // p can not be inserted either the '-Y' option is used and ab is a hull //
- // segment or '-YY' option is used. //
- // //
--// p can be inserted if it is in one of the following cases: //
--// (1) if L = |a - b| is too long wrt the edge constraint; or //
--// (2) if |x - p| > \alpha_2 H(x) for x = a, b; or //
--// (3) if 'refpt' != NULL. //
-+// p can be inserted if it is in one of the following cases (L = |a - b|): //
-+// (1) if ab is too long wrt the edge constraint (bad-quality); or //
-+// (2) if a subface having ab has max. area constraint A, and L^2 > 2 * A, //
-+// (3) if a tet having ab has maximal volume constraint V, and L^3 > 6 * V.//
-+// (4) if |a - p| > \alpha_2 H(a) and |p - b| > \alpha_2 H(b). //
-+// (5) if 'refpt' != NULL. //
-+// //
-+// The purpose of using L instead of area and volume is to avoid resulting //
-+// too skinny triangles and tetrahedron. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
- bool tetgenmesh::acceptsegpt(point segpt, point refpt, face* splitseg)
- {
-- point p[2];
-- REAL L, lfs;
-- int i, j;
-+ triface spintet;
-+ face parentsh, spinsh;
-+ point pa, pb, pc;
-+ REAL ablen, palen, pblen;
-+ REAL V, A;
-
- if (b->nobisect == 1) {
- // '-Y'. It can not be split if it is on the hull.
-- triface spintet;
-- point pc;
- sstpivot(splitseg, &spintet);
- assert(spintet.tet != dummytet);
- pc = apex(spintet);
-@@ -28788,26 +25928,73 @@
- return false;
- }
-
-- p[0] = sorg(*splitseg);
-- p[1] = sdest(*splitseg);
-- if (varconstraint && (areabound(*splitseg) > 0)) {
-- lfs = areabound(*splitseg);
-- L = distance(p[0], p[1]);
-- if (L > lfs) {
-+ pa = sorg(*splitseg);
-+ pb = sdest(*splitseg);
-+ ablen = distance(pa, pb);
-+ if (varconstraint) {
-+ A = areabound(*splitseg);
-+ if ((A > 0.0) && (ablen > A)) {
- return true; // case (1)
- }
- }
-
-- j = 0; // Use j to count the number of inside balls.
-- for (i = 0; i < 2; i++) {
-- // Check if p is inside the protect ball of q.
-- if (p[i][pointmtrindex] > 0.0) {
-- lfs = b->alpha2 * p[i][pointmtrindex];
-- L = distance(p[i], segpt);
-- if (L < lfs) j++; // p is inside ball.
-+ if (varconstraint && in->facetconstraintlist) {
-+ A = ablen * ablen / 2.0;
-+ spinsh = parentsh;
-+ do {
-+ if ((A > areabound(spinsh)) && (areabound(spinsh) > 0.0)) {
-+ return true; // case (2)
-+ }
-+ spivotself(spinsh);
-+ } while (spinsh.sh != parentsh.sh);
-+ }
-+
-+ if (b->varvolume || b->fixedvolume) {
-+ V = ablen * ablen * ablen / 6.0;
-+ if (b->fixedvolume && (V > b->maxvolume)) {
-+ return true; // case (3)
-+ }
-+ if (b->varvolume) {
-+ spivot(*splitseg, parentsh);
-+ if (sorg(parentsh) != pa) sesymself(parentsh);
-+ stpivot(parentsh, spintet);
-+ if (spintet.tet == dummytet) {
-+ sesymself(parentsh);
-+ stpivot(parentsh, spintet);
-+ }
-+ findedge(&spintet, pa, pb);
-+ pc = apex(spintet);
-+ while (true) {
-+ if (!fnextself(spintet)) {
-+ // Meet a boundary, walk through it.
-+ tspivot(spintet, spinsh);
-+ findedge(&spinsh, pa, pb);
-+ sfnextself(spinsh);
-+ stpivot(spinsh, spintet);
-+ findedge(&spintet, pa, pb);
-+ }
-+ if ((V > volumebound(spintet.tet)) &&
-+ (volumebound(spintet.tet) > 0.0)) {
-+ return true; // case (3)
-+ }
-+ if (apex(spintet) == pc) break;
-+ }
-+ }
-+ }
-+
-+ // If p is outside both protect balls of a and b.
-+ palen = distance(segpt, pa);
-+ pblen = distance(segpt, pb);
-+ if (!b->bgmesh) {
-+ if ((palen > (b->alpha2 * pa[pointlfsindex])) &&
-+ (pblen > (b->alpha2 * pb[pointlfsindex]))) {
-+ return true; // case (4)
-+ }
-+ } else {
-+ if ((palen > b->alpha2 * pa[3]) && (pblen > b->alpha2 * pb[3])) {
-+ return true; // case (4)
- }
- }
-- if (j == 0) return true; // case (3).
-
- // If 'refpt' != NULL, force p to be inserted.
- if (refpt != (point) NULL) {
-@@ -28830,20 +26017,26 @@
- // p can not be inserted either the '-Y' option is used and the facet is on //
- // the hull or '-YY' option is used. //
- // //
--// p can be inserted if |p - v| > \alpha_2 H(v), for all v \in V. //
-+// p can be inserted if it is in one of the following cases (f is a subface //
-+// of CBC(p), L = max{|p - v|, v \in V}): //
-+// (1) if f has maximal area constraints A, and L^2 > 2 * A. //
-+// (2) if a tet having f has max. volume constraint V, and L^3 > 6 * V. //
-+// (3) if |p - v| > \alpha_2 H(v), for all v \in V. //
-+// //
-+// The purpose of using L^3 is to avoid resulting too skinny tetrahedron. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
- bool tetgenmesh::acceptfacpt(point facpt, list* subceillist, list* verlist)
- {
-+ triface testtet;
- face *testsh;
-- point p[2], ploop;
-- REAL L, lfs;
-+ point p[3];
-+ REAL L, L2, L3, lfs;
- int idx, i, j;
-
- if (b->nobisect == 1) {
- // '-Y'. p can not be inserted if CBC(p) is on the hull.
-- triface testtet;
- testsh = (face *)(* subceillist)[0];
- stpivot(*testsh, testtet);
- if (testtet.tet != dummytet) {
-@@ -28869,23 +26062,76 @@
- }
- }
- }
--
-- j = 0; // Use j to count the number of inside balls.
-+ // Uninfect collected vertices.
- for (i = 0; i < verlist->len(); i++) {
-- ploop = * (point *)(* verlist)[i];
-- // Uninfect q.
-- idx = pointmark(ploop);
-- setpointmark(ploop, -(idx + 1));
-- // Check if p is inside the protect ball of q.
-- if (ploop[pointmtrindex] > 0.0) {
-- lfs = b->alpha2 * ploop[pointmtrindex];
-- L = distance(ploop, facpt);
-- if (L < lfs) j++; // p is inside ball.
-+ p[0] = * (point *)(* verlist)[i];
-+ idx = pointmark(p[0]);
-+ setpointmark(p[0], -(idx + 1));
-+ }
-+
-+ if (varconstraint && in->facetconstraintlist) {
-+ for (i = 0; i < subceillist->len(); i++) {
-+ testsh = (face *)(* subceillist)[i];
-+ if (areabound(*testsh) > 0.0) {
-+ // Get the longest edge length of testsh = L.
-+ for (j = 0; j < 3; j++) p[j] = (point) testsh->sh[j + 3];
-+ L = distance(p[0], p[1]);
-+ L2 = distance(p[1], p[2]);
-+ L = (L >= L2 ? L : L2);
-+ L2 = distance(p[2], p[0]);
-+ L = (L >= L2 ? L : L2);
-+ L2 = L * L / 2.0;
-+ if (L2 > areabound(*testsh)) {
-+ return true; // case (1)
-+ }
-+ }
-+ }
-+ }
-+
-+ // Check if it is in case (2).
-+ if (b->varvolume || b->fixedvolume) {
-+ for (i = 0; i < subceillist->len(); i++) {
-+ testsh = (face *)(* subceillist)[i];
-+ // Get the longest edge length of testsh = L.
-+ for (j = 0; j < 3; j++) p[j] = (point) testsh->sh[j + 3];
-+ L = distance(p[0], p[1]);
-+ L3 = distance(p[1], p[2]);
-+ L = (L >= L3 ? L : L3);
-+ L3 = distance(p[2], p[0]);
-+ L = (L >= L3 ? L : L3);
-+ L3 = L * L * L / 6.0;
-+ if (b->fixedvolume && (L3 > b->maxvolume)) {
-+ // This face is too large wrt. the maximum volume bound. Split it.
-+ return true; // case (2)
-+ }
-+ if (b->varvolume) {
-+ for (j = 0; j < 2; j ++) {
-+ stpivot(*testsh, testtet);
-+ if (testtet.tet != dummytet) {
-+ if ((L3 > volumebound(testtet.tet)) &&
-+ (volumebound(testtet.tet) > 0.0)) {
-+ // This face is too large wrt the maximum volume bound.
-+ return true; // case (2)
-+ }
-+ }
-+ sesymself(*testsh);
-+ }
-+ }
- }
- }
-- verlist->clear();
-
-- if (j == 0) return true; // case (3).
-+ // Check if p is inside the protect balls of vertices of V.
-+ for (i = 0; i < verlist->len(); i++) {
-+ p[0] = * (point *)(* verlist)[i];
-+ if (!b->bgmesh) {
-+ lfs = b->alpha2 * p[0][pointlfsindex];
-+ } else {
-+ lfs = b->alpha2 * p[0][3];
-+ }
-+ L = distance(p[0], facpt);
-+ if (L < lfs) break; // p is inside ball.
-+ }
-+ if (i == verlist->len()) return true; // case (3).
-
- rejsubpts++;
- return false;
-@@ -28898,15 +26144,17 @@
- // 'ceillist' is B(p). 'verlist' (V) is empty on input, it returns the set //
- // of vertices of B(p). //
- // //
--// p can be split if |p - v| > \alpha_2 H(v), for all v \in V. //
-+// p can be split if it is in one of the following cases: //
-+// (1) if the t \in B(p) has maximal volume constraint V, and vol(t) < V. //
-+// (2) if |p - v| > \alpha_2 H(v), for all v \in V. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
- bool tetgenmesh::acceptvolpt(point volpt, list* ceillist, list* verlist)
- {
- triface* testtet;
-- point p[3], ploop;
-- REAL L, lfs;
-+ point p[4];
-+ REAL L, vol, lfs;
- int idx, i, j;
-
- // Collect the vertices of CBC(p), save them in V.
-@@ -28923,23 +26171,45 @@
- }
- }
- }
-+ // Uninfect collected vertices.
-+ for (i = 0; i < verlist->len(); i++) {
-+ p[0] = * (point *)(* verlist)[i];
-+ idx = pointmark(p[0]);
-+ setpointmark(p[0], -(idx + 1));
-+ }
-+
-+ if (b->varvolume || b->fixedvolume) {
-+ for (i = 0; i < ceillist->len(); i++) {
-+ testtet = (triface *)(* ceillist)[i];
-+ for (j = 0; j < 4; j++) p[j] = (point) testtet->tet[4 + j];
-+ vol = orient3d(p[0], p[1], p[2], p[3]) / 6.0;
-+ if (vol < 0) vol = -vol;
-+ if (b->fixedvolume && (vol > b->maxvolume)) {
-+ // This tet is too large wrt. the maximum volume bound. Split it.
-+ return true; // case (1)
-+ }
-+ if (b->varvolume) {
-+ if ((vol > volumebound(testtet->tet)) &&
-+ (volumebound(testtet->tet) > 0.0)) {
-+ // This tet is too large wrt the maximum volume bound.
-+ return true; // case (1)
-+ }
-+ }
-+ }
-+ }
-
-- j = 0; // Use j to counte the number of inside balls.
-+ // Check if p is inside the protect balls of vertices of V.
- for (i = 0; i < verlist->len(); i++) {
-- ploop = * (point *)(* verlist)[i];
-- // Uninfect q.
-- idx = pointmark(ploop);
-- setpointmark(ploop, -(idx + 1));
-- // Check if p is inside the protect ball of q.
-- if (ploop[pointmtrindex] > 0.0) {
-- lfs = b->alpha2 * ploop[pointmtrindex];
-- L = distance(ploop, volpt);
-- if (L < lfs) j++; // p is inside the protect ball.
-+ p[0] = * (point *)(* verlist)[i];
-+ if (!b->bgmesh) {
-+ lfs = b->alpha2 * p[0][pointlfsindex];
-+ } else {
-+ lfs = b->alpha2 * p[0][3];
- }
-+ L = distance(p[0], volpt);
-+ if (L < lfs) break; // p is inside ball.
- }
-- verlist->clear();
--
-- if (j == 0) return true; // case (2).
-+ if (i == verlist->len()) return true; // case (2).
-
- rejtetpts++;
- return false;
-@@ -28997,27 +26267,17 @@
- // Add a random perturbation on newpt.
- d1 = distance(ei, newpt);
- d2 = distance(newpt, refpt);
-- ps = randgenerator(d2 * b->epsilon2 * 1e+2);
-+ ps = randgenerator(d2 * b->epsilon2);
- rs = ps / d1;
- // Perturb newpt away from ei.
- for (i = 0; i < 3; i++) newpt[i] = ei[i] + (1.0+rs) * (newpt[i] - ei[i]);
- } else {
- // Both endpoints are acute or not. Split it at the middle.
- for (i = 0; i < 3; i++) newpt[i] = 0.5 * (e1[i] + e2[i]);
-- // Add a random perturbation on newpt.
-- d1 = 0.5 * distance(e1, e2);
-- ps = randgenerator(d1 * b->epsilon2 * 1e+2);
-- rs = ps / d1;
-- for (i = 0; i < 3; i++) newpt[i] = e1[i] + (1.0+rs) * (newpt[i] - e1[i]);
- }
- } else {
- // Split the segment at its midpoint.
- for (i = 0; i < 3; i++) newpt[i] = 0.5 * (e1[i] + e2[i]);
-- // Add a random perturbation on newpt.
-- d1 = 0.5 * distance(e1, e2);
-- ps = randgenerator(d1 * b->epsilon2 * 1e+2);
-- rs = ps / d1;
-- for (i = 0; i < 3; i++) newpt[i] = e1[i] + (1.0+rs) * (newpt[i] - e1[i]);
- }
- }
-
-@@ -29050,10 +26310,10 @@
- sumweight += weights[i];
- }
- // Interpolate.
-- newpt[pointmtrindex] = 0.0;
-+ newpt[pointlfsindex] = 0.0;
- for (i = 0; i < verlist->len(); i++) {
- neipt = * (point *)(* verlist)[i];
-- newpt[pointmtrindex] += (weights[i] * neipt[pointmtrindex]) / sumweight;
-+ newpt[pointlfsindex] += (weights[i] * neipt[pointlfsindex]) / sumweight;
- }
-
- delete [] weights;
-@@ -29064,33 +26324,22 @@
- // setnewpointsize() Set the size for a new point. //
- // //
- // The size of the new point p is interpolated either from a background mesh //
--// (b->bgmesh) or from the two input endpoints. //
-+// (b->bgmesh) or from the sizes of the adjacent vertices of p. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--void tetgenmesh::setnewpointsize(point newpt, point e1, point e2)
-+void tetgenmesh::setnewpointsize(point newpt, list* verlist)
- {
-- if (b->metric) {
-- // Interpolate the point size in a background mesh.
-+ if (b->bgmesh) {
- triface bgmtet;
-+ point pa;
- // Get a tet in background mesh for locating p.
-- decode(point2bgmtet(e1), bgmtet);
-- p1interpolatebgm(newpt, &bgmtet, NULL);
-+ pa = * (point *)(* verlist)[0];
-+ decode(point2bgmtet(pa), bgmtet);
-+ interpolatepointsize(newpt, &bgmtet, NULL);
- } else {
-- if (e2 != (point) NULL) {
-- // Interpolate the size between the two endpoints.
-- REAL split, l, d;
-- l = distance(e1, e2);
-- d = distance(e1, newpt);
-- split = d / l;
--#ifdef SELF_CHECK
-- // Check if e1 and e2 are endpoints of a sharp segment.
-- assert(e1[pointmtrindex] > 0.0);
-- assert(e2[pointmtrindex] > 0.0);
--#endif
-- newpt[pointmtrindex] = (1.0 - split) * e1[pointmtrindex]
-- + split * e2[pointmtrindex];
-- }
-+ // Interpolate a local size for p using Shepard interpolation.
-+ shepardinterpolate(newpt, verlist);
- }
- }
-
-@@ -29101,93 +26350,82 @@
- ///////////////////////////////////////////////////////////////////////////////
-
- void tetgenmesh::splitencseg(point newpt, face* splitseg, list* tetlist,
-- list* sublist, list* verlist, queue* flipque, bool chkencsub, bool chkbadtet,
-- bool optflag)
-+ list* sublist, list* verlist, queue* flipque, bool chkencsub, bool chkbadtet)
- {
-- list *mytetlist;
-- queue *myflipque;
- triface starttet;
- face startsh, spinsh, checksh;
- int i;
-
-- if (optflag) {
-- mytetlist = new list(sizeof(triface), NULL, 1024);
-- myflipque = new queue(sizeof(badface));
-- tetlist = mytetlist;
-- flipque = myflipque;
-- }
--
- // Use the base orientation (important in this routine).
- splitseg->shver = 0;
- // Insert p, this should always success.
- sstpivot(splitseg, &starttet);
- splittetedge(newpt, &starttet, flipque);
-+ if (steinerleft > 0) steinerleft--;
- // Remove locally non-Delaunay faces by flipping.
-- flip(flipque, NULL); // lawson(NULL, flipque);
-+ flip(flipque, NULL);
-
-- if (!optflag) {
-- // Check the two new subsegs to see if they're encroached (not by p).
-- for (i = 0; i < 2; i++) {
-+ // Check the two new subsegs to see if they're encroached (not by p).
-+ for (i = 0; i < 2; i++) {
-+ if (!shell2badface(*splitseg)) {
-+ checkseg4encroach(splitseg, NULL, NULL, true);
- if (!shell2badface(*splitseg)) {
-- checkseg4encroach(splitseg, NULL, NULL, true);
-+ if (varconstraint && (areabound(*splitseg) > 0.0)) {
-+ checkseg4badqual(splitseg, true);
-+ }
- }
-- if (i == 1) break; // Two new segs have been checked.
-- senextself(*splitseg);
-- spivotself(*splitseg);
-+ }
-+ if (i == 1) break; // Two new segs have been checked.
-+ senextself(*splitseg);
-+ spivotself(*splitseg);
- #ifdef SELF_CHECK
-- assert(splitseg->sh != (shellface *) NULL);
-+ assert(splitseg->sh != (shellface *) NULL);
- #endif
-- splitseg->shver = 0;
-- }
-- // Check the new subfaces to see if they're encroached (not by p).
-- if (chkencsub) {
-- spivot(*splitseg, startsh);
-- spinsh = startsh;
-- do {
-- sublist->append(&spinsh);
-- formstarpolygon(newpt, sublist, verlist);
-- for (i = 0; i < sublist->len(); i++) {
-- checksh = * (face *)(* sublist)[i];
-+ splitseg->shver = 0;
-+ }
-+ // Check the new subfaces to see if they're encroached (not by p).
-+ if (chkencsub) {
-+ spivot(*splitseg, startsh);
-+ spinsh = startsh;
-+ do {
-+ sublist->append(&spinsh);
-+ formstarpolygon(newpt, sublist, verlist);
-+ for (i = 0; i < sublist->len(); i++) {
-+ checksh = * (face *)(* sublist)[i];
-+ if (!shell2badface(checksh)) {
-+ checksub4encroach(&checksh, NULL, true);
- if (!shell2badface(checksh)) {
-- checksub4encroach(&checksh, NULL, true);
-+ if (varconstraint && (areabound(checksh) > 0.0)) {
-+ checksub4badqual(&checksh, true);
-+ }
- }
- }
-- sublist->clear();
-- if (verlist) verlist->clear();
-- spivotself(spinsh);
-- } while (spinsh.sh != startsh.sh);
-- }
-- } // if (!optflag)
--
-+ }
-+ sublist->clear();
-+ verlist->clear();
-+ spivotself(spinsh);
-+ } while (spinsh.sh != startsh.sh);
-+ }
-+
- // Collect the new tets connecting at p.
- sstpivot(splitseg, &starttet);
- tetlist->append(&starttet);
- formstarpolyhedron(newpt, tetlist, verlist, true);
-
-- if (!optflag) {
-- // Check if p encroaches adjacent segments.
-- tallencsegs(newpt, 1, &tetlist);
-- if (chkencsub) {
-- // Check if p encroaches adjacent subfaces.
-- tallencsubs(newpt, 1, &tetlist);
-- }
-- if (chkbadtet) {
-- // Check if there are new bad quality tets at p.
-- for (i = 0; i < tetlist->len(); i++) {
-- starttet = * (triface *)(* tetlist)[i];
-- checktet4badqual(&starttet, true);
-- }
-- }
-- tetlist->clear();
-- } else {
-- // Check if new tets are non-optimal.
-+ // Check if p encroaches adjacent segments.
-+ tallencsegs(newpt, 1, &tetlist);
-+ if (chkencsub) {
-+ // Check if p encroaches adjacent subfaces.
-+ tallencsubs(newpt, 1, &tetlist);
-+ }
-+ if (chkbadtet) {
-+ // Check if there are new bad quality tets at p.
- for (i = 0; i < tetlist->len(); i++) {
- starttet = * (triface *)(* tetlist)[i];
-- checktet4opt(&starttet, true);
-+ checktet4badqual(&starttet, true);
- }
-- delete mytetlist;
-- delete myflipque;
- }
-+ tetlist->clear();
- }
-
- ///////////////////////////////////////////////////////////////////////////////
-@@ -29227,6 +26465,11 @@
- // Found a segment. Test it if it isn't in enc-list.
- if (!shell2badface(checkseg)) {
- checkseg4encroach(&checkseg, testpt, NULL, true);
-+ if (!shell2badface(checkseg)) {
-+ if (varconstraint && (areabound(checkseg) > 0.0)) {
-+ checkseg4badqual(&checkseg, true);
-+ }
-+ }
- }
- }
- enextself(ceiltet);
-@@ -29241,6 +26484,11 @@
- // Test it if it isn't in enc-list.
- if (!shell2badface(checkseg)) {
- checkseg4encroach(&checkseg, testpt, NULL, true);
-+ if (!shell2badface(checkseg)) {
-+ if (varconstraint && (areabound(checkseg) > 0.0)) {
-+ checkseg4badqual(&checkseg, true);
-+ }
-+ }
- }
- checkseg.sh = shellfacetraverse(subsegs);
- }
-@@ -29284,6 +26532,11 @@
- // Found a subface. Test it if it isn't in enc-list.
- if (!shell2badface(checksh)) {
- checksub4encroach(&checksh, testpt, true);
-+ if (!shell2badface(checksh)) {
-+ if (varconstraint && (areabound(checksh) > 0.0)) {
-+ checksub4badqual(&checksh, true);
-+ }
-+ }
- }
- }
- }
-@@ -29296,6 +26549,11 @@
- // Test it if it isn't in enc-list.
- if (!shell2badface(checksh)) {
- checksub4encroach(&checksh, testpt, true);
-+ if (!shell2badface(checksh)) {
-+ if (varconstraint && (areabound(checksh) > 0.0)) {
-+ checksub4badqual(&checksh, true);
-+ }
-+ }
- }
- checksh.sh = shellfacetraverse(subfaces);
- }
-@@ -29340,17 +26598,18 @@
- {
- list **tetlists, **ceillists;
- list **sublists, **subceillists;
-- list *tetlist, *sublist;
-+ list *tetlist, *sublist, *verlist;
- queue *flipque;
- badface *encloop;
- face splitseg, symsplitseg;
- point newpt, sympt, refpt;
-- point e1, e2;
- enum locateresult symloc;
- int nmax, n, i, j;
-
- n = 0;
- nmax = 128;
-+ tetlist = (list *) NULL;
-+ flipque = (queue *) NULL;
- if (!b->fliprepair) {
- tetlists = new list*[nmax];
- ceillists = new list*[nmax];
-@@ -29359,6 +26618,9 @@
- } else {
- tetlist = new list(sizeof(triface), NULL, 1024);
- sublist = new list(sizeof(face), NULL, 256);
-+ }
-+ verlist = new list(sizeof(point *), NULL, 256);
-+ if (b->fliprepair) {
- flipque = new queue(sizeof(badface));
- }
-
-@@ -29385,6 +26647,9 @@
- }
- // Create the new point p (at the middle of s).
- makepoint(&newpt);
-+ // for (i = 0; i < 3; i++) {
-+ // newpt[i] = 0.5 * (encloop->forg[i] + encloop->fdest[i]);
-+ // }
- getsplitpoint(encloop->forg, encloop->fdest, refpt, newpt);
- setpointtype(newpt, FREESEGVERTEX);
- setpoint2sh(newpt, sencode(splitseg));
-@@ -29403,13 +26668,6 @@
- // Insert sympt.
- setpointtype(sympt, FREESEGVERTEX);
- setpoint2sh(sympt, sencode(symsplitseg));
-- // Save the endpoints of the seg for size interpolation.
-- e1 = sorg(symsplitseg);
-- if (shelltype(symsplitseg) == SHARP) {
-- e2 = sdest(symsplitseg);
-- } else {
-- e2 = (point) NULL; // No need to do size interpolation.
-- }
- if (!b->fliprepair) {
- // Form BC(symp), B(symp), CBC(symp)s, C(symp)s.
- formbowatcavity(sympt, &symsplitseg, NULL, &n, &nmax,
-@@ -29418,9 +26676,9 @@
- if (trimbowatcavity(sympt, &symsplitseg, n, sublists,
- subceillists, tetlists, ceillists, -1.0)) {
- bowatinsertsite(sympt, &symsplitseg, n, sublists,
-- subceillists, tetlists, ceillists, NULL, flipque,
-+ subceillists, tetlists, ceillists, verlist, flipque,
- true, chkencsub, chkbadtet);
-- setnewpointsize(sympt, e1, e2);
-+ setnewpointsize(sympt, verlist);
- if (steinerleft > 0) steinerleft--;
- } else {
- // p did not insert for invalid BC(symp).
-@@ -29430,11 +26688,12 @@
- releasebowatcavity(&symsplitseg, n, sublists, subceillists,
- tetlists, ceillists);
- } else {
-- splitencseg(sympt, &symsplitseg, tetlist, sublist, NULL,
-- flipque, chkencsub, chkbadtet, false);
-- setnewpointsize(sympt, e1, e2);
-+ splitencseg(sympt, &symsplitseg, tetlist, sublist, verlist,
-+ flipque, chkencsub, chkbadtet);
-+ setnewpointsize(sympt, verlist);
- if (steinerleft > 0) steinerleft--;
- }
-+ verlist->clear();
- } else {
- // The sympt are on the same segment. It is possible when
- // splitseg is the symmetric rotating axes.
-@@ -29451,13 +26710,6 @@
- }
- } // for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++)
- } // if (checkpbcs)
-- // Save the endpoints of the seg for size interpolation.
-- e1 = sorg(splitseg);
-- if (shelltype(splitseg) == SHARP) {
-- e2 = sdest(splitseg);
-- } else {
-- e2 = (point) NULL; // No need to do size interoplation.
-- }
- if (!b->fliprepair) {
- // Form BC(p), B(p), CBC(p)s, and C(p)s.
- formbowatcavity(newpt, &splitseg, NULL, &n, &nmax, sublists,
-@@ -29466,9 +26718,9 @@
- if (trimbowatcavity(newpt, &splitseg, n, sublists, subceillists,
- tetlists, ceillists, -1.0)) {
- bowatinsertsite(newpt, &splitseg, n, sublists, subceillists,
-- tetlists, ceillists, NULL, flipque, true,
-+ tetlists, ceillists, verlist, flipque, true,
- chkencsub, chkbadtet);
-- setnewpointsize(newpt, e1, e2);
-+ setnewpointsize(newpt, verlist);
- if (steinerleft > 0) steinerleft--;
- } else {
- // p did not insert for invalid B(p).
-@@ -29478,11 +26730,12 @@
- releasebowatcavity(&splitseg, n, sublists, subceillists, tetlists,
- ceillists);
- } else {
-- splitencseg(newpt, &splitseg, tetlist, sublist, NULL, flipque,
-- chkencsub, chkbadtet, false);
-- setnewpointsize(newpt, e1, e2);
-+ splitencseg(newpt, &splitseg, tetlist, sublist, verlist, flipque,
-+ chkencsub, chkbadtet);
-+ setnewpointsize(newpt, verlist);
- if (steinerleft > 0) steinerleft--;
- }
-+ verlist->clear();
- } else {
- // p did not accept for insertion.
- pointdealloc(newpt);
-@@ -29501,6 +26754,9 @@
- } else {
- delete tetlist;
- delete sublist;
-+ }
-+ delete verlist;
-+ if (b->fliprepair) {
- delete flipque;
- }
- }
-@@ -29525,7 +26781,7 @@
- list *verlist;
- badface *encloop;
- face splitsub, symsplitsub;
-- point newpt, sympt, e1;
-+ point newpt, sympt;
- enum locateresult loc, symloc;
- bool reject;
- long oldptnum;
-@@ -29545,17 +26801,21 @@
- // Clear the in-queue flag of f.
- setshell2badface(splitsub, NULL);
- // f may not be the same one when it was determined to be encroached.
-- if (!isdead(&splitsub)
-- && (sorg(splitsub) == encloop->forg)
-- && (sdest(splitsub) == encloop->fdest)
-- && (sapex(splitsub) == encloop->fapex)) {
-+ if (!isdead(&splitsub) && (sorg(splitsub) == encloop->forg) &&
-+ (sdest(splitsub) == encloop->fdest) &&
-+ (sapex(splitsub) == encloop->fapex)) {
- if (b->verbose > 1) {
- printf(" Dequeuing ensub (%d, %d, %d) [%d].\n",
- pointmark(encloop->forg), pointmark(encloop->fdest),
- pointmark(encloop->fapex), quenumber);
- }
-- // Create a new point p at the circumcenter of f.
-+ // Create a new point p.
- makepoint(&newpt);
-+ // If f was added by checksub4badqual(), calculate its circumcenter.
-+ if (quenumber == 2) {
-+ circumsphere(encloop->forg, encloop->fdest, encloop->fapex, NULL,
-+ encloop->cent, NULL);
-+ }
- for (i = 0; i < 3; i++) newpt[i] = encloop->cent[i];
- setpointtype(newpt, FREESUBVERTEX);
- setpoint2sh(newpt, sencode(splitsub));
-@@ -29571,11 +26831,12 @@
- // Form BC(p), B(p), CBC(p) and C(p).
- formbowatcavity(newpt, NULL, &splitsub, &n, NULL, &sublist,
- &subceillist, tetlists, ceillists);
-- // Check for encroached subsegments (on B(p)).
-+ // Check for encroaching subsegments (on B(p)).
- reject = tallencsegs(newpt, 2, ceillists);
-- // Execute point accept rule if p does not encroach upon any segment.
- if (!reject) {
-+ // Decide whether f is allowed to be split or not?
- reject = !acceptfacpt(newpt, subceillist, verlist);
-+ verlist->clear();
- }
- if (!reject) {
- // Validate/update cavity.
-@@ -29605,6 +26866,7 @@
- reject = tallencsegs(sympt, 2, ceillists);
- if (!reject) {
- reject = !acceptfacpt(sympt, subceillist, verlist);
-+ verlist->clear();
- }
- if (!reject) {
- reject = !trimbowatcavity(sympt,NULL,n,&sublist,&subceillist,
-@@ -29616,23 +26878,21 @@
- setpoint2pbcpt(sympt, newpt);
- setpointtype(sympt, FREESUBVERTEX);
- setpoint2sh(sympt, sencode(symsplitsub));
-- // Save a point for size interpolation.
-- e1 = sorg(symsplitsub);
- bowatinsertsite(sympt, NULL, n, &sublist, &subceillist,
-- tetlists,ceillists,NULL,NULL,false,true,chkbadtet);
-- setnewpointsize(sympt, e1, NULL);
-+ tetlists,ceillists,verlist,NULL,false,true,chkbadtet);
-+ setnewpointsize(sympt, verlist);
-+ verlist->clear();
- if (steinerleft > 0) steinerleft--;
-- // Release CBC(symp) and BC(symp) and free the memory..
-- releasebowatcavity(NULL, n, &sublist, &subceillist, tetlists,
-- ceillists);
- } else {
- // symp is rejected for one of the following reasons:
- // (1) BC(symp) is not valid; or
- // (2) symp encroaches upon some subsegments (queued); or
- // (3) symp is rejected by point accepting rule.
- pointdealloc(sympt);
-- // Cavity will be released by the following code.
- }
-+ // Release CBC(symp) and BC(symp) and free the memory..
-+ releasebowatcavity(NULL, n, &sublist, &subceillist, tetlists,
-+ ceillists);
- } else {
- // Do not insert sympt for invalid PBC data.
- pointdealloc(sympt);
-@@ -29653,11 +26913,10 @@
- ceillists, -1.0);
- }
- }
-- // Save a point for size interpolation.
-- e1 = sorg(splitsub);
- bowatinsertsite(newpt, NULL, n, &sublist, &subceillist, tetlists,
-- ceillists, NULL, NULL, true, true, chkbadtet);
-- setnewpointsize(newpt, e1, NULL);
-+ ceillists, verlist, NULL, true, true, chkbadtet);
-+ setnewpointsize(newpt, verlist);
-+ verlist->clear();
- if (steinerleft > 0) steinerleft--;
- } else {
- // p is rejected for the one of the following reasons:
-@@ -29669,7 +26928,8 @@
- pointdealloc(newpt);
- } // if (!reject)
- // Release the cavity and free the memory.
-- releasebowatcavity(NULL,n,&sublist,&subceillist,tetlists,ceillists);
-+ releasebowatcavity(NULL, n, &sublist, &subceillist, tetlists,
-+ ceillists);
- if (reject) {
- // Are there queued encroached subsegments.
- if (badsubsegs->items > 0) {
-@@ -29682,6 +26942,11 @@
- if (!isdead(&splitsub)) {
- if (!shell2badface(splitsub)) {
- checksub4encroach(&splitsub, NULL, true);
-+ if (!shell2badface(splitsub)) {
-+ if (varconstraint && (areabound(splitsub) > 0.0)) {
-+ checksub4badqual(&splitsub, true);
-+ }
-+ }
- }
- }
- }
-@@ -29715,6 +26980,11 @@
- if (!isdead(&splitsub)) {
- // The subface has been changed, re-check it.
- checksub4encroach(&splitsub, NULL, true);
-+ if (!shell2badface(splitsub)) {
-+ if (varconstraint && (areabound(splitsub) > 0.0)) {
-+ checksub4badqual(&splitsub, true);
-+ }
-+ }
- }
- } // if (!isdead(&splitsub) && (sorg(splitsub) == encloop->forg) &&
- // Remove this entry from list.
-@@ -29742,7 +27012,7 @@
- list *verlist;
- badface *badtet;
- triface starttet;
-- point newpt, e1;
-+ point newpt;
- enum locateresult loc;
- bool reject;
- long oldptnum;
-@@ -29756,20 +27026,14 @@
- // if an unlimited number of Steiner points is allowed.
- while ((badtetrahedrons->items > 0) && (steinerleft != 0)) {
- // Get a bad-quality tet t.
-- badtet = topbadtetra();
-+ badtet = dequeuebadtet();
- // Make sure that the tet is still the same one when it was tested.
- // Subsequent transformations may have made it a different tet.
-- if ((badtet != (badface *) NULL) && !isdead(&badtet->tt)
-- && org(badtet->tt) == badtet->forg
-- && dest(badtet->tt) == badtet->fdest
-- && apex(badtet->tt) == badtet->fapex
-- && oppo(badtet->tt) == badtet->foppo) {
-- if (b->verbose > 1) {
-- printf(" Dequeuing btet (%d, %d, %d, %d).\n",
-- pointmark(badtet->forg), pointmark(badtet->fdest),
-- pointmark(badtet->fapex), pointmark(badtet->foppo));
-- }
-- // Create the new point p (at the circumcenter of t).
-+ if (!isdead(&badtet->tt) && org(badtet->tt) == badtet->forg &&
-+ dest(badtet->tt) == badtet->fdest &&
-+ apex(badtet->tt) == badtet->fapex &&
-+ oppo(badtet->tt) == badtet->foppo) {
-+ // Create the new point p.
- makepoint(&newpt);
- for (i = 0; i < 3; i++) newpt[i] = badtet->cent[i];
- setpointtype(newpt, FREEVOLVERTEX);
-@@ -29787,9 +27051,8 @@
- // Check for encroached subfaces.
- reject = tallencsubs(newpt, 1, &ceillist);
- }
-- // Execute point accepting rule if p does not encroach upon any
-- // subsegment and subface.
- if (!reject) {
-+ // Does p allowed to be inseted?
- reject = !acceptvolpt(newpt, ceillist, verlist);
- }
- if (!reject) {
-@@ -29805,12 +27068,10 @@
- if (reject) outbowatcircumcount++;
- }
- if (!reject) {
-- // Save a point for size interpolation.
-- e1 = org(starttet);
- // Insert p.
- bowatinsertsite(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist,
- NULL, NULL, false, false, true);
-- setnewpointsize(newpt, e1, NULL);
-+ setnewpointsize(newpt, verlist);
- if (steinerleft > 0) steinerleft--;
- } else {
- // p is rejected for one of the following reasons:
-@@ -29828,6 +27089,7 @@
- }
- tetlist->clear();
- ceillist->clear();
-+ verlist->clear();
- // Split encroached subsegments/subfaces if there are.
- if (reject) {
- oldptnum = points->items;
-@@ -29838,8 +27100,7 @@
- repairencsubs(true);
- }
- if (points->items > oldptnum) {
-- // Some encroaching subsegments/subfaces got split. Re-queue the
-- // tet if it is still alive.
-+ // Some encroaching subsegments/subfaces have been split.
- starttet = badtet->tt;
- if (!isdead(&starttet)) {
- checktet4badqual(&starttet, true);
-@@ -29872,8 +27133,8 @@
- pointdealloc(newpt);
- } // if ((loc != ONVERTEX) && (loc != OUTSIDE))
- } // if (!isdead(&badtet->tt) && org(badtet->tt) == badtet->forg &&
-- // Remove the tet from the queue.
-- dequeuebadtet();
-+ // Remove the tet from the pool.
-+ badfacedealloc(badtetrahedrons, badtet);
- } // while ((badtetrahedrons->items > 0) && (steinerleft != 0))
-
- delete tetlist;
-@@ -29901,17 +27162,18 @@
- r2count = r3count = 0l;
- }
-
-- // If both '-D' and '-r' options are used.
-- if (b->conformdel && b->refine) {
-- markacutevertices(65.0);
-- }
-- // If '-m' is not used.
-- if (!b->metric) {
-- // Find and mark all sharp segments.
-- marksharpsegments(65.0);
-- // Decide the sizes for feature points.
-- decidefeaturepointsizes();
-+ if (b->refine) {
-+ // Mark segment vertices (acute or not).
-+ markacutevertices(89.0);
- }
-+ if (!b->bgmesh) {
-+ // Calculate the node local feature sizes.
-+ calclocalfeaturesizes();
-+ }
-+ // Mark sharp subfaces (for termination).
-+ marksharpsubsegs(89.0);
-+ // Mark skinny subfaces (for reducing Steiner points).
-+ markskinnysubfaces(19.0);
-
- // Initialize the pool of encroached subsegments.
- badsubsegs = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
-@@ -29954,11 +27216,8 @@
- badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0);
- // Initialize the priority queues of bad tets.
- for (i = 0; i < 64; i++) tetquefront[i] = (badface *) NULL;
-- firstnonemptyq = -1;
-- recentq = -1;
-+ for (i = 0; i < 64; i++) tetquetail[i] = &tetquefront[i];
- // Looking for bad quality tets.
-- cosmaxdihed = cos(b->maxdihedral * PI / 180.0);
-- cosmindihed = cos(b->mindihedral * PI / 180.0);
- tallbadtetrahedrons();
- if (b->verbose && badtetrahedrons->items > 0) {
- printf(" Splitting bad tetrahedra.\n");
-@@ -29985,36 +27244,9 @@
- //
-
- //
--// Begin of mesh optimization routines
-+// Begin of mesh smoothing routines
- //
-
--void tetgenmesh::dumpbadtets()
--{
-- FILE *fout;
-- badface *remtet;
--
-- // Write out a file of remaining bad tets.
-- printf(" Writing bad tets to file bad-dump.lua.\n");
-- fout = fopen("bad-dump.lua", "w");
-- fprintf(fout, "-- %ld remaining bad tets (> %g degree).\n",
-- badtetrahedrons->items, b->maxdihedral);
-- badtetrahedrons->traversalinit();
-- remtet = badfacetraverse(badtetrahedrons);
-- while (remtet != (badface *) NULL) {
-- if (!isdead(&remtet->tt) && org(remtet->tt) == remtet->forg &&
-- dest(remtet->tt) == remtet->fdest &&
-- apex(remtet->tt) == remtet->fapex &&
-- oppo(remtet->tt) == remtet->foppo) {
-- fprintf(fout, "p:draw_tet(%d, %d, %d, %d) -- %g\n",
-- pointmark(remtet->forg), pointmark(remtet->fdest),
-- pointmark(remtet->fapex), pointmark(remtet->foppo),
-- acos(remtet->key) * 180.0 / PI);
-- }
-- remtet = badfacetraverse(badtetrahedrons);
-- }
-- fclose(fout);
--}
--
- ///////////////////////////////////////////////////////////////////////////////
- // //
- // checktet4ill() Check a tet to see if it is illegal. //
-@@ -30046,15 +27278,10 @@
- fnext(*testtet, checktet);
- tspivot(checktet, checksh2);
- if (checksh2.sh != dummysh) {
-- // Two subfaces share this edge.
-+ // Two subfaces share this edge. It should be a segment.
- sspivot(checksh1, checkseg);
- if (checkseg.sh == dummysh) {
-- // The four corners of the tet are on one facet. Illegal! Try to
-- // flip the opposite edge of the current one.
-- enextfnextself(*testtet);
-- enextself(*testtet);
-- illflag = true;
-- break;
-+ illflag = true; break;
- }
- }
- enextself(*testtet);
-@@ -30068,7 +27295,7 @@
- // Allocate space for the bad tetrahedron.
- newbadtet = (badface *) badtetrahedrons->alloc();
- newbadtet->tt = *testtet;
-- newbadtet->key = -1.0; // = 180 degree.
-+ newbadtet->key = 0.0;
- for (i = 0; i < 3; i++) newbadtet->cent[i] = 0.0;
- newbadtet->forg = org(*testtet);
- newbadtet->fdest = dest(*testtet);
-@@ -30082,594 +27309,727 @@
- }
- }
-
-- return illflag;
-+ return illflag;
-+}
-+
-+///////////////////////////////////////////////////////////////////////////////
-+// //
-+// checktet4sliver() Check a tet to see if it is a sliver. //
-+// //
-+// A sliver is a tet has no small edges, but has a nearly zero volume. When //
-+// the mesh quality is measured by radios-edge ratio, slivers can have rela- //
-+// tively small value and are not classified as bad quality. //
-+// //
-+// This routine finds whether a tet is a sliver or not by checking the bigg- //
-+// est dihedral angle of the tet. It is a sliver if the angle is larger than //
-+// 'maxdihed' (default is 170 degree, can be adjusted by '-s' option). //
-+// //
-+// If the flag 'chkill' is set, only check the volume of tet. It is a sliver //
-+// if it has a zero or negative volume. //
-+// //
-+///////////////////////////////////////////////////////////////////////////////
-+
-+bool tetgenmesh::checktet4sliver(triface* testtet, bool chkill, bool enqflag)
-+{
-+ badface *newbadtet;
-+ point pa, pb, pc, pd;
-+ REAL N[4][3], volume, len;
-+ REAL cosd, smallcosd;
-+ bool enq;
-+ int edgeno, i, j;
-+
-+ enq = false;
-+
-+ pa = (point) testtet->tet[4];
-+ pb = (point) testtet->tet[5];
-+ pc = (point) testtet->tet[6];
-+ pd = (point) testtet->tet[7];
-+ // Compute the 4 face normals (N[0], ..., N[3]).
-+ tetallnormal(pa, pb, pc, pd, N, &volume);
-+ // Normalize the normals.
-+ for (i = 0; i < 4; i++) {
-+ len = sqrt(dot(N[i], N[i]));
-+ if (len != 0.0) {
-+ for (j = 0; j < 3; j++) N[i][j] /= len;
-+ }
-+ }
-+ // Find the largest dihedral and the edge.
-+ smallcosd = -dot(N[2], N[3]); // Edge ab.
-+ edgeno = 0;
-+ for (i = 1; i < 4; i++) {
-+ cosd = -dot(N[0], N[i]); // Edge cd, bd, bc.
-+ if (cosd < smallcosd) {
-+ smallcosd = cosd;
-+ edgeno = i;
-+ }
-+ }
-+ for (i = 2; i < 4; i++) {
-+ cosd = -dot(N[1], N[i]); // Edge ad, ac.
-+ if (cosd < smallcosd) {
-+ smallcosd = cosd;
-+ edgeno = i + 2;
-+ }
-+ }
-+ // Check if abcd is sliver.
-+ if (!chkill) {
-+ enq = ((smallcosd > cosmindihed) || ((smallcosd < cosmaxdihed)));
-+ } else {
-+ enq = (volume <= 0.0);
-+ }
-+
-+ if (enq && enqflag) {
-+ // Let t represent the edge having the biggest dihedral angle.
-+ testtet->loc = 0;
-+ testtet->ver = 0;
-+ switch (edgeno) {
-+ case 0: break; // edge ab
-+ case 1: // edge cd
-+ enextfnextself(*testtet);
-+ enextself(*testtet);
-+ break;
-+ case 2: // edge bd
-+ enextfnextself(*testtet);
-+ enext2self(*testtet);
-+ break;
-+ case 3: // edge bc
-+ enextself(*testtet);
-+ break;
-+ case 4: // edge ad
-+ enext2fnextself(*testtet);
-+ enextself(*testtet);
-+ break;
-+ case 5: // edge ac
-+ enext2self(*testtet);
-+ break;
-+ }
-+ // Allocate space for the bad tetrahedron.
-+ newbadtet = (badface *) badtetrahedrons->alloc();
-+ newbadtet->tt = *testtet;
-+ newbadtet->key = smallcosd;
-+ for (i = 0; i < 3; i++) newbadtet->cent[i] = 0.0;
-+ newbadtet->forg = org(*testtet);
-+ newbadtet->fdest = dest(*testtet);
-+ newbadtet->fapex = apex(*testtet);
-+ newbadtet->foppo = oppo(*testtet);
-+ newbadtet->nextitem = (badface *) NULL;
-+ if (b->verbose > 2) {
-+ printf(" Queueing sliver: (%d, %d, %d, %d), maxdihed %g (degree).\n",
-+ pointmark(newbadtet->forg), pointmark(newbadtet->fdest),
-+ pointmark(newbadtet->fapex), pointmark(newbadtet->foppo),
-+ acos(smallcosd) * 180.0 / PI);
-+ }
-+ }
-+
-+ return enq;
-+}
-+
-+///////////////////////////////////////////////////////////////////////////////
-+// //
-+// removetetbystripoff() Remove a boundary tet by stripping it off. //
-+// //
-+// 'striptet' (abcd) is on boundary and can be removed by stripping it off. //
-+// Let abc and bad are the external boundary faces. //
-+// //
-+// To strip 'abcd' from the mesh is to detach its two interal faces (dca and //
-+// cdb) from their adjoining tets together with a 2-to-2 flip to transform //
-+// two subfaces (abc and bad) into another two (dca and cdb). //
-+// //
-+///////////////////////////////////////////////////////////////////////////////
-+
-+void tetgenmesh::removetetbystripoff(triface *striptet)
-+{
-+ triface abcd, badc;
-+ triface dcacasing, cdbcasing;
-+ face abc, bad;
-+
-+ if (b->verbose > 1) {
-+ printf(" by stripping it off.\n");
-+ }
-+
-+ striptetcount++;
-+
-+ abcd = *striptet;
-+ adjustedgering(abcd, CCW);
-+
-+ // Get the external subfaces abc, bad.
-+ fnext(abcd, badc);
-+ esymself(badc);
-+ tspivot(abcd, abc);
-+ tspivot(badc, bad);
-+#ifdef SELF_CHECK
-+ assert((abc.sh != dummysh) && (bad.sh != dummysh));
-+#endif
-+ findedge(&abc, org(abcd), dest(abcd));
-+ findedge(&bad, org(badc), dest(badc));
-+
-+ // Get the casing tets at the internal sides.
-+ enextfnext(abcd, cdbcasing);
-+ enext2fnext(abcd, dcacasing);
-+ symself(cdbcasing);
-+ symself(dcacasing);
-+#ifdef SELF_CHECK
-+ assert(cdbcasing.tet != dummytet && dcacasing.tet != dummytet);
-+#endif
-+
-+ // Do a 2-to-2 flip on abc and bad, transform abc->dca, bad->cdb.
-+ flip22sub(&abc, NULL);
-+ // Detach abcd from the two internal faces.
-+ dissolve(cdbcasing);
-+ dissolve(dcacasing);
-+ // The two internal faces become boundary faces.
-+ tsbond(cdbcasing, bad);
-+ tsbond(dcacasing, abc);
-+ // Delete abcd.
-+ tetrahedrondealloc(abcd.tet);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// checktet4opt() Check a tet to see if it needs to be optimized. //
-+// removetetbyflip32() Remove a tet by a 3-to-2 flip. //
- // //
--// A tet t needs to be optimized if it fails to certain quality measures. //
--// The only quality measure currently used is the maximal dihedral angle at //
--// edges. The desired maximal dihedral angle is b->maxdihed (set by the '-s' //
--// option. //
-+// 'fliptet' (abcd) is going to be removed by a 3-to-2 flip. ab is the edge //
-+// will be flipped away, i.e., abc, bad, and abe are three internal faces. //
- // //
--// A tet may have one, two, or three big dihedral angles. Examples: Let the //
--// tet t = abcd, and its four corners are nearly co-planar. Then t has one //
--// big dihedral angle if d is very close to the edge ab; t has three big //
--// dihedral angles if d's projection on the face abc is also inside abc, i.e.//
--// the shape of t likes a hat; finally, t has two big dihedral angles if d's //
--// projection onto abc is outside abc. //
-+// Note: If abc and bad are subfaces(abe must not), a 2-to-2 flip is used to //
-+// transform abc, bad into dca, cdb prior to the 3-to-2 flip. //
-+// //
-+// If 'enq' flag is set, check the two new tets after flip to see if they're //
-+// slivers or illegal tets according to the 'chkill' flag. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--bool tetgenmesh::checktet4opt(triface* testtet, bool enqflag)
-+void tetgenmesh::removetetbyflip32(triface *fliptet, bool enq, bool chkill)
- {
-- badface *newbadtet;
-- point pa, pb, pc, pd;
-- REAL N[4][3], len;
-- REAL cosd;
-- bool enq;
-- int i, j;
-+ triface abcd, badc;
-+ triface cdab, dcba;
-+ triface baccasing, abdcasing;
-+ triface dcacasing, cdbcasing;
-+ face abc, bad;
-+ REAL attrib, volume;
-+ int i;
-
-- enq = false;
-- pa = (point) testtet->tet[4];
-- pb = (point) testtet->tet[5];
-- pc = (point) testtet->tet[6];
-- pd = (point) testtet->tet[7];
-- // Compute the 4 face normals: N[0] cbd, N[1] acd, N[2] bad, N[3] abc.
-- tetallnormal(pa, pb, pc, pd, N, NULL);
-- // Normalize the normals.
-- for (i = 0; i < 4; i++) {
-- len = sqrt(dot(N[i], N[i]));
-- if (len != 0.0) {
-- for (j = 0; j < 3; j++) N[i][j] /= len;
-- }
-+ if (b->verbose > 1) {
-+ printf(" by a 3-to-2 flip.\n");
- }
-- // Find all large dihedral angles.
-- for (i = 0; i < 6; i++) {
-- // Locate the edge i and calculate the dihedral angle at the edge.
-- testtet->loc = 0;
-- testtet->ver = 0;
-- switch (i) {
-- case 0: // edge ab
-- cosd = -dot(N[2], N[3]);
-- break;
-- case 1: // edge cd
-- enextfnextself(*testtet);
-- enextself(*testtet);
-- cosd = -dot(N[0], N[1]);
-- break;
-- case 2: // edge bd
-- enextfnextself(*testtet);
-- enext2self(*testtet);
-- cosd = -dot(N[0], N[2]);
-- break;
-- case 3: // edge bc
-- enextself(*testtet);
-- cosd = -dot(N[0], N[3]);
-- break;
-- case 4: // edge ad
-- enext2fnextself(*testtet);
-- enextself(*testtet);
-- cosd = -dot(N[1], N[2]);
-- break;
-- case 5: // edge ac
-- enext2self(*testtet);
-- cosd = -dot(N[1], N[3]);
-- break;
-+
-+ fliptetcount++;
-+
-+ abcd = *fliptet;
-+ adjustedgering(abcd, CCW);
-+ fnext(abcd, badc);
-+ esymself(badc);
-+ sym(abcd, baccasing);
-+ sym(badc, abdcasing);
-+#ifdef SELF_CHECK
-+ assert((baccasing.tet != dummytet) && (abdcasing.tet != dummytet));
-+ assert(oppo(baccasing) == oppo(abdcasing));
-+#endif
-+
-+ // Get subfaces abc, bad.
-+ tspivot(abcd, abc);
-+ tspivot(badc, bad);
-+ if (abc.sh != dummysh) {
-+#ifdef SELF_CHECK
-+ // Because ab is not a subsegment.
-+ assert(bad.sh != dummysh);
-+#endif
-+ // abc and bad are internal subfaces. tets baccasing and abdcasing must
-+ // have the same attributes (such as the region attribute if the -A
-+ // switch is in use). But abcd may not be at the same region. After
-+ // flip32, if abcd is not deleted, it will have the wrong attributes.
-+ // Set abcd be the same region attributes as baccasing and abdcasing.
-+ for (i = 0; i < in->numberoftetrahedronattributes; i++) {
-+ attrib = elemattribute(baccasing.tet, i);
-+#ifdef SELF_CHECK
-+ REAL testattr = elemattribute(abdcasing.tet, i);
-+ assert(attrib == testattr);
-+#endif
-+ setelemattribute(abcd.tet, i, attrib);
- }
-- if (cosd < cosmaxdihed) {
-- // A bigger dihedral angle.
-- if (enqflag) {
-- // Allocate space for the bad tetrahedron.
-- newbadtet = (badface *) badtetrahedrons->alloc();
-- newbadtet->tt = *testtet;
-- newbadtet->key = cosd;
-- for (j = 0; j < 3; j++) newbadtet->cent[j] = 0.0;
-- newbadtet->forg = org(*testtet);
-- newbadtet->fdest = dest(*testtet);
-- newbadtet->fapex = apex(*testtet);
-- newbadtet->foppo = oppo(*testtet);
-- newbadtet->nextitem = (badface *) NULL;
-- if (b->verbose > 2) {
-- printf(" Queueing tet: (%d, %d, %d, %d), dihed %g (degree).\n",
-- pointmark(newbadtet->forg), pointmark(newbadtet->fdest),
-- pointmark(newbadtet->fapex), pointmark(newbadtet->foppo),
-- acos(cosd) * 180.0 / PI);
-- }
-- }
-- enq = true;
-+ if (b->varvolume) {
-+ volume = volumebound(baccasing.tet);
-+ setvolumebound(abcd.tet, volume);
- }
-+ findedge(&abc, org(abcd), dest(abcd));
-+ findedge(&bad, org(badc), dest(badc));
-+ // Detach abc, bad from the four tets at both sides.
-+ stdissolve(abc);
-+ stdissolve(bad);
-+ sesymself(abc);
-+ sesymself(bad);
-+ stdissolve(abc);
-+ stdissolve(bad);
-+ sesymself(abc);
-+ sesymself(bad);
-+ // Detach the four tets which hold abc and bad.
-+ tsdissolve(abcd);
-+ tsdissolve(badc);
-+ tsdissolve(baccasing);
-+ tsdissolve(abdcasing);
-+ // Perform a 2-to-2 flip on abc, bad, transform abc->dca, bad->cdb.
-+ flip22sub(&abc, NULL);
-+ // Insert the flipped subfaces abc and bad into tets.
-+ enextfnext(abcd, dcba); // dcba = bcda
-+ esymself(dcba); // dcba = cbda
-+ enext2fnext(abcd, cdab); // cdab = cadb
-+ esymself(cdab); // cdab = acdb
-+ findedge(&abc, org(cdab), dest(cdab));
-+ tsbond(cdab, abc);
-+ findedge(&bad, org(dcba), dest(dcba));
-+ tsbond(dcba, bad);
-+ // Bond the other sides of cdab, dcba, they may outer space.
-+ sym(cdab, dcacasing);
-+ sym(dcba, cdbcasing);
-+ sesymself(abc);
-+ sesymself(bad);
-+ tsbond(dcacasing, abc);
-+ tsbond(cdbcasing, bad);
- }
-+ // Remove abcd by a 3-to-2 flip.
-+ flip32(&abcd, NULL);
-+ // After flip abc is the internal face.
-
-- return enq;
-+ if (enq) {
-+ // Get the adjtet of abcd (in badc).
-+ sym(abcd, badc);
-+ if (chkill) {
-+ // Test the two new tets to see if they are illegal.
-+ checktet4ill(&abcd, true);
-+ checktet4ill(&badc, true);
-+ } else {
-+ // Test the two new tets to see if they are sliver.
-+ checktet4sliver(&abcd, false, true);
-+ checktet4sliver(&badc, false, true);
-+ }
-+ }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// removeedge() Remove an edge //
-+// removetetbyrecon() Remove a tet by local reconnection. //
- // //
--// 'remedge' is a tet (abcd) having the edge ab wanted to be removed. Local //
--// reconnecting operations are used to remove edge ab. The following opera- //
--// tion will be tryed. //
-+// 'remtet' (abcd) is wanted to be removed from the mesh. ab is the primary //
-+// edge (which is diagonal if a, b, c, and d form a convex quadrilateral). //
- // //
--// If ab is on the hull, and abc and abd are both hull faces. Then ab can be //
--// removed by stripping abcd from the mesh. However, if ab is a segemnt, do //
--// the operation only if 'b->optlevel' > 1 and 'b->nobisect == 0'. //
-+// abcd is removable if it is not a segment, and either it can be stripped //
-+// off or it can be flipped away. //
- // //
--// If ab is an internal edge, there are n tets contains it. Then ab can be //
--// removed if there exists another m tets which can replace the n tets with- //
--// out changing the boundary of the n tets. //
--// //
--// If 'optflag' is set. The value 'remedge->key' means cos(theta), where //
--// 'theta' is the maximal dishedral angle at ab. In this case, even if the //
--// n-to-m flip exists, it will not be performed if the maximum dihedral of //
--// the new tets is larger than 'theta'. //
-+// The return value indicates abcd is remveable or not. Note, although abcd //
-+// is removeable but it may not be removed when 'chkill' is FALSE. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--bool tetgenmesh::removeedge(badface* remedge, bool optflag)
-+bool tetgenmesh::removetetbyrecon(badface* remtet, bool chkill)
- {
- triface abcd, badc; // Tet configuration at edge ab.
- triface baccasing, abdcasing;
-- triface abtetlist[11]; // Old configuration at ab, save maximum 10 tets.
-- triface bftetlist[11]; // Old configuration at bf, save maximum 10 tets.
-- triface newtetlist[33]; // New configuration after removing ab.
-- face checksh;
-- enum fliptype fty;
-- REAL key;
-- bool remflag, subflag;
-- int n, n1, m, i, j;
--
-- // First try to strip abcd from the mesh. This needs to check either ab
-- // or cd is on the hull. Try to strip it whichever is true.
-- abcd = remedge->tt;
-- adjustedgering(abcd, CCW);
-- i = 0;
-- do {
-- sym(abcd, baccasing);
-- // Is the tet on the hull?
-- if (baccasing.tet == dummytet) {
-+ face abseg;
-+ point pa, pb, pc, pd, pe;
-+ REAL ori1, ori2;
-+ REAL cosmaxd1, cosmaxd2;
-+ bool remflag;
-+ int i;
-+
-+ remflag = false;
-+ // tet 'abcd' is indicated to remove.
-+ abcd = remtet->tt;
-+ // Check if abcd is removeable (at edge ab and cd).
-+ for (i = 0; i < 2; i++) {
-+ // If ab a segment, it is unremoveable.
-+ tsspivot(&abcd, &abseg);
-+ if (abseg.sh == dummysh) {
-+ adjustedgering(abcd, CCW);
-+ // Get the tet configuration at edge ab (or cd).
- fnext(abcd, badc);
-+ esymself(badc);
-+ sym(abcd, baccasing);
- sym(badc, abdcasing);
-- if (abdcasing.tet == dummytet) {
-- // Strip the tet from the mesh -> ab is removed as well.
-- if (removetetbypeeloff(&abcd)) {
-- if (b->verbose > 1) {
-- printf(" Stripped tet from the mesh.\n");
-+ // Can 'abcd' be stripped off?
-+ if ((baccasing.tet == dummytet) && (abdcasing.tet == dummytet)) {
-+ removetetbystripoff(&abcd);
-+ remflag = true;
-+ break; // abcd has been removed.
-+ } else if (oppo(baccasing) == oppo(abdcasing)) {
-+ // Can 'abcd' be flipped away?
-+ pa = org(abcd);
-+ pb = dest(abcd);
-+ pc = apex(abcd);
-+ pd = oppo(abcd);
-+ pe = oppo(baccasing);
-+ // Check if face cde is crossed by ab.
-+ ori1 = orient3d(pc, pd, pe, pa);
-+ ori2 = orient3d(pc, pd, pe, pb);
-+ if (ori1 * ori2 < 0.0) {
-+ // ab can be flipped away.
-+ if (!chkill) {
-+ // Do flip if the maximal dihedrals of the new tets are reduced?
-+ tetalldihedral(pd, pc, pe, pa, NULL, &cosmaxd1, NULL);
-+ tetalldihedral(pc, pd, pe, pb, NULL, &cosmaxd2, NULL);
-+ if ((remtet->key <= cosmaxd1) && (remtet->key <= cosmaxd2)) {
-+ removetetbyflip32(&abcd, true, chkill);
-+ remflag = true;
-+ break; // abcd has been removed.
-+ }
-+ } else {
-+ removetetbyflip32(&abcd, true, chkill);
-+ remflag = true;
-+ break; // abcd has been removed.
- }
-- optcount[0]++;
-- return true;
- }
- }
-- }
-- // Check if the oppsite edge cd is on the hull.
-- enext2fnextself(abcd);
-+ } // if (abseg.sh == dummysh)
-+ // 'abcd' is not removed (although it may be removeable).
-+ if (i == 1) break; // Stop if both ab and cd have been checked.
-+ // Go to edge cd, re-use handle abcd.
-+ enextfnextself(abcd);
-+ esymself(abcd);
- enext2self(abcd);
-- esymself(abcd); // --> cdab
-- i++;
-- } while (i < 2);
--
-- // Get the tets configuration at ab. Collect maximum 10 tets.
-- subflag = false;
-- abcd = remedge->tt;
-- adjustedgering(abcd, CW);
-- n = 0;
-- abtetlist[n] = abcd;
-- do {
-- // Is the list full?
-- if (n == 10) break;
-- // Stop if a subface appears.
-- tspivot(abtetlist[n], checksh);
-- if (checksh.sh != dummysh) {
-- // ab is either a segment or a facet edge. The latter case is not
-- // handled yet! An edge flip is needed.
-- subflag = true; break; // return false;
-- }
-- // Get the next tet at ab.
-- fnext(abtetlist[n], abtetlist[n + 1]);
-- n++;
-- } while (apex(abtetlist[n]) != apex(abcd));
-+ } // for (i = 0; i < 2; i++)
-
-- remflag = false;
-- key = remedge->key;
-+ return remflag;
-+}
-
-- if (subflag && optflag) {
-- abcd = remedge->tt;
-+///////////////////////////////////////////////////////////////////////////////
-+// //
-+// removetetbysplit() Remove a tet by inserting a point in it. //
-+// //
-+///////////////////////////////////////////////////////////////////////////////
-+
-+bool tetgenmesh::removetetbysplit(badface* remtet)
-+{
-+ list **tetlists, **ceillists;
-+ list **sublists, **subceillists;
-+ list *tetlist, *ceillist, *verlist;
-+ triface abcd, starttet;
-+ face abseg, abcsh;
-+ point newpt, refpt;
-+ REAL maxcosd;
-+ int nmax, n;
-+ int i, j;
-+
-+ // tet 'abcd' is indicated to remove.
-+ abcd = remtet->tt;
-+ abseg.sh = dummysh;
-+ abcsh.sh = dummysh;
-+
-+ // Check if ab or cd is a segment.
-+ tsspivot(&abcd, &abseg);
-+ if (abseg.sh == dummysh) {
- adjustedgering(abcd, CCW);
-- // Try to flip face cda or cdb to improve quality.
-- for (j = 0; j < 2; j++) {
-- if (j == 0) {
-- enext2fnext(abcd, abtetlist[0]); // Goto cda.
-- } else {
-- enextfnext(abcd, abtetlist[0]); // Goto cdb.
-- }
-- fty = categorizeface(abtetlist[0]);
-- if (fty == T23) {
-- // A 2-to-3 flip is possible.
-- sym(abtetlist[0], abtetlist[1]);
-- assert(abtetlist[1].tet != dummytet);
-- n = 2;
-- m = 3;
-- remflag = removefacebyflip23(&key, abtetlist, newtetlist, NULL);
-- } else if (fty == T22) {
-- // A 2-to-2 or 4-to-4 flip is possible.
-- n = 2;
-- newtetlist[0] = abtetlist[0];
-- adjustedgering(newtetlist[0], CW);
-- fnext(newtetlist[0], newtetlist[1]);
-- assert(newtetlist[1].tet != dummytet);
-- // May it is 4-to-4 flip.
-- if (fnext(newtetlist[1], newtetlist[2])) {
-- fnext(newtetlist[2], newtetlist[3]);
-- assert(newtetlist[3].tet != dummytet);
-- n = 4;
-- }
-- m = n;
-- remflag = removeedgebyflip22(&key, n, newtetlist, NULL);
-- }
-- // Has quality been improved?
-- if (remflag) {
-- if (b->verbose > 1) {
-- printf(" Done flip %d-to-%d. Qual: %g -> %g.\n", n, m,
-- acos(remedge->key) / PI * 180.0, acos(key) / PI * 180.0);
-- }
-- // Delete the old tets. Note, flip22() does not create new tets.
-- if (m == 3) {
-- for (i = 0; i < n; i++) {
-- tetrahedrondealloc(abtetlist[i].tet);
-- }
-- }
-- for (i = 0; i < m; i++) {
-- checktet4opt(&(newtetlist[i]), true);
-+ enextfnextself(abcd);
-+ enextself(abcd);
-+ tsspivot(&abcd, &abseg);
-+ }
-+ if (abseg.sh == dummysh) {
-+ abcd = remtet->tt;
-+ adjustedgering(abcd, CCW);
-+ // Check if abc is a subface.
-+ tspivot(abcd, abcsh);
-+ if (abcsh.sh == dummysh) {
-+ // Check if bad is a subface.
-+ fnextself(abcd);
-+ tspivot(abcd, abcsh);
-+ if (abcsh.sh == dummysh) {
-+ // Check if cda is a subface
-+ abcd = remtet->tt;
-+ adjustedgering(abcd, CCW);
-+ enext2fnextself(abcd);
-+ enext2self(abcd);
-+ esymself(abcd);
-+ tspivot(abcd, abcsh);
-+ if (abcsh.sh == dummysh) {
-+ // Check if cdb is a subface
-+ fnextself(abcd);
-+ tspivot(abcd, abcsh);
- }
-- optcount[1]++;
-- return true;
- }
-- } // if (j = 0; j < 2; j++)
-- // Faces are not flipable. Return.
-- return false;
-- }
--
-- // 2 <= n <= 10.
-- if (n == 3) {
-- // There are three tets at ab. Try to do a flip32 at ab.
-- remflag = removeedgebyflip32(&key, abtetlist, newtetlist, NULL);
-- } else if ((n == 4) || (n == 5) || (n == 6)) {
-- // Four tets case. Try to do edge transformation.
-- remflag = removeedgebytranNM(&key,n,abtetlist,newtetlist,NULL,NULL,NULL);
-- } else {
-- if (b->verbose > 1) {
-- printf(" !! Unhandled case: n = %d.\n", n);
- }
- }
-- if (remflag) {
-- optcount[n]++;
-- // Delete the old tets.
-- for (i = 0; i < n; i++) {
-- tetrahedrondealloc(abtetlist[i].tet);
-- }
-- m = (n - 2) * 2; // The numebr of new tets.
-- if (b->verbose > 1) {
-- printf(" Done flip %d-to-%d. ", n, m);
-- if (optflag) {
-- printf("Qual: %g -> %g.", acos(remedge->key) / PI * 180.0,
-- acos(key) / PI * 180.0);
-- }
-- printf("\n");
-- }
-- }
-
-- if (!remflag && (key == remedge->key) && (n < 7)) {
-- // Try to do a combination of flips.
-- n1 = 0;
-- remflag = removeedgebycombNM(&key, n, abtetlist, &n1, bftetlist,
-- newtetlist, NULL);
-- if (remflag) {
-- optcount[9]++;
-- // Delete the old tets.
-- for (i = 0; i < n; i++) {
-- tetrahedrondealloc(abtetlist[i].tet);
-- }
-- for (i = 0; i < n1; i++) {
-- if (!isdead(&(bftetlist[i]))) {
-- tetrahedrondealloc(bftetlist[i].tet);
-+ if (abseg.sh != dummysh) {
-+ if (checkpbcs) {
-+ // Do not split ab if it belongs to any pbcgroup.
-+ i = shellmark(abseg) - 1;
-+ if (idx2segpglist[i + 1] > idx2segpglist[i]) {
-+ return false; // There are pbc facets at ab.
-+ }
-+ }
-+ // Find if segment ab is encroached by an existing point.
-+ refpt = (point) NULL;
-+ checkseg4encroach(&abseg, NULL, &refpt, false);
-+ // Find a point in segment ab.
-+ makepoint(&newpt);
-+ getsplitpoint(sorg(abseg), sdest(abseg), refpt, newpt);
-+ setpointtype(newpt, FREESEGVERTEX);
-+ setpoint2sh(newpt, sencode(abseg));
-+ maxcosd = remtet->key;
-+ if (refpt != (point) NULL) {
-+ // ab is encroached. Force p to be inserted.
-+ maxcosd = -1.0; // 180 degree
-+ }
-+ n = 0;
-+ nmax = 128;
-+ tetlists = new list*[nmax];
-+ ceillists = new list*[nmax];
-+ sublists = new list*[nmax];
-+ subceillists = new list*[nmax];
-+ verlist = new list(sizeof(point *), NULL, 256);
-+ // Form BC(p).
-+ formbowatcavity(newpt, &abseg, NULL, &n, &nmax, sublists, subceillists,
-+ tetlists, ceillists);
-+ // Can local maximal dihedral be reduced by inserting p?
-+ if (trimbowatcavity(newpt, &abseg, n, sublists, subceillists, tetlists,
-+ ceillists, maxcosd)) {
-+ // Inserting p. Ignore any new enc-seg, enc-sub, and bad tets.
-+ bowatinsertsite(newpt, &abseg, n, sublists, subceillists, tetlists,
-+ ceillists, verlist, NULL, false, false, false);
-+ setnewpointsize(newpt, verlist);
-+ // Check if there are new slivers at p.
-+ for (j = 0; j < n; j++) {
-+ tetlist = ceillists[j];
-+ for (i = 0; i < tetlist->len(); i++) {
-+ starttet = * (triface *)(* tetlist)[i];
-+ checktet4sliver(&starttet, false, true);
- }
- }
-- m = ((n1 - 2) * 2 - 1) + (n - 3) * 2; // The number of new tets.
-- if (b->verbose > 1) {
-- printf(" Done flip %d-to-%d (n-1=%d, n1=%d). ", n+n1-2, m, n-1,n1);
-- if (optflag) {
-- printf("Qual: %g -> %g.", acos(remedge->key) / PI * 180.0,
-- acos(key) / PI * 180.0);
-+ refpt != (point) NULL ? smoothcdtsegpt++ : smoothsegpt++;
-+ } else {
-+ // The local quality will not be improved. Do not insert p.
-+ pointdealloc(newpt);
-+ newpt = (point) NULL;
-+ refpt != (point) NULL ? unsmoothcdtsegpt++ : unsmoothsegpt++;
-+ }
-+ // Free the memory allocated in formbowatcavity().
-+ releasebowatcavity(&abseg, n, sublists, subceillists, tetlists, ceillists);
-+ delete [] tetlists;
-+ delete [] ceillists;
-+ delete [] sublists;
-+ delete [] subceillists;
-+ delete verlist;
-+ } else if (abcsh.sh != dummysh) {
-+ if (checkpbcs) {
-+ // Do not split abc if it belongs to a pbcgroup.
-+ if (shellpbcgroup(abcsh) >= 0) {
-+ return false; // It is on a pbc facet.
-+ }
-+ }
-+ // Insert the midpoint of ab which is on a facet.
-+ makepoint(&newpt);
-+ getsplitpoint(org(abcd), dest(abcd), NULL, newpt);
-+ setpointtype(newpt, FREESUBVERTEX);
-+ setpoint2sh(newpt, sencode(abcsh));
-+ n = 2;
-+ tetlists = new list*[2];
-+ ceillists = new list*[2];
-+ sublists = new list*[2];
-+ subceillists = new list*[2];
-+ verlist = new list(sizeof(point *), NULL, 256);
-+ // Form BC(p).
-+ formbowatcavity(newpt, NULL, &abcsh, &n, NULL, sublists, subceillists,
-+ tetlists, ceillists);
-+ // Can local maximal dihedral be reduced by inserting p?
-+ if (trimbowatcavity(newpt, NULL, n, sublists, subceillists, tetlists,
-+ ceillists, remtet->key)) {
-+ // Inserting p. Ignore any new enc-seg, enc-sub, and bad tets.
-+ bowatinsertsite(newpt, NULL, n, sublists, subceillists, tetlists,
-+ ceillists, verlist, NULL, false, false, false);
-+ setnewpointsize(newpt, verlist);
-+ // Check if there are new slivers at p.
-+ for (j = 0; j < n; j++) {
-+ tetlist = ceillists[j];
-+ for (i = 0; i < tetlist->len(); i++) {
-+ starttet = * (triface *)(* tetlist)[i];
-+ checktet4sliver(&starttet, false, true);
- }
-- printf("\n");
- }
-+ smoothsubpt++;
-+ } else {
-+ // The local quality will not be improved. Do not insert p.
-+ pointdealloc(newpt);
-+ newpt = (point) NULL;
-+ unsmoothsubpt++;
- }
-- }
--
-- if (remflag) {
-- // edge is removed. Test new tets for further optimization.
-- for (i = 0; i < m; i++) {
-- if (optflag) {
-- checktet4opt(&(newtetlist[i]), true);
-- } else {
-- checktet4ill(&(newtetlist[i]), true);
-+ // Free the memory allocated in formbowatcavity().
-+ releasebowatcavity(NULL, n, sublists, subceillists, tetlists, ceillists);
-+ delete [] tetlists;
-+ delete [] ceillists;
-+ delete [] sublists;
-+ delete [] subceillists;
-+ delete verlist;
-+ } else {
-+ // Insert the midpoint of the edge having largest dihedral angle.
-+ abcd = remtet->tt;
-+ makepoint(&newpt);
-+ getsplitpoint(org(abcd), dest(abcd), NULL, newpt);
-+ setpointtype(newpt, FREEVOLVERTEX);
-+ // Form BC(p).
-+ tetlist = new list(sizeof(triface), NULL, 1024);
-+ ceillist = new list(sizeof(triface), NULL, 1024);
-+ verlist = new list(sizeof(point *), NULL, 256);
-+ starttet = abcd;
-+ infect(starttet);
-+ tetlist->append(&starttet);
-+ formbowatcavityquad(newpt, tetlist, ceillist);
-+ // Can local maximal dihedral be reduced by inserting p?
-+ if (trimbowatcavity(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist,
-+ remtet->key)) {
-+ // Inserting p. Ignore any new enc-seg, enc-sub, and bad tets.
-+ bowatinsertsite(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist, verlist,
-+ NULL, false, false, false);
-+ setnewpointsize(newpt, verlist);
-+ // Check if there are new slivers at p.
-+ for (i = 0; i < ceillist->len(); i++) {
-+ starttet = * (triface *)(* ceillist)[i];
-+ checktet4sliver(&starttet, false, true);
- }
-+ smoothvolpt++;
-+ } else {
-+ // The local quality will not be improved. Do not insert p.
-+ pointdealloc(newpt);
-+ newpt = (point) NULL;
-+ // Uninfect tets of BC(p).
-+ for (i = 0; i < tetlist->len(); i++) {
-+ starttet = * (triface *)(* tetlist)[i];
-+ uninfect(starttet);
-+ }
-+ unsmoothvolpt++;
- }
-+ delete tetlist;
-+ delete ceillist;
-+ delete verlist;
- }
-
-- return remflag;
-+ return newpt != (point) NULL;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// smoothsliver() Remove a sliver by smoothing a vertex of it. //
--// //
--// The 'slivtet' represents a sliver abcd, and ab is the current edge which //
--// has a large dihedral angle (close to 180 degree). //
-+// tallslivers() Queue all the slivers in the mesh. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--bool tetgenmesh::smoothsliver(badface* remedge, list *starlist)
-+void tetgenmesh::tallslivers(bool chkill)
- {
-- triface checktet;
-- point smthpt;
-- bool smthed;
-- int idx, i, j;
--
-- // Find a Steiner volume point and smooth it.
-- smthed = false;
-- for (i = 0; i < 4 && !smthed; i++) {
-- smthpt = (point) remedge->tt.tet[4 + i];
-- // Is it a volume point?
-- if (pointtype(smthpt) == FREEVOLVERTEX) {
-- // Is it a Steiner point?
-- idx = pointmark(smthpt) - in->firstnumber;
-- if (!(idx < in->numberofpoints)) {
-- // Smooth a Steiner volume point.
-- starlist->append(&(remedge->tt.tet));
-- formstarpolyhedron(smthpt, starlist, NULL, false);
-- smthed = smoothpoint(smthpt,NULL,NULL,starlist,false,&remedge->key);
-- // If it is smoothed. Queue new bad tets.
-- if (smthed) {
-- for (j = 0; j < starlist->len(); j++) {
-- checktet = * (triface *)(* starlist)[j];
-- checktet4opt(&checktet, true);
-- }
-- }
-- starlist->clear();
-- }
-- }
-- }
-+ triface tetloop;
-
-- /* Omit to smooth segment points. This may cause infinite loop.
-- if (smthed) {
-- return true;
-- }
-- face abseg, nextseg, prevseg;
-- point pt[2];
-- // Check if ab is a segment.
-- tsspivot(slivtet, &abseg);
-- if (abseg.sh == dummysh) {
-- // ab is not a segment. Check if a or b is a Steiner segment point.
-- for (i = 0; i < 2 && !smthed; i++) {
-- smthpt = (i == 0 ? org(*slivtet) : dest(*slivtet));
-- if (pointtype(smthpt) == FREESEGVERTEX) {
-- // Is it a Steiner point?
-- idx = pointmark(smthpt) - in->firstnumber;
-- if (!(idx < in->numberofpoints)) {
-- // Smooth a Steiner segment point. Get the segment.
-- sdecode(point2sh(smthpt), nextseg);
-- locateseg(smthpt, &nextseg);
-- assert(sorg(nextseg) == smthpt);
-- pt[0] = sdest(nextseg);
-- senext2(nextseg, prevseg);
-- spivotself(prevseg);
-- prevseg.shver = 0;
-- if (sorg(prevseg) == smthpt) sesymself(prevseg);
-- assert(sdest(prevseg) == smthpt);
-- pt[1] = sorg(prevseg);
-- starlist->append(slivtet);
-- formstarpolyhedron(smthpt, starlist, NULL, true);
-- smthed = smoothpoint(smthpt, pt[0], pt[1], starlist, false);
-- // If it is smoothed. Check if the tet is still a sliver.
-- if (smthed) checktet4opt(slivtet, true);
-- starlist->clear();
-- }
-+ tetrahedrons->traversalinit();
-+ tetloop.tet = tetrahedrontraverse();
-+ while (tetloop.tet != (tetrahedron *) NULL) {
-+ if (chkill) {
-+ if (!checktet4sliver(&tetloop, true, true)) {
-+ checktet4ill(&tetloop, true);
- }
-+ } else {
-+ checktet4sliver(&tetloop, false, true);
- }
-+ tetloop.tet = tetrahedrontraverse();
- }
-- */
--
-- return smthed;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// splitsliver() Remove a sliver by inserting a point. //
--// //
--// The 'remedge->tt' represents a sliver abcd, ab is the current edge which //
--// has a large dihedral angle (close to 180 degree). //
-+// repairmesh() Remove illegal tets in the mesh. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--bool tetgenmesh::splitsliver(badface *remedge, list *tetlist, list *ceillist)
-+void tetgenmesh::repairmesh()
- {
-- triface starttet;
-- face checkseg;
-- point newpt, pt[4];
-- bool remflag;
-- int i;
-+ badface *remtet, *lastunrementry;
-
-- starttet = remedge->tt;
--
-- // Check if cd is a segment.
-- adjustedgering(starttet, CCW);
-- enextfnextself(starttet);
-- enextself(starttet);
-- tsspivot(&starttet, &checkseg);
-- if (b->nobisect == 0) {
-- if (checkseg.sh != dummysh) {
-- // cd is a segment. The seg will be split. BUT do not flip! Due to the
-- // exact predicates, lot of slivers ay be rsulted and hard to remove.
-- checkseg.shver = 0;
-- pt[0] = sorg(checkseg);
-- pt[1] = sdest(checkseg);
-- makepoint(&newpt);
-- getsplitpoint(pt[0], pt[1], NULL, newpt);
-- setpointtype(newpt, FREESEGVERTEX);
-- setpoint2sh(newpt, sencode(checkseg));
-- // Insert p, this should always success.
-- sstpivot(&checkseg, &starttet);
-- splittetedge(newpt, &starttet, NULL);
-- // Collect the new tets connecting at p.
-- sstpivot(&checkseg, &starttet);
-- ceillist->append(&starttet);
-- formstarpolyhedron(newpt, ceillist, NULL, true);
-- setnewpointsize(newpt, pt[0], NULL);
-- if (steinerleft > 0) steinerleft--;
-- // Smooth p.
-- smoothpoint(newpt, pt[0], pt[1], ceillist, false, NULL);
-- // Queue new slivers.
-- for (i = 0; i < ceillist->len(); i++) {
-- starttet = * (triface *)(* ceillist)[i];
-- checktet4opt(&starttet, true);
-- }
-- ceillist->clear();
-- return true;
-- }
-+ if (!b->quiet) {
-+ printf("Repairing mesh.\n");
- }
-
-- // Get the four corners.
-- for (i = 0; i < 4; i++) {
-- pt[i] = (point) starttet.tet[4 + i];
-- }
-- // Create the new point p (at the circumcenter of t).
-- makepoint(&newpt);
-- for (i = 0; i < 3; i++) {
-- newpt[i] = 0.25 * (pt[0][i] + pt[1][i] + pt[2][i] + pt[3][i]);
-- }
-- setpointtype(newpt, FREEVOLVERTEX);
-+ // Initialize the pool of bad tets
-+ badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0);
-+ lastunrementry = (badface *) NULL;
-+ striptetcount = fliptetcount = unimprovecount = 0l;
-
-- // Form the Bowyer-Watson cavity of p.
-- remflag = false;
-- infect(starttet);
-- tetlist->append(&starttet);
-- formbowatcavityquad(newpt, tetlist, ceillist);
-- if (trimbowatcavity(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist, -1.0)) {
-- // Smooth p.
-- if (smoothpoint( newpt, NULL, NULL, ceillist, false, &remedge->key)) {
-- // Insert p.
-- bowatinsertsite(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist, NULL,
-- NULL, false, false, false);
-- setnewpointsize(newpt, pt[0], NULL);
-- if (steinerleft > 0) steinerleft--;
-- // Queue new slivers.
-- for (i = 0; i < ceillist->len(); i++) {
-- starttet = * (triface *)(* ceillist)[i];
-- checktet4opt(&starttet, true);
-+ // Looking for illegal tets.
-+ tallslivers(true);
-+
-+ // Loop until pool 'badtetrahedrons' is empty.
-+ while (badtetrahedrons->items > 0) {
-+ badtetrahedrons->traversalinit();
-+ remtet = badfacetraverse(badtetrahedrons);
-+ while (remtet != (badface *) NULL) {
-+ // Make sure that the tet is still the same one when it was tested.
-+ // Subsequent transformations may have made it a different tet.
-+ if (!isdead(&remtet->tt) && org(remtet->tt) == remtet->forg &&
-+ dest(remtet->tt) == remtet->fdest &&
-+ apex(remtet->tt) == remtet->fapex &&
-+ oppo(remtet->tt) == remtet->foppo) {
-+ if (b->verbose > 1) {
-+ printf(" Repair tet (%d, %d, %d, %d).\n", pointmark(remtet->forg),
-+ pointmark(remtet->fdest), pointmark(remtet->fapex),
-+ pointmark(remtet->foppo));
-+ }
-+ if (!removetetbyrecon(remtet, true)) {
-+ // An unremoveable tet. Check if it forms a loop.
-+ if (lastunrementry != (badface *) NULL) {
-+ if (remtet == lastunrementry) break;
-+ } else {
-+ // Remember this tet as a breakpoint.
-+ lastunrementry = remtet;
-+ }
-+ } else {
-+ // Clear the breakpoint.
-+ lastunrementry = (badface *) NULL;
-+ // Remove the entry from the queue.
-+ badfacedealloc(badtetrahedrons, remtet);
-+ }
-+ } else {
-+ // Remove the entry from the queue.
-+ badfacedealloc(badtetrahedrons, remtet);
- }
-- remflag = true;
-- } // if (smoothpoint)
-- } // if (trimbowatcavity)
--
-- if (!remflag) {
-- // p is rejected for BC(p) is not valid.
-- pointdealloc(newpt);
-- // Uninfect tets of BC(p).
-- for (i = 0; i < tetlist->len(); i++) {
-- starttet = * (triface *)(* tetlist)[i];
-- uninfect(starttet);
-+ remtet = badfacetraverse(badtetrahedrons);
- }
-+ // Stop if the above loop was out by force.
-+ if (remtet != (badface *) NULL) break;
- }
-- tetlist->clear();
-- ceillist->clear();
-
-- return remflag;
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
--// tallslivers() Queue all the slivers in the mesh. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--void tetgenmesh::tallslivers(bool optflag)
--{
-- triface tetloop;
--
-- tetrahedrons->traversalinit();
-- tetloop.tet = tetrahedrontraverse();
-- while (tetloop.tet != (tetrahedron *) NULL) {
-- if (optflag) {
-- checktet4opt(&tetloop, true);
-- } else {
-- checktet4ill(&tetloop, true);
-+ if (b->verbose) {
-+ if (striptetcount > 0l) {
-+ printf(" %ld tets are stripped off.\n", striptetcount);
-+ }
-+ if (fliptetcount > 0l) {
-+ printf(" %ld tets are flipped away.\n", fliptetcount);
-+ }
-+ if (badtetrahedrons->items > 0l) {
-+ printf(" %ld tets are unremoveable.\n", badtetrahedrons->items);
- }
-- tetloop.tet = tetrahedrontraverse();
- }
-+
-+ delete badtetrahedrons;
-+ badtetrahedrons = (memorypool *) NULL;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// optimizemesh() Improve mesh quality by mesh optimizations. //
--// //
--// Available mesh optimizing operations are: (1) multiple edge flips (3-to-2,//
--// 4-to-4, 5-to-6, etc), (2) free vertex deletion, (3) new vertex insertion. //
--// (1) is mandatory, while (2) and (3) are optionally. //
--// //
--// The variable 'b->optlevel' (set after '-s') determines the use of these //
--// operations. If it is: 0, do no optimization; 1, only do (1) operation; 2, //
--// do (1) and (2) operations; 3, do all operations. Deault, b->optlvel = 2. //
-+// smoothmesh() Smooth the mesh. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--void tetgenmesh::optimizemesh(bool optflag)
-+void tetgenmesh::smoothmesh()
- {
-- list *splittetlist, *tetlist, *ceillist;
-- badface *remtet, *lastentry;
-- REAL maxdihed, objdihed, curdihed;
-- long oldnum;
-- int iter, i;
-+ badface *remtet, *lastunrementry;
-
- if (!b->quiet) {
-- if (optflag) {
-- printf("Optimizing mesh.\n");
-- } else {
-- printf("Repairing mesh.\n");
-- }
-- }
--
--#ifdef SELF_CHECK
-- if (optflag && (b->verbose)) {
-- printf(" level = %d.\n", b->optlevel);
-+ printf("Smoothing mesh.\n");
- }
--#endif
-
-- // Initialize the pool of bad tets.
-+ // Initialize the pool of bad tets
- badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0);
-- if (optflag) {
-- cosmaxdihed = cos(b->maxdihedral * PI / 180.0);
-- cosmindihed = cos(b->mindihedral * PI / 180.0);
-- // The radian of the maximum dihedral angle.
-- maxdihed = b->maxdihedral / 180.0 * PI;
-- // A sliver has an angle large than 'objdihed' will be split.
-- objdihed = b->maxdihedral + 5.0;
-- if (objdihed < 170.0) objdihed = 170.0;
-- objdihed = objdihed / 180.0 * PI;
-- }
-- // Looking for non-optimal tets.
-- tallslivers(optflag);
--
-- optcount[0] = 0l; // tet strip count.
-- optcount[1] = 0l; // face (2-3) and edge (2-2) flip count.
-- optcount[3] = optcount[4] = optcount[5] = optcount[6] = 0l; // edge flips.
-- optcount[9] = 0l; // combined flip count.
-+ cosmaxdihed = cos(b->maxdihedral * PI / 180.0);
-+ cosmindihed = 1.0;
-+ striptetcount = fliptetcount = unimprovecount = 0l;
-+ smoothcdtsegpt = smoothsegpt = smoothsubpt = smoothvolpt = 0l;
-+ unsmoothcdtsegpt = unsmoothsegpt = unsmoothsubpt = unsmoothvolpt = 0l;
-
-- // Perform edge flip to improve quality.
-- lastentry = (badface *) NULL;
-+ // Looking for bad tets.
-+ tallslivers(false);
-+
-+ lastunrementry = (badface *) NULL;
- // Loop until pool 'badtetrahedrons' is empty.
- while (badtetrahedrons->items > 0) {
- badtetrahedrons->traversalinit();
-@@ -30682,22 +28042,21 @@
- apex(remtet->tt) == remtet->fapex &&
- oppo(remtet->tt) == remtet->foppo) {
- if (b->verbose > 1) {
-- printf(" Repair tet (%d, %d, %d, %d) %g (degree).\n",
-- pointmark(remtet->forg), pointmark(remtet->fdest),
-- pointmark(remtet->fapex), pointmark(remtet->foppo),
-- acos(remtet->key) / PI * 180.0);
-+ printf(" Repair tet (%d, %d, %d, %d).\n", pointmark(remtet->forg),
-+ pointmark(remtet->fdest), pointmark(remtet->fapex),
-+ pointmark(remtet->foppo));
- }
-- if (!removeedge(remtet, optflag)) {
-+ if (!removetetbyrecon(remtet, false)) {
- // An unremoveable tet. Check if it forms a loop.
-- if (lastentry != (badface *) NULL) {
-- if (remtet == lastentry) break;
-+ if (lastunrementry != (badface *) NULL) {
-+ if (remtet == lastunrementry) break;
- } else {
- // Remember this tet as a breakpoint.
-- lastentry = remtet;
-+ lastunrementry = remtet;
- }
- } else {
- // Clear the breakpoint.
-- lastentry = (badface *) NULL;
-+ lastunrementry = (badface *) NULL;
- // Remove the entry from the queue.
- badfacedealloc(badtetrahedrons, remtet);
- }
-@@ -30712,97 +28071,71 @@
- }
-
- if (b->verbose) {
-- if (optcount[0] > 0l) {
-- printf(" %ld tets are peeled off.\n", optcount[0]);
-+ if (striptetcount > 0l) {
-+ printf(" %ld tets are stripped off.\n", striptetcount);
- }
-- if (optcount[1] > 0l) {
-- printf(" %ld faces are flipped.\n", optcount[1]);
-+ if (fliptetcount > 0l) {
-+ printf(" %ld tets are flipped away.\n", fliptetcount);
- }
-- if (optcount[3] + optcount[4] + optcount[5] + optcount[6] +
-- optcount[9] > 0l) {
-- printf(" %ld edges are flipped.\n", optcount[3] + optcount[4] +
-- optcount[5] + optcount[6] + optcount[9]);
-- }
-- // if (badtetrahedrons->items > 0l) {
-- // printf(" %ld edges remain.\n", badtetrahedrons->items);
-- // }
- }
-
-- if ((badtetrahedrons->items > 0l) && optflag && (b->optlevel > 2)) {
-- splittetlist = new list(sizeof(badface), NULL, 256);
-- tetlist = new list(sizeof(triface), NULL, 256);
-- ceillist = new list(sizeof(triface), NULL, 256);
-- oldnum = points->items;
-- smoothsegverts = smoothvolverts = 0;
-- optcount[1] = 0l;
-- optcount[3] = optcount[4] = optcount[5] = optcount[6] = 0l; // edge flips.
-- optcount[9] = 0l; // combined flip count.
-- iter = 0;
--
-- do {
-- // Form a list of slivers to be split and clean the pool.
-- badtetrahedrons->traversalinit();
-- remtet = badfacetraverse(badtetrahedrons);
-- while (remtet != (badface *) NULL) {
-- splittetlist->append(remtet);
-- // Remove the entry from the queue.
-- badfacedealloc(badtetrahedrons, remtet);
-- remtet = badfacetraverse(badtetrahedrons);
-- }
-- for (i = 0; i < splittetlist->len(); i++) {
-- remtet = (badface *)(* splittetlist)[i];
-- // Make sure that the tet is still the same one when it was tested.
-- // Subsequent transformations may have made it a different tet.
-- if (!isdead(&remtet->tt) && org(remtet->tt) == remtet->forg &&
-- dest(remtet->tt) == remtet->fdest &&
-- apex(remtet->tt) == remtet->fapex &&
-- oppo(remtet->tt) == remtet->foppo) {
-- // The sliver may get smoothed due to a neighboring tet.
-- curdihed = facedihedral(remtet->forg, remtet->fdest, remtet->fapex,
-- remtet->foppo);
-- // The dihedral angle of a tet must less than PI, correct it.
-- if (curdihed > PI) curdihed = 2 * PI - curdihed;
-- // Is it a large angle?
-- if (curdihed > objdihed) {
-- remtet->key = cos(curdihed);
-- if (b->verbose > 1) {
-- printf(" Get sliver (%d, %d, %d, %d) %g (degree).\n",
-- pointmark(remtet->forg), pointmark(remtet->fdest),
-- pointmark(remtet->fapex), pointmark(remtet->foppo),
-- acos(remtet->key) / PI * 180.0);
-- }
-- if (!removeedge(remtet, optflag)) {
-- if (!smoothsliver(remtet, tetlist)) {
-- splitsliver(remtet, tetlist, ceillist);
-- }
-+ lastunrementry = (badface *) NULL;
-+ // Loop until pool 'badtetrahedrons' is empty.
-+ while (badtetrahedrons->items > 0) {
-+ badtetrahedrons->traversalinit();
-+ remtet = badfacetraverse(badtetrahedrons);
-+ while (remtet != (badface *) NULL) {
-+ // Make sure that the tet is still the same one when it was tested.
-+ // Subsequent transformations may have made it a different tet.
-+ if (!isdead(&remtet->tt) && org(remtet->tt) == remtet->forg &&
-+ dest(remtet->tt) == remtet->fdest &&
-+ apex(remtet->tt) == remtet->fapex &&
-+ oppo(remtet->tt) == remtet->foppo) {
-+ if (b->verbose > 1) {
-+ printf(" Repair tet (%d, %d, %d, %d).\n", pointmark(remtet->forg),
-+ pointmark(remtet->fdest), pointmark(remtet->fapex),
-+ pointmark(remtet->foppo));
-+ }
-+ if (!removetetbyrecon(remtet, false)) {
-+ // An unremoveable tet. Find if a segment which can be split.
-+ if (!removetetbysplit(remtet)) {
-+ // An unremoveable tet. Check if it forms a loop.
-+ if (lastunrementry != (badface *) NULL) {
-+ if (remtet == lastunrementry) break;
-+ } else {
-+ // Remember this tet as a breakpoint.
-+ lastunrementry = remtet;
- }
-+ } else {
-+ // Clear the breakpoint.
-+ lastunrementry = (badface *) NULL;
-+ // Remove the entry from the queue.
-+ badfacedealloc(badtetrahedrons, remtet);
- }
-+ } else {
-+ // Clear the breakpoint.
-+ lastunrementry = (badface *) NULL;
-+ // Remove the entry from the queue.
-+ badfacedealloc(badtetrahedrons, remtet);
- }
-+ } else {
-+ // Remove the entry from the queue.
-+ badfacedealloc(badtetrahedrons, remtet);
- }
-- iter++;
-- } while ((badtetrahedrons->items > 0l) && (iter < b->optpasses));
--
-- if (b->verbose) {
-- printf(" %d passes.\n", iter);
-- if ((points->items - oldnum) > 0l) {
-- printf(" %ld points are inserted (%d on segment).\n",
-- points->items - oldnum, smoothsegverts);
-- }
-- if (optcount[1] > 0l) {
-- printf(" %ld faces are flipped.\n", optcount[1]);
-- }
-- if (optcount[3] + optcount[4] + optcount[5] + optcount[6] +
-- optcount[9] > 0l) {
-- printf(" %ld edges are flipped.\n", optcount[3] + optcount[4] +
-- optcount[5] + optcount[6] + optcount[9]);
-- }
-- // if (badtetrahedrons->items > 0l) {
-- // printf(" %ld edges remain.\n", badtetrahedrons->items);
-- // }
-+ remtet = badfacetraverse(badtetrahedrons);
-+ }
-+ // Stop if the above loop was out by force.
-+ if (remtet != (badface *) NULL) break;
-+ }
-+
-+ if (b->verbose) {
-+ if ((smoothcdtsegpt + smoothsegpt + smoothsubpt + smoothvolpt) > 0l) {
-+ printf(" %ld smooth points.\n",
-+ smoothcdtsegpt + smoothsegpt + smoothsubpt + smoothvolpt);
-+ }
-+ if (badtetrahedrons->items > 0l) {
-+ printf(" %ld remaining tets.\n", badtetrahedrons->items);
- }
-- delete tetlist;
-- delete ceillist;
-- delete splittetlist;
- }
-
- delete badtetrahedrons;
-@@ -30810,7 +28143,7 @@
- }
-
- //
--// End of mesh optimization routines
-+// End of mesh smoothing routines
- //
-
- //
-@@ -30834,13 +28167,11 @@
- REAL x, y, z;
- int coordindex;
- int attribindex;
-- int mtrindex;
- int i, j;
-
- // Read the points.
- coordindex = 0;
- attribindex = 0;
-- mtrindex = 0;
- for (i = 0; i < in->numberofpoints; i++) {
- makepoint(&pointloop);
- // Read the point coordinates.
-@@ -30851,10 +28182,6 @@
- for (j = 0; j < in->numberofpointattributes; j++) {
- pointloop[3 + j] = in->pointattributelist[attribindex++];
- }
-- // Read the point metric tensor.
-- for (j = 0; j < in->numberofpointmtrs; j++) {
-- pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++];
-- }
- // Determine the smallest and largests x, y and z coordinates.
- if (i == 0) {
- xmin = xmax = x;
-@@ -30870,6 +28197,7 @@
- }
- }
- // 'longest' is the largest possible edge length formed by input vertices.
-+ // It is used as the measure to distinguish two identical points.
- x = xmax - xmin;
- y = ymax - ymin;
- z = zmax - zmin;
-@@ -30878,7 +28206,6 @@
- printf("Error: The point set is trivial.\n");
- terminatetetgen(1);
- }
-- // Two identical points are distinguished by 'lengthlimit'.
- lengthlimit = longest * b->epsilon * 1e+2;
- }
-
-@@ -30969,6 +28296,15 @@
- int hitbdry, ptmark;
- int i, j;
-
-+ // The 'edgeindex' (from 0 to 5) is list as follows:
-+ // 0 - (v0, v1), 1 - (v1, v2), 2 - (v2, v0)
-+ // 3 - (v3, v0), 4 - (v3, v1), 5 - (v3, v2)
-+ // Define an edgeindex map: (loc, ver)->edgeindex.
-+ int edgeindexmap[4][6] = {{0, 0, 1, 1, 2, 2},
-+ {3, 3, 4, 4, 0, 0},
-+ {4, 4, 5, 5, 1, 1},
-+ {5, 5, 3, 3, 2, 2}};
-+
- if (!b->quiet) {
- printf("Adding vertices for second-order tetrahedra.\n");
- }
-@@ -31011,21 +28347,44 @@
- while (tetloop.tet != (tetrahedron *) NULL) {
- // Get the list of extra nodes.
- extralist = (point *) tetloop.tet[highorderindex];
-- worktet.tet = tetloop.tet;
- for (i = 0; i < 6; i++) {
- if (extralist[i] == (point) NULL) {
- // Operate on this edge.
-- worktet.loc = edge2locver[i][0];
-- worktet.ver = edge2locver[i][1];
-+ worktet = tetloop;
-+ worktet.loc = 0; worktet.ver = 0;
-+ // Get the correct edge in 'worktet'.
-+ switch(i) {
-+ case 0: // (v0, v1)
-+ break;
-+ case 1: // (v1, v2)
-+ enextself(worktet);
-+ break;
-+ case 2: // (v2, v0)
-+ enext2self(worktet);
-+ break;
-+ case 3: // (v3, v0)
-+ fnextself(worktet);
-+ enext2self(worktet);
-+ break;
-+ case 4: // (v3, v1)
-+ enextself(worktet);
-+ fnextself(worktet);
-+ enext2self(worktet);
-+ break;
-+ case 5: // (v3, v2)
-+ enext2self(worktet);
-+ fnextself(worktet);
-+ enext2self(worktet);
-+ }
- // Create a new node on this edge.
- torg = org(worktet);
- tdest = dest(worktet);
- // Create a new node in the middle of the edge.
- newpoint = (point) points->alloc();
- // Interpolate its attributes.
-- for (j = 0; j < 3 + in->numberofpointattributes; j++) {
-- newpoint[j] = 0.5 * (torg[j] + tdest[j]);
-- }
-+ // for (j = 0; j < 3 + in->numberofpointattributes; j++) {
-+ // newpoint[j] = 0.5 * (torg[j] + tdest[j]);
-+ // }
- ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1);
- setpointmark(newpoint, ptmark);
- // Add this node to its extra node list.
-@@ -31040,7 +28399,7 @@
- // Get the extra node list of 'spintet'.
- adjextralist = (point *) spintet.tet[highorderindex];
- // Find the index of its extra node list.
-- j = locver2edge[spintet.loc][spintet.ver];
-+ j = edgeindexmap[spintet.loc][spintet.ver];
- // Only set 'newpoint' into 'adjextralist' if it is a NULL.
- // Because two faces can belong to the same tetrahedron.
- if (adjextralist[j] == (point) NULL) {
-@@ -31098,7 +28457,8 @@
- }
- }
-
-- nextras = in->numberofpointattributes;
-+ // nextras = in->numberofpointattributes;
-+ nextras = 0; // After version 1.4.0, don't output point attributes.
- bmark = !b->nobound && in->pointmarkerlist;
-
- // Avoid compile warnings.
-@@ -31282,11 +28642,8 @@
- {
- FILE *outfile;
- char outmtrfilename[FILENAMESIZE];
-- list *tetlist, *ptlist;
-- triface tetloop;
-- point ptloop, neipt;
-- REAL lave, len; // lmin, lmax,
-- int mtrindex;
-+ point pointloop;
-+ int nextras, attribindex;
- int i;
-
- if (out == (tetgenio *) NULL) {
-@@ -31304,103 +28661,53 @@
-
- // Avoid compile warnings.
- outfile = (FILE *) NULL;
-- mtrindex = 0;
-+ attribindex = 0;
-
-+ nextras = 0;
-+ if (b->bgmesh) {
-+ nextras = bgm->in->numberofpointattributes;
-+ } else if (b->quality) {
-+ nextras = 1;
-+ }
- if (out == (tetgenio *) NULL) {
- outfile = fopen(outmtrfilename, "w");
- if (outfile == (FILE *) NULL) {
- printf("File I/O Error: Cannot create file %s.\n", outmtrfilename);
- terminatetetgen(1);
- }
-- // Number of points, number of point metrices,
-- // fprintf(outfile, "%ld %d\n", points->items, sizeoftensor + 3);
-- fprintf(outfile, "%ld %d\n", points->items, 1);
-- } else {
-- // Allocate space for 'pointmtrlist' if necessary;
-- // out->pointmtrlist = new REAL[points->items * (sizeoftensor + 3)];
-- out->pointmtrlist = new REAL[points->items];
-- if (out->pointmtrlist == (REAL *) NULL) {
-- printf("Error: Out of memory.\n");
-- terminatetetgen(1);
-+ // Number of points, number of point attributes,
-+ fprintf(outfile, "%ld %d\n", points->items, nextras);
-+ } else {
-+ // Allocate space for 'pointattributelist' if necessary;
-+ if (nextras > 0) {
-+ out->pointattributelist = new REAL[points->items * nextras];
-+ if (out->pointattributelist == (REAL *) NULL) {
-+ printf("Error: Out of memory.\n");
-+ terminatetetgen(1);
-+ }
- }
-- out->numberofpointmtrs = 1; // (sizeoftensor + 3);
-- mtrindex = 0;
-+ out->numberofpointattributes = nextras;
-+ attribindex = 0;
- }
-
-- // Initialize the point2tet field of each point.
-- points->traversalinit();
-- ptloop = pointtraverse();
-- while (ptloop != (point) NULL) {
-- setpoint2tet(ptloop, (tetrahedron) NULL);
-- ptloop = pointtraverse();
-- }
-- // Create the point-to-tet map.
-- tetrahedrons->traversalinit();
-- tetloop.tet = tetrahedrontraverse();
-- while (tetloop.tet != (tetrahedron *) NULL) {
-- for (i = 0; i < 4; i++) {
-- ptloop = (point) tetloop.tet[4 + i];
-- setpoint2tet(ptloop, encode(tetloop));
-- }
-- tetloop.tet = tetrahedrontraverse();
-- }
--
-- tetlist = new list(sizeof(triface), NULL, 256);
-- ptlist = new list(sizeof(point *), NULL, 256);
--
- points->traversalinit();
-- ptloop = pointtraverse();
-- while (ptloop != (point) NULL) {
-- decode(point2tet(ptloop), tetloop);
-- if (!isdead(&tetloop)) {
-- // Form the star of p.
-- tetlist->append(&tetloop);
-- formstarpolyhedron(ptloop, tetlist, ptlist, true);
-- // lmin = longest;
-- // lmax = 0.0;
-- lave = 0.0;
-- for (i = 0; i < ptlist->len(); i++) {
-- neipt = * (point *)(* ptlist)[i];
-- len = distance(ptloop, neipt);
-- // lmin = lmin < len ? lmin : len;
-- // lmax = lmax > len ? lmax : len;
-- lave += len;
-- }
-- lave /= ptlist->len();
-- }
-+ pointloop = pointtraverse();
-+ while (pointloop != (point) NULL) {
- if (out == (tetgenio *) NULL) {
-- // for (i = 0; i < sizeoftensor; i++) {
-- // fprintf(outfile, "%-16.8e ", ptloop[pointmtrindex + i]);
-- // }
-- if (ptlist->len() > 0) {
-- // fprintf(outfile, "%-16.8e %-16.8e %-16.8e", lmin, lmax, lave);
-- fprintf(outfile, "%-16.8e ", lave);
-- } else {
-- fprintf(outfile, "0.0 "); // fprintf(outfile, "0.0 0.0 0.0");
-+ for (i = 0; i < nextras; i++) {
-+ // Write an attribute.
-+ fprintf(outfile, "%-22.17e ", pointloop[3 + i]);
- }
- fprintf(outfile, "\n");
- } else {
-- // for (i = 0; i < sizeoftensor; i++) {
-- // out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex + i];
-- // }
-- if (ptlist->len() > 0) {
-- // out->pointmtrlist[mtrindex++] = lmin;
-- // out->pointmtrlist[mtrindex++] = lmax;
-- out->pointmtrlist[mtrindex++] = lave;
-- } else {
-- // out->pointmtrlist[mtrindex++] = 0.0;
-- // out->pointmtrlist[mtrindex++] = 0.0;
-- out->pointmtrlist[mtrindex++] = 0.0;
-+ for (i = 0; i < nextras; i++) {
-+ // Output an attribute.
-+ out->pointattributelist[attribindex++] = pointloop[3 + i];
- }
- }
-- tetlist->clear();
-- ptlist->clear();
-- ptloop = pointtraverse();
-+ pointloop = pointtraverse();
- }
-
-- delete tetlist;
-- delete ptlist;
--
- if (out == (tetgenio *) NULL) {
- fprintf(outfile, "# Generated by %s\n", b->commandline);
- fclose(outfile);
-@@ -31567,7 +28874,6 @@
- char facefilename[FILENAMESIZE];
- int *elist;
- int *emlist;
-- int neigh1, neigh2;
- int index;
- triface tface, tsymface;
- face checkmark;
-@@ -31621,14 +28927,6 @@
- terminatetetgen(1);
- }
- }
-- if (b->neighout > 1) {
-- // '-nn' switch.
-- out->adjtetlist = new int[subfaces->items * 2];
-- if (out->adjtetlist == (int *) NULL) {
-- printf("Error: Out of memory.\n");
-- terminatetetgen(1);
-- }
-- }
- out->numberoftrifaces = faces;
- elist = out->trifacelist;
- emlist = out->trifacemarkerlist;
-@@ -31675,15 +28973,6 @@
- marker = tsymface.tet != dummytet ? 1 : 0;
- }
- }
-- if (b->neighout > 1) {
-- // '-nn' switch. Output adjacent tets indices.
-- neigh1 = * (int *)(tface.tet + elemmarkerindex);
-- if (tsymface.tet != dummytet) {
-- neigh2 = * (int *)(tsymface.tet + elemmarkerindex);
-- } else {
-- neigh2 = -1;
-- }
-- }
- if (out == (tetgenio *) NULL) {
- // Face number, indices of three vertices.
- fprintf(outfile, "%5d %4d %4d %4d", facenumber,
-@@ -31693,9 +28982,6 @@
- // Output a boundary marker.
- fprintf(outfile, " %d", marker);
- }
-- if (b->neighout > 1) {
-- fprintf(outfile, " %5d %5d", neigh1, neigh2);
-- }
- fprintf(outfile, "\n");
- } else {
- // Output indices of three vertices.
-@@ -31705,10 +28991,6 @@
- if (bmark) {
- emlist[facenumber - in->firstnumber] = marker;
- }
-- if (b->neighout > 1) {
-- out->adjtetlist[(facenumber - in->firstnumber) * 2] = neigh1;
-- out->adjtetlist[(facenumber - in->firstnumber) * 2 + 1] = neigh2;
-- }
- }
- facenumber++;
- }
-@@ -31843,7 +29125,7 @@
- char facefilename[FILENAMESIZE];
- int *elist;
- int *emlist;
-- int index, index1, index2;
-+ int index;
- triface abuttingtet;
- face faceloop;
- point torg, tdest, tapex;
-@@ -31869,8 +29151,7 @@
- outfile = (FILE *) NULL;
- elist = (int *) NULL;
- emlist = (int *) NULL;
-- index = index1 = index2 = 0;
-- faceid = marker = 0;
-+ index = marker = 0;
- neigh1 = neigh2 = 0;
-
- bmark = !b->nobound && in->facetmarkerlist;
-@@ -31909,6 +29190,7 @@
- out->numberoftrifaces = subfaces->items;
- elist = out->trifacelist;
- emlist = out->trifacemarkerlist;
-+ index = 0;
- }
-
- // Determine the first index (0 or 1).
-@@ -31963,176 +29245,28 @@
- fprintf(outfile, "%5d %4d %4d %4d", facenumber,
- pointmark(torg) - shift, pointmark(tdest) - shift,
- pointmark(tapex) - shift);
-- if (bmark) {
-- fprintf(outfile, " %d", marker);
-- }
-- if (b->neighout > 1) {
-- fprintf(outfile, " %5d %5d", neigh1, neigh2);
-- }
-- fprintf(outfile, "\n");
-- } else {
-- // Output three vertices of this face;
-- elist[index++] = pointmark(torg) - shift;
-- elist[index++] = pointmark(tdest) - shift;
-- elist[index++] = pointmark(tapex) - shift;
-- if (bmark) {
-- emlist[index1++] = marker;
-- }
-- if (b->neighout > 1) {
-- out->adjtetlist[index2++] = neigh1;
-- out->adjtetlist[index2++] = neigh2;
-- }
-- }
-- facenumber++;
-- faceloop.sh = shellfacetraverse(subfaces);
-- }
--
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, "# Generated by %s\n", b->commandline);
-- fclose(outfile);
-- }
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
--// outedges() Output all edges to a .edge file or a structure. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--void tetgenmesh::outedges(tetgenio* out)
--{
-- FILE *outfile;
-- char edgefilename[FILENAMESIZE];
-- int *elist, *emlist;
-- int index, index1;
-- triface tetloop, worktet, spintet;
-- face checksh;
-- point torg, tdest;
-- long faces, edges;
-- int firstindex, shift;
-- int edgenumber, faceid, marker;
-- int hitbdry, i;
--
-- if (out == (tetgenio *) NULL) {
-- strcpy(edgefilename, b->outfilename);
-- strcat(edgefilename, ".edge");
-- }
--
-- if (!b->quiet) {
-- if (out == (tetgenio *) NULL) {
-- printf("Writing %s.\n", edgefilename);
-- } else {
-- printf("Writing edges.\n");
-- }
-- }
--
-- // Avoid compile warnings.
-- outfile = (FILE *) NULL;
-- elist = (int *) NULL;
-- emlist = (int *) NULL;
-- index = index1 = 0;
-- faceid = marker = 0;
--
-- // Using the Euler formula (V-E+F-T=1) to get the total number of edges.
-- faces = (4l * tetrahedrons->items + hullsize) / 2l;
-- edges = points->items + faces - tetrahedrons->items - 1l;
--
-- if (out == (tetgenio *) NULL) {
-- outfile = fopen(edgefilename, "w");
-- if (outfile == (FILE *) NULL) {
-- printf("File I/O Error: Cannot create file %s.\n", edgefilename);
-- terminatetetgen(1);
-- }
-- // Write the number of edges, boundary markers (0 or 1).
-- fprintf(outfile, "%ld %d\n", edges, !b->nobound);
-- } else {
-- // Allocate memory for 'edgelist'.
-- out->edgelist = new int[edges * 2];
-- if (out->edgelist == (int *) NULL) {
-- printf("Error: Out of memory.\n");
-- terminatetetgen(1);
-- }
-- if (!b->nobound) {
-- out->edgemarkerlist = new int[edges];
-- }
-- out->numberofedges = edges;
-- elist = out->edgelist;
-- emlist = out->edgemarkerlist;
-- }
--
-- // Determine the first index (0 or 1).
-- firstindex = b->zeroindex ? 0 : in->firstnumber;
-- shift = 0; // Default no shiftment.
-- if ((in->firstnumber == 1) && (firstindex == 0)) {
-- shift = 1; // Shift (reduce) the output indices by 1.
-- }
--
-- tetrahedrons->traversalinit();
-- tetloop.tet = tetrahedrontraverse();
-- edgenumber = firstindex; // in->firstnumber;
-- while (tetloop.tet != (tetrahedron *) NULL) {
-- // Count the number of Voronoi faces. Look at the six edges of each
-- // tetrahedron. Count the edge only if the tetrahedron's pointer is
-- // smaller than those of all other tetrahedra that share the edge.
-- worktet.tet = tetloop.tet;
-- for (i = 0; i < 6; i++) {
-- worktet.loc = edge2locver[i][0];
-- worktet.ver = edge2locver[i][1];
-- adjustedgering(worktet, CW);
-- spintet = worktet;
-- hitbdry = 0;
-- while (hitbdry < 2) {
-- if (fnextself(spintet)) {
-- if (apex(spintet) == apex(worktet)) break;
-- if (spintet.tet < worktet.tet) break;
-- } else {
-- hitbdry++;
-- if (hitbdry < 2) {
-- esym(worktet, spintet);
-- fnextself(spintet); // In the same tet.
-- }
-- }
-+ if (bmark) {
-+ fprintf(outfile, " %d", marker);
- }
-- // Count this edge if no adjacent tets are smaller than this tet.
-- if (spintet.tet >= worktet.tet) {
-- torg = org(worktet);
-- tdest = dest(worktet);
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, "%5d %4d %4d", edgenumber,
-- pointmark(torg) - shift, pointmark(tdest) - shift);
-- } else {
-- // Output three vertices of this face;
-- elist[index++] = pointmark(torg) - shift;
-- elist[index++] = pointmark(tdest) - shift;
-- }
-- if (!b->nobound) {
-- if (hitbdry > 0) {
-- // It is a boundary edge. Get the boundary marker of the facet
-- // containing this edge. Note there may have more than one
-- // facet, choose one arbitrarily.
-- if ((b->plc || b->refine) && in->facetmarkerlist) {
-- tspivot(spintet, checksh);
-- faceid = shellmark(checksh) - 1;
-- marker = in->facetmarkerlist[faceid];
-- } else {
-- marker = 1; // Indicate it's a boundary edge.
-- }
-- } else {
-- marker = 0;
-- }
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, " %d", marker);
-- } else {
-- emlist[index1++] = marker;
-- }
-- }
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, "\n");
-- }
-- edgenumber++;
-+ if (b->neighout > 1) {
-+ fprintf(outfile, " %5d %5d", neigh1, neigh2);
-+ }
-+ fprintf(outfile, "\n");
-+ } else {
-+ // Output three vertices of this face;
-+ elist[index++] = pointmark(torg) - shift;
-+ elist[index++] = pointmark(tdest) - shift;
-+ elist[index++] = pointmark(tapex) - shift;
-+ if (bmark) {
-+ emlist[facenumber - in->firstnumber] = marker;
-+ }
-+ if (b->neighout > 1) {
-+ out->adjtetlist[(facenumber - in->firstnumber) * 2] = neigh1;
-+ out->adjtetlist[(facenumber - in->firstnumber) * 2 + 1] = neigh2;
- }
- }
-- tetloop.tet = tetrahedrontraverse();
-+ facenumber++;
-+ faceloop.sh = shellfacetraverse(subfaces);
- }
-
- if (out == (tetgenio *) NULL) {
-@@ -32167,7 +29301,7 @@
- if (out == (tetgenio *) NULL) {
- printf("Writing %s.\n", edgefilename);
- } else {
-- printf("Writing edges.\n");
-+ printf("Writing faces.\n");
- }
- }
-
-@@ -32193,6 +29327,7 @@
- }
- out->numberofedges = subsegs->items;
- elist = out->edgelist;
-+ index = 0;
- }
-
- // Determine the first index (0 or 1).
-@@ -32205,556 +29340,113 @@
- subsegs->traversalinit();
- edgeloop.sh = shellfacetraverse(subsegs);
- edgenumber = firstindex; // in->firstnumber;
-- while (edgeloop.sh != (shellface *) NULL) {
-- torg = sorg(edgeloop);
-- tdest = sdest(edgeloop);
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, "%5d %4d %4d\n", edgenumber,
-- pointmark(torg) - shift, pointmark(tdest) - shift);
-- } else {
-- // Output three vertices of this face;
-- elist[index++] = pointmark(torg) - shift;
-- elist[index++] = pointmark(tdest) - shift;
-- }
-- edgenumber++;
-- edgeloop.sh = shellfacetraverse(subsegs);
-- }
--
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, "# Generated by %s\n", b->commandline);
-- fclose(outfile);
-- }
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
--// outneighbors() Output tet neighbors to a .neigh file or a structure. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--void tetgenmesh::outneighbors(tetgenio* out)
--{
-- FILE *outfile;
-- char neighborfilename[FILENAMESIZE];
-- int *nlist;
-- int index;
-- triface tetloop, tetsym;
-- int neighbor1, neighbor2, neighbor3, neighbor4;
-- int firstindex;
-- int elementnumber;
--
-- if (out == (tetgenio *) NULL) {
-- strcpy(neighborfilename, b->outfilename);
-- strcat(neighborfilename, ".neigh");
-- }
--
-- if (!b->quiet) {
-- if (out == (tetgenio *) NULL) {
-- printf("Writing %s.\n", neighborfilename);
-- } else {
-- printf("Writing neighbors.\n");
-- }
-- }
--
-- // Avoid compile warnings.
-- outfile = (FILE *) NULL;
-- nlist = (int *) NULL;
-- index = 0;
--
-- if (out == (tetgenio *) NULL) {
-- outfile = fopen(neighborfilename, "w");
-- if (outfile == (FILE *) NULL) {
-- printf("File I/O Error: Cannot create file %s.\n", neighborfilename);
-- terminatetetgen(1);
-- }
-- // Number of tetrahedra, four faces per tetrahedron.
-- fprintf(outfile, "%ld %d\n", tetrahedrons->items, 4);
-- } else {
-- // Allocate memory for 'neighborlist'.
-- out->neighborlist = new int[tetrahedrons->items * 4];
-- if (out->neighborlist == (int *) NULL) {
-- printf("Error: Out of memory.\n");
-- terminatetetgen(1);
-- }
-- nlist = out->neighborlist;
-- }
--
-- // Determine the first index (0 or 1).
-- firstindex = b->zeroindex ? 0 : in->firstnumber;
--
-- tetrahedrons->traversalinit();
-- tetloop.tet = tetrahedrontraverse();
-- elementnumber = firstindex; // in->firstnumber;
-- while (tetloop.tet != (tetrahedron *) NULL) {
-- tetloop.loc = 2;
-- sym(tetloop, tetsym);
-- neighbor1 = * (int *) (tetsym.tet + elemmarkerindex);
-- tetloop.loc = 3;
-- sym(tetloop, tetsym);
-- neighbor2 = * (int *) (tetsym.tet + elemmarkerindex);
-- tetloop.loc = 1;
-- sym(tetloop, tetsym);
-- neighbor3 = * (int *) (tetsym.tet + elemmarkerindex);
-- tetloop.loc = 0;
-- sym(tetloop, tetsym);
-- neighbor4 = * (int *) (tetsym.tet + elemmarkerindex);
-- if (out == (tetgenio *) NULL) {
-- // Tetrahedra number, neighboring tetrahedron numbers.
-- fprintf(outfile, "%4d %4d %4d %4d %4d\n", elementnumber,
-- neighbor1, neighbor2, neighbor3, neighbor4);
-- } else {
-- nlist[index++] = neighbor1;
-- nlist[index++] = neighbor2;
-- nlist[index++] = neighbor3;
-- nlist[index++] = neighbor4;
-- }
-- tetloop.tet = tetrahedrontraverse();
-- elementnumber++;
-- }
--
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, "# Generated by %s\n", b->commandline);
-- fclose(outfile);
-- }
--}
--
--///////////////////////////////////////////////////////////////////////////////
--// //
--// outvoronoi() Output the Voronoi diagram to .v.node, .v.edge, v.face, //
--// and .v.cell. //
--// //
--// The Voronoi diagram is the geometric dual of the Delaunay triangulation. //
--// The Voronoi vertices are the circumcenters of Delaunay tetrahedra. Each //
--// Voronoi edge connects two Voronoi vertices at two sides of a common Dela- //
--// unay face. At a face of convex hull, it becomes a ray (goto the infinity).//
--// A Voronoi face is the convex hull of all Voronoi vertices around a common //
--// Delaunay edge. It is a closed polygon for any interal Delaunay edge. At a //
--// ridge, it is unbounded. Each Voronoi cell is the convex hull of all Vor- //
--// onoi vertices around a common Delaunay vertex. It is a polytope for any //
--// internal Delaunay vertex. It is an unbounded polyhedron for a Delaunay //
--// vertex belonging to the convex hull. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--void tetgenmesh::outvoronoi(tetgenio* out)
--{
-- FILE *outfile;
-- char outfilename[FILENAMESIZE];
-- tetgenio::voroedge *vedge;
-- tetgenio::vorofacet *vfacet;
-- list *tetlist, *ptlist;
-- triface tetloop, worktet, spintet;
-- point pt[4], ptloop, neipt;
-- REAL ccent[3], infvec[3], vec1[3], vec2[3], L;
-- long faces, edges;
-- int *tetfaceindexarray, *tetedgeindexarray;
-- int arraysize, *vertarray;
-- int vpointcount, vedgecount, vfacecount, tcount;
-- int index, shift;
-- int end1, end2;
-- int hitbdry, i, j, k;
--
-- // Output Voronoi vertices to .v.node file.
-- if (out == (tetgenio *) NULL) {
-- strcpy(outfilename, b->outfilename);
-- strcat(outfilename, ".v.node");
-- }
--
-- if (!b->quiet) {
-- if (out == (tetgenio *) NULL) {
-- printf("Writing %s.\n", outfilename);
-- } else {
-- printf("Writing Voronoi vertices.\n");
-- }
-- }
--
-- // Determine the first index (0 or 1).
-- shift = (b->zeroindex ? 0 : in->firstnumber);
-- // The number of Delaunay faces (= the number of Voronoi edges).
-- faces = (4l * tetrahedrons->items + hullsize) / 2l;
-- // The number of Delaunay edges (= the number of Voronoi faces).
-- edges = points->items + faces - tetrahedrons->items - 1;
-- outfile = (FILE *) NULL; // Avoid compile warnings.
--
-- if (out == (tetgenio *) NULL) {
-- outfile = fopen(outfilename, "w");
-- if (outfile == (FILE *) NULL) {
-- printf("File I/O Error: Cannot create file %s.\n", outfilename);
-- terminatetetgen(1);
-- }
-- // Number of voronoi points, 3 dim, no attributes, no marker.
-- fprintf(outfile, "%ld 3 0 0\n", tetrahedrons->items);
-- } else {
-- // Allocate space for 'vpointlist'.
-- out->numberofvpoints = (int) tetrahedrons->items;
-- out->vpointlist = new REAL[out->numberofvpoints * 3];
-- if (out->vpointlist == (REAL *) NULL) {
-- printf("Error: Out of memory.\n");
-- terminatetetgen(1);
-- }
-- }
--
-- // Loop the tetrahedronlist once, do the following:
-- // (1) Output Voronoi vertices (the circumcenter of the tetrahedron).
-- // (2) Make a map from points-to-tetrahedra (for Voronoi cells).
-- tetrahedrons->traversalinit();
-- tetloop.tet = tetrahedrontraverse();
-- vpointcount = 0;
-- index = 0;
-- while (tetloop.tet != (tetrahedron *) NULL) {
-- // Calculate the circumcenter.
-- for (i = 0; i < 4; i++) {
-- pt[i] = (point) tetloop.tet[4 + i];
-- setpoint2tet(pt[i], encode(tetloop));
-- }
-- circumsphere(pt[0], pt[1], pt[2], pt[3], ccent, NULL);
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, "%4d %16.8e %16.8e %16.8e\n", vpointcount + shift,
-- ccent[0], ccent[1], ccent[2]);
-- } else {
-- out->vpointlist[index++] = ccent[0];
-- out->vpointlist[index++] = ccent[1];
-- out->vpointlist[index++] = ccent[2];
-- }
-- // Remember the index of this element.
-- * (int *) (tetloop.tet + elemmarkerindex) = vpointcount;
-- vpointcount++;
-- tetloop.tet = tetrahedrontraverse();
-- }
-- // Set the outside element marker.
-- * (int *) (dummytet + elemmarkerindex) = -1;
--
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, "# Generated by %s\n", b->commandline);
-- fclose(outfile);
-- }
--
-- // Output Voronoi edges to .v.edge file.
-- if (out == (tetgenio *) NULL) {
-- strcpy(outfilename, b->outfilename);
-- strcat(outfilename, ".v.edge");
-- }
--
-- if (!b->quiet) {
-- if (out == (tetgenio *) NULL) {
-- printf("Writing %s.\n", outfilename);
-- } else {
-- printf("Writing Voronoi edges.\n");
-- }
-- }
--
-- if (out == (tetgenio *) NULL) {
-- outfile = fopen(outfilename, "w");
-- if (outfile == (FILE *) NULL) {
-- printf("File I/O Error: Cannot create file %s.\n", outfilename);
-- terminatetetgen(1);
-- }
-- // Number of Voronoi edges, no marker.
-- fprintf(outfile, "%ld 0\n", faces);
-- } else {
-- // Allocate space for 'vpointlist'.
-- out->numberofedges = (int) faces;
-- out->vedgelist = new tetgenio::voroedge[out->numberofvedges];
-- }
--
-- // Loop the tetrahedronlist once, output the Voronoi edges. The index of
-- // each Voronoi edge corresponding to the index of the Delaunay face.
-- // The four faces' indices of each tetrahedron are saved in the list
-- // 'tetfaceindexarray', in the entry of i, where i (0-based) is the
-- // index of this tetrahedron (= vpointcount).
-- tetfaceindexarray = new int[tetrahedrons->items * 4];
-- tetrahedrons->traversalinit();
-- tetloop.tet = tetrahedrontraverse();
-- vedgecount = 0;
-- index = 0;
-- while (tetloop.tet != (tetrahedron *) NULL) {
-- // Count the number of Voronoi edges. Look at the four faces of each
-- // tetrahedron. Count the face if the tetrahedron's pointer is
-- // smaller than its neighbor's or the neighbor is outside.
-- end1 = * (int *) (tetloop.tet + elemmarkerindex);
-- for (i = 0; i < 4; i++) {
-- decode(tetloop.tet[i], worktet);
-- if ((worktet.tet == dummytet) || (tetloop.tet < worktet.tet)) {
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, "%4d %4d", vedgecount + shift, end1 + shift);
-- } else {
-- vedge = &(out->vedgelist[index++]);
-- vedge->v1 = end1 + shift;
-- }
-- end2 = * (int *) (worktet.tet + elemmarkerindex);
-- // Note that end2 may be -1 (worktet.tet is outside).
-- if (end2 == -1) {
-- // Calculate the out normal of this hull face.
-- worktet.tet = tetloop.tet;
-- worktet.loc = i;
-- worktet.ver = 1; // The CW edge ring.
-- pt[0] = org(worktet);
-- pt[1] = dest(worktet);
-- pt[2] = apex(worktet);
-- for (j = 0; j < 3; j++) vec1[j] = pt[1][j] - pt[0][j];
-- for (j = 0; j < 3; j++) vec2[j] = pt[2][j] - pt[0][j];
-- cross(vec1, vec2, infvec);
-- // Normalize it.
-- L = sqrt(infvec[0] * infvec[0] + infvec[1] * infvec[1]
-- + infvec[2] * infvec[2]);
-- if (L > 0) for (j = 0; j < 3; j++) infvec[j] /= L;
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, " -1");
-- fprintf(outfile, " %g %g %g\n", infvec[0], infvec[1], infvec[2]);
-- } else {
-- vedge->v2 = -1;
-- vedge->vnormal[0] = infvec[0];
-- vedge->vnormal[1] = infvec[1];
-- vedge->vnormal[2] = infvec[2];
-- }
-- } else {
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, " %4d\n", end2 + shift);
-- } else {
-- vedge->v2 = end2 + shift;
-- vedge->vnormal[0] = 0.0;
-- vedge->vnormal[1] = 0.0;
-- vedge->vnormal[2] = 0.0;
-- }
-- }
-- // Save the face index in this tet and its neighbor if exists.
-- tetfaceindexarray[end1 * 4 + i] = vedgecount;
-- if (end2 != -1) {
-- tetfaceindexarray[end2 * 4 + worktet.loc] = vedgecount;
-- }
-- vedgecount++;
-- }
-- }
-- tetloop.tet = tetrahedrontraverse();
-- }
--
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, "# Generated by %s\n", b->commandline);
-- fclose(outfile);
-- }
--
-- // Output Voronoi faces to .v.face file.
-- if (out == (tetgenio *) NULL) {
-- strcpy(outfilename, b->outfilename);
-- strcat(outfilename, ".v.face");
-- }
--
-- if (!b->quiet) {
-- if (out == (tetgenio *) NULL) {
-- printf("Writing %s.\n", outfilename);
-- } else {
-- printf("Writing Voronoi faces.\n");
-- }
-- }
--
-- if (out == (tetgenio *) NULL) {
-- outfile = fopen(outfilename, "w");
-- if (outfile == (FILE *) NULL) {
-- printf("File I/O Error: Cannot create file %s.\n", outfilename);
-- terminatetetgen(1);
-- }
-- // Number of Voronoi faces.
-- fprintf(outfile, "%ld 0\n", edges);
-- } else {
-- out->numberofvfacets = edges;
-- out->vfacetlist = new tetgenio::vorofacet[out->numberofvfacets];
-- if (out->vfacetlist == (tetgenio::vorofacet *) NULL) {
-- printf("Error: Out of memory.\n");
-- terminatetetgen(1);
-+ while (edgeloop.sh != (shellface *) NULL) {
-+ torg = sorg(edgeloop);
-+ tdest = sdest(edgeloop);
-+ if (out == (tetgenio *) NULL) {
-+ fprintf(outfile, "%5d %4d %4d\n", edgenumber,
-+ pointmark(torg) - shift, pointmark(tdest) - shift);
-+ } else {
-+ // Output three vertices of this face;
-+ elist[index++] = pointmark(torg) - shift;
-+ elist[index++] = pointmark(tdest) - shift;
- }
-- }
--
-- // Loop the tetrahedronlist once, Output Voronoi facets. The index of each
-- // Voronoi facet corresponding to the index of the Delaunay edge. The
-- // six edges' indices of each tetrahedron are saved in the list 'tetedge-
-- // indexarray', in the entry of i, where i (0-based) is the index of
-- // this tetrahedron (= vpointcount).
-- tetedgeindexarray = new int[tetrahedrons->items * 6];
-- tetrahedrons->traversalinit();
-- tetloop.tet = tetrahedrontraverse();
-- vfacecount = 0;
-- while (tetloop.tet != (tetrahedron *) NULL) {
-- // Count the number of Voronoi faces. Look at the six edges of each
-- // tetrahedron. Count the edge only if the tetrahedron's pointer is
-- // smaller than those of all other tetrahedra that share the edge.
-- worktet = tetloop;
-- for (i = 0; i < 6; i++) {
-- worktet.loc = edge2locver[i][0];
-- worktet.ver = edge2locver[i][1];
-- // Now count the number of tets surrounding this edge.
-- tcount = 1;
-- adjustedgering(worktet, CW);
-- spintet = worktet;
-- hitbdry = 0;
-- while (hitbdry < 2) {
-- if (fnextself(spintet)) {
-- if (apex(spintet) == apex(worktet)) break;
-- if (spintet.tet < worktet.tet) break;
-- tcount++;
-- } else {
-- hitbdry++;
-- if (hitbdry < 2) {
-- esym(worktet, spintet);
-- fnextself(spintet); // In the same tet.
-- }
-- }
-- }
-- // Count this edge if no adjacent tets are smaller than this tet.
-- if (spintet.tet >= worktet.tet) {
-- // Get the two endpoints of this edge.
-- pt[0] = org(worktet);
-- pt[1] = dest(worktet);
-- end1 = pointmark(pt[0]) - in->firstnumber;
-- end2 = pointmark(pt[1]) - in->firstnumber;
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, "%4d %4d %4d %-2d ", vfacecount + shift,
-- end1 + shift, end2 + shift, tcount + (hitbdry > 0));
-- } else {
-- vfacet = &(out->vfacetlist[vfacecount]);
-- vfacet->c1 = end1 + shift;
-- vfacet->c2 = end2 + shift;
-- vfacet->elist = new int[tcount + (hitbdry > 0) + 1];
-- vfacet->elist[0] = tcount + (hitbdry > 0);
-- index = 1;
-- }
-- // If hitbdry > 0, then spintet is a hull face.
-- if (hitbdry > 0) {
-- // The edge list starts with a ray.
-- vpointcount = * (int *) (spintet.tet + elemmarkerindex);
-- vedgecount = tetfaceindexarray[vpointcount * 4 + spintet.loc];
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, " %d", vedgecount + shift);
-- } else {
-- vfacet->elist[index++] = vedgecount + shift;
-- }
-- // Save this facet number in tet.
-- tetedgeindexarray[vpointcount * 6 +
-- locver2edge[spintet.loc][spintet.ver]] = vfacecount;
-- esymself(spintet);
-- fnextself(spintet); // In the same tet.
-- }
-- // Output internal Voronoi edges.
-- for (j = 0; j < tcount; j++) {
-- vpointcount = * (int *) (spintet.tet + elemmarkerindex);
-- vedgecount = tetfaceindexarray[vpointcount * 4 + spintet.loc];
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, " %d", vedgecount + shift);
-- } else {
-- vfacet->elist[index++] = vedgecount + shift;
-- }
-- // Save this facet number in tet.
-- tetedgeindexarray[vpointcount * 6 +
-- locver2edge[spintet.loc][spintet.ver]] = vfacecount;
-- fnextself(spintet);
-- }
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, "\n");
-- }
-- vfacecount++;
-- }
-- } // if (i = 0; i < 6; i++)
-- tetloop.tet = tetrahedrontraverse();
-+ edgenumber++;
-+ edgeloop.sh = shellfacetraverse(subsegs);
- }
-
- if (out == (tetgenio *) NULL) {
- fprintf(outfile, "# Generated by %s\n", b->commandline);
- fclose(outfile);
- }
-+}
-+
-+///////////////////////////////////////////////////////////////////////////////
-+// //
-+// outneighbors() Output tet neighbors to a .neigh file or a structure. //
-+// //
-+///////////////////////////////////////////////////////////////////////////////
-+
-+void tetgenmesh::outneighbors(tetgenio* out)
-+{
-+ FILE *outfile;
-+ char neighborfilename[FILENAMESIZE];
-+ int *nlist;
-+ int index;
-+ triface tetloop, tetsym;
-+ int neighbor1, neighbor2, neighbor3, neighbor4;
-+ int firstindex;
-+ int elementnumber;
-
-- // Output Voronoi cells to .v.cell file.
- if (out == (tetgenio *) NULL) {
-- strcpy(outfilename, b->outfilename);
-- strcat(outfilename, ".v.cell");
-+ strcpy(neighborfilename, b->outfilename);
-+ strcat(neighborfilename, ".neigh");
- }
--
-+
- if (!b->quiet) {
- if (out == (tetgenio *) NULL) {
-- printf("Writing %s.\n", outfilename);
-+ printf("Writing %s.\n", neighborfilename);
- } else {
-- printf("Writing Voronoi cells.\n");
-+ printf("Writing neighbors.\n");
- }
- }
-
-+ // Avoid compile warnings.
-+ outfile = (FILE *) NULL;
-+ nlist = (int *) NULL;
-+ index = 0;
-+
- if (out == (tetgenio *) NULL) {
-- outfile = fopen(outfilename, "w");
-+ outfile = fopen(neighborfilename, "w");
- if (outfile == (FILE *) NULL) {
-- printf("File I/O Error: Cannot create file %s.\n", outfilename);
-+ printf("File I/O Error: Cannot create file %s.\n", neighborfilename);
- terminatetetgen(1);
- }
-- // Number of Voronoi cells.
-- fprintf(outfile, "%ld\n", points->items);
-+ // Number of tetrahedra, four faces per tetrahedron.
-+ fprintf(outfile, "%ld %d\n", tetrahedrons->items, 4);
- } else {
-- out->numberofvcells = points->items;
-- out->vcelllist = new int*[out->numberofvcells];
-- if (out->vcelllist == (int **) NULL) {
-+ // Allocate memory for 'neighborlist'.
-+ out->neighborlist = new int[tetrahedrons->items * 4];
-+ if (out->neighborlist == (int *) NULL) {
- printf("Error: Out of memory.\n");
- terminatetetgen(1);
- }
-+ nlist = out->neighborlist;
-+ index = 0;
- }
-
-- // Loop through point list, for each point, output a Voronoi cell.
-- tetlist = new list(sizeof(triface), NULL, 256);
-- ptlist = new list(sizeof(point *), NULL, 256);
-- points->traversalinit();
-- ptloop = pointtraverse();
-- vpointcount = 0;
-- while (ptloop != (point) NULL) {
-- decode(point2tet(ptloop), tetloop);
-- // assert(!isdead(&tetloop));
-- if (!isdead(&tetloop)) {
-- // Form the star of p.
-- tetlist->append(&tetloop);
-- formstarpolyhedron(ptloop, tetlist, ptlist, true);
-- tcount = ptlist->len();
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, "%4d %-2d ", vpointcount + shift, tcount);
-- } else {
-- arraysize = tcount;
-- vertarray = out->vcelllist[vpointcount];
-- vertarray = new int[arraysize + 1];
-- vertarray[0] = arraysize;
-- index = 1;
-- }
-- // List Voronoi facets bounding this cell.
-- for (i = 0; i < ptlist->len(); i++) {
-- neipt = * (point *)(* ptlist)[i];
-- // Find a tet in tetlist having edge (ptloop, neipt) -- Very Slow.
-- for (j = 0; j < tetlist->len(); j++) {
-- tetloop = * (triface *)(* tetlist)[j];
-- for (k = 0; k < 6; k++) {
-- tetloop.loc = edge2locver[k][0];
-- tetloop.ver = edge2locver[k][1];
-- if (org(tetloop) == ptloop) {
-- if (dest(tetloop) == neipt) break;
-- } else if (org(tetloop) == neipt) {
-- if (dest(tetloop) == ptloop) break;
-- }
-- }
-- if (k < 6) break; // Found this edge.
-- }
-- assert(j < tetlist->len());
-- // k is the right edge number.
-- end1 = * (int *) (tetloop.tet + elemmarkerindex);
-- vfacecount = tetedgeindexarray[end1 * 6 + k];
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, " %d", vfacecount + shift);
-- } else {
-- vertarray[index++] = vfacecount + shift;
-- }
-- } // for (i = 0; i < ptlist->len(); i++) {
-- if (out == (tetgenio *) NULL) {
-- fprintf(outfile, "\n");
-- }
-- vpointcount++;
-+ // Determine the first index (0 or 1).
-+ firstindex = b->zeroindex ? 0 : in->firstnumber;
-+
-+ tetrahedrons->traversalinit();
-+ tetloop.tet = tetrahedrontraverse();
-+ elementnumber = firstindex; // in->firstnumber;
-+ while (tetloop.tet != (tetrahedron *) NULL) {
-+ tetloop.loc = 2;
-+ sym(tetloop, tetsym);
-+ neighbor1 = * (int *) (tetsym.tet + elemmarkerindex);
-+ tetloop.loc = 3;
-+ sym(tetloop, tetsym);
-+ neighbor2 = * (int *) (tetsym.tet + elemmarkerindex);
-+ tetloop.loc = 1;
-+ sym(tetloop, tetsym);
-+ neighbor3 = * (int *) (tetsym.tet + elemmarkerindex);
-+ tetloop.loc = 0;
-+ sym(tetloop, tetsym);
-+ neighbor4 = * (int *) (tetsym.tet + elemmarkerindex);
-+ if (out == (tetgenio *) NULL) {
-+ // Tetrahedra number, neighboring tetrahedron numbers.
-+ fprintf(outfile, "%4d %4d %4d %4d %4d\n", elementnumber,
-+ neighbor1, neighbor2, neighbor3, neighbor4);
-+ } else {
-+ nlist[index++] = neighbor1;
-+ nlist[index++] = neighbor2;
-+ nlist[index++] = neighbor3;
-+ nlist[index++] = neighbor4;
- }
-- tetlist->clear();
-- ptlist->clear();
-- ptloop = pointtraverse();
-+ tetloop.tet = tetrahedrontraverse();
-+ elementnumber++;
- }
-- delete tetlist;
-- delete ptlist;
-- delete [] tetfaceindexarray;
-- delete [] tetedgeindexarray;
-
- if (out == (tetgenio *) NULL) {
- fprintf(outfile, "# Generated by %s\n", b->commandline);
-@@ -33087,7 +29779,7 @@
- tetrahedron* tetptr;
- triface tface, tsymface;
- face segloop, checkmark;
-- point ptloop, p1, p2, p3, p4;
-+ point pointloop, p1, p2, p3, p4;
- long faces;
- int pointnumber;
- int i;
-@@ -33121,19 +29813,20 @@
- fprintf(outfile, "%ld\n", points->items);
-
- points->traversalinit();
-- ptloop = pointtraverse();
-+ pointloop = pointtraverse();
- pointnumber = 1; // Medit need start number form 1.
-- while (ptloop != (point) NULL) {
-+ while (pointloop != (point) NULL) {
- // Point coordinates.
-- fprintf(outfile, "%.17g %.17g %.17g", ptloop[0], ptloop[1], ptloop[2]);
-+ fprintf(outfile, "%.17g %.17g %.17g",
-+ pointloop[0], pointloop[1], pointloop[2]);
- if (in->numberofpointattributes > 0) {
- // Write an attribute, ignore others if more than one.
-- fprintf(outfile, " %.17g\n", ptloop[3]);
-+ fprintf(outfile, " %.17g\n", pointloop[3]);
- } else {
- fprintf(outfile, " 0\n");
- }
-- setpointmark(ptloop, pointnumber);
-- ptloop = pointtraverse();
-+ setpointmark(pointloop, pointnumber);
-+ pointloop = pointtraverse();
- pointnumber++;
- }
-
-@@ -33234,7 +29927,7 @@
- tetrahedron* tetptr;
- triface tface, tsymface;
- face sface;
-- point ptloop, p1, p2, p3, p4;
-+ point pointloop, p1, p2, p3, p4;
- int pointnumber;
- int elementnumber;
-
-@@ -33260,19 +29953,19 @@
- fprintf(outfile, "coordinates\n");
-
- points->traversalinit();
-- ptloop = pointtraverse();
-+ pointloop = pointtraverse();
- pointnumber = 1; // Gid need start number form 1.
-- while (ptloop != (point) NULL) {
-+ while (pointloop != (point) NULL) {
- // Point coordinates.
- fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber,
-- ptloop[0], ptloop[1], ptloop[2]);
-+ pointloop[0], pointloop[1], pointloop[2]);
- if (in->numberofpointattributes > 0) {
- // Write an attribute, ignore others if more than one.
-- fprintf(outfile, " %.17g", ptloop[3]);
-+ fprintf(outfile, " %.17g", pointloop[3]);
- }
- fprintf(outfile, "\n");
-- setpointmark(ptloop, pointnumber);
-- ptloop = pointtraverse();
-+ setpointmark(pointloop, pointnumber);
-+ pointloop = pointtraverse();
- pointnumber++;
- }
-
-@@ -33322,19 +30015,19 @@
- fprintf(outfile, "coordinates\n");
-
- points->traversalinit();
-- ptloop = pointtraverse();
-+ pointloop = pointtraverse();
- pointnumber = 1; // Gid need start number form 1.
-- while (ptloop != (point) NULL) {
-+ while (pointloop != (point) NULL) {
- // Point coordinates.
- fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber,
-- ptloop[0], ptloop[1], ptloop[2]);
-+ pointloop[0], pointloop[1], pointloop[2]);
- if (in->numberofpointattributes > 0) {
- // Write an attribute, ignore others if more than one.
-- fprintf(outfile, " %.17g", ptloop[3]);
-+ fprintf(outfile, " %.17g", pointloop[3]);
- }
- fprintf(outfile, "\n");
-- setpointmark(ptloop, pointnumber);
-- ptloop = pointtraverse();
-+ setpointmark(pointloop, pointnumber);
-+ pointloop = pointtraverse();
- pointnumber++;
- }
-
-@@ -33388,7 +30081,7 @@
- FILE *outfile;
- char offfilename[FILENAMESIZE];
- triface tface, tsymface;
-- point ptloop, p1, p2, p3;
-+ point pointloop, p1, p2, p3;
- long faces;
- int shift;
-
-@@ -33418,10 +30111,11 @@
-
- // Write the points.
- points->traversalinit();
-- ptloop = pointtraverse();
-- while (ptloop != (point) NULL) {
-- fprintf(outfile, " %.17g %.17g %.17g\n",ptloop[0], ptloop[1], ptloop[2]);
-- ptloop = pointtraverse();
-+ pointloop = pointtraverse();
-+ while (pointloop != (point) NULL) {
-+ fprintf(outfile, " %.17g %.17g %.17g\n", pointloop[0], pointloop[1],
-+ pointloop[2]);
-+ pointloop = pointtraverse();
- }
-
- // OFF always use zero as the first index.
-@@ -33833,10 +30527,10 @@
- case T32: printf("\"T32\""); break;
- case T22: printf("\"T22\""); break;
- case T44: printf("\"T44\""); break;
-- case N32: printf("\"N32\""); break;
-- case N40: printf("\"N40\""); break;
-+ case UNFLIPABLE: printf("\"UNFLIPABLE\""); break;
- case FORBIDDENFACE:printf("\"FORBIDDENFACE\""); break;
- case FORBIDDENEDGE:printf("\"FORBIDDENEDGE\""); break;
-+ case NONCONVEX:printf("\"NONCONVEX\""); break;
- }
- printf("\n");
- }
-@@ -33860,6 +30554,69 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
-+// checkdegeneracy() Check if the point set contains degeneracies. //
-+// //
-+// 'eps' is a relative error tolerance for testing approximatly degeneracies.//
-+// Set it to zero if only exact test is desired. //
-+// //
-+///////////////////////////////////////////////////////////////////////////////
-+
-+void tetgenmesh::checkdegeneracy(REAL eps)
-+{
-+ triface tetraloop;
-+ triface oppotet;
-+ point tetorg, tetdest, tetapex, tetoppo;
-+ point oppooppo;
-+ REAL sign;
-+ int horrors;
-+
-+ if (!b->quiet) {
-+ printf(" Checking degeneracies in the point set...\n");
-+ }
-+ horrors = 0;
-+ // Run through the list of triangles, checking each one.
-+ tetrahedrons->traversalinit();
-+ tetraloop.tet = tetrahedrontraverse();
-+ while (tetraloop.tet != (tetrahedron *) NULL) {
-+ // Check all four faces of the tetrahedron.
-+ for (tetraloop.loc = 0; tetraloop.loc < 4; tetraloop.loc++) {
-+ tetorg = org(tetraloop);
-+ tetdest = dest(tetraloop);
-+ tetapex = apex(tetraloop);
-+ tetoppo = oppo(tetraloop);
-+ sym(tetraloop, oppotet);
-+ oppooppo = oppo(oppotet);
-+ // Only do test if there is an adjoining tetrahedron whose pointer is
-+ // larger (to ensure that each pair isn't tested twice).
-+ if ((oppotet.tet != dummytet) && (tetoppo != (point) NULL) &&
-+ (oppooppo != (point) NULL) && (tetraloop.tet < oppotet.tet)) {
-+ sign = insphere(tetdest, tetorg, tetapex, tetoppo, oppooppo);
-+ if ((sign != 0.0) && (eps > 0.0)) {
-+ if (iscospheric(tetdest, tetorg, tetapex, tetoppo, oppooppo, sign,
-+ eps)) sign = 0.0;
-+ }
-+ if (sign == 0.0) {
-+ printf(" !! Degenerate set (%d, %d, %d, %d, %d).\n",
-+ pointmark(tetorg), pointmark(tetdest), pointmark(tetapex),
-+ pointmark(tetoppo), pointmark(oppooppo));
-+ horrors++;
-+ }
-+ }
-+ }
-+ tetraloop.tet = tetrahedrontraverse();
-+ }
-+
-+ if (horrors == 0) {
-+ if (!b->quiet) {
-+ printf(" The point set is non-degenerate.\n");
-+ }
-+ } else {
-+ printf(" !! !! !! !! %d obscenities viewed with horror.\n", horrors);
-+ }
-+}
-+
-+///////////////////////////////////////////////////////////////////////////////
-+// //
- // checkconforming() Ensure that the mesh is conforming Delaunay. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-@@ -33916,14 +30673,9 @@
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--#ifdef SELF_CHECK
--
- void tetgenmesh::algorithmicstatistics()
- {
-- /*
- printf("Algorithmic statistics:\n\n");
-- printf(" Point location millisecond: %g\n", (REAL) tloctime * 1e+3);
-- printf(" Flip millisecond: %g\n", (REAL) tfliptime * 1e+3);
- if (b->plc || b->refine) {
- printf(" Number of facet above points calculations: %ld\n", abovecount);
- }
-@@ -33932,11 +30684,12 @@
- r3count);
- }
- if (b->quality) {
-- printf(" Bowyer-Watson insertions: seg %ld, sub %ld, vol %ld.\n",
-+ printf(" Bowyer-Watson counts (seg, sub, vol)\n");
-+ printf(" Insert vertices: %ld, %ld, %ld\n",
- bowatsegcount, bowatsubcount, bowatvolcount);
-- printf(" Bowyer-Watson corrections: seg %ld, sub %ld, vol %ld\n",
-+ printf(" Update cavities: %ld, %ld, %ld\n",
- updsegcount, updsubcount, updvolcount);
-- printf(" Bowyer-Watson failures: seg %ld, sub %ld, vol %ld\n",
-+ printf(" Failed cavities: %ld, %ld, %ld\n",
- failsegcount, failsubcount, failvolcount);
- printf(" Number of repair flips: %ld.\n", repairflipcount);
- printf(" Number of circumcenters outside Bowat-cav.: %ld.\n",
-@@ -33945,21 +30698,25 @@
- printf(" Segment split rules: R2 %ld, R3 %ld\n", r2count, r3count);
- printf(" Number of CDT enforcement points: %ld.\n", cdtenforcesegpts);
- }
-- printf(" Number of Rejections: seg %ld, sub %ld, tet %ld.\n", rejsegpts,
-- rejsubpts, rejtetpts);
-- if (b->optlevel) {
-- printf(
-- " Optimization flips: f32 %ld, f44 %ld, f56 %ld, f68 %ld, fnm %ld.\n",
-- optcount[3], optcount[4], optcount[5], optcount[6], optcount[9]);
-- printf(" Optimization segment deletions: %ld.\n", optcount[1]);
-+ printf(" Reject vertices counts:\n");
-+ printf(" Rejected seg splits: %ld.\n", rejsegpts);
-+ printf(" Rejected sub splits: %ld.\n", rejsubpts);
-+ printf(" Rejected tet splits: %ld.\n", rejtetpts);
-+ if (b->smooth) {
-+ printf(" Mesh smooth counts:\n");
-+ printf(" %4ld cdt enforcement points.\n", smoothcdtsegpt);
-+ printf(" %4ld segment points.\n", smoothsegpt);
-+ printf(" %4ld facet points.\n", smoothsubpt);
-+ printf(" %4ld volume points.\n", smoothvolpt);
-+ printf(" %4ld failed cdt enforcement points.\n", unsmoothcdtsegpt);
-+ printf(" %4ld unimproved segment points.\n", unsmoothsegpt);
-+ printf(" %4ld unimproved facet points.\n", unsmoothsubpt);
-+ printf(" %4ld unimproved volume points.\n", unsmoothvolpt);
- }
- }
- printf("\n");
-- */
- }
-
--#endif // #ifdef SELF_CHECK
--
- ///////////////////////////////////////////////////////////////////////////////
- // //
- // qualitystatistics() Print statistics about the quality of the mesh. //
-@@ -33968,28 +30725,25 @@
-
- void tetgenmesh::qualitystatistics()
- {
-- triface tetloop, neightet;
-+ triface tetloop;
- point p[4];
- char sbuf[128];
- REAL radiusratiotable[12];
- REAL aspectratiotable[12];
- REAL A[4][4], rhs[4], D;
- REAL V[6][3], N[4][3], H[4]; // edge-vectors, face-normals, face-heights.
-- REAL edgelength[6], alldihed[6], faceangle[3];
-+ REAL edgelength[6], alldihed[6];
- REAL shortest, longest;
- REAL smallestvolume, biggestvolume;
- REAL smallestdiangle, biggestdiangle;
-- REAL smallestfaangle, biggestfaangle;
- REAL tetvol, minaltitude;
- REAL cirradius, minheightinv; // insradius;
- REAL shortlen, longlen;
- REAL tetaspect, tetradius;
- REAL smalldiangle, bigdiangle;
-- REAL smallfaangle, bigfaangle;
- int radiustable[12];
- int aspecttable[16];
- int dihedangletable[18];
-- int faceangletable[18];
- int indx[4];
- int radiusindex;
- int aspectindex;
-@@ -34019,7 +30773,6 @@
- for (i = 0; i < 12; i++) radiustable[i] = 0;
- for (i = 0; i < 12; i++) aspecttable[i] = 0;
- for (i = 0; i < 18; i++) dihedangletable[i] = 0;
-- for (i = 0; i < 18; i++) faceangletable[i] = 0;
-
- minaltitude = xmax - xmin + ymax - ymin + zmax - zmin;
- minaltitude = minaltitude * minaltitude;
-@@ -34027,8 +30780,8 @@
- longest = 0.0;
- smallestvolume = minaltitude;
- biggestvolume = 0.0;
-- smallestdiangle = smallestfaangle = 180.0;
-- biggestdiangle = biggestfaangle = 0.0;
-+ smallestdiangle = 180.0;
-+ biggestdiangle = 0.0;
-
- // Loop all elements, calculate quality parameters for each element.
- tetrahedrons->traversalinit();
-@@ -34172,45 +30925,6 @@
- }
- dihedangletable[tendegree]++;
-
-- // Calulate the largest and smallest face angles.
-- tetloop.ver = 0;
-- for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
-- sym(tetloop, neightet);
-- // Only do the calulation once for a face.
-- if ((neightet.tet == dummytet) || (tetloop.tet < neightet.tet)) {
-- p[0] = org(tetloop);
-- p[1] = dest(tetloop);
-- p[2] = apex(tetloop);
-- faceangle[0] = interiorangle(p[0], p[1], p[2], NULL);
-- faceangle[1] = interiorangle(p[1], p[2], p[0], NULL);
-- faceangle[2] = PI - (faceangle[0] + faceangle[1]);
-- // Translate angles into degrees.
-- for (i = 0; i < 3; i++) {
-- faceangle[i] = (faceangle[i] * 180.0) / PI;
-- }
-- // Calculate the largest and smallest face angles.
-- for (i = 0; i < 3; i++) {
-- if (i == 0) {
-- smallfaangle = bigfaangle = faceangle[i];
-- } else {
-- smallfaangle = faceangle[i] < smallfaangle ?
-- faceangle[i] : smallfaangle;
-- bigfaangle = faceangle[i] > bigfaangle ? faceangle[i] : bigfaangle;
-- }
-- if (faceangle[i] < smallestfaangle) {
-- smallestfaangle = faceangle[i];
-- }
-- if (faceangle[i] > biggestfaangle) {
-- biggestfaangle = faceangle[i];
-- }
-- }
-- tendegree = (int) (smallfaangle / 10.);
-- faceangletable[tendegree]++;
-- tendegree = (int) (bigfaangle / 10.);
-- faceangletable[tendegree]++;
-- }
-- }
--
- // Calculate aspect ratio and radius-edge ratio for this element.
- tetradius = cirradius / sqrt(shortlen);
- // tetaspect = sqrt(longlen) / (2.0 * insradius);
-@@ -34237,12 +30951,6 @@
- smallestvolume, biggestvolume);
- printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n",
- shortest, longest);
-- sprintf(sbuf, "%.17g", biggestfaangle);
-- if (strlen(sbuf) > 8) {
-- sbuf[8] = '\0';
-- }
-- printf(" Smallest facangle: %14.5g | Largest facangle: %s\n",
-- smallestfaangle, sbuf);
- sprintf(sbuf, "%.17g", biggestdiangle);
- if (strlen(sbuf) > 8) {
- sbuf[8] = '\0';
-@@ -34250,7 +30958,6 @@
- printf(" Smallest dihedral: %14.5g | Largest dihedral: %s\n\n",
- smallestdiangle, sbuf);
-
-- /*
- printf(" Radius-edge ratio histogram:\n");
- printf(" < %-6.6g : %8d | %6.6g - %-6.6g : %8d\n",
- radiusratiotable[0], radiustable[0], radiusratiotable[5],
-@@ -34267,7 +30974,6 @@
- printf(" (A tetrahedron's radius-edge ratio is its radius of ");
- printf("circumsphere divided\n");
- printf(" by its shortest edge length)\n\n");
-- */
-
- printf(" Aspect ratio histogram:\n");
- printf(" < %-6.6g : %8d | %6.6g - %-6.6g : %8d\n",
-@@ -34286,18 +30992,6 @@
- printf(" divided by its\n");
- printf(" smallest side height)\n\n");
-
-- printf(" Face angle histogram:\n");
-- for (i = 0; i < 9; i++) {
-- printf(" %3d - %3d degrees: %8d | %3d - %3d degrees: %8d\n",
-- i * 10, i * 10 + 10, faceangletable[i],
-- i * 10 + 90, i * 10 + 100, faceangletable[i + 9]);
-- }
-- if (minfaceang != PI) {
-- printf(" Minimum input face angle is %g (degree).\n",
-- minfaceang / PI * 180.0);
-- }
-- printf("\n");
--
- printf(" Dihedral angle histogram:\n");
- // Print the three two rows:
- printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n",
-@@ -34315,10 +31009,7 @@
- 60, 70, dihedangletable[7], 170, 175, dihedangletable[16]);
- printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n",
- 70, 80, dihedangletable[8], 175, 180, dihedangletable[17]);
-- if (minfacetdihed != PI) {
-- printf(" Minimum input facet dihedral angle is %g (degree).\n",
-- minfacetdihed / PI * 180.0);
-- }
-+
- printf("\n");
- }
-
-@@ -34337,7 +31028,6 @@
- }
- if (b->plc) {
- printf(" Input facets: %d\n", in->numberoffacets);
-- printf(" Input segments: %ld\n", insegments);
- printf(" Input holes: %d\n", in->numberofholes);
- printf(" Input regions: %d\n", in->numberofregions);
- }
-@@ -34345,35 +31035,20 @@
- printf("\n Mesh points: %ld\n", points->items);
- printf(" Mesh tetrahedra: %ld\n", tetrahedrons->items);
- if (b->plc || b->refine) {
-- printf(" Mesh triangles: %ld\n", (4l*tetrahedrons->items+hullsize)/2l);
-+ printf(" Mesh faces: %ld\n", (4l * tetrahedrons->items + hullsize) / 2l);
- }
- if (b->plc || b->refine) {
- printf(" Mesh subfaces: %ld\n", subfaces->items);
- printf(" Mesh subsegments: %ld\n\n", subsegs->items);
- } else {
-- printf(" Convex hull triangles: %ld\n\n", hullsize);
-+ printf(" Convex hull faces: %ld\n\n", hullsize);
- }
- if (b->verbose > 0) {
-- qualitystatistics();
-- unsigned long totalmeshbytes;
-- printf("Memory allocation statistics:\n\n");
-- printf(" Maximum number of vertices: %ld\n", points->maxitems);
-- totalmeshbytes = points->maxitems * points->itembytes;
-- printf(" Maximum number of tetrahedra: %ld\n", tetrahedrons->maxitems);
-- totalmeshbytes += tetrahedrons->maxitems * tetrahedrons->itembytes;
-- if (subfaces != (memorypool *) NULL) {
-- printf(" Maximum number of subfaces: %ld\n", subfaces->maxitems);
-- totalmeshbytes += subfaces->maxitems * subfaces->itembytes;
-- }
-- if (subsegs != (memorypool *) NULL) {
-- printf(" Maximum number of segments: %ld\n", subsegs->maxitems);
-- totalmeshbytes += subsegs->maxitems * subsegs->itembytes;
-- }
-- printf(" Approximate heap memory used by the mesh (K bytes): %g\n\n",
-- (double) totalmeshbytes / 1024.0);
- #ifdef SELF_CHECK
-- algorithmicstatistics();
-+ // algorithmicstatistics();
- #endif
-+ qualitystatistics();
-+ printf("\n");
- }
- }
-
-@@ -34469,7 +31144,7 @@
- longest = 0.0;
- hullsize = 0l;
- insegments = 0l;
-- pointmtrindex = 0;
-+ pointlfsindex = 0;
- pointmarkindex = 0;
- point2simindex = 0;
- point2pbcptindex = 0;
-@@ -34479,7 +31154,6 @@
- shmarkindex = 0;
- areaboundindex = 0;
- checksubfaces = 0;
-- checksubsegs = 0;
- checkpbcs = 0;
- varconstraint = 0;
- nonconvex = 0;
-@@ -34490,11 +31164,10 @@
- collapverts = 0;
- unsupverts = 0;
- jettisoninverts = 0;
-- symbolic = 1;
-+ symbolic = 0;
- samples = 0l;
-- randomseed = 1l;
-+ randomseed = 0l;
- macheps = 0.0;
-- minfaceang = minfacetdihed = PI;
- maxcavfaces = maxcavverts = 0;
- expcavcount = 0;
- abovecount = 0l;
-@@ -34503,11 +31176,10 @@
- repairflipcount = 0l;
- outbowatcircumcount = 0l;
- failvolcount = failsubcount = failsegcount = 0l;
-- r1count = r2count = r3count = 0l;
-+ r1count = r2count = r3count = r4count = 0l;
- cdtenforcesegpts = 0l;
- rejsegpts = rejsubpts = rejtetpts = 0l;
- flip23s = flip32s = flip22s = flip44s = 0l;
-- tloctime = tfliptime = 0.0;
- }
-
- //
-@@ -34542,29 +31214,31 @@
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
-+#include <time.h> // Defined type clock_t, constant CLOCKS_PER_SEC.
-+
- void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
-- tetgenio *addin, tetgenio *bgmin)
-+ tetgenio *bgmesh)
- {
- tetgenmesh m;
-- // Variables for timing the performance of TetGen (defined in time.h).
-- clock_t tv[14];
-+ clock_t tv0, tv1, tv2, tv3, tv4, tv5, tv6, tv7, tv8, tv9, tv10, tv11;
-
-- tv[0] = clock();
-+ tv0 = clock();
-
- m.b = b;
- m.in = in;
- m.macheps = exactinit();
- m.steinerleft = b->steiner;
-- if (b->metric) {
-+ if (b->bgmesh) {
-+ // '-m' switch
- m.bgm = new tetgenmesh();
- m.bgm->b = b;
-- m.bgm->in = bgmin;
-+ m.bgm->in = bgmesh;
- m.bgm->macheps = exactinit();
- }
- m.initializepools();
- m.transfernodes();
-
-- tv[1] = clock();
-+ tv1 = clock();
-
- if (b->refine) {
- m.reconstructmesh();
-@@ -34572,149 +31246,103 @@
- m.delaunizevertices();
- }
-
-- tv[2] = clock();
--
-+ tv2 = clock();
- if (!b->quiet) {
- if (b->refine) {
-- printf("Mesh reconstruction seconds:");
-- } else {
-- printf("Delaunay seconds:");
-- }
-- printf(" %g\n", (tv[2] - tv[1]) / (REAL) CLOCKS_PER_SEC);
-- }
--
-- if (b->metric) {
-- if (bgmin != (tetgenio *) NULL) {
-- m.bgm->initializepools();
-- m.bgm->transfernodes();
-- m.bgm->reconstructmesh();
-+ printf("Mesh reconstruction seconds: %g\n",
-+ (tv2 - tv1) / (REAL) CLOCKS_PER_SEC);
- } else {
-- m.bgm->in = in;
-- m.bgm->initializepools();
-- m.duplicatebgmesh();
-- }
-- }
--
-- tv[3] = clock();
--
-- if (!b->quiet) {
-- if (b->metric) {
-- printf("Background mesh reconstruct seconds: %g\n",
-- (tv[3] - tv[2]) / (REAL) CLOCKS_PER_SEC);
-+ printf("Delaunay seconds: %g\n", (tv2 - tv1) / (REAL) CLOCKS_PER_SEC);
- }
- }
-
- if (b->useshelles && !b->refine) {
-- m.meshsurface();
-+ m.insegments = m.meshsurface();
- if (b->diagnose != 1) {
-- m.markacutevertices(89.0);
-- m.incrperturbvertices(b->epsilon);
-+ m.incrperturbvertices(b->epsilon); // '-p' switch.
- m.delaunizesegments();
-- if (m.checkpbcs) {
-- long oldnum;
-- do {
-- oldnum = m.points->items;
-- m.incrperturbvertices(b->epsilon);
-- if (m.points->items > oldnum) {
-- oldnum = m.points->items;
-- m.delaunizesegments();
-- }
-- } while (oldnum < m.points->items);
-- }
- m.constrainedfacets();
- } else {
-- m.detectinterfaces();
-+ m.detectinterfaces(); // '-d' switch.
- }
- }
-
-- tv[4] = clock();
--
-+ tv3 = clock();
- if (!b->quiet) {
- if (b->useshelles && !b->refine) {
- if (b->diagnose != 1) {
-- printf("Segment and facet ");
-+ printf("Segment and facet seconds: %g\n",
-+ (tv3 - tv2) / (REAL) CLOCKS_PER_SEC);
- } else {
-- printf("Intersection ");
-+ printf("Intersection seconds: %g\n",
-+ (tv3 - tv2) / (REAL) CLOCKS_PER_SEC);
- }
-- printf("seconds: %g\n", (tv[4] - tv[3]) / (REAL) CLOCKS_PER_SEC);
-- }
-+ }
- }
-
- if (b->plc && !(b->diagnose == 1)) {
- m.carveholes();
- }
-
-- tv[5] = clock();
--
-+ tv4 = clock();
- if (!b->quiet) {
- if (b->plc && !(b->diagnose == 1)) {
-- printf("Hole seconds: %g\n", (tv[5] - tv[4]) / (REAL) CLOCKS_PER_SEC);
-+ printf("Hole seconds: %g\n", (tv4 - tv3) / (REAL) CLOCKS_PER_SEC);
- }
- }
-
- if ((b->plc || b->refine) && !(b->diagnose == 1)) {
-- m.optimizemesh(false);
-+ m.repairmesh();
- }
-
-- tv[6] = clock();
--
-+ tv5 = clock();
- if (!b->quiet) {
- if ((b->plc || b->refine) && !(b->diagnose == 1)) {
-- printf("Repair seconds: %g\n", (tv[6] - tv[5]) / (REAL) CLOCKS_PER_SEC);
-+ printf("Repair seconds: %g\n", (tv5 - tv4) / (REAL) CLOCKS_PER_SEC);
- }
- }
-
- if ((b->plc && b->nobisect) && !(b->diagnose == 1)) {
-- m.removesteiners(false);
-+ m.removesteiners();
- }
-
-- tv[7] = clock();
--
-+ tv6 = clock();
- if (!b->quiet) {
- if ((b->plc && b->nobisect) && !(b->diagnose == 1)) {
- printf("Steiner removal seconds: %g\n",
-- (tv[7] - tv[6]) / (REAL) CLOCKS_PER_SEC);
-+ (tv6 - tv5) / (REAL) CLOCKS_PER_SEC);
- }
- }
-
-- if (b->insertaddpoints && (addin != (tetgenio *) NULL)) {
-- if (addin->numberofpoints > 0) {
-- m.insertconstrainedpoints(addin);
-+ if (b->insertaddpoints) {
-+ if (in->numberofaddpoints == 0) {
-+ in->load_addnodes(b->infilename);
- }
-- }
--
-- tv[8] = clock();
--
-- if (!b->quiet) {
-- if ((b->plc || b->refine) && (b->insertaddpoints)) {
-- printf("Constrained points seconds: %g\n",
-- (tv[8] - tv[7]) / (REAL) CLOCKS_PER_SEC);
-+ if (in->numberofaddpoints > 0) {
-+ m.insertaddpoints();
- }
- }
-
-- if (b->metric) {
-- m.interpolatesizemap();
-- }
--
-- tv[9] = clock();
--
-+ tv7 = clock();
- if (!b->quiet) {
-- if (b->metric) {
-- printf("Size interpolating seconds: %g\n",
-- (tv[9] - tv[8]) / (REAL) CLOCKS_PER_SEC);
-+ if ((b->plc || b->refine) && (in->numberofaddpoints > 0)) {
-+ printf("Add points seconds: %g\n", (tv7 - tv6) / (REAL) CLOCKS_PER_SEC);
- }
- }
-
-- if (b->coarse) {
-- m.removesteiners(true);
-+ if (b->bgmesh) {
-+ // '-b' switch
-+ m.bgm->initializepools();
-+ m.bgm->transfernodes();
-+ m.bgm->reconstructmesh();
-+ m.interpolatesizemap();
- }
-
-- tv[10] = clock();
--
-+ tv8 = clock();
- if (!b->quiet) {
-- if (b->coarse) {
-- printf("Mesh coarsening seconds: %g\n",
-- (tv[10] - tv[9]) / (REAL) CLOCKS_PER_SEC);
-+ if (b->bgmesh) {
-+ printf("Background mesh reconstruct seconds: %g\n",
-+ (tv8 - tv7) / (REAL) CLOCKS_PER_SEC);
- }
- }
-
-@@ -34722,25 +31350,21 @@
- m.enforcequality();
- }
-
-- tv[11] = clock();
--
-+ tv9 = clock();
- if (!b->quiet) {
- if (b->quality) {
-- printf("Quality seconds: %g\n",
-- (tv[11] - tv[10]) / (REAL) CLOCKS_PER_SEC);
-+ printf("Quality seconds: %g\n", (tv9 - tv8) / (REAL) CLOCKS_PER_SEC);
- }
- }
-
-- if (b->quality && (b->optlevel > 0)) {
-- m.optimizemesh(true);
-+ if (b->quality && b->smooth) {
-+ m.smoothmesh();
- }
-
-- tv[12] = clock();
--
-+ tv10 = clock();
- if (!b->quiet) {
-- if (b->quality && (b->optlevel > 0)) {
-- printf("Optimize seconds: %g\n",
-- (tv[12] - tv[11]) / (REAL) CLOCKS_PER_SEC);
-+ if (b->quality && b->smooth) {
-+ printf("Smooth seconds: %g\n", (tv10 - tv9) / (REAL) CLOCKS_PER_SEC);
- }
- }
-
-@@ -34769,12 +31393,13 @@
- } else {
- if (b->diagnose == 1) {
- if (m.subfaces->items > 0l) {
-- m.outnodes(out); // Only output when self-intersecting faces exist.
-+ // Only output when there are intersecting faces.
-+ m.outnodes(out);
- }
- } else {
- m.outnodes(out);
-- if (b->quality || b->metric) {
-- // m.outmetrics(out);
-+ if (b->metric) {
-+ m.outmetrics(out);
- }
- }
- }
-@@ -34798,20 +31423,24 @@
- } else {
- if (b->facesout) {
- if (m.tetrahedrons->items > 0l) {
-- m.outfaces(out); // Output all faces.
-+ // Output all faces.
-+ m.outfaces(out);
- }
- } else {
- if (b->diagnose == 1) {
- if (m.subfaces->items > 0l) {
-- m.outsubfaces(out); // Only output self-intersecting faces.
-+ // Only output when there are intersecting faces.
-+ m.outsubfaces(out);
- }
- } else if (b->plc || b->refine) {
- if (m.subfaces->items > 0l) {
-- m.outsubfaces(out); // Output boundary faces.
-+ // Output boundary faces.
-+ m.outsubfaces(out);
- }
- } else {
- if (m.tetrahedrons->items > 0l) {
-- m.outhullfaces(out); // Output convex hull faces.
-+ // Output convex hull faces.
-+ m.outhullfaces(out);
- }
- }
- }
-@@ -34821,11 +31450,9 @@
- m.outpbcnodes(out);
- }
-
-- if (b->edgesout) {
-- if (b->edgesout > 1) {
-- m.outedges(out); // -ee, output all mesh edges.
-- } else {
-- m.outsubsegments(out); // -e, only output subsegments.
-+ if (b->edgesout && b->plc) {
-+ if (m.subsegs->items > 0l) {
-+ m.outsubsegments(out);
- }
- }
-
-@@ -34852,17 +31479,11 @@
- m.outneighbors(out);
- }
-
-- if (b->voroout) {
-- m.outvoronoi(out);
-- }
--
-- tv[13] = clock();
--
-+ tv11 = clock();
- if (!b->quiet) {
-- printf("\nOutput seconds: %g\n",
-- (tv[13] - tv[12]) / (REAL) CLOCKS_PER_SEC);
-+ printf("\nOutput seconds: %g\n", (tv11 - tv10) / (REAL) CLOCKS_PER_SEC);
- printf("Total running seconds: %g\n",
-- (tv[13] - tv[0]) / (REAL) CLOCKS_PER_SEC);
-+ (tv11 - tv0) / (REAL) CLOCKS_PER_SEC);
- }
-
- if (b->docheck) {
-@@ -34884,7 +31505,7 @@
- m.statistics();
- }
-
-- if (b->metric) {
-+ if (bgmesh) {
- delete m.bgm;
- }
- }
-@@ -34908,7 +31529,7 @@
- ///////////////////////////////////////////////////////////////////////////////
-
- void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
-- tetgenio *addin, tetgenio *bgmin)
-+ tetgenio *bgmesh)
-
- #endif // not TETLIBRARY
-
-@@ -34917,7 +31538,7 @@
-
- #ifndef TETLIBRARY
-
-- tetgenio in, addin, bgmin;
-+ tetgenio in, bgmesh;
-
- if (!b.parse_commandline(argc, argv)) {
- terminatetetgen(1);
-@@ -34931,21 +31552,16 @@
- terminatetetgen(1);
- }
- }
-- if (b.insertaddpoints) {
-- if (!addin.load_node(b.addinfilename)) {
-- addin.numberofpoints = 0l;
-- }
-- }
-- if (b.metric) {
-- if (!bgmin.load_tetmesh(b.bgmeshfilename)) {
-- bgmin.numberoftetrahedra = 0l;
-+ if (b.bgmesh) {
-+ if (!bgmesh.load_tetmesh(b.bgmeshfilename)) {
-+ bgmesh.numberoftetrahedra = 0l;
- }
- }
-
-- if (bgmin.numberoftetrahedra > 0l) {
-- tetrahedralize(&b, &in, NULL, &addin, &bgmin);
-+ if (bgmesh.numberoftetrahedra > 0l) {
-+ tetrahedralize(&b, &in, NULL, &bgmesh);
- } else {
-- tetrahedralize(&b, &in, NULL, &addin, NULL);
-+ tetrahedralize(&b, &in, NULL, NULL);
- }
-
- return 0;
-@@ -34955,7 +31571,7 @@
- if (!b.parse_commandline(switches)) {
- terminatetetgen(1);
- }
-- tetrahedralize(&b, in, out, addin, bgmin);
-+ tetrahedralize(&b, in, out, bgmesh);
-
- #endif // not TETLIBRARY
- }
-Index: tetgen1.4.2/tetgen.h
-===================================================================
---- tetgen1.4.2.orig/tetgen.h 2008-02-16 01:32:48.444098094 +0100
-+++ tetgen1.4.2/tetgen.h 2008-02-16 01:33:05.227498420 +0100
-@@ -5,22 +5,16 @@
- // A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator //
- // //
- // Version 1.4 //
--// April 16, 2007 //
-+// January 14, 2006 //
- // //
--// Copyright (C) 2002--2007 //
-+// Copyright 2002, 2004, 2005, 2006 //
- // Hang Si //
--// Research Group Numerical Mathematics and Scientific Computing //
--// Weierstrass Institute for Applied Analysis and Stochastics //
--// Mohrenstr. 39, 10117 Berlin, Germany //
-+// Rathausstr. 9, 10178 Berlin, Germany //
- // si at wias-berlin.de //
- // //
--// TetGen is freely available through the website: http://tetgen.berlios.de. //
--// It may be copied, modified, and redistributed for non-commercial use. //
--// Please consult the file LICENSE for the detailed copyright notices. //
--// //
--///////////////////////////////////////////////////////////////////////////////
--
--///////////////////////////////////////////////////////////////////////////////
-+// You can obtain TetGen via internet: http://tetgen.berlios.de. It may be //
-+// freely copied, modified, and redistributed under the copyright notices //
-+// given in the file LICENSE. //
- // //
- // TetGen computes Delaunay tetrahedralizations, constrained Delaunay tetra- //
- // hedralizations, and quality Delaunay tetrahedral meshes. The latter are //
-@@ -34,25 +28,26 @@
- // //
- // The efficient Delaunay tetrahedralization algorithm is: H. Edelsbrunner //
- // and N. R. Shah, "Incremental Topological Flipping Works for Regular //
--// Triangulations". Algorithmica 15: 223--241, 1996. //
-+// Triangulations". Algorithmica 15: 223-241, 1996. //
- // //
- // The constrained Delaunay tetrahedralization algorithm is described in: //
- // H. Si and K. Gaertner, "Meshing Piecewise Linear Complexes by Constr- //
- // ained Delaunay Tetrahedralizations". In Proceeding of the 14th Inter- //
- // national Meshing Roundtable. September 2005. //
- // //
--// The mesh refinement algorithm is from: Hang Si, "Adaptive Tetrahedral //
--// Mesh Generation by Constrained Delaunay Refinement". WIAS Preprint No. //
--// 1176, Berlin 2006. //
-+// The Delaunay refinement algorithm is from: Hang Si, "On Refinement of //
-+// Constrained Delaunay Tetrahedralizations". In Proceeding of the 15th //
-+// International Meshing Roundtable. September 2006. //
- // //
- // The mesh data structure of TetGen is a combination of two types of mesh //
- // data structures. The tetrahedron-based mesh data structure introduced //
- // by Shewchuk is eligible for tetrahedralization algorithms. The triangle //
- // -edge data structure developed by Muecke is adopted for representing //
--// boundary elements: subfaces and subsegments. //
-+// boundary elements: subfaces and subsegments. Both data structures have //
-+// a set of fast mesh manipulation primitives. //
- // //
- // J. R. Shewchuk, "Delaunay Refinement Mesh Generation". PhD thesis, //
--// Carnegie Mellon University, Pittsburgh, PA, 1997. //
-+// Carnegie Mellon University, 1997. //
- // //
- // E. P. Muecke, "Shapes and Implementations in Three-Dimensional //
- // Geometry". PhD thesis, Univ. of Illinois, Urbana, Illinois, 1993. //
-@@ -79,15 +74,6 @@
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
--// Here are the most general used head files for C/C++ programs.
--
--#include <stdio.h> // Standard IO: FILE, NULL, EOF, printf(), ...
--#include <stdlib.h> // Standard lib: abort(), system(), getenv(), ...
--#include <string.h> // String lib: strcpy(), strcat(), strcmp(), ...
--#include <math.h> // Math lib: sin(), sqrt(), pow(), ...
--#include <time.h> // Defined type clock_t, constant CLOCKS_PER_SEC.
--#include <assert.h>
--
- ///////////////////////////////////////////////////////////////////////////////
- // //
- // TetGen Library Overview //
-@@ -142,30 +128,40 @@
- #define REAL double
- #endif // not defined SINGLE
-
-+// Here are the most general used head files for C/C++ programs.
-+
-+#include <stdio.h> // Standard IO: FILE, NULL, EOF, printf(), ...
-+#include <stdlib.h> // Standard lib: abort(), system(), getenv(), ...
-+#include <string.h> // String lib: strcpy(), strcat(), strcmp(), ...
-+#include <math.h> // Math lib: sin(), sqrt(), pow(), ...
-+#include <assert.h>
-+
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// tetgenio Passing data into and out of the library of TetGen. //
-+// The tetgenio data type //
- // //
--// The tetgenio data structure is actually a collection of arrays of points, //
--// facets, tetrahedra, and so forth. The library will read and write these //
--// arrays according to the options specified in tetgenbehavior structure. //
-+// Used to pass data into and out of the library of TetGen. //
- // //
- // If you want to program with the library of TetGen, it's necessary for you //
--// to understand this data type,while the other two structures can be hidden //
--// through calling the global function "tetrahedralize()". Each array corre- //
--// sponds to a list of data in the file formats of TetGen. It is necessary //
--// to understand TetGen's input/output file formats (see user's manual). //
--// //
--// Once an object of tetgenio is declared, no array is created. One has to //
--// allocate enough memory for them, e.g., use the "new" operator in C++. On //
--// deletion of the object, the memory occupied by these arrays needs to be //
--// freed. Routine deinitialize() will be automatically called. It will de- //
--// allocate the memory for an array if it is not a NULL. However, it assumes //
--// that the memory is allocated by the C++ "new" operator. If you use malloc //
--// (), you should free() them and set the pointers to NULLs before reaching //
--// deinitialize(). //
-+// to understand the tetgenio data type, while the other two data types can //
-+// be hidden through calling the global function "tetrahedralize()". As you //
-+// will see, that tetgenio is just a collection of arrays to storing points //
-+// (by coodinates), tetrahedra (by indexes), faces, boundary markers, and so //
-+// forth. Each array corresponds to a list of data in the file formats of //
-+// TetGen. It is necessary to understand TetGen's input/output file formats //
-+// (see user's manual) before using tetgenio objects. //
-+// //
-+// Once an object of tetgenio is declared (or created), all arrays of it are //
-+// automatically initialized to NULLs (by routine initialize()). Before they //
-+// can be used, one has to first allocate enough memory for them, i.e., use //
-+// either 'malloc()' or 'new' operator. On deletion of the object, one needs //
-+// to free the memory occupied by these arrays. Routine deinitialize() will //
-+// be automatically called. It will deallocate the memory for an array if it //
-+// is not a NULL. However, it assumes that the memory is allocated by 'new' //
-+// (C++ operator). If you use malloc(), you should free() them and set the //
-+// pointers to NULLs before reaching deinitialize(). //
- // //
--// In all cases, the first item in an array is stored starting at index [0]. //
-+// In all cases, the first item in any array is stored starting at index [0].//
- // However, that item is item number `firstnumber' which may be '0' or '1'. //
- // Be sure to set the 'firstnumber' be '1' if your indices pointing into the //
- // pointlist is starting from '1'. Default, it is initialized be '0'. //
-@@ -222,30 +218,6 @@
- f->numberofholes = 0;
- }
-
-- // A 'voroedge' is an edge of the Voronoi diagram. It corresponds to a
-- // Delaunay face. Each voroedge is either a line segment connecting
-- // two Voronoi vertices or a ray starting from a Voronoi vertex to an
-- // "infinite vertex". 'v1' and 'v2' are two indices pointing to the
-- // list of Voronoi vertices. 'v1' must be non-negative, while 'v2' may
-- // be -1 if it is a ray, in this case, the unit normal of this ray is
-- // given in 'vnormal'.
-- typedef struct {
-- int v1, v2;
-- REAL vnormal[3];
-- } voroedge;
--
-- // A 'vorofacet' is an facet of the Voronoi diagram. It corresponds to a
-- // Delaunay edge. Each Voronoi facet is a convex polygon formed by a
-- // list of Voronoi edges, it may not be closed. 'c1' and 'c2' are two
-- // indices pointing into the list of Voronoi cells, i.e., the two cells
-- // share this facet. 'elist' is an array of indices pointing into the
-- // list of Voronoi edges, 'elist[0]' saves the number of Voronoi edges
-- // (including rays) of this facet.
-- typedef struct {
-- int c1, c2;
-- int *elist;
-- } vorofacet;
--
- // The periodic boundary condition group data structure. A "pbcgroup"
- // contains the definition of a pbc and the list of pbc point pairs.
- // 'fmark1' and 'fmark2' are the facetmarkers of the two pbc facets f1
-@@ -264,27 +236,27 @@
-
- // Items are numbered starting from 'firstnumber' (0 or 1), default is 0.
- int firstnumber;
-+
- // Dimension of the mesh (2 or 3), default is 3.
- int mesh_dim;
-- // Does the lines in .node file contain index or not, default is TRUE.
-- bool useindex;
-
-- // 'pointlist': An array of point coordinates. The first point's x
-+ // `pointlist': An array of point coordinates. The first point's x
- // coordinate is at index [0] and its y coordinate at index [1], its
- // z coordinate is at index [2], followed by the coordinates of the
- // remaining points. Each point occupies three REALs.
-- // 'pointattributelist': An array of point attributes. Each point's
-- // attributes occupy 'numberofpointattributes' REALs.
-- // 'pointmtrlist': An array of metric tensors at points. Each point's
-- // tensor occupies 'numberofpointmtr' REALs.
-+ // `pointattributelist': An array of point attributes. Each point's
-+ // attributes occupy `numberofpointattributes' REALs.
-+ // 'addpointlist': An array of additional point coordinates.
-+ // 'addpointattributelist': An array of attributes for addition points.
- // `pointmarkerlist': An array of point markers; one int per point.
- REAL *pointlist;
- REAL *pointattributelist;
-- REAL *pointmtrlist;
-+ REAL *addpointlist;
-+ REAL *addpointattributelist;
- int *pointmarkerlist;
- int numberofpoints;
- int numberofpointattributes;
-- int numberofpointmtrs;
-+ int numberofaddpoints;
-
- // `elementlist': An array of element (triangle or tetrahedron) corners.
- // The first element's first corner is at index [0], followed by its
-@@ -342,6 +314,13 @@
- REAL *segmentconstraintlist;
- int numberofsegmentconstraints;
-
-+ // `nodeconstraintlist': An array of segment length constraints. Two
-+ // REALs per constraint. The first one is the index (pointing into
-+ // 'pointlist') of the node, the second is its edge length bound.
-+ // Note the 'nodeconstraintlist' is used only for the 'q' switch.
-+ REAL *nodeconstraintlist;
-+ int numberofnodeconstraints;
-+
- // 'pbcgrouplist': An array of periodic boundary condition groups.
- pbcgroup *pbcgrouplist;
- int numberofpbcgroups;
-@@ -352,7 +331,7 @@
- // `adjtetlist': An array of adjacent tetrahedra to the faces of
- // trifacelist. Each face has at most two adjacent tets, the first
- // face's adjacent tets are at [0], [1]. Two ints per face. A '-1'
-- // indicates outside (no adj. tet). This list is output when '-nn'
-+ // indicates outside (no adj. tet). This list is output when '-n'
- // switch is used.
- // `trifacemarkerlist': An array of face markers; one int per face.
- int *trifacelist;
-@@ -368,21 +347,6 @@
- int *edgemarkerlist;
- int numberofedges;
-
-- // 'vpointlist': An array of Voronoi vertex coordinates (like pointlist).
-- // 'vedgelist': An array of Voronoi edges. Each entry is a 'voroedge'.
-- // 'vfacetlist': An array of Voronoi facets. Each entry is a 'vorofacet'.
-- // 'vcelllist': An array of Voronoi cells. Each entry is an array of
-- // indices pointing into 'vfacetlist'. The 0th entry is used to store
-- // the length of this array.
-- REAL *vpointlist;
-- voroedge *vedgelist;
-- vorofacet *vfacetlist;
-- int **vcelllist;
-- int numberofvpoints;
-- int numberofvedges;
-- int numberofvfacets;
-- int numberofvcells;
--
- public:
-
- // Initialize routine.
-@@ -392,6 +356,7 @@
- // Input & output routines.
- bool load_node_call(FILE* infile, int markers, char* nodefilename);
- bool load_node(char* filename);
-+ bool load_addnodes(char* filename);
- bool load_pbc(char* filename);
- bool load_var(char* filename);
- bool load_mtr(char* filename);
-@@ -402,7 +367,6 @@
- bool load_medit(char* filename);
- bool load_plc(char* filename, int object);
- bool load_tetmesh(char* filename);
-- bool load_voronoi(char* filename);
- void save_nodes(char* filename);
- void save_elements(char* filename);
- void save_faces(char* filename);
-@@ -423,7 +387,9 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
--// tetgenbehavior Parsing command line switches and file names. //
-+// The tetgenbehavior data type //
-+// //
-+// Used to parse command line switches and file names. //
- // //
- // It includes a list of variables corresponding to the commandline switches //
- // for control the behavior of TetGen. These varibales are all initialized //
-@@ -459,29 +425,28 @@
-
- enum objecttype {NONE, NODES, POLY, OFF, PLY, STL, MEDIT, MESH};
-
-- // Variables of command line switches. Each variable corresponds to a
-- // switch and will be initialized. The meanings of these switches
-- // are explained in the user's manul.
-+ // Variables of command line switches. Each variable is corresponding
-+ // to a specific switch and will be properly initialized. Read the
-+ // user's manul to find out the meaning of these switches.
-
- int plc; // '-p' switch, 0.
-- int quality; // '-q' switch, 0.
- int refine; // '-r' switch, 0.
-- int coarse; // '-R' switch, 0.
-+ int quality; // '-q' switch, 0.
-+ int smooth; // '-s' switch, 0.
- int metric; // '-m' switch, 0.
-+ int bgmesh; // '-b' switch, 0.
- int varvolume; // '-a' switch without number, 0.
- int fixedvolume; // '-a' switch with number, 0.
- int insertaddpoints; // '-i' switch, 0.
- int regionattrib; // '-A' switch, 0.
-+ int offcenter; // '-R' switch, 0.
- int conformdel; // '-D' switch, 0.
- int diagnose; // '-d' switch, 0.
- int zeroindex; // '-z' switch, 0.
-- int optlevel; // number specified after '-s' switch, 3.
-- int optpasses; // number specified after '-ss' switch, 5.
- int order; // element order, specified after '-o' switch, 1.
- int facesout; // '-f' switch, 0.
- int edgesout; // '-e' switch, 0.
- int neighout; // '-n' switch, 0.
-- int voroout; // '-v',switch, 0.
- int meditview; // '-g' switch, 0.
- int gidview; // '-G' switch, 0.
- int geomview; // '-O' switch, 0.
-@@ -490,27 +455,26 @@
- int noelewritten; // '-E' switch, 0.
- int nofacewritten; // '-F' switch, 0.
- int noiterationnum; // '-I' switch, 0.
-- int nomerge; // '-M',switch, 0.
-+ int nomerge; // count of how often '-M' switch is selected, 0.
- int nobisect; // count of how often '-Y' switch is selected, 0.
-- int noflip; // do not perform flips. '-X' switch. 0.
-+ int noflip; // do not perform flips. '-Y' switch. 0.
- int nojettison; // do not jettison redundants nodes. '-J' switch. 0.
- int steiner; // number after '-S' switch. 0.
- int fliprepair; // '-X' switch, 1.
-- int offcenter; // '-R' switch, 0.
- int docheck; // '-C' switch, 0.
- int quiet; // '-Q' switch, 0.
- int verbose; // count of how often '-V' switch is selected, 0.
-- int useshelles; // '-p', '-r', '-q', '-d', or '-R' switch, 0.
-+ int tol; // count of how often '-T' switch is selected, 0.
-+ int useshelles; // '-p', '-r', '-q', '-d', or '-c' switch, 0.
- REAL minratio; // number after '-q' switch, 2.0.
- REAL goodratio; // number calculated from 'minratio', 0.0.
- REAL minangle; // minimum angle bound, 20.0.
- REAL goodangle; // cosine squared of minangle, 0.0.
- REAL maxvolume; // number after '-a' switch, -1.0.
-- REAL mindihedral; // number after '-qq' switch, 5.0.
-- REAL maxdihedral; // number after '-qqq' switch, 165.0.
-- REAL alpha1; // number after '-m' switch, sqrt(2).
-- REAL alpha2; // number after '-mm' switch, 1.0.
-- REAL alpha3; // number after '-mmm' switch, 0.6.
-+ REAL maxdihedral; // number after '-s' switch, 175.0.
-+ REAL alpha1; // number after '-R' switch, sqrt(2).
-+ REAL alpha2; // number after '-RR' switch, 1/sqrt(2).
-+ REAL alpha3; // number after '-RRR' switch, 0.6.
- REAL epsilon; // number after '-T' switch, 1.0e-8.
- REAL epsilon2; // number after '-TT' switch, 1.0e-5.
- enum objecttype object; // determined by -p, or -r switch. NONE.
-@@ -519,7 +483,6 @@
- char commandline[1024];
- char infilename[1024];
- char outfilename[1024];
-- char addinfilename[1024];
- char bgmeshfilename[1024];
-
- tetgenbehavior();
-@@ -542,8 +505,9 @@
- // //
- // Return one of the values +1, 0, and -1 on basic geometric questions such //
- // as the orientation of point sets, in-circle, and in-sphere tests. They //
--// are basic units for implmenting geometric algorithms. TetGen uses two 3D //
--// geometric predicates: the orientation and in-sphere tests. //
-+// are basic units for the composition of geometric algorithms. TetGen uses //
-+// two 3D geometric predicates, which are the orientation test and the in- //
-+// sphere test (e.g. the locally Deklaunay test). //
- // //
- // Orientation test: let a, b, c be a sequence of 3 non-collinear points in //
- // R^3. They defines a unique hypeplane H. Let H+ and H- be the two spaces //
-@@ -626,15 +590,20 @@
- // read from input (.node file or tetgenio structure) or an isolated
- // vertex (outside the mesh). It is the default type for a newpoint.
- enum verttype {UNUSEDVERTEX, DUPLICATEDVERTEX, NACUTEVERTEX, ACUTEVERTEX,
-- FREESEGVERTEX, FREESUBVERTEX, FREEVOLVERTEX, DEADVERTEX = -32768};
-+ FREESEGVERTEX, FACETVERTEX, FREESUBVERTEX, VOLVERTEX,
-+ FREEVOLVERTEX, DEADVERTEX = -32768};
-
-- // Labels that signify the type of a subface/subsegment.
-- enum shestype {NSHARP, SHARP};
-+ // Labels that signify the type of a subface/subsegment. A subface is
-+ // SKINNY if it has two edges which are subsegments and form a small
-+ // angle (e.g., 10 degree); a subsegment is a SHARP if it is between
-+ // two facets which form an acute dihedral angle.
-+ enum shestype {NSHARPNSKINNY, SHARP, SKINNY};
-
- // Labels that signify the type of flips can be applied on a face.
- // A flipable face has the one of the types T23, T32, T22, and T44.
-- // Types N32, N40 are unflipable.
-- enum fliptype {T23, T32, T22, T44, N32, N40, FORBIDDENFACE, FORBIDDENEDGE};
-+ // Types UNFLIPABLE, NONCONVEX are unflipable.
-+ enum fliptype {T23, T32, T22, T44, UNFLIPABLE, FORBIDDENFACE,
-+ FORBIDDENEDGE, NONCONVEX};
-
- // Labels that signify the result of triangle-triangle intersection test.
- // Two triangles are DISJOINT, or adjoint at a vertex SHAREVERTEX, or
-@@ -798,7 +767,7 @@
- // The point data structure. It is actually an array of REALs:
- // - x, y and z coordinates;
- // - a list of user-defined point attributes (optional);
-- // - a list of REALs of a user-defined metric tensor (optional);
-+ // - a REAL of local feature sizes (optional -p switch);
- // - a pointer to a simplex (tet, tri, edge, or vertex);
- // - a pointer to a parent (or duplicate) point;
- // - a pointer to a tet in background mesh (optional);
-@@ -946,6 +915,61 @@
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
-+// The Metric tensor data structure //
-+// //
-+// A metric is a function that specifies the "distance" between two points //
-+// in a metric space E. Recall if d(p, q) is a metric of E, then we have: //
-+// (1) d(p, q) = d(q, p). (d is symmetric) //
-+// (2) d(p, q) = 0 if and only if p = q. //
-+// (3) d(p, x) + d(x, q) >= d(p, q). (d satisfies triangle inequality) //
-+// //
-+// In d dimensions, the metric tensor of a point p is a (dxd) symmetric //
-+// positive definie (non-degenerate) matrix M(p). Very roughly, it tells how //
-+// to compute the distance of p and other points in the metric space of p. //
-+// d_M(p, q) = \sqrt{(p - q)' M (p -q)}. //
-+// If for any point p, a metric tensor M(p) is given, the field of tensors //
-+// thus defines a Riemannian space. For example, if M(q) is a metric tensor //
-+// defined on q. Then the distance d(p, q) can be calculated by: //
-+// d(p, q) = \int_{0}{1} \sqrt((p - q)' M(t) (p - q)) dt. //
-+// where M(t) is the interpolation of metric tensors between p and q, M(0) = //
-+// M(p) and M(1) = M(q). //
-+// //
-+// A metric tensor in three dimension, for example, is a matrix: //
-+// | a b c | //
-+// M = | b d e | //
-+// | c e f | //
-+// such that a > 0, d > 0, f > 0, det(M) = adf + 2bce -ccd - eea - bbf > 0. //
-+// //
-+// It is defined as an array mat[6] = {a, b, c, d, e, f}. Operation on //
-+// tensors are defined as well. //
-+// //
-+///////////////////////////////////////////////////////////////////////////////
-+
-+ class metric {
-+
-+ public:
-+
-+ REAL mat[6];
-+
-+ // Initialization.
-+ void init() {for (int i = 0; i < 6; i++) mat[i] = 0.0;}
-+ void set(REAL a, REAL b, REAL c, REAL d, REAL e, REAL f) {
-+ mat[0] = a; mat[1] = b; mat[2] = c;
-+ mat[3] = d; mat[4] = e;
-+ mat[5] = f;
-+ }
-+ void set(REAL a, REAL d, REAL f) {
-+ mat[0] = a; mat[1] = 0.0; mat[2] = 0.0;
-+ mat[3] = d; mat[4] = 0.0;
-+ mat[5] = f;
-+ }
-+
-+ // Constructors.
-+ metric() {init();}
-+ };
-+
-+///////////////////////////////////////////////////////////////////////////////
-+// //
- // The list, link and queue data structures //
- // //
- // These data types are used to manipulate a set of (same-typed) data items. //
-@@ -974,8 +998,12 @@
- // take two pointers of the corresponding date type, perform the
- // comparation, and return -1, 0 or 1 indicating the default linear
- // order of them.
-+
-+ // Compare two 'integers'.
- static int compare_2_ints(const void* x, const void* y);
-+ // Compare two 'longs'.
- static int compare_2_longs(const void* x, const void* y);
-+ // Compare two 'unsigned longs'.
- static int compare_2_unsignedlongs(const void* x, const void* y);
-
- // The function used to determine the size of primitive data types and
-@@ -1168,7 +1196,7 @@
- bool locate(int pos);
- void *add(void* newitem);
- void *insert(int pos, void* insitem);
-- void *deletenode(void** delnode);
-+ void *del(void* delitem);
- void *del(int pos);
- void *getitem();
- void *getnitem(int pos);
-@@ -1179,7 +1207,7 @@
- // //
- // Queue data structure. //
- // //
--// A 'queue' is basically a link. Following is an image of a queue. //
-+// A 'queue' is a basically a link. Following is an image of a queue. //
- // ___________ ___________ ___________ //
- // Pop() <-- |_ _|<--|_ _|<--|_ _| <-- Push() //
- // |_ Data0 _| |_ Data1 _| |_ Data2 _| //
-@@ -1193,27 +1221,12 @@
- public:
-
- queue(int bytes, int count = 256) : link(bytes, NULL, count) {}
-- bool empty() { return linkitems == 0; }
-- void *push(void* newitem) {return link::add(newitem);}
-- void *pop() {return link::deletenode((void **) *head);}
-- // Stack is implemented as a single link list.
-- void *stackpush() {
-- void **newnode = (void **) alloc();
-- // if (newitem != (void *) NULL) {
-- // memcpy((void *)(newnode + 2), newitem, linkitembytes);
-- // }
-- void **nextnode = (void **) *head;
-- *head = (void *) newnode;
-- *newnode = (void *) nextnode;
-- linkitems++;
-- return (void *)(newnode + 2);
-- }
-- void *stackpop() {
-- void **deadnode = (void **) *head;
-- *head = *deadnode;
-- linkitems--;
-- return (void *)(deadnode + 2);
-- }
-+ queue(char* str, int count = 256) : link(str, count) {}
-+
-+ int empty() { return linkitems == 0; }
-+ void *push(void* newitem) { return link::add(newitem); }
-+ void *bot() { return link::getnitem(1); }
-+ void *pop() { return link::del(1); }
- };
-
- ///////////////////////////////////////////////////////////////////////////////
-@@ -1274,9 +1287,7 @@
- // enqueue an item. The queues are ordered from 63 (highest priority)
- // to 0 (lowest priority).
- badface *subquefront[3], **subquetail[3];
-- badface *tetquefront[64], *tetquetail[64];
-- int nextnonemptyq[64];
-- int firstnonemptyq, recentq;
-+ badface *tetquefront[64], **tetquetail[64];
-
- // Pointer to a recently visited tetrahedron. Improves point location
- // if proximate points are inserted sequentially.
-@@ -1288,8 +1299,7 @@
- long hullsize; // Number of faces of convex hull.
- long insegments; // Number of input segments.
- int steinerleft; // Number of Steiner points not yet used.
-- int sizeoftensor; // Number of REALs per metric tensor.
-- int pointmtrindex; // Index to find the metric tensor of a point.
-+ int pointlfsindex; // Index to find the local feature size of a point.
- int point2simindex; // Index to find a simplex adjacent to a point.
- int pointmarkindex; // Index to find boundary marker of a point.
- int point2pbcptindex; // Index to find a pbc point to a point.
-@@ -1300,7 +1310,6 @@
- int shmarkindex; // Index to find boundary marker of a subface.
- int areaboundindex; // Index to find area bound of a subface.
- int checksubfaces; // Are there subfaces in the mesh yet?
-- int checksubsegs; // Are there subsegs in the mesh yet?
- int checkpbcs; // Are there periodic boundary conditions?
- int varconstraint; // Are there variant (node, seg, facet) constraints?
- int nonconvex; // Is current mesh non-convex?
-@@ -1310,15 +1319,12 @@
- int suprelverts; // The number of suppressed relocated vertices.
- int collapverts; // The number of collapsed relocated vertices.
- int unsupverts; // The number of unsuppressed vertices.
-- int smoothsegverts; // The number of smoothed vertices.
-- int smoothvolverts; // The number of smoothed vertices.
- int jettisoninverts; // The number of jettisoned input vertices.
- int symbolic; // Use symbolic insphere test.
- long samples; // Number of random samples for point location.
- unsigned long randomseed; // Current random number seed.
- REAL macheps; // The machine epsilon.
- REAL cosmaxdihed, cosmindihed; // The cosine values of max/min dihedral.
-- REAL minfaceang, minfacetdihed; // The minimum input (dihedral) angles.
- int maxcavfaces, maxcavverts; // The size of the largest cavity.
- int expcavcount; // The times of expanding cavitys.
- long abovecount; // Number of abovepoints calculation.
-@@ -1327,12 +1333,13 @@
- long failvolcount, failsubcount, failsegcount; // Bow-Wat fails.
- long repairflipcount; // Number of flips for repairing segments.
- long outbowatcircumcount; // Number of circumcenters outside Bowat-cav.
-- long r1count, r2count, r3count; // Numbers of edge splitting rules.
-+ long r1count, r2count, r3count, r4count; // Number of rules performed.
- long cdtenforcesegpts; // Number of CDT enforcement points.
- long rejsegpts, rejsubpts, rejtetpts; // Number of rejected points.
-- long optcount[10]; // Numbers of various optimizing operations.
-+ long striptetcount, fliptetcount, unimprovecount; // Mesh smooth counts.
-+ long smoothcdtsegpt, smoothsegpt, smoothsubpt, smoothvolpt;
-+ long unsmoothcdtsegpt, unsmoothsegpt, unsmoothsubpt, unsmoothvolpt;
- long flip23s, flip32s, flip22s, flip44s; // Number of flips performed.
-- REAL tloctime, tfliptime; // Time (microseconds) of point location.
-
- ///////////////////////////////////////////////////////////////////////////////
- // //
-@@ -1376,10 +1383,6 @@
- // new 'ver'. Note: Only valid for 'ver' equals one of {0, 2, 4}.
- static int locver2nextf[4][6][2];
-
-- // The edge number (from 0 to 5) of a tet is defined as follows:
-- static int locver2edge[4][6];
-- static int edge2locver[6][2];
--
- // For enumerating three edges of a triangle.
- static int plus1mod3[3];
- static int minus1mod3[3];
-@@ -1473,7 +1476,7 @@
- inline void tspivot(triface& t, face& s);
- inline void stpivot(face& s, triface& t);
- inline void tsbond(triface& t, face& s);
-- inline void tsdissolve(triface& t);
-+ inline void tsdissolve(triface& t);
- inline void stdissolve(face& s);
-
- // Primitives for interacting subfaces and subsegs.
-@@ -1481,10 +1484,6 @@
- inline void ssbond(face& s, face& edge);
- inline void ssdissolve(face& s);
-
-- inline void tsspivot1(triface& t, face& seg);
-- inline void tssbond1(triface& t, face& seg);
-- inline void tssdissolve1(triface& t);
--
- // Primitives for points.
- inline int pointmark(point pt);
- inline void setpointmark(point pt, int value);
-@@ -1510,6 +1509,7 @@
- inline bool isfacehaspoint(face* t, point testpoint);
- inline bool isfacehasedge(face* s, point tend1, point tend2);
- inline bool issymexist(triface* t);
-+ bool getnextface(triface*, triface*);
- void getnextsface(face*, face*);
- void tsspivot(triface*, face*);
- void sstpivot(face*, triface*);
-@@ -1544,14 +1544,16 @@
- enum interresult edge_vert_col_inter(REAL*, REAL*, REAL*);
- enum interresult edge_edge_cop_inter(REAL*, REAL*, REAL*, REAL*, REAL*);
- enum interresult tri_vert_cop_inter(REAL*, REAL*, REAL*, REAL*, REAL*);
-- enum interresult tri_edge_cop_inter(REAL*, REAL*, REAL*,REAL*,REAL*,REAL*);
-+ enum interresult tri_edge_cop_inter(REAL*, REAL*, REAL*, REAL*, REAL*,
-+ REAL*);
- enum interresult tri_edge_inter_tail(REAL*, REAL*, REAL*, REAL*, REAL*,
-- REAL, REAL);
-+ REAL, REAL);
- enum interresult tri_edge_inter(REAL*, REAL*, REAL*, REAL*, REAL*);
- enum interresult tri_tri_inter(REAL*, REAL*, REAL*, REAL*, REAL*, REAL*);
-
- // Geometric predicates
-- REAL insphere_sos(REAL*, REAL*, REAL*, REAL*, REAL*, int, int,int,int,int);
-+ REAL insphere_sos(REAL*, REAL*, REAL*, REAL*, REAL*, int, int, int, int,
-+ int);
- bool iscollinear(REAL*, REAL*, REAL*, REAL eps);
- bool iscoplanar(REAL*, REAL*, REAL*, REAL*, REAL vol6, REAL eps);
- bool iscospheric(REAL*, REAL*, REAL*, REAL*, REAL*, REAL vol24, REAL eps);
-@@ -1574,7 +1576,6 @@
- REAL facedihedral(REAL* pa, REAL* pb, REAL* pc1, REAL* pc2);
- void tetalldihedral(point, point, point, point, REAL*, REAL*, REAL*);
- void tetallnormal(point, point, point, point, REAL N[4][3], REAL* volume);
-- REAL tetaspectratio(point, point, point, point);
- bool circumsphere(REAL*, REAL*, REAL*, REAL*, REAL* cent, REAL* radius);
- void inscribedsphere(REAL*, REAL*, REAL*, REAL*, REAL* cent, REAL* radius);
- void rotatepoint(REAL* p, REAL rotangle, REAL* p1, REAL* p2);
-@@ -1610,7 +1611,6 @@
- enum locateresult preciselocate(point searchpt, triface* searchtet, long);
- enum locateresult locate(point searchpt, triface* searchtet);
- enum locateresult adjustlocate(point, triface*, enum locateresult, REAL);
-- enum locateresult hullwalk(point searchpt, triface* hulltet);
- enum locateresult locatesub(point searchpt, face* searchsh, int, REAL);
- enum locateresult adjustlocatesub(point, face*, enum locateresult, REAL);
- enum locateresult locateseg(point searchpt, face* searchseg);
-@@ -1635,15 +1635,8 @@
- void flip22(triface* flipface, queue* flipqueue);
- void flip22sub(face* flipedge, queue* flipqueue);
- long flip(queue* flipqueue, badface **plastflip);
-- long lawson(list *misseglist, queue* flipqueue);
- void undoflip(badface *lastflip);
- long flipsub(queue* flipqueue);
-- bool removetetbypeeloff(triface *striptet);
-- bool removefacebyflip23(REAL *key, triface*, triface*, queue*);
-- bool removeedgebyflip22(REAL *key, int, triface*, queue*);
-- bool removeedgebyflip32(REAL *key, triface*, triface*, queue*);
-- bool removeedgebytranNM(REAL*,int,triface*,triface*,point,point,queue*);
-- bool removeedgebycombNM(REAL*,int,triface*,int*,triface*,triface*,queue*);
-
- void splittetrahedron(point newpoint, triface* splittet, queue* flipqueue);
- void unsplittetrahedron(triface* splittet);
-@@ -1659,8 +1652,6 @@
- bool approx, queue* flipqueue);
- void undosite(enum insertsiteresult insresult, triface* splittet,
- point torg, point tdest, point tapex, point toppo);
-- void closeopenface(triface* openface, queue* flipque);
-- void inserthullsite(point inspoint, triface* horiz, queue* flipque);
-
- void formbowatcavitysub(point, face*, list*, list*);
- void formbowatcavityquad(point, list*, list*);
-@@ -1683,6 +1674,8 @@
- // Delaunay tetrahedralization routines.
- void formstarpolyhedron(point pt, list* tetlist, list* verlist, bool);
- bool unifypoint(point testpt, triface*, enum locateresult, REAL);
-+ void closeopenface(triface* openface, queue* flipque);
-+ void inserthullsite(point inspoint, triface* horiz, queue* flipque);
- void incrflipdelaunay(triface*, point*, long, bool, bool, REAL, queue*);
- long delaunizevertices();
-
-@@ -1705,7 +1698,7 @@
- int holes, REAL* holelist, memorypool* viri, queue*);
- void retrievenewsubs(list* newshlist, bool removeseg);
- void unifysegments();
-- void mergefacets(queue* flipqueue);
-+ void mergefacets(queue* flipqueue);
- long meshsurface();
-
- // Detect intersecting facets of PLC.
-@@ -1739,8 +1732,6 @@
- point scoutrefpoint(triface* searchtet, point tend);
- point getsegmentorigin(face* splitseg);
- point getsplitpoint(face* splitseg, point refpoint);
-- bool insertsegment(face *insseg, list *misseglist);
-- void tallmissegs(list *misseglist);
- void delaunizesegments();
-
- // Facets recovery routines.
-@@ -1800,43 +1791,46 @@
- void restorepolyhedron(list* oldtetlist);
- bool suppressfacetpoint(face* supsh, list* frontlist, list* misfrontlist,
- list* ptlist, list* conlist, memorypool* viri,
-- queue* flipque, bool noreloc, bool optflag);
-+ queue* flipque);
- bool suppresssegpoint(face* supseg, list* spinshlist, list* newsegshlist,
- list* frontlist, list* misfrontlist, list* ptlist,
-- list* conlist, memorypool* viri, queue* flipque,
-- bool noreloc, bool optflag);
-- bool suppressvolpoint(triface* suptet, list* frontlist, list* misfrontlist,
-- list* ptlist, queue* flipque, bool optflag);
-- bool smoothpoint(point smthpt, point, point, list *starlist, bool, REAL*);
-- void removesteiners(bool coarseflag);
-+ list* conlist, memorypool* viri, queue* flipque);
-+ bool suppressvolpoint(point suppt, list* frontlist, list* misfrontlist,
-+ list* ptlist, queue* flipque);
-+ bool collapseedgepoint(point colpt, list* oldtetlist, list* newtetlist,
-+ list* ptlist);
-+ void removesteiners();
-
-- // Mesh reconstruction routines.
-+ // Mesh reconstruction rotuines.
- long reconstructmesh();
-- // Constrained points insertion routines.
-- void insertconstrainedpoints(tetgenio *addio);
-+ bool intettest(point testpt, triface* testtet, REAL eps);
-+ void insertaddpoints();
-+
- // Background mesh operations.
-- bool p1interpolatebgm(point pt, triface* bgmtet, long *scount);
-+ bool interpolatepointsize(point pt, triface* bgmtet, long *scount);
-+ void searchpointrecursive(triface *curtet, long *scount);
- void interpolatesizemap();
-- void duplicatebgmesh();
-
- // Delaunay refinement routines.
-- void marksharpsegments(REAL sharpangle);
-- void decidefeaturepointsizes();
-+ void calclocalfeaturesizes();
-+ void marksharpsubsegs(REAL dihedbound);
-+ void markskinnysubfaces(REAL anglebound);
-+ void enqueuebadtet(triface* tt, REAL key, REAL* cent);
- void enqueueencsub(face* ss, point encpt, int quenumber, REAL* cent);
-+ badface* dequeuebadtet();
- badface* dequeueencsub(int* quenumber);
-- void enqueuebadtet(triface* tt, REAL key, REAL* cent);
-- badface* topbadtetra();
-- void dequeuebadtet();
- bool checkseg4encroach(face* testseg, point testpt, point*, bool enqflag);
- bool checksub4encroach(face* testsub, point testpt, bool enqflag);
-+ bool checkseg4badqual(face* testseg, bool enqflag);
-+ bool checksub4badqual(face* testsub, bool enqflag);
- bool checktet4badqual(triface* testtet, bool enqflag);
- bool acceptsegpt(point segpt, point refpt, face* splitseg);
- bool acceptfacpt(point facpt, list* subceillist, list* verlist);
- bool acceptvolpt(point volpt, list* ceillist, list* verlist);
- void getsplitpoint(point e1, point e2, point refpt, point newpt);
- void shepardinterpolate(point newpt, list* verlist);
-- void setnewpointsize(point newpt, point e1, point e2);
-- void splitencseg(point, face*, list*, list*, list*,queue*,bool,bool,bool);
-+ void setnewpointsize(point newpt, list* verlist);
-+ void splitencseg(point, face*, list*, list*, list*, queue*, bool, bool);
- bool tallencsegs(point testpt, int n, list** ceillists);
- bool tallencsubs(point testpt, int n, list** ceillists);
- void tallbadtetrahedrons();
-@@ -1845,15 +1839,16 @@
- void repairbadtets();
- void enforcequality();
-
-- // Mesh optimization routines.
-- void dumpbadtets();
-+ // Mesh Smoothing routines.
- bool checktet4ill(triface* testtet, bool enqflag);
-- bool checktet4opt(triface* testtet, bool enqflag);
-- bool removeedge(badface* remedge, bool optflag);
-- bool smoothsliver(badface* remedge, list *starlist);
-- bool splitsliver(badface* remedge, list *tetlist, list *ceillist);
-- void tallslivers(bool optflag);
-- void optimizemesh(bool optflag);
-+ bool checktet4sliver(triface* testtet, bool chkill, bool enqflag);
-+ void removetetbystripoff(triface *striptet);
-+ void removetetbyflip32(triface *fliptet, bool enq, bool chkill);
-+ bool removetetbyrecon(badface* remtet, bool chkill);
-+ bool removetetbysplit(badface* remtet);
-+ void tallslivers(bool chkill);
-+ void repairmesh();
-+ void smoothmesh();
-
- // I/O routines
- void transfernodes();
-@@ -1865,10 +1860,8 @@
- void outfaces(tetgenio* out);
- void outhullfaces(tetgenio* out);
- void outsubfaces(tetgenio* out);
-- void outedges(tetgenio* out);
- void outsubsegments(tetgenio* out);
- void outneighbors(tetgenio* out);
-- void outvoronoi(tetgenio* out);
- void outpbcnodes(tetgenio* out);
- void outsmesh(char* smfilename);
- void outmesh2medit(char* mfilename);
-@@ -1880,6 +1873,7 @@
- void checkmesh();
- void checkshells();
- void checkdelaunay(REAL eps, queue* flipqueue);
-+ void checkdegeneracy(REAL eps);
- void checkconforming();
- void algorithmicstatistics();
- void qualitystatistics();
-@@ -1899,18 +1893,23 @@
- // Delaunay tetrahedralizations, constrained Delaunay //
- // tetrahedralizations, quality tetrahedral meshes. //
- // //
-+// Two functions (interfaces) are available. The difference is only the way //
-+// of passing switches. One directly accepts an object of 'tetgenbehavior', //
-+// while the other accepts a string which is the same as one can used in the //
-+// command line. The latter may be more convenient for users who don't want //
-+// to kown the 'tetgenbehavir' structure. //
-+// //
- // 'in' is an object of 'tetgenio' which contains a PLC you want to tetrahed-//
- // ralize or a previously generated tetrahedral mesh you want to refine. It //
- // must not be a NULL. 'out' is another object of 'tetgenio' for storing the //
- // generated tetrahedral mesh. It can be a NULL. If so, the output will be //
--// saved to file(s). If 'bgmin' != NULL, it contains a background mesh which //
--// defines a mesh size distruction function. //
-+// saved to file(s). //
- // //
- ///////////////////////////////////////////////////////////////////////////////
-
- void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
-- tetgenio *addin = NULL, tetgenio *bgmin = NULL);
-+ tetgenio *bgmesh = NULL);
- void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
-- tetgenio *addin = NULL, tetgenio *bgmin = NULL);
-+ tetgenio *bgmesh = NULL);
-
- #endif // #ifndef tetgenH
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/tetgen.git
More information about the debian-science-commits
mailing list