[tetgen] 01/15: Copy debian folder from svn-repo.

Anton Gladky gladk at moszumanska.debian.org
Tue Jan 28 22:13:44 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 e48b4a66f6a3479d7ac11036692ddf2e2695a382
Author: Anton Gladky <gladk at debian.org>
Date:   Tue Jan 28 19:57:11 2014 +0100

    Copy debian folder from svn-repo.
---
 debian/changelog             |    82 +
 debian/compat                |     1 +
 debian/control               |    44 +
 debian/copyright             |    54 +
 debian/dirs                  |     2 +
 debian/docs                  |     1 +
 debian/patches/quality.patch | 14927 +++++++++++++++++++++++++++++++++++++++++
 debian/patches/series        |     1 +
 debian/rules                 |   119 +
 debian/tetgen.manpages       |     1 +
 debian/tetgen.sgml           |   256 +
 debian/watch                 |     2 +
 12 files changed, 15490 insertions(+)

diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..eb0243f
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,82 @@
+tetgen (1.4.3-1) unstable; urgency=low
+
+  * Team upload
+  * Package migrated to the Debian Science team
+  * Standards-Version updated to version 3.9.2
+  * lintian error "weak-library-dev-dependency" on libtet1.4.2-dev fixed
+  * Fix debian-rules-missing-recommended-target build-arch
+  * Update of the uploaders (Closes: #550418)
+
+  [ Christophe Trophime ]
+  * debian/rules: change definition of tetgenbin and tetgendev variables
+  * fix lintian errors
+
+  [Christophe Prud'homme]
+  * New upstream release (Closes: #618574)
+    - A new implementation of the Bowyer-Watson algorithm for Delaunay
+      tetrahedralization. It is generally faster than the incremental flip
+      algorithm. From my tests, the flip algorithm usually constructs about
+      twice (or more) as many intermediate tetrahedra as B-W algorithm. Now
+      B-W algorithm is the default algorithm for Delaunay
+      tetrahedralization.
+    - A new implementaton of the constrained Delaunay tetrahedralization
+      algorithm (the -p option).
+    - A new implementation of the Steiner point removal algorithm (the -Y
+      option).
+    - Improved the implementation of the constrained Delaunay refinement
+      algorithm (the -q option).
+    - Add the minimum dihedral angle of tetrahedra as the tetrahedral
+      shape quality parameter (set after -qq option). The minimum dihedral
+      angle is made the major mesh quality measure now. Default it is 5
+      degree. One can increase it as larger as 18 degree. The radius-edge
+      ratio (set after -q option) is still in use.
+    - Support the read and write of the legacy VTK file format which can be
+      visualized by Paraview (see .vtk file format and -K option).
+  * renamed lib version to 1.4 instead of 1.4.x
+
+ -- Sylvestre Ledru <sylvestre at debian.org>  Thu, 15 Sep 2011 09:50:08 +0200
+
+tetgen (1.4.2-4) UNRELEASED; urgency=low
+
+  [ Daniel Leidert ]
+  * debian/control: Vcs fields transition. Vcs-Svn fix.
+  * debian/rules (build-stamp): Add missing linkages for unresolved symbols.
+    (clean): Fixed to make the package build twice in a row.
+
+ -- Daniel Leidert (dale) <daniel.leidert at wgdd.de>  Wed, 26 Mar 2008 00:44:37 +0100
+
+tetgen (1.4.2-3) unstable; urgency=low
+
+  * Ondrej Certik added to Uploaders.
+  * DM-Upload-Allowed: yes field added
+  * removing the predicates.patch, that is not necessary
+  * patches converted to quilt
+  * Homepage moved from description to the Homepage field.
+  * empty directory /usr/sbin removed
+  * Standards version updated to 3.7.3 
+
+ -- Ondrej Certik <ondrej at certik.cz>  Sat, 16 Feb 2008 01:41:43 +0100
+
+tetgen (1.4.2-2) unstable; urgency=low
+
+  [Christophe Prud'homme]
+  * debian/rules: renamed libtetgen.so to libtet.so
+  * debian/control: fixed libtet1.4.2-dev Depends field (Closes: #434753)
+
+ -- Christophe Prud'homme <prudhomm at debian.org>  Wed, 25 Jul 2007 10:11:58 +0200
+
+tetgen (1.4.2-1oc1) unstable; urgency=low
+
+  * unofficial release
+  * Applied patches to create a better mesh (in fact we reverted back to
+    1.4.1, until the 1.4.2 is fixed upstream)
+
+ -- Ondrej Certik <ondrej at certik.cz>  Sat, 07 Jul 2007 23:05:08 +0200
+
+tetgen (1.4.2-1) unstable; urgency=low
+
+  [Ondrej Certik]
+  * Initial release (Closes: #427094)
+
+ -- Christophe Prud'homme <prudhomm at debian.org>  Wed, 04 Jul 2007 22:43:29 +0200
+
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..4742131
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,44 @@
+Source: tetgen
+Priority: extra
+Section: non-free/math
+Maintainer: Debian Science Team <debian-science-maintainers at lists.alioth.debian.org>
+Uploaders: Christophe Prud'homme <prudhomm at debian.org>
+Build-Depends: debhelper (>= 5), docbook-to-man, quilt
+Standards-Version: 3.9.2
+Vcs-Svn: svn://svn.debian.org/svn/pkg-scicomp/tetgen/trunk/
+Vcs-Browser: http://svn.debian.org/wsvn/pkg-scicomp/tetgen/
+XS-DM-Upload-Allowed: yes
+Homepage: http://tetgen.berlios.de/
+
+Package: tetgen
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Quality Tetrahedral Mesh Generator
+ TetGen generates the Delaunay tetrahedralization, Voronoi diagram, and convex
+ hull for three-dimensional point sets, generates the constrained Delaunay
+ tetrahedralizations and quality tetrahedral meshes for three-dimensional
+ domains with piecewise linear boundary.
+
+Package: libtet1.4
+Architecture: any
+Section: non-free/libs
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Quality Tetrahedral Mesh Generator
+ TetGen generates the Delaunay tetrahedralization, Voronoi diagram, and convex
+ hull for three-dimensional point sets, generates the constrained Delaunay
+ tetrahedralizations and quality tetrahedral meshes for three-dimensional
+ domains with piecewise linear boundary.
+ .
+ This package provides the runtime shared library.
+
+Package: libtet1.4-dev
+Architecture: any
+Section: non-free/libdevel
+Depends: libtet1.4 (= ${binary:Version}), ${misc:Depends}
+Description: Quality Tetrahedral Mesh Generator
+ TetGen generates the Delaunay tetrahedralization, Voronoi diagram, and convex
+ hull for three-dimensional point sets, generates the constrained Delaunay
+ tetrahedralizations and quality tetrahedral meshes for three-dimensional
+ domains with piecewise linear boundary.
+ .
+ This package provides header file and static library.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..57736c7
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,54 @@
+This package was debianized by Ondrej Certik <ondrej at certik.cz> on
+Fri, 01 Jun 2007 22:46:00 +0200.
+
+It was downloaded from http://www.wias-berlin.de/people/si/tetgen1.4.2.tar.gz
+
+Upstream Author: 
+
+    Hang Si <si at wias-berlin.de>
+
+Copyright: 
+
+    Copyright 2002, 2004, 2005, 2006
+    Hang Si
+    Rathausstr. 9, 10178 Berlin, Germany
+    si at wias-berlin.de
+
+
+License:
+
+Permission is hereby granted, free  of charge, to any person obtaining
+a  copy  of this  software  and  associated  documentation files  (the
+"Software"), to  deal in  the Software without  restriction, including
+without limitation  the rights to  use, copy, modify,  merge, publish,
+distribute,  sublicense and/or  sell copies  of the  Software,  and to
+permit persons to whom the Software  is furnished to do so, subject to
+the following conditions:
+
+Distribution of  modified  versions  of this code is permissible UNDER
+THE CONDITION THAT  THIS CODE AND ANY MODIFICATIONS  MADE TO IT IN THE
+SAME SOURCE FILES  tetgen.h AND tetgen.cxx  REMAIN UNDER  COPYRIGHT OF
+THE  ORIGINAL AUTHOR,  BOTH  SOURCE AND OBJECT  CODE  ARE MADE  FREELY
+AVAILABLE  WITHOUT   CHARGE,   AND  CLEAR   NOTICE  IS  GIVEN  OF  THE
+MODIFICATIONS.
+
+Distribution of this code for  any  commercial purpose  is permissible
+ONLY BY DIRECT ARRANGEMENT WITH THE COPYRIGHT OWNER.
+
+The  above  copyright  notice  and  this permission  notice  shall  be
+included in all copies or substantial portions of the Software.
+
+THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
+EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT  SHALL THE AUTHORS OR COPYRIGHT HOLDERS  BE LIABLE FOR ANY
+CLAIM, DAMAGES OR  OTHER LIABILITY, WHETHER IN AN  ACTION OF CONTRACT,
+TORT  OR OTHERWISE, ARISING  FROM, OUT  OF OR  IN CONNECTION  WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+The Debian packaging is (C) 2007, Ondrej Certik <ondrej at certik.cz> and
+is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
+
+The file predicates.cxx is Copyright 1996 Jonathan Richard Shewchuk and it was
+placed in the public domain.
diff --git a/debian/dirs b/debian/dirs
new file mode 100644
index 0000000..ca882bb
--- /dev/null
+++ b/debian/dirs
@@ -0,0 +1,2 @@
+usr/bin
+usr/sbin
diff --git a/debian/docs b/debian/docs
new file mode 100644
index 0000000..e845566
--- /dev/null
+++ b/debian/docs
@@ -0,0 +1 @@
+README
diff --git a/debian/patches/quality.patch b/debian/patches/quality.patch
new file mode 100644
index 0000000..4150041
--- /dev/null
+++ b/debian/patches/quality.patch
@@ -0,0 +1,14927 @@
+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
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1 @@
+
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..7e40981
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,119 @@
+#!/usr/bin/make -f
+
+TETGEN_VERSION = 1.4.3
+TETGEN_LIBVERSION = 1.4
+
+CFLAGS = -Wall -g
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+	CFLAGS += -O0
+else
+	CFLAGS += -O2
+endif
+
+
+tetgenbin = $(CURDIR)/debian/libtet$(TETGEN_LIBVERSION)
+tetgendev = $(CURDIR)/debian/libtet$(TETGEN_LIBVERSION)-dev
+
+configure: configure-stamp
+configure-stamp:
+	dh_testdir
+	# Add here commands to configure the package.
+	QUILT_PATCHES=debian/patches quilt push -a || test $$? = 2
+
+	touch configure-stamp
+
+build: build-arch build-indep
+build-arch: build-stamp
+build-indep: build-stamp
+
+build-stamp: configure-stamp
+	dh_testdir
+
+	# Add here commands to compile the package.
+	$(MAKE) CXXFLAGS="-O3 -fPIC" PREDCXXFLAGS="-O0 -fPIC"
+	$(MAKE) tetlib CXXFLAGS="-O3 -fPIC"
+	mkdir -p tmp-tetgen-shlib; \
+	cd tmp-tetgen-shlib; \
+	ar x ../libtet.a; \
+	gcc -shared -fPIC -lstdc++ -lm -Wl,-soname,libtet.so.$(TETGEN_VERSION) -o ../libtet.so.$(TETGEN_VERSION) *.o
+
+	docbook-to-man debian/tetgen.sgml > tetgen.1
+
+	touch $@
+
+clean:
+	dh_testdir
+	dh_testroot
+	rm -f build-stamp configure-stamp
+
+	# Add here commands to clean up after the build process.
+	$(MAKE) clean RM="rm -f"
+	rm -rf tmp-tetgen-shlib
+	QUILT_PATCHES=debian/patches quilt pop -a -R || test $$? = 2
+
+	# Remove 
+	rm -f tetgen.1
+	rm -f libtet.so.1.4.3
+	rm -f $(tetgenbin)/usr/lib/libtet.so.1.4.3
+	rm -f $(tetgendev)/usr/lib/libtet.*
+
+	dh_clean
+
+install: build
+	dh_testdir
+	dh_testroot
+	dh_clean -k
+	dh_installdirs
+
+	mkdir -p $(tetgenbin)/usr/lib
+	mkdir -p $(tetgendev)/usr/lib
+	mkdir -p $(tetgendev)/usr/include
+	dh_install --sourcedir=$(CURDIR) tetgen usr/bin/
+	dh_installexamples --sourcedir=$(CURDIR) example.poly
+
+	cp $(CURDIR)/tetgen.h $(tetgendev)/usr/include/
+	cp $(CURDIR)/libtet.a $(tetgendev)/usr/lib
+	ln -s /usr/lib/libtet.so.$(TETGEN_VERSION) $(tetgendev)/usr/lib/libtet.so
+	cp $(CURDIR)/libtet.so.$(TETGEN_VERSION) $(tetgenbin)/usr/lib/
+	rm -r $(CURDIR)/debian/tetgen/usr/sbin
+
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+	dh_testdir
+	dh_testroot
+	dh_installchangelogs
+	dh_installdocs
+	dh_installexamples
+	dh_installman
+	dh_link
+	dh_strip
+	dh_compress
+	dh_fixperms
+	dh_makeshlibs
+	dh_installdeb
+	dh_shlibdeps
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
+
+
+#DEB_STRIPPED_UPSTREAM_VERSION = $(shell echo $(DEB_UPSTREAM_VERSION) | sed -n -e 's/.*$$//p')
+TETGEN_VERSION=1.4.3
+ #$(DEB_UPSTREAM_VERSION)
+
+get-orig-source:
+	uscan --force-download --rename --verbose --upstream-version $(TETGEN_VERSION)
+	tar xzf ../tetgen_$(TETGEN_VERSION).orig.tar.gz
+	mv tetgen$(TETGEN_VERSION) tetgen-$(TETGEN_VERSION)
+	tar czf tetgen_$(TETGEN_VERSION).orig.tar.gz tetgen-$(TETGEN_VERSION)
+	rm -rf tetgen-$(TETGEN_VERSION).dfsg
+	if test -d ../tarballs; then mv tetgen_$(TETGEN_VERSION).orig.tar.gz ../tarballs; fi
diff --git a/debian/tetgen.manpages b/debian/tetgen.manpages
new file mode 100644
index 0000000..d8f34db
--- /dev/null
+++ b/debian/tetgen.manpages
@@ -0,0 +1 @@
+tetgen.1
diff --git a/debian/tetgen.sgml b/debian/tetgen.sgml
new file mode 100644
index 0000000..752ddf8
--- /dev/null
+++ b/debian/tetgen.sgml
@@ -0,0 +1,256 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
+
+<!-- Process this file with docbook-to-man to generate an nroff manual
+     page: `docbook-to-man manpage.sgml > manpage.1'.  You may view
+     the manual page with: `docbook-to-man manpage.sgml | nroff -man |
+     less'.  A typical entry in a Makefile or Makefile.am is:
+
+manpage.1: manpage.sgml
+	docbook-to-man $< > $@
+
+    
+	The docbook-to-man binary is found in the docbook-to-man package.
+	Please remember that if you create the nroff version in one of the
+	debian/rules file targets (such as build), you will need to include
+	docbook-to-man in your Build-Depends control field.
+
+    Preview with:
+
+    docbook-to-man tetgen.sgml | groff -mandoc -Tlatin1 |less
+
+  -->
+
+  <!-- Fill in your name for FIRSTNAME and SURNAME. -->
+  <!ENTITY dhfirstname "<firstname>Ondrej</firstname>">
+  <!ENTITY dhsurname   "<surname>Certik</surname>">
+  <!-- Please adjust the date whenever revising the manpage. -->
+  <!ENTITY dhdate      "<date>June  1, 2007</date>">
+  <!-- SECTION should be 1-8, maybe w/ subsection other parameters are
+       allowed: see man(7), man(1). -->
+  <!ENTITY dhsection   "<manvolnum>1</manvolnum>">
+  <!ENTITY dhemail     "<email><ondrej at certik.cz&gt</email>">
+  <!ENTITY dhusername  "Ondrej Certik">
+  <!ENTITY dhucpackage "<refentrytitle>TETGEN</refentrytitle>">
+  <!ENTITY dhpackage   "tetgen">
+
+  <!ENTITY debian      "<productname>Debian</productname>">
+  <!ENTITY gnu         "<acronym>GNU</acronym>">
+  <!ENTITY gpl         "&gnu; <acronym>GPL</acronym>">
+]>
+
+<refentry>
+  <refentryinfo>
+    <address>
+      &dhemail;
+    </address>
+    <author>
+      &dhfirstname;
+      &dhsurname;
+    </author>
+    <copyright>
+      <year>2003</year>
+      <holder>&dhusername;</holder>
+    </copyright>
+    &dhdate;
+  </refentryinfo>
+  <refmeta>
+    &dhucpackage;
+
+    &dhsection;
+  </refmeta>
+  <refnamediv>
+    <refname>&dhpackage;</refname>
+
+    <refpurpose>A Quality Tetrahedral Mesh Generator</refpurpose>
+  </refnamediv>
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>&dhpackage;</command>
+
+      <arg><option>-pq__a__AriYMS__T__dzjo_fengGOJBNEFICQVvh</option></arg>
+
+      <arg choice="req">file</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+  <refsect1>
+    <title>DESCRIPTION</title>
+
+    <para>This manual page documents briefly the
+      <command>&dhpackage;</command> command. Full documentation is available
+      online: http://tetgen.berlios.de/</para>
+
+    <para><command>&dhpackage;</command>
+ generates the Delaunay tetrahedralization, Voronoi diagram, and convex
+ hull for three-dimensional point sets, generates the constrained Delaunay
+ tetrahedralizations and quality tetrahedral meshes for three-dimensional
+ domains with piecewise linear boundary.
+    </para>
+
+  </refsect1>
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <para>A summary of
+      options is included below.  For a complete description, see the
+      online documentation.
+    </para>
+
+<variablelist>
+<varlistentry><term><option>-p</option> </term> <listitem>
+  <para>Tetrahedralizes a picecwise linear complex (.poly or .smesh file).</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-q</option> </term> <listitem>
+  <para>Quality mesh generation. A minimum radius-edge ratio may be specifyed
+  (default 2.0).</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-a</option> </term> <listitem>
+  <para>Applies a maximum tetrahedron volume constraint.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-A</option> </term> <listitem>
+  <para>Assigns attributes to identify tetrahedra in certain regions.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-r</option> </term> <listitem>
+  <para>Reconstructs/Refines a previously generated mesh.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-Y</option> </term> <listitem>
+  <para>Suppresses boundary facets/segments splitting.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-i</option> </term> <listitem>
+  <para>Inserts a list of additional points into mesh.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-M</option> </term> <listitem>
+  <para>Does not merge coplanar facets.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-T</option> </term> <listitem>
+  <para>Set a tolerance for coplanar test (default 1e-8).</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-d</option> </term> <listitem>
+  <para>Detect intersections of PLC facets.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-z</option> </term> <listitem>
+  <para>Numbers all output items starting from zero.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-j</option> </term> <listitem>
+  <para>Jettison unused vertices from output .node file.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-o2</option> </term> <listitem>
+  <para>Generates second-order subparametric elements.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-f</option> </term> <listitem>
+  <para>Outputs faces (including non-boundary faces) to .face file.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-e</option> </term> <listitem>
+  <para>Outputs subsegments to .edge file.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-n</option> </term> <listitem>
+  <para>Outputs tetrahedra neighbors to .neigh file.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-g</option> </term> <listitem>
+  <para>Outputs mesh to .mesh file for viewing by Medit.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-G</option> </term> <listitem>
+  <para>Outputs mesh to .msh file for viewing by Gid.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-O</option> </term> <listitem>
+  <para>Outputs mesh to .off file for viewing by Geomview.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-B</option> </term> <listitem>
+  <para>Suppresses output of boundary information.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-N</option> </term> <listitem>
+  <para>Suppresses output of .node file.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-E</option> </term> <listitem>
+  <para>Suppresses output of .ele file.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-F</option> </term> <listitem>
+  <para>Suppresses output of .face file.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-I</option> </term> <listitem>
+  <para>Suppresses mesh iteration numbers.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-C</option> </term> <listitem>
+  <para>Checks the consistency of the final mesh.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-Q</option> </term> <listitem>
+  <para>Quiet: No terminal output except errors.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-V</option> </term> <listitem>
+  <para>Verbose: Detailed information on what I'm doing.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-v</option> </term> <listitem>
+  <para>Prints the version information.</para> </listitem> 
+</varlistentry>
+<varlistentry><term><option>-h</option> </term> <listitem>
+  <para>Help: A brief instruction for using TetGen.</para> </listitem> 
+</varlistentry>
+</variablelist>
+  </refsect1>
+  <refsect1>
+    <title>EXAMPLES</title>
+
+    <para>
+   The wing is described in two files: wing.node and wing.poly.
+   The command line:
+
+   tetgen -pq wing
+
+   generates the quality mesh in three files:
+   wing.1.node, wing.1.ele, and wing.1.face.
+    </para>
+    <para>
+    Default, the radius-edge ratio of each tetrahedron is bounded below 2.0.
+    You can impose a tight bound by adding a number directly after the '-q'
+    switch. Like this:
+
+    tetgen -pq1.2 wing
+
+    generates a quality mesh which have more points
+    inserted than the mesh created in above.
+    </para>
+    <para>
+    See http://tetgen.berlios.de/switches.examples.html for more examples.
+    </para>
+
+  </refsect1>
+  <refsect1>
+    <title>SEE ALSO</title>
+
+    <para>netgen (1)</para>
+
+  </refsect1>
+  <refsect1>
+    <title>AUTHOR</title>
+
+    <para>This manual page was written by &dhusername; &dhemail; for
+      the &debian; system (but may be used by others).  Permission is
+      granted to copy, distribute and/or modify this document under
+      the terms of the &gnu; General Public License, Version 2 any 
+	  later version published by the Free Software Foundation.
+    </para>
+	<para>
+	  On Debian systems, the complete text of the GNU General Public
+	  License can be found in /usr/share/common-licenses/GPL.
+	</para>
+
+  </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
+
+
diff --git a/debian/watch b/debian/watch
new file mode 100644
index 0000000..b65467a
--- /dev/null
+++ b/debian/watch
@@ -0,0 +1,2 @@
+version=3
+http://tetgen.berlios.de/files/tetgen(.*)\.tar\.gz

-- 
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