From 4d69aaee512c078e7a6a6a02cbcb48a69fd38762 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Wed, 2 May 2007 07:59:29 +0000
Subject: [PATCH] - tetgen update - polished mesh option strings in gui -
 merged modified extrusion patch from <mi.benham@free.fr>

---
 Fltk/GUI.cpp                  |    10 +-
 Geo/GModel.cpp                |     4 +-
 Geo/GModelIO_Mesh.cpp         |    12 +-
 Geo/GPoint.h                  |     9 +
 Mesh/meshGEdge.cpp            |    14 +-
 Mesh/meshGRegionExtruded.cpp  |    56 +-
 contrib/Tetgen/README         |    12 +-
 contrib/Tetgen/predicates.cxx |    11 +
 contrib/Tetgen/tetgen.cxx     | 10428 +++++++++++++++++++++-----------
 contrib/Tetgen/tetgen.h       |   435 +-
 10 files changed, 7215 insertions(+), 3776 deletions(-)

diff --git a/Fltk/GUI.cpp b/Fltk/GUI.cpp
index e8a95b2d06..aa90140b9d 100644
--- a/Fltk/GUI.cpp
+++ b/Fltk/GUI.cpp
@@ -1,4 +1,4 @@
-// $Id: GUI.cpp,v 1.605 2007-04-26 12:23:04 geuzaine Exp $
+// $Id: GUI.cpp,v 1.606 2007-05-02 07:59:27 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -2280,11 +2280,11 @@ void GUI::create_option_window()
       Fl_Group *o = new Fl_Group(L + WB, WB + BH, width - 2 * WB, height - 2 * WB - BH, "Advanced");
       o->hide();
 
-      mesh_butt[1] = new Fl_Check_Button(L + 2 * WB, 2 * WB + 1 * BH, BW, BH, "Compute characteritic lenghts automatically from curvatures" );
+      mesh_butt[1] = new Fl_Check_Button(L + 2 * WB, 2 * WB + 1 * BH, BW, BH, "Compute characteritic lengths from curvatures" );
       mesh_butt[1]->type(FL_TOGGLE_BUTTON);
       mesh_butt[1]->callback(mesh_options_ok_cb);
 
-      mesh_butt[5] = new Fl_Check_Button(L + 2 * WB, 2 * WB + 2 * BH, BW, BH, "Constrain background mesh with characteristic length field");
+      mesh_butt[5] = new Fl_Check_Button(L + 2 * WB, 2 * WB + 2 * BH, BW, BH, "Constrain background mesh with other length fields");
       mesh_butt[5]->type(FL_TOGGLE_BUTTON);
       mesh_butt[5]->callback(mesh_options_ok_cb);
 
@@ -2295,11 +2295,11 @@ void GUI::create_option_window()
 #endif
       mesh_butt[2]->callback(mesh_options_ok_cb);
 
-      mesh_butt[3] = new Fl_Check_Button(L + 2 * WB, 2 * WB + 4 * BH, BW, BH, "Optimize high order mesh (currently only for 2D-plane)");
+      mesh_butt[3] = new Fl_Check_Button(L + 2 * WB, 2 * WB + 4 * BH, BW, BH, "Optimize high order mesh (only for 2D-plane)");
       mesh_butt[3]->type(FL_TOGGLE_BUTTON);
       mesh_butt[3]->callback(mesh_options_ok_cb);
 
-      mesh_butt[21] = new Fl_Check_Button(L + 2 * WB, 2 * WB + 5 * BH, BW, BH, "Impose C1 continuity (only for degrees 2 and 3 and 2D-plane)");
+      mesh_butt[21] = new Fl_Check_Button(L + 2 * WB, 2 * WB + 5 * BH, BW, BH, "Impose C1 continuity (only for 2D-plane, order 2 and 3)");
       mesh_butt[21]->type(FL_TOGGLE_BUTTON);
       mesh_butt[21]->callback(mesh_options_ok_cb);
 
diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp
index 2dff9f5ff6..c47ebcb4fd 100644
--- a/Geo/GModel.cpp
+++ b/Geo/GModel.cpp
@@ -1,4 +1,4 @@
-// $Id: GModel.cpp,v 1.40 2007-04-21 19:40:00 geuzaine Exp $
+// $Id: GModel.cpp,v 1.41 2007-05-02 07:59:27 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -250,7 +250,7 @@ bool GModel::noPhysicalGroups()
 static void addInGroup(GEntity* ge, std::map<int, std::vector<GEntity*> > &group)
 {
   for(unsigned int i = 0; i < ge->physicals.size(); i++){
-    // phyicals can be stored with negative signs when the entity
+    // physicals can be stored with negative signs when the entity
     // should be "reversed"
     int p = std::abs(ge->physicals[i]);
     if(std::find(group[p].begin(), group[p].end(), ge) == group[p].end())
diff --git a/Geo/GModelIO_Mesh.cpp b/Geo/GModelIO_Mesh.cpp
index f00eebe113..ba7fbf0fa4 100644
--- a/Geo/GModelIO_Mesh.cpp
+++ b/Geo/GModelIO_Mesh.cpp
@@ -1,4 +1,4 @@
-// $Id: GModelIO_Mesh.cpp,v 1.15 2007-04-21 19:40:00 geuzaine Exp $
+// $Id: GModelIO_Mesh.cpp,v 1.16 2007-05-02 07:59:27 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -571,9 +571,6 @@ int GModel::writeMSH(const std::string &name, double version, bool binary,
     return 0;
   }
 
-  // binary format exists only in version 2
-  if(binary) version = 2.0;
-
   // if there are no physicals we save all the elements
   if(noPhysicalGroups()) saveAll = true;
 
@@ -581,6 +578,9 @@ int GModel::writeMSH(const std::string &name, double version, bool binary,
   // continuous sequence
   int numVertices = renumberMeshVertices(saveAll);
   
+  // binary format exists only in version 2
+  if(binary) version = 2.0;
+
   // get the number of elements (we assume that all the elements in a
   // list have the same type, i.e., they are all of the same
   // polynomial order)
@@ -725,10 +725,10 @@ int GModel::writePOS(const std::string &name, bool saveAll, double scalingFactor
     return 0;
   }
 
-  int status = getMeshStatus();
-
   if(noPhysicalGroups()) saveAll = true;
 
+  int status = getMeshStatus();
+
   if(status >= 3){
     fprintf(fp, "View \"Volumes\" {\n");
     fprintf(fp, "T2(1.e5,30,%d){\"Elementary Entity\", \"Element Number\", "
diff --git a/Geo/GPoint.h b/Geo/GPoint.h
index 66b1690903..bd6a60b1df 100644
--- a/Geo/GPoint.h
+++ b/Geo/GPoint.h
@@ -20,6 +20,8 @@
 // 
 // Please report all bugs and problems to <gmsh@geuz.org>.
 
+#include <math.h>
+
 class GEntity;
 
 class GPoint 
@@ -48,6 +50,13 @@ class GPoint
     par[0] = p[0];
     par[1] = p[1];
   }
+  double distance(GPoint &p)
+  {
+    double dx = X - p.x();
+    double dy = Y - p.y();
+    double dz = Z - p.z();
+    return sqrt(dx * dx + dy * dy + dz * dz);
+  }
 };
 
 #endif
diff --git a/Mesh/meshGEdge.cpp b/Mesh/meshGEdge.cpp
index eb4899aff0..61824ec7c4 100644
--- a/Mesh/meshGEdge.cpp
+++ b/Mesh/meshGEdge.cpp
@@ -1,4 +1,4 @@
-// $Id: meshGEdge.cpp,v 1.37 2007-04-26 09:47:38 remacle Exp $
+// $Id: meshGEdge.cpp,v 1.38 2007-05-02 07:59:27 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -189,14 +189,6 @@ void deMeshGEdge::operator() (GEdge *ge)
   if(ge->meshRep) ge->meshRep->destroy();
 }
 
-double GPointDist(GPoint &p1, GPoint &p2)
-{
-  double dx = p1.x() - p2.x();
-  double dy = p1.y() - p2.y();
-  double dz = p1.z() - p2.z();
-  return sqrt(dx * dx + dy * dy + dz * dz);
-}
-
 void meshGEdge::operator() (GEdge *ge) 
 {  
   if(ge->geomType() == GEntity::DiscreteCurve) return;
@@ -276,8 +268,8 @@ void meshGEdge::operator() (GEdge *ge)
 	}
 	else{
 	  double lc = BGM_MeshSize(ge, t, 0, V.x(), V.y(), V.z());
-	  if(GPointDist(V, last_p) > 0.7 * lc && 
-	     !(NUMP == N - 2 && GPointDist(V, end_p) < 0.7 * lc)){
+	  if(V.distance(last_p) > 0.7 * lc && 
+	     !(NUMP == N - 2 && V.distance(end_p) < 0.7 * lc)){
 	    last_p = V;
 	    ge->mesh_vertices[NUMP2 - 1] = new MEdgeVertex(V.x(), V.y(), V.z(), ge, t);
 	    NUMP2++;
diff --git a/Mesh/meshGRegionExtruded.cpp b/Mesh/meshGRegionExtruded.cpp
index f69c5c6e30..f0e37e01cb 100644
--- a/Mesh/meshGRegionExtruded.cpp
+++ b/Mesh/meshGRegionExtruded.cpp
@@ -1,4 +1,4 @@
-// $Id: meshGRegionExtruded.cpp,v 1.13 2007-03-18 12:05:16 geuzaine Exp $
+// $Id: meshGRegionExtruded.cpp,v 1.14 2007-05-02 07:59:27 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -386,13 +386,53 @@ void phase1(GRegion *gr,
     for(int j = 0; j < ep->mesh.NbLayer; j++) {
       for(int k = 0; k < ep->mesh.NbElmLayer[j]; k++) {
 	std::vector<MVertex*> v;
-	if(getExtrudedVertices(from->triangles[i], ep, j, k, pos, v) == 6){
-	  if(!edgeExists(v[0], v[4], edges))
-	    createEdge(v[1], v[3], edges);
-	  if(!edgeExists(v[4], v[2], edges))
-	    createEdge(v[1], v[5], edges);
-	  if(!edgeExists(v[3], v[2], edges))
-	    createEdge(v[0], v[5], edges);
+        if(getExtrudedVertices(from->triangles[i], ep, j, k, pos, v) == 6){
+#if 0 // this is the old version
+          if(!edgeExists(v[0], v[4], edges))
+            createEdge(v[1], v[3], edges);
+          if(!edgeExists(v[4], v[2], edges))
+            createEdge(v[1], v[5], edges);
+          if(!edgeExists(v[3], v[2], edges))
+            createEdge(v[0], v[5], edges);
+#else // new version from Michel Benhamou <mi.benham@free.fr>
+          int v0 = 0;
+          for(int l = 1; l < 6; l++){
+            if(v[l] < v[v0]) v0 = l;
+          }
+          v0 = (v0 + 2) % 3;
+          int vn[6];
+          for(int l = 0; l < 3; l++){
+            vn[l] = (v0 + l) % 3;
+            vn[l + 3] = vn[l] + 3;
+          }
+
+          if(v[vn[1]] < v[vn[0]]){
+            if(!edgeExists(v[vn[0]], v[vn[4]], edges))
+              createEdge(v[vn[1]], v[vn[3]], edges);
+          }
+          else{
+            if(!edgeExists(v[vn[1]], v[vn[3]], edges))
+              createEdge(v[vn[0]], v[vn[4]], edges);
+          }
+
+          if(v[vn[1]] < v[vn[4]]){
+            if(!edgeExists(v[vn[4]], v[vn[2]], edges))
+              createEdge(v[vn[1]], v[vn[5]], edges);
+          }
+          else{
+            if(!edgeExists(v[vn[1]], v[vn[5]], edges))
+              createEdge(v[vn[4]], v[vn[2]], edges);
+          }
+
+          if(v[vn[0]] < v[vn[3]]){
+            if(!edgeExists(v[vn[3]], v[vn[2]], edges))
+              createEdge(v[vn[0]], v[vn[5]], edges);
+          }
+          else{
+            if(!edgeExists(v[vn[0]], v[vn[5]], edges))
+              createEdge(v[vn[3]], v[vn[2]], edges);
+          }
+#endif
 	}
       }
     }
diff --git a/contrib/Tetgen/README b/contrib/Tetgen/README
index 429553ab84..125c22c4fa 100644
--- a/contrib/Tetgen/README
+++ b/contrib/Tetgen/README
@@ -1,14 +1,16 @@
-This is TetGen version 1.4.1 (released on July 28, 2006)
+This is TetGen version 1.4.2 (released on April 16, 2007)
 
-Please see the user's manul (available at the following link) for compiling
-and using TetGen.
+Please see the documentation of TetGen (available at the following link) for
+compiling and using TetGen.
 
             http://tetgen.berlios.de/index.html
 
 TetGen may be freely copied, modified, and redistributed under the
-following copyright notices stated in the file LICENSE.
+copyright notices stated in the file LICENSE.
 
 Please send bugs/comments to Hang Si <si@wias-berlin.de>
 
+Thank you and enjoy!
+
 Hang Si
-July 28, 2006
+April 16, 2007
diff --git a/contrib/Tetgen/predicates.cxx b/contrib/Tetgen/predicates.cxx
index 0d41e5badf..bc0bd39f9e 100644
--- a/contrib/Tetgen/predicates.cxx
+++ b/contrib/Tetgen/predicates.cxx
@@ -1869,6 +1869,17 @@ REAL orient3dadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL permanent)
   REAL fin1[192], fin2[192];
   int finlength;
 
+  ////////////////////////////////////////////////////////
+  // To avoid uninitialized warnings reported by valgrind.
+  int i;
+  for (i = 0; i < 8; i++) {
+    adet[i] = bdet[i] = cdet[i] = 0.0;
+  }
+  for (i = 0; i < 16; i++) {
+    abdet[i] = 0.0;
+  }
+  ////////////////////////////////////////////////////////
+
   REAL adxtail, bdxtail, cdxtail;
   REAL adytail, bdytail, cdytail;
   REAL adztail, bdztail, cdztail;
diff --git a/contrib/Tetgen/tetgen.cxx b/contrib/Tetgen/tetgen.cxx
index 348a256569..91035a6404 100644
--- a/contrib/Tetgen/tetgen.cxx
+++ b/contrib/Tetgen/tetgen.cxx
@@ -5,16 +5,18 @@
 // A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator         //
 //                                                                           //
 // Version 1.4                                                               //
-// January 14, 2006                                                          //
+// April 16, 2007                                                            //
 //                                                                           //
-// Copyright 2002, 2004, 2005, 2006                                          //
+// Copyright (C) 2002--2007                                                  //
 // Hang Si                                                                   //
-// Rathausstr. 9, 10178 Berlin, Germany                                      //
+// Research Group Numerical Mathematics and Scientific Computing             //
+// Weierstrass Institute for Applied Analysis and Stochastics                //
+// Mohrenstr. 39, 10117 Berlin, Germany                                      //
 // si@wias-berlin.de                                                         //
 //                                                                           //
-// 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 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.     //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -22,7 +24,7 @@
 //                                                                           //
 // tetgen.cxx                                                                //
 //                                                                           //
-// The C++ implementation file of the TetGen library.                        //
+// The TetGen library and program.                                           //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -64,15 +66,15 @@ void tetgenio::initialize()
 {
   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;
-  addpointlist = (REAL *) NULL;
-  addpointattributelist = (REAL *) NULL;
+  pointmtrlist = (REAL *) NULL;
   pointmarkerlist = (int *) NULL;
   numberofpoints = 0;
   numberofpointattributes = 0;
-  numberofaddpoints = 0;
+  numberofpointmtrs = 0;
 
   tetrahedronlist = (int *) NULL;
   tetrahedronattributelist = (REAL *) NULL;
@@ -105,11 +107,18 @@ void tetgenio::initialize()
   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;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -140,11 +149,8 @@ void tetgenio::deinitialize()
   if (pointattributelist != (REAL *) NULL) {
     delete [] pointattributelist;
   }
-  if (addpointlist != (REAL *) NULL) {
-    delete [] addpointlist;
-  }
-  if (addpointattributelist != (REAL *) NULL) {
-    delete [] addpointattributelist;
+  if (pointmtrlist != (REAL *) NULL) {
+    delete [] pointmtrlist;
   }
   if (pointmarkerlist != (int *) NULL) {
     delete [] pointmarkerlist;
@@ -210,9 +216,6 @@ void tetgenio::deinitialize()
   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]);
@@ -222,6 +225,24 @@ void tetgenio::deinitialize()
     }
     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;
+  }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -274,13 +295,15 @@ bool tetgenio::load_node_call(FILE* infile, int markers, char* infilename)
   attribindex = 0;
   for (i = 0; i < numberofpoints; i++) {
     stringptr = readnumberline(inputline, infile, infilename);
-    if (i == 0) {
-      firstnode = (int) strtol (stringptr, &stringptr, 0);
-      if ((firstnode == 0) || (firstnode == 1)) {
-        firstnumber = firstnode;
+    if (useindex) {
+      if (i == 0) {
+        firstnode = (int) strtol (stringptr, &stringptr, 0);
+        if ((firstnode == 0) || (firstnode == 1)) {
+          firstnumber = firstnode;
+        }
       }
-    }
-    stringptr = findnextnumber(stringptr);
+      stringptr = findnextnumber(stringptr);
+    } // if (useindex)
     if (*stringptr == '\0') {
       printf("Error:  Point %d has no x coordinate.\n", firstnumber + i);
       break;
@@ -372,34 +395,50 @@ bool tetgenio::load_node(char* filename)
     return false;
   }
   printf("Opening %s.\n", innodefilename);  
-  // Read number of points, number of dimensions, number of point
-  //   attributes, and number of boundary markers.
+  // Read the first line of the file.
   stringptr = readnumberline(inputline, infile, innodefilename);
-  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
-  stringptr = findnextnumber(stringptr);
-  if (*stringptr == '\0') {
-    mesh_dim = 3;
+  // 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);
+    }
   } else {
+    // It is a rbox (qhull) input file.
+    stringptr = inputline;
+    // Get the dimension.
     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);
+    // Get the number of points.
+    stringptr = readnumberline(inputline, infile, innodefilename);
+    numberofpoints = (int) strtol (stringptr, &stringptr, 0);
+    // There is no index column.
+    useindex = 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);
@@ -415,91 +454,6 @@ bool tetgenio::load_node(char* filename)
   return true;
 }
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// 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'.              //
@@ -716,43 +670,6 @@ bool tetgenio::load_var(char* filename)
     }
   }
 
-  // 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;
 }
@@ -772,8 +689,8 @@ bool tetgenio::load_mtr(char* filename)
   char mtrfilename[FILENAMESIZE];
   char inputline[INPUTLINESIZE];
   char *stringptr;
-  REAL attrib;
-  int attribindex;
+  REAL mtr;
+  int mtrindex;
   int i, j;
 
   strcpy(mtrfilename, filename);
@@ -789,38 +706,33 @@ bool tetgenio::load_mtr(char* filename)
   // Read number of points, number of columns (1, 3, or 6).
   stringptr = readnumberline(inputline, infile, mtrfilename);
   stringptr = findnextnumber(stringptr); // Skip number of points.
-  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;
+  if (*stringptr != '\0') {
+    numberofpointmtrs = (int) strtol (stringptr, &stringptr, 0);
   }
-
-  // Metric tensors are saved in pointattributelist.
-  if (pointattributelist != (REAL *) NULL) {
-    delete [] pointattributelist;
-    pointattributelist = (REAL *) NULL;
+  if (numberofpointmtrs == 0) {
+    // Column number doesn't match. Set a default number (1).
+    numberofpointmtrs = 1;
   }
-  numberofpointattributes = i;
-  // Allocate space for pointattributelist.
-  pointattributelist = new REAL[numberofpoints * numberofpointattributes];
-  if (pointattributelist == (REAL *) NULL) {
+
+  // Allocate space for pointmtrlist.
+  pointmtrlist = new REAL[numberofpoints * numberofpointmtrs];
+  if (pointmtrlist == (REAL *) NULL) {
     printf("Error:  Out of memory.\n");
     terminatetetgen(1);
   }
-  attribindex = 0;
+  mtrindex = 0;
   for (i = 0; i < numberofpoints; i++) {
     // Read metrics.
     stringptr = readnumberline(inputline, infile, mtrfilename);
-    for (j = 0; j < numberofpointattributes; j++) {
-      // stringptr = findnextnumber(stringptr);
+    for (j = 0; j < numberofpointmtrs; j++) {
       if (*stringptr == '\0') {
         printf("Error:  Metric %d is missing value #%d in %s.\n",
                i + firstnumber, j + 1, mtrfilename);
         terminatetetgen(1);
       }
-      attrib = (REAL) strtod(stringptr, &stringptr);
-      pointattributelist[attribindex++] = attrib;
+      mtr = (REAL) strtod(stringptr, &stringptr);
+      pointmtrlist[mtrindex++] = mtr;
+      stringptr = findnextnumber(stringptr);
     }
   }
 
@@ -1817,20 +1729,21 @@ bool tetgenio::load_stl(char* filename)
 // 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 and triangles,   //
-// other sections (such as tetrahedra, edges, ...) are ignored.              //
+// This routine ONLY reads the sections containing vertices, triangles, and  //
+// quadrilaters. Other sections (such as tetrahedra, edges, ...) are ignored.//
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 bool tetgenio::load_medit(char* filename)
 {
   FILE *fp;
-  tetgenio::facet *f;
+  tetgenio::facet *tmpflist, *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;
@@ -1931,6 +1844,7 @@ bool tetgenio::load_medit(char* filename)
     } 
     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");
@@ -1953,13 +1867,32 @@ bool tetgenio::load_medit(char* filename)
         }
         nfaces = strtol(bufferp, &bufferp, 0);
         // Allocate memory for 'tetgenio'
-        if (nfaces > 0) {        
-          numberoffacets = nfaces;
-          facetlist = new tetgenio::facet[nfaces];
-          facetmarkerlist = new int[nfaces];
+        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];
+          }
         }
         // Read the following list of faces.
-        for (i = 0; i < nfaces; i++) {
+        for (i = numberoffacets; i < numberoffacets + nfaces; i++) {
           bufferp = readline(buffer, fp, &line_count);
           if (bufferp == NULL) {
             printf("Unexpected end of file on line %d in file %s\n",
@@ -2001,10 +1934,12 @@ bool tetgenio::load_medit(char* filename)
             facetmarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
           }
         }
-        continue;
+        // Have read in a list of triangles/quads.
+        numberoffacets += nfaces;
+        nfaces = 0;
       }
     }
-    if (nverts > 0 && nfaces > 0) break; // Ignore other data.
+    // if (nverts > 0 && nfaces > 0) break; // Ignore other data.
   }
 
   // Close file
@@ -2092,38 +2027,43 @@ bool tetgenio::load_tetmesh(char* filename)
     printf("File I/O Error:  Cannot access file %s.\n", infilename);
     return false;
   }
-  // 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;
+  // 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);
+    }
   } else {
+    // It is a rbox (qhull) input file.
+    stringptr = inputline;
+    // Get the dimension.
     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);
-  }
-
-  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;
+    // Get the number of points.
+    stringptr = readnumberline(inputline, infile, infilename);
+    numberofpoints = (int) strtol (stringptr, &stringptr, 0);
+    // There is no index column.
+    useindex = 0;
   }
 
   // Load the list of nodes.
@@ -2134,86 +2074,92 @@ bool tetgenio::load_tetmesh(char* filename)
   fclose(infile);
 
   // Read the elements from an .ele file.
-  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);
+  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);
       }
-      // 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);
-        }
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        numberoftetrahedronattributes = 0; // Default no attribute.
+      } else {
+        numberoftetrahedronattributes = (int) strtol(stringptr, &stringptr, 0);
       }
-    }
-    // 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);
+      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);
         }
-        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);
+        // 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);
+          }
         }
-        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);
+      // 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 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;
         }
-        tetrahedronattributelist[attribindex++] = attrib;
       }
+      fclose(infile);
     }
-    fclose(infile);
-  }
+  } // if (meshdim == 3)
   
   // Read the hullfaces or subfaces from a .face file if it exists.
-  infilename = infacefilename;
+  if (mesh_dim == 3) {
+    infilename = infacefilename;
+  } else {
+    infilename = inelefilename;
+  }
   infile = fopen(infilename, "r");
   if (infile != (FILE *) NULL) {
     printf("Opening %s.\n", infilename);
@@ -2221,6 +2167,10 @@ bool tetgenio::load_tetmesh(char* filename)
     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 {
@@ -2357,7 +2307,167 @@ bool tetgenio::load_tetmesh(char* filename)
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// save_nodes()    Save points to a .node file.                              //
+// load_voronoi()    Load a Voronoi diagram from files.                      //
+//                                                                           //
+// 'filename' is the inputfile without suffix.  The Voronoi diagram is read  //
+// from files: filename.v.node, filename.v.edge, and filename.v.face.        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+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.           //
 //                                                                           //
@@ -2367,6 +2477,7 @@ void tetgenio::save_nodes(char* filename)
 {
   FILE *fout;
   char outnodefilename[FILENAMESIZE];
+  char outmtrfilename[FILENAMESIZE];
   int i, j;
 
   sprintf(outnodefilename, "%s.node", filename);
@@ -2391,8 +2502,22 @@ void tetgenio::save_nodes(char* filename)
     }
     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);
+  }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -2772,16 +2897,16 @@ tetgenbehavior::tetgenbehavior()
 {
   // Initialize command line switches.
   plc = 0;
-  refine = 0;
   quality = 0;
-  smooth = 1;
+  refine = 0;
+  coarse = 0;
   metric = 0;
-  bgmesh = 0;
   minratio = 2.0;
   goodratio = 0.0;
   minangle = 20.0;
   goodangle = 0.0;
-  maxdihedral = 170.0;
+  maxdihedral = 165.0;
+  mindihedral = 5.0;
   varvolume = 0;
   fixedvolume = 0;
   maxvolume = -1.0;
@@ -2791,15 +2916,18 @@ tetgenbehavior::tetgenbehavior()
   offcenter = 0;
   conformdel = 0;
   alpha1 = sqrt(2.0);
-  alpha2 = 0.5;
+  alpha2 = 1.0;
   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;
@@ -2815,7 +2943,6 @@ tetgenbehavior::tetgenbehavior()
   docheck = 0;
   quiet = 0;
   verbose = 0;
-  tol = 0;
   useshelles = 0;
   epsilon = 1.0e-8;
   epsilon2 = 1.0e-5;
@@ -2824,6 +2951,7 @@ tetgenbehavior::tetgenbehavior()
   commandline[0] = '\0';
   infilename[0] = '\0';
   outfilename[0] = '\0';
+  addinfilename[0] = '\0';
   bgmeshfilename[0] = '\0';
 }
 
@@ -2835,7 +2963,12 @@ tetgenbehavior::tetgenbehavior()
 
 void tetgenbehavior::versioninfo()
 {
-  printf("Version 1.4.1 (July 06, 2006).\n");
+  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@wias-berlin.de\n");
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -2846,27 +2979,28 @@ void tetgenbehavior::versioninfo()
 
 void tetgenbehavior::syntax()
 {
-  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("  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("    -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 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("    -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("    -z  Numbers all output items starting from zero.\n");
   printf("    -o2 Generates second-order subparametric elements.\n");
-  printf("    -P  Outputs triangulated PLC facets to .smesh file.\n");
-  printf("    -f  Outputs all faces (instead of boundary faces) to .face ");
+  printf("    -f  Outputs all faces to .face file.");
   printf("file.\n");
-  printf("    -e  Outputs subsegments to .edge file.\n");
+  printf("    -e  Outputs all edges 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");
@@ -2879,7 +3013,6 @@ void tetgenbehavior::syntax()
   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");
 }
 
@@ -2896,11 +3029,6 @@ void tetgenbehavior::usage()
   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@wias-berlin.de\n");
-  printf("\n");
   printf("What Can TetGen Do?\n");
   printf("\n");
   printf("  TetGen generates exact Delaunay tetrahedralizations, exact\n");
@@ -2974,7 +3102,7 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
   int startindex;
   int increment;
   int meshnumber;
-  int Rcount;
+  int scount;
   int i, j, k;
   char workstring[1024];
 
@@ -2990,7 +3118,7 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
   }
   
   // Rcount used to count the number of '-R' be used.
-  Rcount = 0;
+  scount = 0;
 
   for (i = startindex; i < argc; i++) {
     // Remember the command line switches.
@@ -3011,12 +3139,10 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
         plc = 1;
       } else if (argv[i][j] == 'r') {
         refine = 1;
-      } else if (argv[i][j] == 'm') {
-        metric = 1;
-      } else if (argv[i][j] == 'b') {
-        bgmesh = 1;
+      } else if (argv[i][j] == 'R') {
+        coarse = 1;
       } else if (argv[i][j] == 'q') {
-        quality = 1;
+        quality++;
         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
             (argv[i][j + 1] == '.')) {
           k = 0;
@@ -3027,10 +3153,37 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
             k++;
           }
           workstring[k] = '\0';
-          minratio = (REAL) strtod(workstring, (char **) NULL);
-        } 
+          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++;
+        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 (metric == 1) {
+            alpha1 = (REAL) strtod(workstring, (char **) NULL);
+          } else if (metric == 2) {
+            alpha2 = (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;
@@ -3058,9 +3211,11 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
       } else if (argv[i][j] == 'f') {
         facesout = 1;
       } else if (argv[i][j] == 'e') {
-        edgesout = 1;
+        edgesout++;
       } 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') {
@@ -3103,6 +3258,7 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
           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;
@@ -3114,34 +3270,15 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
             k++;
           }
           workstring[k] = '\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++;
+          if (scount == 1) {
+            optlevel = (int) strtol(workstring, (char **) NULL, 0);
+          } else if (scount == 2) {
+            optpasses = (int) strtol(workstring, (char **) NULL, 0);
           }
-          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;
@@ -3153,11 +3290,7 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
             k++;
           }
           workstring[k] = '\0';
-          if (tol == 1) {
-            epsilon = (REAL) strtod(workstring, (char **) NULL);
-          } else if (tol == 2) {
-            epsilon2 = (REAL) strtod(workstring, (char **) NULL);
-          }
+          epsilon = (REAL) strtod(workstring, (char **) NULL);
         } 
       } else if (argv[i][j] == 'C') {
         docheck++;
@@ -3167,9 +3300,9 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
         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();
@@ -3224,7 +3357,7 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
     }
   }
   plc = plc || diagnose;
-  useshelles = plc || refine || quality;
+  useshelles = plc || refine || coarse || quality;
   goodratio = minratio;
   goodratio *= goodratio;
 
@@ -3235,7 +3368,7 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
   }
   if (refine && (plc || noiterationnum)) {
     printf("Error:  Switches %s cannot use together with -r.\n",
-           "-p, -d, -c, and -I");
+           "-p, -d, and -I");
     return false;
   }
   if (diagnose && (quality || insertaddpoints || (order == 2) || neighout
@@ -3255,6 +3388,12 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
   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;
@@ -3291,6 +3430,9 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
     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");
@@ -4046,18 +4188,15 @@ void* tetgenmesh::link::insert(int pos, void* insitem)
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// del()    Delete a node containing the given pointer.                      //
+// del()    Delete a node.                                                   //
 //                                                                           //
 // 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::del(void* delitem)
+void* tetgenmesh::link::deletenode(void** deadnode)
 {
-  void **deadnode = (void **) ((void **) delitem - 2);
-  
-  // now delete the nownode
   void **nextnode = (void **) *deadnode;
   void **prevnode = (void **) *(deadnode + 1);
   *prevnode = (void *) nextnode;
@@ -4085,7 +4224,7 @@ void* tetgenmesh::link::del(int pos)
   if (!locate(pos) || (linkitems == 0)) {
     return (void *) NULL;
   }
-  return del((void *) ((void **) nextlinkitem + 2));
+  return deletenode((void **) nextlinkitem);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -4220,6 +4359,26 @@ int tetgenmesh::locver2nextf[4][6][2] = {
   { {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.
 //
@@ -4369,12 +4528,67 @@ inline void tetgenmesh::enext2self(triface& t) {
 //   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) {
-  return getnextface(&t1, &t2);
-}
-
-inline bool tetgenmesh::fnextself(triface& t) {
-  return getnextface(&t, NULL);
+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;
 }
 
 // enextfnext() and enext2fnext() are combination primitives of enext(),
@@ -4708,6 +4922,32 @@ inline void tetgenmesh::ssdissolve(face& s) {
 // End of primitives for interacting between subfaces and subsegs
 //
 
+//
+// 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
 //
@@ -4840,64 +5080,6 @@ inline bool tetgenmesh::issymexist(triface* t) {
   return ptr != dummytet;
 }
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// 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.                //
@@ -4967,13 +5149,13 @@ void tetgenmesh::tsspivot(triface* checkedge, face* checkseg)
   do {
     tspivot(spintet, parentsh);
     // Does spintet have a (non-fake) subface attached? 
-    if (parentsh.sh != dummysh && !isdead(&parentsh)) {
-      // Find a subface!
+    if ((parentsh.sh != dummysh) && (sapex(parentsh) != NULL)) {
+      // Find a subface! Find the edge in it.      
       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) != sorg(parentsh)) {
+        if (sorg(*checkseg) != org(*checkedge)) {
           sesymself(*checkseg);
         }
       }
@@ -5477,7 +5659,7 @@ void tetgenmesh::printtet(triface* tface)
   if (b->useshelles) {
     tmpface = *tface;
     facecount = 0;
-    while(facecount < 4) {
+    while(facecount < 6) {
       tmpface.loc = facecount;
       tspivot(tmpface, tmpsh);
       if(tmpsh.sh != dummysh) {
@@ -5523,8 +5705,6 @@ void tetgenmesh::printsh(face* sface)
   if (sapex(*sface) != NULL) {
     if (shelltype(*sface) == SHARP) {
       printf(" (sharp)");
-    } else if (shelltype(*sface) == SKINNY) {
-      printf(" (skinny)");
     }
   } else {
     if (shelltype(*sface) == SHARP) {
@@ -7365,6 +7545,72 @@ void tetgenmesh::tetallnormal(point pa, point pb, point pc, point pd,
   for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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) //
@@ -7891,29 +8137,41 @@ void tetgenmesh::initializepools()
     varconstraint = 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; 
+  // 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; 
   } else {
-    pointlfsindex = 3 + in->numberofpointattributes; 
+    // For '-q' option. Make sure to have space for saving a scalar value.
+    sizeoftensor = b->quality ? 1 : 0;
   }
-  // The index within each point at which a element pointer is found, where
+  // The index within each point at which an element pointer is found, where
   //   the index is measured in pointers. Ensure the index is aligned to a
   //   sizeof(tetrahedron)-byte address.
-  point2simindex = ((pointlfsindex + b->quality) * sizeof(REAL) 
+  point2simindex = ((pointmtrindex + sizeoftensor) * 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()).
-    pointsize = (point2simindex + 3) * sizeof(tetrahedron);
-    if (bgm != (tetgenmesh *) NULL) {
-      // Increase the size by one pointer to a tet of the background mesh.
+    if (b->metric) {
+      // Increase 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)
@@ -7941,7 +8199,11 @@ void tetgenmesh::initializepools()
   // 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 * 4) * sizeof(tetrahedron);
+  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);
+  }
   // 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);
@@ -7958,15 +8220,15 @@ void tetgenmesh::initializepools()
     elesize = volumeboundindex * sizeof(REAL);
   }
   // If element neighbor graph is requested (-n switch), an additional
-  //   integer is allocated for each element. 
-  if (b->neighout) {
-    elemmarkerindex = (elesize + sizeof(int) - 1) / sizeof(int);
+  //   integer is allocated for each element.
+  elemmarkerindex = (elesize + sizeof(int) - 1) / sizeof(int);
+  if (b->neighout || b->voroout) {
     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.
@@ -8172,6 +8434,8 @@ void tetgenmesh::maketetrahedron(triface *newtet)
     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);
@@ -8219,7 +8483,7 @@ void tetgenmesh::makeshellface(memorypool *pool, face *newface)
   // Set the boundary marker to zero.
   setshellmark(*newface, 0);
   // Set the type.
-  setshelltype(*newface, NSHARPNSKINNY);
+  setshelltype(*newface, NSHARP);
   if (checkpbcs) {
     // Set the pbcgroup be ivalid.
     setshellpbcgroup(*newface, -1);
@@ -8244,21 +8508,19 @@ void tetgenmesh::makepoint(point* pnewpoint)
   (*pnewpoint)[1] = 0.0;
   (*pnewpoint)[2] = 0.0;
   // Initialize the list of user-defined attributes.
-  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;
-    }
+  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 (b->plc || b->refine) {
     // Initialize the point-to-simplex filed.
     setpoint2tet(*pnewpoint, NULL);
     setpoint2sh(*pnewpoint, NULL);
     setpoint2ppt(*pnewpoint, NULL);
-    if (bgm != (tetgenmesh *) NULL) {
+    if (b->metric) {
       setpoint2bgmtet(*pnewpoint, NULL);
     }
     if (checkpbcs) {
@@ -8269,7 +8531,7 @@ void tetgenmesh::makepoint(point* pnewpoint)
   // Initialize the point marker (starting from in->firstnumber).
   ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1);
   setpointmark(*pnewpoint, ptmark);
-  // Initialize the point type be UNUSEDVERTEX.
+  // Initialize the point type.
   setpointtype(*pnewpoint, UNUSEDVERTEX);
 }
 
@@ -8289,8 +8551,24 @@ void tetgenmesh::makepoint(point* pnewpoint)
 
 unsigned long tetgenmesh::randomnation(unsigned int choices)
 {
-  randomseed = (randomseed * 1366l + 150889l) % 714025l;
-  return randomseed / (714025l / choices + 1);
+  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);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -8363,8 +8641,12 @@ enum tetgenmesh::locateresult tetgenmesh::preciselocate(point searchpt,
   }
   // '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
@@ -8499,8 +8781,8 @@ enum tetgenmesh::locateresult tetgenmesh::preciselocate(point searchpt,
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::locateresult tetgenmesh::
-locate(point searchpt, triface *searchtet)
+enum tetgenmesh::locateresult tetgenmesh::locate(point searchpt, 
+  triface *searchtet)
 {
   tetrahedron *firsttet, *tetptr;
   void **sampleblock;
@@ -8519,8 +8801,12 @@ locate(point searchpt, triface *searchtet)
     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);
@@ -8602,9 +8888,8 @@ locate(point searchpt, triface *searchtet)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-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;
@@ -8753,6 +9038,77 @@ adjustlocate(point searchpt, triface* searchtet, enum locateresult precise,
   return INTETRAHEDRON;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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.               //
@@ -9179,26 +9535,21 @@ adjustlocateseg(point searchpt, face* searchseg, enum locateresult precise,
 //                                                                           //
 // categorizeface()    Determine the flip type of a given face.              //
 //                                                                           //
-// 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'.                                                           //
+// 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.                  //
 //                                                                           //
 // 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' 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. //
+//   - 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.                                   //
 //                                                                           //
 // 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  //
@@ -9224,7 +9575,7 @@ enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
   sym(horiz, symhoriz);
   if (symhoriz.tet == dummytet) {
     // A hull face is unflipable and locally Delaunay.
-    return NONCONVEX;
+    return N40;
   }
   
   adjustedgering(horiz, CCW);
@@ -9309,7 +9660,7 @@ enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
           return FORBIDDENEDGE;
         }
       }
-      return UNFLIPABLE;
+      return N32;
     }
     ori2 = orient3d(pb, pc, pd, pe);
     if (checksubfaces && ori2 != 0.0) {
@@ -9356,7 +9707,7 @@ enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
           return FORBIDDENEDGE;
         }
       }
-      return UNFLIPABLE;
+      return N32;
     } 
     ori3 = orient3d(pc, pa, pd, pe);
     if (checksubfaces && ori3 != 0.0) {
@@ -9406,7 +9757,7 @@ enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
           return FORBIDDENEDGE;
         }
       }
-      return UNFLIPABLE;
+      return N32;
     }
     if (ori1 == 0.0) {
       // e is coplanar with abd.
@@ -9415,7 +9766,7 @@ enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
         // assert(!(ori2 == 0.0 && ori3 == 0.0));
         // Three points (d, e, and a or b) are collinear, abc is unflipable
         //   and locally Delaunay.
-        return NONCONVEX;
+        return N40;
       }
     } else if (ori2 == 0.0) {
       // e is coplanar with bcd.
@@ -9424,7 +9775,7 @@ enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
         // assert(!(ori1 == 0.0 && ori3 == 0.0));
         // Three points (d, e, and b or c) are collinear, abc is unflipable
         //   and locally Delaunay.
-        return NONCONVEX;
+        return N40;
       }
       // Adjust 'horiz' and 'symhoriz' be the edge bc.
       enextself(horiz);
@@ -9436,7 +9787,7 @@ enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
         // assert(!(ori1 == 0.0 && ori2 == 0.0));
         // Three points (d, e, and c or a) are collinear, abc is unflipable
         //   and locally Delaunay.
-        return NONCONVEX;
+        return N40;
       }
       // Adjust 'horiz' and 'symhoriz' be the edge ca.
       enext2self(horiz);
@@ -9489,14 +9840,14 @@ enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
         pc = apex(horiz);
         // Be careful not to create an inverted tetrahedron. Check the case.
         ori1 = orient3d(pc, pd, pe, pa);
-        if (ori1 <= 0) return NONCONVEX;
+        if (ori1 <= 0) return N40;
         ori1 = orient3d(pd, pc, pe, pb);
-        if (ori1 <= 0) return NONCONVEX;
+        if (ori1 <= 0) return N40;
         if (pf != (point) NULL) {
           ori1 = orient3d(pd, pf, pe, pa);
-          if (ori1 <= 0) return NONCONVEX;
+          if (ori1 <= 0) return N40;
           ori1 = orient3d(pf, pd, pe, pb);
-          if (ori1 <= 0) return NONCONVEX;
+          if (ori1 <= 0) return N40;
         }
       }
       if (pf == (point) NULL) {
@@ -9511,7 +9862,7 @@ enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
       }
     } else {
       // ab has more than four faces around it, unflipable.
-      return UNFLIPABLE;
+      return N32;
     }
   } else if (adjtet == 1) {
     // One of its three edges is locally non-convex. Type T32 is possible.
@@ -9566,7 +9917,7 @@ enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
     }
     if (ori1 <= 0.0) {
       // a lies above or is coplanar cde, abc is locally Delaunay.
-      return NONCONVEX;
+      return N40;
     }
     ori2 = orient3d(pd, pc, pe, pb);
     if (checksubfaces && ori2 != 0.0) {
@@ -9597,7 +9948,7 @@ enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
     }
     if (ori2 <= 0.0) {
       // b lies above dce, unflipable, and abc is locally Delaunay.
-      return NONCONVEX;
+      return N40;
     }
     // Edge ab crosses face cde properly.
     if (checksubfaces) {
@@ -9622,14 +9973,14 @@ enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
           printf("Warning:  A tetrahedron spans two subfaces of a facet.\n");
         }
         // Temporarily, let it be there.
-        return UNFLIPABLE;
+        return N32;
       }
     }
     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 NONCONVEX;
+    return N40;
   }
 }
 
@@ -9647,12 +9998,14 @@ enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
 void tetgenmesh::enqueueflipface(triface& checkface, queue* flipqueue)
 {
   badface *queface;
+  triface symface;
 
-  queface = (badface *) flipqueue->push((void *) NULL);
-  queface->tt = checkface;
-  queface->forg = org(checkface);
-  queface->fdest = dest(checkface);
-  queface->fapex = apex(checkface);
+  sym(checkface, symface);
+  if (symface.tet != dummytet) {
+    queface = (badface *) flipqueue->push((void *) NULL);
+    queface->tt = checkface;
+    queface->foppo = oppo(symface);
+  }
 }
 
 void tetgenmesh::enqueueflipedge(face& checkedge, queue* flipqueue)
@@ -9686,10 +10039,14 @@ void tetgenmesh::flip23(triface* flipface, queue* flipqueue)
   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;
@@ -9697,27 +10054,25 @@ void tetgenmesh::flip23(triface* flipface, queue* flipqueue)
 
   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).\n", pointmark(pa),
-           pointmark(pb), pointmark(pc), pointmark(pd));
+    printf("    Do T23 on face (%d, %d, %d) %d, %d.\n", pointmark(pa),
+           pointmark(pb), pointmark(pc), pointmark(pd), pointmark(pe));
   }
   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);
@@ -9738,6 +10093,24 @@ void tetgenmesh::flip23(triface* flipface, queue* flipqueue)
     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.
@@ -9771,10 +10144,10 @@ void tetgenmesh::flip23(triface* flipface, queue* flipqueue)
 
   // Clear old bonds in edab(was abcd) and edbc(was bace).
   for (i = 0; i < 4; i ++) {
-    edab.loc = i;
-    dissolve(edab);
-    edbc.loc = i;
-    dissolve(edbc);
+    edab.tet[i] = (tetrahedron) dummytet;
+  }
+  for (i = 0; i < 4; i ++) {
+    edbc.tet[i] = (tetrahedron) dummytet;
   }
   // Bond the faces inside the convex hull.
   edab.loc = 0;
@@ -9798,7 +10171,7 @@ void tetgenmesh::flip23(triface* flipface, queue* flipqueue)
   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).
@@ -9832,6 +10205,55 @@ void tetgenmesh::flip23(triface* flipface, queue* flipqueue)
       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;
@@ -9889,40 +10311,44 @@ void tetgenmesh::flip32(triface* flipface, queue* flipqueue)
   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);
-  fnext(edab, edbc);
-  symself(edbc);
-  findedge(&edbc, org(edab), dest(edab));
-  fnext(edbc, edca);
-  symself(edca);
-  findedge(&edca, org(edab), dest(edab));
   pa = apex(edab);
   pb = oppo(edab);
-  pc = oppo(edbc);
   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);
+  fnext(edbc, edca);
+  symself(edca);
+  edca.ver = 0;
+  for (i = 0; (i < 3) && (org(edca) != pe); i++) {
+    enextself(edca);
+  }
 
   if (b->verbose > 2) {
-    printf("    Do T32 on face (%d, %d, %d, %d).\n",
-           pointmark(pe), pointmark(pd), pointmark(pa), pointmark(pb));
+    printf("    Do T32 on edge (%d, %d) %d, %d, %d.\n", pointmark(pe),
+           pointmark(pd), pointmark(pa), pointmark(pb), pointmark(pc));
   }
   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);
@@ -9943,6 +10369,28 @@ void tetgenmesh::flip32(triface* flipface, queue* flipqueue)
     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.
@@ -9961,10 +10409,10 @@ void tetgenmesh::flip32(triface* flipface, queue* flipqueue)
 
   // Clear the old bonds in abcd (was edab) and bace (was edbc).
   for (i = 0; i < 4; i ++) {
-    abcd.loc = i;
-    dissolve(abcd);
-    bace.loc = i;
-    dissolve(bace);
+    abcd.tet[i] = (tetrahedron) dummytet;
+  }
+  for (i = 0; i < 4; i ++) {
+    bace.tet[i] = (tetrahedron) dummytet;
   }
   // Bond the inside face of the convex hull.
   abcd.loc = 0;
@@ -9986,35 +10434,72 @@ void tetgenmesh::flip32(triface* flipface, queue* flipqueue)
   if (checksubfaces) {
     // Clear old bonds in abcd(was edab) and bace(was edbc).
     for (i = 0; i < 4; i ++) {
-      abcd.loc = i;
-      tsdissolve(abcd);
-      bace.loc = i;
-      tsdissolve(bace);
+      abcd.tet[8 + i] = (tetrahedron) dummysh;
+    }
+    for (i = 0; i < 4; i ++) {
+      bace.tet[8 + i] = (tetrahedron) dummysh;
     }
     if (abdsh.sh != dummysh) {
       abcd.loc = 1;
       tsbond(abcd, abdsh);
     }
-    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 (baesh.sh != dummysh) {
+      bace.loc = 1;
+      tsbond(bace, baesh);
+    }
+    if (cbesh.sh != dummysh) {
+      bace.loc = 3;
+      tsbond(bace, cbesh);
+    }
     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;
@@ -10084,10 +10569,14 @@ void tetgenmesh::flip22(triface* flipface, queue* flipqueue)
   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;
+  int mirrorflag, i;
 
   adjustedgering(*flipface, CCW); // 'flipface' is bae.
   fnext(*flipface, abce);
@@ -10109,12 +10598,20 @@ void tetgenmesh::flip22(triface* flipface, queue* flipqueue)
   sym(abce, bacf);
   mirrorflag = bacf.tet != dummytet;
   if (mirrorflag) {
-    findedge(&bacf, pb, pa);
+    // findedge(&bacf, pb, pa);
+    bacf.ver = 0;
+    for (i = 0; (i < 3) && (org(bacf) != pb); i++) {
+      enextself(bacf);
+    }
     sym(bade, abdf);
 #ifdef SELF_CHECK
     assert(abdf.tet != dummytet);
 #endif
-    findedge(&abdf, pa, pb);
+    // findedge(&abdf, pa, pb);
+    abdf.ver = 0;
+    for (i = 0; (i < 3) && (org(abdf) != pa); i++) {
+      enextself(abdf);
+    }
     pf = oppo(bacf);
 #ifdef SELF_CHECK
     assert(oppo(abdf) == pf);
@@ -10127,12 +10624,6 @@ void tetgenmesh::flip22(triface* flipface, queue* flipqueue)
   }
   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);
@@ -10149,6 +10640,29 @@ void tetgenmesh::flip22(triface* flipface, queue* flipqueue)
     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);
@@ -10164,6 +10678,20 @@ void tetgenmesh::flip22(triface* flipface, queue* flipqueue)
       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);
     }
   }
 
@@ -10194,6 +10722,75 @@ void tetgenmesh::flip22(triface* flipface, queue* flipqueue)
     } 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.
@@ -10223,6 +10820,75 @@ void tetgenmesh::flip22(triface* flipface, queue* flipqueue)
       } 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);
+      }
     }
   }
 
@@ -10553,15 +11219,10 @@ long tetgenmesh::flip(queue* flipqueue, badface **plastflip)
   while (!flipqueue->empty()) {
     qface = (badface *) flipqueue->pop();
     flipface = qface->tt;
-    // 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;
+    if (isdead(&flipface)) 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) != (point) NULL) {
+    if ((symface.tet != dummytet) && (oppo(symface) == qface->foppo)) {
       // For positive orientation that insphere() test requires.
       adjustedgering(flipface, CW);
       pa = org(flipface);
@@ -10569,7 +11230,7 @@ long tetgenmesh::flip(queue* flipqueue, badface **plastflip)
       pc = apex(flipface);
       pd = oppo(flipface);
       pe = oppo(symface);
-      // if (symbolic) {
+      if (symbolic) {
         ia = pointmark(pa);
         ib = pointmark(pb);
         ic = pointmark(pc);
@@ -10577,9 +11238,9 @@ long tetgenmesh::flip(queue* flipqueue, badface **plastflip)
         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.
     }
@@ -10591,7 +11252,7 @@ long tetgenmesh::flip(queue* flipqueue, badface **plastflip)
         epscount = 0;
         while (epscount < 32) {
           fc = categorizeface(flipface);
-          if (fc == NONCONVEX) {
+          if (fc == N40) {
             b->epsilon *= 1e-1;
             epscount++;
             continue;
@@ -10603,12 +11264,12 @@ long tetgenmesh::flip(queue* flipqueue, badface **plastflip)
           if (b->verbose > 0) {
             printf("Warning:  Can't flip a degenerate tetrahedron.\n");
           }
-          fc = NONCONVEX;
+          fc = N40;
         }
       } else {
         fc = categorizeface(flipface);
 #ifdef SELF_CHECK
-        assert(fc != NONCONVEX);
+        assert(fc != N40);
 #endif
       }
       switch (fc) {
@@ -10624,14 +11285,14 @@ long tetgenmesh::flip(queue* flipqueue, badface **plastflip)
         flip32(&flipface, flipqueue); 
         break;
       // The following face types are unflipable.
-      case UNFLIPABLE:
+      case N32:
         break;
       case FORBIDDENFACE:
         break;
       case FORBIDDENEDGE:
         break;
       // This case is only possible when the domain is nonconvex.
-      case NONCONVEX:
+      case N40:
         // assert(nonconvex);
         break;
       }
@@ -10659,6 +11320,233 @@ long tetgenmesh::flip(queue* flipqueue, badface **plastflip)
   return flipcount;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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().       //
@@ -10727,7 +11615,8 @@ long tetgenmesh::flipsub(queue* flipqueue)
 
   edgeflips = 0;
 
-  while ((qedge = (badface *) flipqueue->pop()) != NULL) {
+  while (!flipqueue->empty()) {
+    qedge = (badface *) flipqueue->pop();
     flipedge = qedge->ss;
     if (flipedge.sh == dummysh) continue;
     if ((sorg(flipedge) != qedge->forg) || 
@@ -10786,46 +11675,1131 @@ long tetgenmesh::flipsub(queue* flipqueue)
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// splittetrahedron()    Insert a point into a tetrahedron, split it into    //
-//                       four tetrahedra.                                    //
+// removetetbypeeloff()    Remove a boundary tet by peeling it off.          //
 //                                                                           //
-// The tetrahedron is given by 'splittet'.  Let it is abcd.  The inserting   //
-// point 'newpoint' v should lie strictly inside abcd.                       //
+// 'striptet' (abcd) is on boundary and can be removed by stripping it off.  //
+// Let abc and bad are the external boundary faces.                          //
 //                                                                           //
-// Splitting a tetrahedron is to shrink abcd to abcv,  and create three new  //
-// tetrahedra badv, cbdv, and acdv.                                          //
+// 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).                //
 //                                                                           //
-// On completion, 'splittet' returns abcv.  If 'flipqueue' is not NULL, it   //
-// contains all possibly non-locally Delaunay faces.                         //
+// 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.           //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-splittetrahedron(point newpoint, triface* splittet, queue* flipqueue)
+bool tetgenmesh::removetetbypeeloff(triface *striptet)
 {
-  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));
+  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;
   }
 
-  fnext(abcv, oldabd);
+  // 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));
+  }
+
+  fnext(abcv, oldabd);
   enextfnext(abcv, oldbcd);
   enext2fnext(abcv, oldcad);
   sym(oldabd, abdcasing);
@@ -10889,6 +12863,51 @@ splittetrahedron(point newpoint, triface* splittet, queue* flipqueue)
       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;
@@ -11022,14 +13041,18 @@ void tetgenmesh::unsplittetrahedron(triface* splittet)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-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;
@@ -11065,13 +13088,6 @@ splittetface(point newpoint, triface* splittet, queue* flipqueue)
            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);
@@ -11208,6 +13224,95 @@ splittetface(point newpoint, triface* splittet, queue* flipqueue)
       // 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.
@@ -11400,8 +13505,8 @@ void tetgenmesh::unsplittetface(triface* splittet)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-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;
@@ -11706,13 +13811,15 @@ void tetgenmesh::unsplitsubface(face* splitsh)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-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;
@@ -11855,14 +13962,14 @@ splittetedge(point newpoint, triface* splittet, queue* flipqueue)
     }
 #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
   }
 
@@ -11898,6 +14005,29 @@ splittetedge(point newpoint, triface* splittet, queue* flipqueue)
     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) {
@@ -12308,6 +14438,7 @@ void tetgenmesh::splitsubedge(point newpoint, face* splitsh, queue* flipqueue)
       // 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
@@ -12584,8 +14715,8 @@ void tetgenmesh::unsplitsubedge(face* splitsh)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-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;
@@ -12677,38 +14808,176 @@ insertsite(point newpoint, triface* searchtet, bool approx, queue* flipqueue)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-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);
+  if (oppo(*splittet) != toppo) {
+    symself(*splittet);
+#ifdef SELF_CHECK
+    assert(oppo(*splittet) == toppo);
+#endif
+    // The sym() operation may inverse the edge, correct it if so.
+    findedge(splittet, torg, tdest);
+  }
+  
+  // Unsplit the tetrahedron according to 'insresult'.  
+  switch (insresult) {
+  case SUCCESSINTET:
+    // 'splittet' should be the face with 'newpoint' as its opposite.
+    unsplittetrahedron(splittet);
+    break;
+  case SUCCESSONFACE:
+    // 'splittet' should be the one of three splitted face with 'newpoint'
+    //   as its apex.
+    unsplittetface(splittet);
+    break;
+  case SUCCESSONEDGE:
+    // 'splittet' should be the tet with destination is 'newpoint'.
+    unsplittetedge(splittet);
+    break;
+  default: // To omit compile warnings.
+    break;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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)
 {
-  // Set the four corners of 'splittet' exactly be 'torg', ... 'toppo'.
-  findface(splittet, torg, tdest, tapex);
-  if (oppo(*splittet) != toppo) {
-    symself(*splittet);
-#ifdef SELF_CHECK
-    assert(oppo(*splittet) == toppo);
-#endif
-    // The sym() operation may inverse the edge, correct it if so.
-    findedge(splittet, torg, tdest);
+  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);
   }
-  
-  // Unsplit the tetrahedron according to 'insresult'.  
-  switch (insresult) {
-  case SUCCESSINTET:
-    // 'splittet' should be the face with 'newpoint' as its opposite.
-    unsplittetrahedron(splittet);
-    break;
-  case SUCCESSONFACE:
-    // 'splittet' should be the one of three splitted face with 'newpoint'
-    //   as its apex.
-    unsplittetface(splittet);
-    break;
-  case SUCCESSONEDGE:
-    // 'splittet' should be the tet with destination is 'newpoint'.
-    unsplittetedge(splittet);
-    break;
-  default: // To omit compile warnings.
-    break;
+  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);
   }
 }
 
@@ -13925,17 +16194,7 @@ void tetgenmesh::bowatinsertsite(point bp,face* splitseg,int n,list** sublists,
       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);
       }
@@ -13962,11 +16221,6 @@ void tetgenmesh::bowatinsertsite(point bp,face* splitseg,int n,list** sublists,
         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; 
@@ -14046,15 +16300,17 @@ void tetgenmesh::formstarpolyhedron(point pt, list* tetlist, list* verlist,
   // Add t into T.
   * (triface *)(* tetlist)[0] = starttet;
   infect(starttet);
-  // 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]));
+  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]));
+    }
   }
 
   // Find other tets by a broadth-first search.
@@ -14077,14 +16333,17 @@ void tetgenmesh::formstarpolyhedron(point pt, list* tetlist, list* verlist,
           // Add n into T.
           infect(neightet);
           tetlist->append(&neightet);
-          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]));
+          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]));
+            }
           }
         }
       }
@@ -14097,11 +16356,13 @@ void tetgenmesh::formstarpolyhedron(point pt, list* tetlist, list* verlist,
     starttet = * (triface *)(* tetlist)[i];
     uninfect(starttet);
   }
-  // Uninfect vertices.
-  for (i = 0; i < verlist->len(); i++) {
-    ver[0] = * (point *)(* verlist)[i];
-    idx = pointmark(ver[0]);
-    setpointmark(ver[0], -(idx + 1));
+  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));
+    }
   }
 }
 
@@ -14200,145 +16461,6 @@ bool tetgenmesh::unifypoint(point testpt, triface *starttet, enum locateresult
   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);
-  }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// 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);
-  }
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // incrflipdelaunay()   Construct a delaunay tetrahedrization from a set of  //
@@ -14367,6 +16489,7 @@ void tetgenmesh::incrflipdelaunay(triface* oldtet, point* insertarray,
   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");
@@ -14451,6 +16574,11 @@ void tetgenmesh::incrflipdelaunay(triface* oldtet, point* insertarray,
     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]);
@@ -14465,18 +16593,18 @@ void tetgenmesh::incrflipdelaunay(triface* oldtet, point* insertarray,
       setvolumebound(newtet.tet, volume);
     }
   }
-  // Set vertex type be VOLVERTEX if it has no type yet.
+  // Set vertex type be FREEVOLVERTEX if it has no type yet.
   if (pointtype(insertarray[0]) == UNUSEDVERTEX) {
-    setpointtype(insertarray[0], VOLVERTEX);
+    setpointtype(insertarray[0], FREEVOLVERTEX);
   }
   if (pointtype(insertarray[1]) == UNUSEDVERTEX) {
-    setpointtype(insertarray[1], VOLVERTEX);
+    setpointtype(insertarray[1], FREEVOLVERTEX);
   }
   if (pointtype(insertarray[2]) == UNUSEDVERTEX) {
-    setpointtype(insertarray[2], VOLVERTEX);
+    setpointtype(insertarray[2], FREEVOLVERTEX);
   }
   if (pointtype(lastpt) == UNUSEDVERTEX) {
-    setpointtype(lastpt, VOLVERTEX);
+    setpointtype(lastpt, FREEVOLVERTEX);
   }
   // Bond to 'dummytet' for point location.
   dummytet[0] = encode(newtet);
@@ -14497,11 +16625,18 @@ void tetgenmesh::incrflipdelaunay(triface* oldtet, point* insertarray,
   // 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) {
@@ -14549,18 +16684,26 @@ void tetgenmesh::incrflipdelaunay(triface* oldtet, point* insertarray,
     }
     if (pointtype(insertarray[i]) == UNUSEDVERTEX) {
       // p_i becomes a (volume) vertex of T.
-      setpointtype(insertarray[i], VOLVERTEX);
+      setpointtype(insertarray[i], FREEVOLVERTEX);
     }
+#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->noflip && b->verbose > 0) {
+  if (b->verbose > 0) {
     printf("  %ld Flips (T23 %ld, T32 %ld, T22 %ld, T44 %ld)\n",
       flip23s+flip32s+flip22s+flip44s, flip23s, flip32s, flip22s, flip44s);
   }
@@ -14591,23 +16734,29 @@ long tetgenmesh::delaunizevertices()
     }
   }
 
+  flipque = new queue(sizeof(badface));
   // Prepare the array of points for inserting.
   arraysize = points->items;
-  insertarray = new point[arraysize];
+  insertarray = new point[arraysize];  
+  points->traversalinit();
+
   // 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();
   }
-  flipque = new queue(sizeof(badface));
+
+  // Use lawson flip.
+  b->noflip = 1;
 
   // 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;
@@ -14650,12 +16799,15 @@ void tetgenmesh::formstarpolygon(point pt, list* trilist, list* vertlist)
     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);
-  vertlist->append(&pa);
-  vertlist->append(&pb);
+  if (vertlist != (list *) NULL) {
+    // Add two verts a, b into V,
+    vertlist->append(&pa);
+    vertlist->append(&pb);
+  }
 
   // Rotate edge pa to the left (CW) until meet pb or a segment.
   lnextsh = steinsh;
@@ -14677,8 +16829,10 @@ void tetgenmesh::formstarpolygon(point pt, list* trilist, list* vertlist)
     // Add edge ca to E.
     pc = sorg(lnextsh);
     if (pc == pb) break; // Rotate back.
-    // Add vert c to V.
-    vertlist->append(&pc);
+    if (vertlist != (list *) NULL) {
+      // Add vert c into V.
+      vertlist->append(&pc);
+    }
   } while (true);
 
   if (pc != pb) {
@@ -14701,8 +16855,10 @@ void tetgenmesh::formstarpolygon(point pt, list* trilist, list* vertlist)
       // Add edge bd to E.
       pd = sdest(rnextsh);
       if (pd == pa) break; // Rotate back.
-      // Add vert d to V.
-      vertlist->append(&pd);
+      if (vertlist != (list *) NULL) {
+        // Add vert d into V.
+        vertlist->append(&pd);
+      }
     } while (true);
   }
 }
@@ -14729,7 +16885,7 @@ void tetgenmesh::formstarpolygon(point pt, list* trilist, list* vertlist)
 //                                                                           //
 // getfacetabovepoint()    Get a point above a plane pass through a facet.   //
 //                                                                           //
-// The calulcated point is saved in 'facetabovepointarray'. The 'abovepoint' //
+// The calculcated point is saved in 'facetabovepointarray'. The 'abovepoint'//
 // is set on return.                                                         //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
@@ -14737,7 +16893,6 @@ void tetgenmesh::formstarpolygon(point pt, list* trilist, list* vertlist)
 void tetgenmesh::getfacetabovepoint(face* facetsh)
 {
   list *verlist, *trilist, *tetlist;
-  tetrahedron tetptr;
   triface adjtet;
   face symsh;
   point p1, p2, p3, pa;
@@ -14804,17 +16959,22 @@ void tetgenmesh::getfacetabovepoint(face* facetsh)
       stpivot(symsh, adjtet);
     }
     if (adjtet.tet == dummytet) {
-      tetptr = point2tet(p1);
-      if (tetptr != (tetrahedron) NULL) {
-        decode(tetptr, adjtet);
-        if (isdead(&adjtet)) {
+      decode(point2tet(p1), adjtet);
+      if (isdead(&adjtet)) {
+        adjtet.tet = dummytet;
+      } else {
+        if (!findorg(&adjtet, p1)) {
           adjtet.tet = dummytet;
         }
       }
     }
     if (adjtet.tet == dummytet) {
       loc = locate(p1, &adjtet);
-      if (loc != ONVERTEX) adjtet.tet = dummytet;
+      if (loc == ONVERTEX) {
+        setpoint2tet(p1, encode(adjtet));
+      } else {
+        adjtet.tet = dummytet;
+      }
     }
     if (adjtet.tet != dummytet) {
       // Get the star polyhedron of p1.
@@ -15088,6 +17248,7 @@ void tetgenmesh::incrflipdelaunaysub(int shmark, REAL eps, list* ptlist,
   REAL det, area;
   bool aboveflag;
   int arraysize;
+  int epscount;
   int fmarker;
   int idx, i, j, k;  
 
@@ -15103,6 +17264,8 @@ void tetgenmesh::incrflipdelaunaysub(int shmark, REAL eps, list* ptlist,
   //   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;
@@ -15128,22 +17291,23 @@ void tetgenmesh::incrflipdelaunaysub(int shmark, REAL eps, list* ptlist,
     // 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) {
-      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");
+    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(", ...");
       }
+      printf(") (%d) is not a valid polygon.\n", shmark);
+      terminatetetgen(1);
     }
-    // Only use the first three points.
-    i = arraysize;
-    // Don't do calculation of abovepoint.
-    aboveflag = false;
+    // Decrease the eps, and continue to try.
+    eps *= 1e-2;
+    epscount++;
+    continue;
   }
+  break;
+  } // while (true);
 
   // Create the initial triangle.
   makeshellface(subfaces, &newsh);
@@ -15152,15 +17316,15 @@ void tetgenmesh::incrflipdelaunaysub(int shmark, REAL eps, list* ptlist,
   setsapex(newsh, insertarray[2]);
   // Remeber the facet it belongs to.
   setshellmark(newsh, shmark);
-  // Set vertex type be FACETVERTEX if it has no type yet.
-  if (pointtype(insertarray[0]) == VOLVERTEX) {
-    setpointtype(insertarray[0], FACETVERTEX);
+  // Set vertex type be FREESUBVERTEX if it has no type yet.
+  if (pointtype(insertarray[0]) == FREEVOLVERTEX) {
+    setpointtype(insertarray[0], FREESUBVERTEX);
   }
-  if (pointtype(insertarray[1]) == VOLVERTEX) {
-    setpointtype(insertarray[1], FACETVERTEX);
+  if (pointtype(insertarray[1]) == FREEVOLVERTEX) {
+    setpointtype(insertarray[1], FREESUBVERTEX);
   }
-  if (pointtype(insertarray[2]) == VOLVERTEX) {
-    setpointtype(insertarray[2], FACETVERTEX);
+  if (pointtype(insertarray[2]) == FREEVOLVERTEX) {
+    setpointtype(insertarray[2], FREESUBVERTEX);
   }
   // Let 'dummysh' point to it (for point location).
   dummysh[0] = sencode(newsh);
@@ -15224,9 +17388,9 @@ void tetgenmesh::incrflipdelaunaysub(int shmark, REAL eps, list* ptlist,
     } else if (loc == ONVERTEX) {
       // !should not happen!
     }
-    // Set p_i's type FACETVERTEX if it has no type yet.
-    if (pointtype(insertarray[i]) == VOLVERTEX) {
-      setpointtype(insertarray[i], FACETVERTEX);
+    // Set p_i's type FREESUBVERTEX if it has no type yet.
+    if (pointtype(insertarray[i]) == FREEVOLVERTEX) {
+      setpointtype(insertarray[i], FREESUBVERTEX);
     }
     flipsub(flipque);
   }
@@ -15847,6 +18011,14 @@ void tetgenmesh::triangulate(int shmark, REAL eps, list* ptlist, list* conlist,
       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]);
   }
 }
 
@@ -16068,8 +18240,8 @@ void tetgenmesh::unifysegments()
 //                                                                           //
 // 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  //
-// FACETVERTEX. Edge flips will be performed to ensure the Delaunay criteria //
-// of the triangulation of merged facets.                                    //
+// FREESUBVERTEX. Edge flips will be performed to ensure the Delaunayness of //
+// the triangulation of merged facets.                                       //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -16146,12 +18318,12 @@ void tetgenmesh::mergefacets(queue* flipqueue)
             j = pointmark(eorg);
             segspernodelist[j]--;
             if (segspernodelist[j] == 0) {
-              setpointtype(eorg, FACETVERTEX);
+              setpointtype(eorg, FREESUBVERTEX);
             }
             j = pointmark(edest);
             segspernodelist[j]--;
             if (segspernodelist[j] == 0) {
-              setpointtype(edest, FACETVERTEX);
+              setpointtype(edest, FREESUBVERTEX);
             }
             // Add 'parentsh' to queue checking for flip.
             enqueueflipedge(parentsh, flipqueue);
@@ -16345,6 +18517,8 @@ long tetgenmesh::meshsurface()
   // 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'.
@@ -16356,7 +18530,7 @@ long tetgenmesh::meshsurface()
     jettisonnodes();
   }
 
-  if (!b->nomerge && !checkpbcs) {
+  if (!b->nomerge && !b->nobisect && !checkpbcs) {
     // No '-M' switch - merge adjacent facets if they are coplanar.
     mergefacets(flipqueue);
   }
@@ -16835,13 +19009,15 @@ enum tetgenmesh::locateresult tetgenmesh:: getsubpbcsympoint(point newpoint,
 
 void tetgenmesh::createsegpbcgrouptable()
 {
-  pbcdata *pd, *pd1, *pd2;
+  shellface** segsperverlist;
+  pbcdata *pd, *ppd, pd1, pd2;
   face segloop, symseg;
   face startsh, spinsh, symsh;
-  point pa, pb;
+  point pa, pb, syma, symb;
   enum locateresult symloc;
   REAL testpt[3], sympt[3];
   bool inflag;
+  int *idx2seglist;
   int segid1, segid2;
   int f1, f2;
   int i, j, k, l;
@@ -16849,6 +19025,11 @@ void tetgenmesh::createsegpbcgrouptable()
   // 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);
@@ -16867,13 +19048,52 @@ void tetgenmesh::createsegpbcgrouptable()
       // Does spinsh belong to a pbcgroup?
       if (shellpbcgroup(spinsh) != -1) {
         // Yes! There exists a segment cd. ab and cd form a pbcgroup.
-        //   '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);
+        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);
 #ifdef SELF_CHECK
-        assert(symloc == ONEDGE);
+          assert(symloc == ONEDGE);
 #endif
-        sspivot(symsh, symseg);
+          sspivot(symsh, symseg);
+        }
 #ifdef SELF_CHECK
         assert(symseg.sh != dummysh);
 #endif
@@ -16898,19 +19118,19 @@ void tetgenmesh::createsegpbcgrouptable()
           pd->ss[0] = segloop;
           pd->ss[1] = symseg;
           // Find the map from ab to cd.
-          getsubpbcgroup(&spinsh, &pd1, &f1, &f2);
-          pd->fmark[0] = pd1->fmark[f1];
-          pd->fmark[1] = pd1->fmark[f2];
+          getsubpbcgroup(&spinsh, &ppd, &f1, &f2);
+          pd->fmark[0] = ppd->fmark[f1];
+          pd->fmark[1] = ppd->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] = pd1->transmat[f1][i][j];
+              pd->transmat[0][i][j] = ppd->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] = pd1->transmat[f2][i][j];
+              pd->transmat[1][i][j] = ppd->transmat[f2][i][j];
             }
           }
         }
@@ -16920,27 +19140,35 @@ void tetgenmesh::createsegpbcgrouptable()
     } 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++) {
@@ -16953,28 +19181,28 @@ void tetgenmesh::createsegpbcgrouptable()
           }
           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]);
           }
         }
       }
@@ -17812,92 +20040,93 @@ void tetgenmesh::incrperturbvertices(REAL eps)
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// markacutevertices()    Mark each vertex to be ACUTE or NACUTE.            //
+// markacutevertices()    Mark acute vertices.                               //
 //                                                                           //
-// 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).                        //
+// 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.                       //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 void tetgenmesh::markacutevertices(REAL acuteangle)
 {
   shellface **segsperverlist;
-  face segloop, workseg, inciseg;
-  point eorg, edest, eapex;
+  face segloop, nextseg;
+  point pointloop, 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 segments have acute corners.\n");
+    printf("  Marking acute vertices.\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 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; 
-            }
+
+  // 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) {
-          setpointtype(eorg, ACUTEVERTEX);
-        } else {
-          setpointtype(eorg, NACUTEVERTEX);
-        }
+      }
+      if (isacute) {
+        // Mark p to be acute.
+        setpointtype(pointloop, ACUTEVERTEX);
+        acutecount++;
       }
     }
-    segloop.sh = shellfacetraverse(subsegs);
+    pointloop = pointtraverse();
   }
 
   delete [] idx2seglist;
   delete [] segsperverlist;
+
+  if ((b->verbose > 0) && (acutecount > 0)) {
+    printf("  %d acute vertices.\n", acutecount);
+  }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -18426,7 +20655,7 @@ tetgenmesh::point tetgenmesh::getsplitpoint(face* splitseg, point refpoint)
   point farorg, fardest;
   point ei, ej, ek, c;
   REAL v[3], r, split;
-  REAL d1, ps, rs;
+  REAL d1, d2, ps, rs;
   bool acuteorg, acutedest;
   int stype, rule;
   int i;   
@@ -18536,7 +20765,6 @@ tetgenmesh::point tetgenmesh::getsplitpoint(face* splitseg, point refpoint)
   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) {
@@ -18550,12 +20778,13 @@ tetgenmesh::point tetgenmesh::getsplitpoint(face* splitseg, point refpoint)
   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;
@@ -18578,6 +20807,100 @@ tetgenmesh::point tetgenmesh::getsplitpoint(face* splitseg, point refpoint)
   return splitpoint;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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   //
@@ -18617,19 +20940,20 @@ tetgenmesh::point tetgenmesh::getsplitpoint(face* splitseg, point refpoint)
 
 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 finish, coll;
+  bool coll;
   long vertcount;
   int i, j;
 
@@ -18637,30 +20961,35 @@ void tetgenmesh::delaunizesegments()
     printf("Delaunizing segments.\n");
   }
 
-  // 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.
+  // Construct a map from points to tets for speeding point location.
+  makepoint2tetmap();
+  // Initialize a flipqueue.
   flipqueue = new queue(sizeof(badface));
-  // '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;
+  // 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;
   // Remember the current number of points.
   vertcount = points->items;
   // Initialize the counters.
-  r1count = r2count = r3count = r4count = 0l;
-
-  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));
+  r1count = r2count = r3count = 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));
       }
       getsearchtet(p1, p2, &searchtet, &tend);
       collinear = finddirection(&searchtet, tend, tetrahedrons->items);
@@ -18684,7 +21013,7 @@ void tetgenmesh::delaunizesegments()
           //   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) == VOLVERTEX) {
+          if (pointtype(checkpoint) == FREEVOLVERTEX) {
             // c is not a segment vertex yet. It becomes NACUTEVERTEX.
             setpointtype(splitpoint, NACUTEVERTEX);  
           } else if (pointtype(checkpoint) == ACUTEVERTEX) {
@@ -18697,7 +21026,7 @@ void tetgenmesh::delaunizesegments()
         } else {
           // Find a reference point p of ab.
           refpoint = scoutrefpoint(&searchtet, tend);
-          if (pointtype(refpoint) == VOLVERTEX) {
+          if (pointtype(refpoint) == FREEVOLVERTEX) {
             // p is an input point, check if it is nearly collinear with ab.
             coll = iscollinear(p1, p2, refpoint, b->epsilon);
             if (coll) {
@@ -18751,7 +21080,7 @@ void tetgenmesh::delaunizesegments()
                   // Let sympoint remember splittet.
                   setpoint2tet(sympoint, encode(splittet));
                   // Do flip in DT.
-                  flip(flipqueue, NULL);
+                  lawson(misseglist, flipqueue);
                   // Insert sympoint into F.
                   symsplitseg.shver = 0;
                   spivot(symsplitseg, symsplitsub);
@@ -18759,6 +21088,13 @@ void tetgenmesh::delaunizesegments()
                   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.
@@ -18781,35 +21117,42 @@ void tetgenmesh::delaunizesegments()
             //   consequent point location.
             setpoint2tet(splitpoint, encode(searchtet));
             // Maintain Delaunayness in DT.
-            flip(flipqueue, NULL);
+            lawson(misseglist, flipqueue);
           }
         }
         // Insert 'splitpoint' into F.
         spivot(segloop, splitsh);
         splitsubedge(splitpoint, &splitsh, flipqueue);
         flipsub(flipqueue);
-        // Remember 'segloop'.
-        lastsplit = segloop;
-      } else {
-        // ab exists. Is it the last one we've checked?
-        if (segloop.sh == lastsplit.sh) {
-          finish = true;
-          break;
-        }
+        // Insert the two subsegments.
+        segloop.shver = 0;
+        insertsegment(&segloop, misseglist);
+        senextself(segloop);
+        spivotself(segloop);
+        segloop.shver = 0;
+        insertsegment(&segloop, misseglist);
       }
-      segloop.sh = shellfacetraverse(subsegs);
-    }
-    if (lastsplit.sh == (shellface *) NULL) {
-      // No missing segment!
-      finish = true;
+  }
+
+  // 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;
     }
+    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;
 }
 
 //
@@ -21110,6 +23453,8 @@ void tetgenmesh::plague(memorypool *viri)
           if (shellmark(neighsh) == 0) {
             setshellmark(neighsh, 1);
           }
+          // This side becomes hull. Update the handle in dummytet.
+          dummytet[0] = encode(neighbor);
         }
       }
     }
@@ -21260,9 +23605,8 @@ void tetgenmesh::removeholetets(memorypool* viri)
       j = pointmark(checkpt);
       tetspernodelist[j]--;
       if (tetspernodelist[j] == 0) {
-        // If it is a volume vertex, mark to delete it.
-        if ((pointtype(checkpt) == VOLVERTEX) ||
-            (pointtype(checkpt) == FREEVOLVERTEX)) { 
+        // If it is added volume vertex or '-j' is not used, delete it.
+        if ((pointtype(checkpt) == FREEVOLVERTEX) || !b->nojettison) { 
           setpointtype(checkpt, UNUSEDVERTEX);
           unuverts++;
         }
@@ -21831,7 +24175,7 @@ bool tetgenmesh::constrainedflip(triface* flipface, triface* front,
         flip22(flipface, flipque);
         return true;
       }
-    } else if (fc == UNFLIPABLE) {
+    } else if (fc == N32) {
       // Is f a crossface?
       if (front != (triface *) NULL) {
         // (6) Is any obstacle face (abd, or abe, ...) flipable?
@@ -22269,7 +24613,7 @@ bool tetgenmesh::constrainedcavity(triface* oldtet, list* floorlist,
            floorlist->len(), ceillist->len(), ptlist->len());
   }
 
-  symbolic = 1;
+  // symbolic = 1;
   
   // Initialize the cavity C.
   initializecavity(floorlist, ceillist, frontlist);
@@ -22310,7 +24654,7 @@ bool tetgenmesh::constrainedcavity(triface* oldtet, list* floorlist,
     retrievenewtets(newtetlist);
   }
   
-  symbolic = 0;
+  // symbolic = 0;
 
   if (misfrontlist->len() == 0) {
     // All fronts have identified in D. Get the shape of C by removing out
@@ -22855,8 +25199,8 @@ void tetgenmesh::collapseedge(point suppt, point conpt, list* oldtetlist,
 
   // 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));
+    oldtet = * (triface *)(* oldtetlist)[i]; // assert(infected(oldtet));
+    uninfect(oldtet);
     pa = org(oldtet);
     pb = dest(oldtet);
     pc = apex(oldtet);
@@ -22945,8 +25289,12 @@ void tetgenmesh::deallocfaketets(list* frontlist)
       }
       // Dealloc the 'fake' tet.
       tetrahedrondealloc(front.tet);
-      // This side (neightet) is a boundary face, let 'dummytet' bond to it.
-      dummytet[0] = encode(neightet);
+      // 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);
+      }
     }
   }
 }
@@ -23012,11 +25360,14 @@ void tetgenmesh::restorepolyhedron(list* oldtetlist)
 // '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)
+  queue* flipque, bool noreloc, bool optflag)
 {
   list *oldtetlist[2], *newtetlist[2];
   list *oldshlist, *newshlist;
@@ -23090,12 +25441,17 @@ bool tetgenmesh::suppressfacetpoint(face* supsh, list* frontlist,
     // Preparation for re-tetrahedralzing old B_i(p).
     orientnewsubs(newshlist, supsh, norm);
     // Tetrahedralize 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.
+    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).
       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.
@@ -23110,6 +25466,10 @@ bool tetgenmesh::suppressfacetpoint(face* supsh, list* frontlist,
         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();
@@ -23151,6 +25511,17 @@ bool tetgenmesh::suppressfacetpoint(face* supsh, list* frontlist,
         }
       }
     }
+    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++;
@@ -23219,7 +25590,7 @@ bool tetgenmesh::suppressfacetpoint(face* supsh, list* frontlist,
 
 bool tetgenmesh::suppresssegpoint(face* supseg, list* spinshlist,
   list* newsegshlist, list* frontlist, list* misfrontlist, list* ptlist,
-  list* conlist, memorypool* viri, queue* flipque)
+  list* conlist, memorypool* viri, queue* flipque, bool noreloc, bool optflag)
 {
   list **oldtetlist, **newtetlist;
   list **oldshlist, **newshlist;
@@ -23230,19 +25601,20 @@ bool tetgenmesh::suppresssegpoint(face* supseg, list* spinshlist,
   face nsupseg, newseg, prevseg, nextseg;
   point suppt, *newpt;
   point pa, pb, *cons;
-  REAL norm[3], pnorm[2][3];
+  REAL pnorm[2][3], norm[3];
   bool success;
   int shmark;
   int n, i, j, k;
 
   // Get the Steiner point p.
-  assert(supseg->shver == 0);
+  assert(supseg->shver < 2);
   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);
@@ -23300,6 +25672,7 @@ bool tetgenmesh::suppresssegpoint(face* supseg, list* spinshlist,
   spivotself(prevseg);
   if (prevseg.sh != dummysh) {
     prevseg.shver = 0;
+    if (sdest(prevseg) != pa) sesymself(prevseg);
     assert(sdest(prevseg) == pa);
     senextself(prevseg);
     senext2self(newseg);
@@ -23311,6 +25684,7 @@ bool tetgenmesh::suppresssegpoint(face* supseg, list* spinshlist,
   spivotself(nextseg);
   if (nextseg.sh != dummysh) {
     nextseg.shver = 0;
+    if (sorg(nextseg) != pb) sesymself(nextseg);
     assert(sorg(nextseg) == pb);
     senext2self(nextseg);
     senextself(newseg);
@@ -23427,13 +25801,16 @@ bool tetgenmesh::suppresssegpoint(face* supseg, list* spinshlist,
       }
     }
     // Tetrahedralize B_i(p).
-    if (!constrainedcavity(&oldtet, dnewshlist, oldtetlist[i], ptlist,
-          frontlist, misfrontlist, newtetlist[i], flipque)) {
+    success = constrainedcavity(&oldtet, dnewshlist, oldtetlist[i], ptlist,
+                frontlist, misfrontlist, newtetlist[i], flipque);
+    if (!success && !noreloc) {
       // 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.
@@ -23448,6 +25825,10 @@ bool tetgenmesh::suppresssegpoint(face* supseg, list* spinshlist,
         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();
@@ -23460,6 +25841,9 @@ bool tetgenmesh::suppresssegpoint(face* supseg, list* spinshlist,
     // 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);
@@ -23495,6 +25879,17 @@ bool tetgenmesh::suppresssegpoint(face* supseg, list* spinshlist,
         }
       }
     }
+    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++;
@@ -23503,22 +25898,27 @@ bool tetgenmesh::suppresssegpoint(face* supseg, list* spinshlist,
     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);
-      supseg->shver = 0;
+      senextself(*supseg); // Restore original state.
+      assert(supseg->shver < 2);
     }
     // 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;
+      // nsupseg.shver = 0;
+      senext2self(nsupseg); // Restore original state
+      assert(nsupseg.shver < 2);
     }
     // Delete the new segment ab.
     shellfacedealloc(subsegs, newseg.sh);
@@ -23589,52 +25989,52 @@ bool tetgenmesh::suppresssegpoint(face* supseg, list* spinshlist,
 //                                                                           //
 // suppressvolpoint()    Suppress a point inside mesh.                       //
 //                                                                           //
-// The point p inside the mesh will be suppressed by being deleted from the  //
-// mesh. p may not be suppressed.                                            //
+// 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.                 //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::suppressvolpoint(point suppt, list* frontlist,
-  list* misfrontlist, list* ptlist, queue* flipque)
+bool tetgenmesh::suppressvolpoint(triface* suptet, list* frontlist,
+  list* misfrontlist, list* ptlist, queue* flipque, bool optflag)
 {
+  list *myfrontlist, *mymisfrontlist, *myptlist;
   list *oldtetlist, *newtetlist;
   list *newshlist; // a dummy list.
-  tetrahedron tetptr;
+  queue *myflipque;
   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);
@@ -23644,20 +26044,30 @@ bool tetgenmesh::suppressvolpoint(point suppt, list* frontlist,
     infect(oldtet);
   }
   // Tetrahedralize old B(p).
-  if (!constrainedcavity(&oldtet, newshlist, oldtetlist, ptlist, frontlist,
-        misfrontlist, newtetlist, flipque)) {
-    // Unable to suppress p. 
-    success = false;
-    // Clean fake tets and quit this option.
+  success = constrainedcavity(&oldtet, newshlist, oldtetlist, ptlist,
+              frontlist, misfrontlist, newtetlist, flipque);
+  if (!success) {
+    // Unable to suppress p.
     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);
@@ -23669,6 +26079,13 @@ bool tetgenmesh::suppressvolpoint(point suppt, list* frontlist,
       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).
@@ -23679,6 +26096,18 @@ bool tetgenmesh::suppressvolpoint(point suppt, list* frontlist,
     }
   }
 
+  // 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;
@@ -23688,61 +26117,177 @@ bool tetgenmesh::suppressvolpoint(point suppt, list* frontlist,
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// collapseedgepoint()    Delete a point by edge collapse.                   //
+// 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'.                                                 //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::collapseedgepoint(point colpt, list *oldtetlist, 
-  list* deadtetlist, list *ptlist)
+bool tetgenmesh::smoothpoint(point smthpt, point e1, point e2, list *starlist,
+  bool invtori, REAL *key)
 {
-  tetrahedron tetptr;
-  triface oldtet, newtet;
-  point conpt;
-  bool success;
+  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;
 
   if (b->verbose > 1) {
-    printf("    Collapse point %d.\n", pointmark(colpt));
-  }
-
-  // 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;
-    }
+    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];
   }
 
-  // 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();
+  // 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;
+    }
   }
-  oldtetlist->clear();
-  ptlist->clear();
 
-  return success;
+  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;
+  }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -23751,7 +26296,7 @@ bool tetgenmesh::collapseedgepoint(point colpt, list *oldtetlist,
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::removesteiners()
+void tetgenmesh::removesteiners(bool coarseflag)
 {
   list *frontlist, *misfrontlist;
   list *spinshlist, *newsegshlist;
@@ -23761,12 +26306,22 @@ void tetgenmesh::removesteiners()
   triface checktet;
   face shloop;
   face segloop, nextseg;
-  point pa;
+  point pa, neipt;
+  REAL len;
   bool remflag;
+  int *worklist;
   int oldnum, rmstein;
-  int i;
+  int i, j;
+
+  if (!b->quiet) {
+    if (!coarseflag) {
+      printf("Removing Steiner points.\n");
+    } else {
+      printf("Coarsening mesh.\n");
+    }
+  }
 
-  // Initiliaze work lists.
+  // Initialize work lists.
   frontlist = new list(sizeof(triface), NULL);
   misfrontlist = new list(sizeof(triface), NULL);
   spinshlist = new list(sizeof(face), NULL);
@@ -23776,13 +26331,10 @@ void tetgenmesh::removesteiners()
   flipque = new queue(sizeof(badface));
   viri = new memorypool(sizeof(shellface *), 1024, POINTER, 0);
   oldnum = unuverts;
-  relverts = suprelverts = collapverts = unsupverts = 0;
+  relverts = suprelverts = collapverts = unsupverts;
+  smoothvolverts = 0;
   expcavcount = 0;
 
-  if (!b->quiet) {
-    printf("Removing Steiner points.\n");
-  }
-
   // Suppress Steiner points inside facets.
   do {
     rmstein = unuverts;
@@ -23795,32 +26347,115 @@ void tetgenmesh::removesteiners()
       for (i = 0; i < 3; i++) {
         pa = sapex(shloop);
         if (pointtype(pa) == FREESUBVERTEX) {
-          // 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);
+          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;
+              }
             }
-            remflag = (checktet.tet == dummytet);
           } else {
-            // '-YY'. Remove p whatever s is a hull face or not.
-            remflag = true;
-          }
-          break;
-        }
+            // 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)
         senextself(shloop);
-      }
+      } // for (i = 0; i < 3; i++)
       if (remflag) {
         suppressfacetpoint(&shloop, frontlist, misfrontlist, ptlist, conlist,
-                           viri, flipque);
+                           viri, flipque, coarseflag, false);
       }
       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;
@@ -23828,95 +26463,202 @@ void tetgenmesh::removesteiners()
     segloop.sh = shellfacetraverse(subsegs);
     while (segloop.sh != (shellface *) NULL) {
       remflag = false;
-      // 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;
+      // 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;
+              }
             }
-          } while (pa != apex(checktet));
-        } else {
-          // '-YY'. Remove p whatever it is on the hull or not.
-          remflag = true;
-        }
-      }
+          } 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++)
       if (remflag) {
         suppresssegpoint(&segloop, spinshlist, newsegshlist, frontlist,
-                         misfrontlist, ptlist, conlist, viri, flipque);
+          misfrontlist, ptlist, conlist, viri, flipque, coarseflag, false);
       }
       segloop.sh = shellfacetraverse(subsegs);
     }
     // Continue if any Steiner point has been removed.
   } while (unuverts > rmstein);
 
-  if (relverts > 0) {
-    // Suppress relocated points.
+  if ((relverts > 0) || coarseflag) {
+    worklist = new int[points->items + 1];
+    // Suppress relocated points & coarse free mesh 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;
-      points->traversalinit();
-      pa = pointtraverse();
-      while (pa != (point) NULL) {
-        remflag = (pointtype(pa) == FREEVOLVERTEX);
+      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++)
         if (remflag) {
-          suppressvolpoint(pa, frontlist, misfrontlist, ptlist, flipque);
+          findorg(&checktet, pa);
+          assert(org(checktet) == pa);
+          suppressvolpoint(&checktet, frontlist, misfrontlist, ptlist, flipque,
+                           false);
         }
-        pa = pointtraverse();
+        checktet.tet = tetrahedrontraverse();
       }
       // Continue if any relocated point has been suppressed.
     } while (unuverts > rmstein);
-  }
 
-  /* 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();
+
+    // Smooth the unsuppressed points if it is not coarse mesh.
+    if (!coarseflag && (relverts > suprelverts)) {
+      if (b->verbose) {
+        printf("  Smoothing relocated points.\n");
       }
-      // Continue if any relocated point has been suppressed.
-    } while (unuverts > rmstein);
-  } */
+      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) {
-    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);
+    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 (unsupverts > 0) {
+        printf("  !! %d points are unsuppressed.\n", unsupverts);
+      }
+    } else {
+      printf("  %d points are removed.\n", unuverts - oldnum);
     }
   }
-  
+
   // Delete work lists.
   delete frontlist;
   delete misfrontlist;
@@ -23932,10 +26674,6 @@ void tetgenmesh::removesteiners()
 // End of boundary Steiner points removing routines
 //
 
-//
-// Begin of mesh reconstruction routines
-//
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // reconstructmesh()    Reconstruct a tetrahedral mesh from a list of        //
@@ -24029,12 +26767,12 @@ long tetgenmesh::reconstructmesh()
     setdest(tetloop, tdest);
     setapex(tetloop, tapex);
     setoppo(tetloop, toppo);
-    // Temporarily set the vertices be type VOLVERTEX, to indicate that
+    // Temporarily set the vertices be type FREEVOLVERTEX, to indicate that
     //   they belong to the mesh.  These types may be changed later.
-    setpointtype(torg, VOLVERTEX);
-    setpointtype(tdest, VOLVERTEX);
-    setpointtype(tapex, VOLVERTEX);
-    setpointtype(toppo, VOLVERTEX);
+    setpointtype(torg, FREEVOLVERTEX);
+    setpointtype(tdest, FREEVOLVERTEX);
+    setpointtype(tapex, FREEVOLVERTEX);
+    setpointtype(toppo, FREEVOLVERTEX);
     // Set element attributes if they exist.
     for (j = 0; j < in->numberoftetrahedronattributes; j++) {
       index = i * in->numberoftetrahedronattributes;
@@ -24106,7 +26844,7 @@ long tetgenmesh::reconstructmesh()
         hullsize++;  // It's a hull face.
         // Bond this side to outer space.
         dummytet[0] = encode(tetloop);
-        if (in->pointmarkerlist != (int *) NULL) {
+        if ((in->pointmarkerlist != (int *) NULL) && !b->coarse) {
           // Set its three corners's markers be boundary (hull) vertices.
           if (in->pointmarkerlist[iorg] == 0) {
             in->pointmarkerlist[iorg] = 1;
@@ -24231,11 +26969,11 @@ long tetgenmesh::reconstructmesh()
         setsorg(subloop, torg);
         setsdest(subloop, tdest);
         setsapex(subloop, tapex);
-        // Set the vertices be FACETVERTEX to indicate they belong to a
+        // Set the vertices be FREESUBVERTEX to indicate they belong to a
         //   facet of the domain.  They may be changed later.
-        setpointtype(torg, FACETVERTEX);
-        setpointtype(tdest, FACETVERTEX);
-        setpointtype(tapex, FACETVERTEX);
+        setpointtype(torg, FREESUBVERTEX);
+        setpointtype(tdest, FREESUBVERTEX);
+        setpointtype(tapex, FREESUBVERTEX);
         tsbond(tetloop, subloop);
         if (neightet.tet != dummytet) {
           sesymself(subloop);
@@ -24353,11 +27091,10 @@ long tetgenmesh::reconstructmesh()
           makeshellface(subsegs, &subseg);
           setsorg(subseg, torg);
           setsdest(subseg, tdest);
-          // 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);
+          // The two vertices have been marked as FREESUBVERTEX. Now mark
+          //   them as NACUTEVERTEX.
+          setpointtype(torg, NACUTEVERTEX);
+          setpointtype(tdest, NACUTEVERTEX);
           setshellmark(subseg, marker);
           marker++;
           // Bond all subfaces to this subsegment.
@@ -24483,24 +27220,6 @@ long tetgenmesh::reconstructmesh()
     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;
@@ -24515,54 +27234,11 @@ long tetgenmesh::reconstructmesh()
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// 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'.      //
+// insertconstrainedpoints()    Insert a list of constrained points.         //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::insertaddpoints()
+void tetgenmesh::insertconstrainedpoints(tetgenio *addio)
 {
   queue *flipqueue;
   triface searchtet;
@@ -24570,6 +27246,8 @@ void tetgenmesh::insertaddpoints()
   point newpoint;
   enum locateresult loc;
   REAL *attr;
+  bool insertflag;
+  int covertices, outvertices;
   int index;
   int i, j;
   
@@ -24579,117 +27257,134 @@ void tetgenmesh::insertaddpoints()
   // Initialize 'flipqueue'.
   flipqueue = new queue(sizeof(badface));
   recenttet.tet = dummytet;
+  covertices = outvertices = 0;
 
   index = 0;
-  for (i = 0; i < in->numberofaddpoints; i++) {
+  for (i = 0; i < addio->numberofpoints; i++) {
     // Create a newpoint.
     makepoint(&newpoint);
-    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];
+    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];
+        }
+      }
     }
     // Find the location of the inserted point.
     searchtet = recenttet;
     loc = locate(newpoint, &searchtet);
-    if (loc != OUTSIDE) {
-      if (loc != ONVERTEX) {
-        loc = adjustlocate(newpoint, &searchtet, loc, b->epsilon);
-      }
+    if (loc != ONVERTEX) {
+      loc = adjustlocate(newpoint, &searchtet, loc, b->epsilon2);
     }
     if (loc == OUTSIDE) {
-      // 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;
-        }
+      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();
+        }
       }
     }
     // Insert the point if it not lies outside or on a vertex.
+    insertflag = true;
     switch (loc) {
     case INTETRAHEDRON:
-      setpointtype(newpoint, VOLVERTEX);
+      setpointtype(newpoint, FREEVOLVERTEX);
       splittetrahedron(newpoint, &searchtet, flipqueue);
       break;
     case ONFACE:
       tspivot(searchtet, checksh);
       if (checksh.sh != dummysh) {
-        setpointtype(newpoint, FREESUBVERTEX);
+        // It is a boundary face. Don't insert it if -Y option is used.
+        if (b->nobisect) {
+          insertflag = false;
+        } else {
+          setpointtype(newpoint, FREESUBVERTEX);
+        }
       } else {
         setpointtype(newpoint, FREEVOLVERTEX);
       }
-      splittetface(newpoint, &searchtet, flipqueue);
+      if (insertflag) {
+        splittetface(newpoint, &searchtet, flipqueue);
+      }
       break;
     case ONEDGE:
       tsspivot(&searchtet, &checkseg);
       if (checkseg.sh != dummysh) {
-        setpointtype(newpoint, FREESEGVERTEX);
-        setpoint2sh(newpoint, sencode(checkseg));
+        if (b->nobisect) {
+          insertflag = false;
+        } else {
+          setpointtype(newpoint, FREESEGVERTEX);
+          setpoint2sh(newpoint, sencode(checkseg));
+        }
       } else {
         tspivot(searchtet, checksh);
         if (checksh.sh != dummysh) {
-          setpointtype(newpoint, FREESUBVERTEX);
+          if (b->nobisect) {
+            insertflag = false;
+          } else {
+            setpointtype(newpoint, FREESUBVERTEX);
+          }
         } else {
-          setpointtype(newpoint, VOLVERTEX);
+          setpointtype(newpoint, FREEVOLVERTEX);
         }
       }
-      splittetedge(newpoint, &searchtet, flipqueue);
+      if (insertflag) {
+        splittetedge(newpoint, &searchtet, flipqueue);
+      }
       break;
     case ONVERTEX:
-      if (!b->quiet) {
-        printf("Warning: Point (%.17g, %.17g, %.17g) falls on a vertex.\n",
-               newpoint[0], newpoint[1], newpoint[2]);
-      }
+      insertflag = false;
+      covertices++;
       break;
     case OUTSIDE:
-      if (!b->quiet) {
-        printf("Warning: Point (%.17g, %.17g, %.17g) lies outside the mesh.\n",
-               newpoint[0], newpoint[1], newpoint[2]);
-      }
+      insertflag = false;
+      outvertices++;
       break;
     }
     // Remember the tetrahedron for next point searching.
     recenttet = searchtet;
-    if (loc == ONVERTEX || loc == OUTSIDE) {
+    if (!insertflag) {
       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
-//
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// interpolatepointsize()    Set a point size by interpolating in bgmesh.    //
-//                                                                           //
-// 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.      //
+// p1interpolatebgm()    Set pt size by p^1 interpolation in background mesh.//
 //                                                                           //
-// 'bgmtet' is a suggesting tet in background mesh for locating 'pt' in it.  //
-// It returns the tet containing 'pt'.                                       //
+// On input, 'bgmtet' is a suggesting tet in background mesh for searching   //
+// 'pt'. It returns the tet containing 'pt'.                                 //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::interpolatepointsize(point pt, triface* bgmtet, long *scount)
+bool tetgenmesh::p1interpolatebgm(point pt, triface* bgmtet, long *scount)
 {
   point bgmpt[4];
   enum locateresult loc;
@@ -24698,23 +27393,25 @@ bool tetgenmesh::interpolatepointsize(point pt, triface* bgmtet, long *scount)
 
   loc = bgm->preciselocate(pt, bgmtet, bgm->tetrahedrons->items);
   if (loc == OUTSIDE) {
-    // 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);
-        assert(loc != OUTSIDE);
-        break;
+    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) {
+        loc = bgm->adjustlocate(pt, bgmtet, OUTSIDE, b->epsilon);
+        if (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.
@@ -24725,11 +27422,11 @@ bool tetgenmesh::interpolatepointsize(point pt, triface* bgmtet, long *scount)
     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->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];
+    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];
     }
   } else {
     setpoint2bgmtet(pt, (tetrahedron) NULL);  // in m
@@ -24737,45 +27434,6 @@ bool tetgenmesh::interpolatepointsize(point pt, triface* bgmtet, long *scount)
   return loc != OUTSIDE;
 }
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// 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.//
@@ -24791,46 +27449,78 @@ void tetgenmesh::searchpointrecursive(triface *curtet, long *scount)
 
 void tetgenmesh::interpolatesizemap()
 {
-  triface tetloop, bgmtet;
+  list *adjtetlist;
+  triface tetloop, neightet, bgmtet;
   point searchpt;
   long scount;
-  int idx, i;
+  int *worklist;
+  int sepcount;
+  int 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)) {
-      // 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.
+      // 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)) {
           bgmtet = bgm->recenttet;
-          if (interpolatepointsize(searchpt, &bgmtet, &scount)) {
-            bgm->recenttet = bgmtet;
+        }
+        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);
           }
-          // Mark p as processed.
-          idx = pointmark(searchpt);
-          setpointmark(searchpt, -idx - 1);
         }
-        enextself(tetloop);
       }
-      // Recursively do the above searching in the neighbring tets of t.
-      searchpointrecursive(&tetloop, &scount);
-    }
+      // Increase the number of separated domains.
+      sepcount++;
+      delete adjtetlist;
+    } // if (!infect())
     tetloop.tet = tetrahedrontraverse();
   }
 
-  // Have searched all points. Unmark tets.
+  // Unmark all tets.
   tetrahedrons->traversalinit();
   tetloop.tet = tetrahedrontraverse();
   while (tetloop.tet != (tetrahedron *) NULL) {
@@ -24838,390 +27528,653 @@ void tetgenmesh::interpolatesizemap()
     uninfect(tetloop);
     tetloop.tet = tetrahedrontraverse();
   }
-  // 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
-  }
+  delete [] worklist;
 
 #ifdef SELF_CHECK
-  if (b->verbose) {
+  if (b->verbose && scount > 0l) {
     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
-//
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// calclocalfeaturesizes()    Calculate local feature sizes of all points.   //
+// duplicatebgmesh()    Duplicate current mesh to background mesh.           //
 //                                                                           //
-// 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).                                //
+// Current mesh 'this' is copied into 'this->bgm'.Both meshes share the same //
+// input tetgenio object, 'this->in', same tetgenbehavior object 'this->b'.  //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::calclocalfeaturesizes()
+void tetgenmesh::duplicatebgmesh()
 {
-  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;
+  triface tetloop, btetloop;
+  triface symtet, bsymtet;
+  face bhullsh, bneighsh;
+  point *idx2bplist, *tetptbaklist;
+  point ploop, bploop;
+  int idx, i;
 
-  if (b->verbose > 0) {
-    printf("  Calculating local feature sizes.\n");
+  if (!b->quiet) {
+    printf("Duplicating background mesh.\n");
   }
 
-  // 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;
+  // 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);
 
+  // Copy point list.
+  idx2bplist = new point[points->items + 1];
+  idx = in->firstnumber;
   points->traversalinit();
   ploop = pointtraverse();
   while (ploop != (point) NULL) {
-    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;
-        }
+    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);
       }
-      // Clear working lists.
-      tetlist->clear();
-      verlist->clear();
     }
+    // Remember the point for searching.
+    idx2bplist[idx++] = bploop; 
     ploop = pointtraverse();
   }
 
-  if (b->verbose > 1) {
-    printf("  smallest lfs = %g (%d).\n", lfssmall, pointmark(ptlfssmall));
-    printf("  largest  lfs = %g (%d).\n", lfslarge, pointmark(ptlfslarge));
+  // 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();
   }
 
-  delete tetlist;
-  delete verlist;
+  // 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);
+  }
+
+  delete [] tetptbaklist;
+  delete [] idx2bplist;
 }
 
+//
+// Begin of Delaunay refinement routines
+//
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// marksharpsubsegs()    Mark all sharp subsegments.                         //
+// 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.                      //
 //                                                                           //
-// 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.          //
+// (*) The internal angle (or dihedral) bewteen two features means the angle //
+// inside the mesh domain.                                                   //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::marksharpsubsegs(REAL dihedbound)
+void tetgenmesh::marksharpsegments(REAL sharpangle)
 {
-  list *spinshlist;
   triface adjtet;
   face startsh, spinsh, neighsh;
   face segloop, prevseg, nextseg;
   point eorg, edest;
-  enum shestype stype;
-  REAL angle, smallang;
+  REAL ang, smallang;
   bool issharp;
-  int scount;
-  int i;
+  int sharpsegcount;
 
   if (b->verbose > 0) {
-    printf("  Marking sharp subsegments.\n");
+    printf("  Marking sharp segments.\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.
+  subsegs->traversalinit();
+  segloop.sh = shellfacetraverse(subsegs);
+  while (segloop.sh != (shellface *) NULL) {
+    segloop.shver = 0;
+    senext2(segloop, prevseg);
+    spivotself(prevseg);
+    if (prevseg.sh == dummysh) {
+      // Operate on this seg s.
+      assert(shelltype(segloop) != SHARP); // It should be unmarked.
+      issharp = false;
+      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.
+          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.
+            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);
   }
 
-  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.
+  // 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;
-    senext2(segloop, prevseg);
-    spivotself(prevseg);
-    if (prevseg.sh == dummysh) {
-      // Operate on this seg.
-      issharp = false;
-      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) {
-        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;
+        // Check if s forms an acute angle with another seg.
+        eorg = sdest(segloop);
+        spinsh = startsh;
+        do {
+          if (sorg(spinsh) != eorg) {
+            sesymself(spinsh);
+          }
+          // Calculate the angle between s and s' of this facet.
+          neighsh = spinsh;
+          ang = 0.0;
           do {
-            if (sorg(spinsh) != eorg) {
-              sesymself(spinsh);
+            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);
             }
-            spinshlist->append(&spinsh);  
-            spivotself(spinsh);
-          } while (spinsh.sh != startsh.sh);
+          } 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);
         }
-        // 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];
-          }
-          // 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;
-        }
-        spinshlist->clear();
-      }
-      // 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);
+        sharpsegcount++;
       }
     }
     segloop.sh = shellfacetraverse(subsegs);
-  }
+  } 
 
-  if (b->verbose > 0) {
-    printf("  %d sharp segments.\n", scount);
+  if ((b->verbose > 0) && (sharpsegcount > 0)) {
+    printf("  %d sharp segments.\n", sharpsegcount);
   }
-  delete spinshlist;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// markskinnysubfaces()    Mark all skinny subfaces.                         //
+// decidefeaturepointsizes()    Decide the sizes for all feature points.     //
 //                                                                           //
-// 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.                             //
+// 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.   //
 //                                                                           //
-// 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.                               //
+// 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::markskinnysubfaces(REAL anglebound)
+void tetgenmesh::decidefeaturepointsizes()
 {
-  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;
+  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("  Marking skinny subfaces.\n");
+    printf("  Deciding feature-point sizes.\n");
   }
 
-  smallang = anglebound * PI / 180.;
-  // Initial working list.
-  skinnyshlist = new list(sizeof(face), NULL, subfaces->items);
+  // 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);
 
-  // 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;
-          }
+  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++;
         }
       }
-      senextself(subloop);
+      ploop = pointtraverse();
     }
-    subloop.sh = shellfacetraverse(subfaces);
+#ifdef SELF_CHECK
+    if ((b->verbose > 0) && (featurecount > 0)) {
+      printf("  %d Steiner points correction.\n", featurecount);
+    }
+#endif
   }
 
-  // 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);
+  // 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;
       }
-      senextself(startsh);
-    }
+    } // if (pointtype(ploop) != FREESEGVERTEX) {
+    ploop = pointtraverse();
   }
 
   if (b->verbose > 0) {
-    printf("  %d skinny subfaces.\n", skinnyshlist->len());
+    printf("  %d feature points.\n", featurecount);
   }
-  delete skinnyshlist;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// enqueuebadtet()    Add a tetrahedron into the queue.                      //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-void tetgenmesh::enqueuebadtet(triface* testtet, REAL ratio2, REAL* cent)
-{
-  badface *newbadtet;
-  int queuenumber;
-  int i;
 
-  // Allocate space for the bad tetrahedron.
-  newbadtet = (badface *) badtetrahedrons->alloc();
-  newbadtet->tt = *testtet;
-  newbadtet->key = ratio2;
-  if (cent != NULL) {
-    for (i = 0; i < 3; i++) newbadtet->cent[i] = cent[i];
-  } else {
-    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;
-  // 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;
+  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);
     }
-  } 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(newbadtet->forg), pointmark(newbadtet->fdest),
-           pointmark(newbadtet->fapex), pointmark(newbadtet->foppo),
-           sqrt(ratio2), queuenumber);
   }
+
+  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;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -25242,11 +28195,7 @@ void tetgenmesh::enqueueencsub(face* testsub, point encpt, int quenumber,
   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 {
-    for (i = 0; i < 3; i++) encsub->cent[i] = cent[i];
-  }
+  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.
@@ -25263,25 +28212,26 @@ void tetgenmesh::enqueueencsub(face* testsub, point encpt, int quenumber,
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// dequeuebadtet()    Remove a tetrahedron from the front of the queue.      //
+// dequeueencsub()    Remove an enc-subface from the front of the queue.     //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-tetgenmesh::badface* tetgenmesh::dequeuebadtet()
+tetgenmesh::badface* tetgenmesh::dequeueencsub(int* pquenumber)
 {
   badface *result;
-  int queuenumber;
+  int quenumber;
 
   // Look for a nonempty queue.
-  for (queuenumber = 63; queuenumber >= 0; queuenumber--) {
-    result = tetquefront[queuenumber];
+  for (quenumber = 2; quenumber >= 0; quenumber--) {
+    result = subquefront[quenumber];
     if (result != (badface *) NULL) {
-      // Remove the tetrahedron from the queue.
-      tetquefront[queuenumber] = result->nextitem;
+      // Remove the badface from the queue.
+      subquefront[quenumber] = result->nextitem;
       // Maintain a pointer to the NULL pointer at the end of the queue.
-      if (tetquefront[queuenumber] == (badface *) NULL) {
-        tetquetail[queuenumber] = &tetquefront[queuenumber];
+      if (subquefront[quenumber] == (badface *) NULL) {
+        subquetail[quenumber] = &subquefront[quenumber];
       }
+      *pquenumber = quenumber;
       return result;
     }
   }
@@ -25290,30 +28240,126 @@ tetgenmesh::badface* tetgenmesh::dequeuebadtet()
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// dequeueencsub()    Remove an enc-subface from the front of the queue.     //
+// enqueuebadtet()    Add a tetrahedron into the queue.                      //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-tetgenmesh::badface* tetgenmesh::dequeueencsub(int* pquenumber)
+void tetgenmesh::enqueuebadtet(triface* testtet, REAL ratio2, REAL* cent)
 {
-  badface *result;
-  int quenumber;
+  badface *newbadtet;
+  int queuenumber;
+  int i;
 
-  // 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];
+  // Allocate space for the bad tetrahedron.
+  newbadtet = (badface *) badtetrahedrons->alloc();
+  newbadtet->tt = *testtet;
+  newbadtet->key = ratio2;
+  if (cent != NULL) {
+    for (i = 0; i < 3; i++) newbadtet->cent[i] = cent[i];
+  } else {
+    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;
+  // 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' 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;
+  }
+
+  // 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++;
       }
-      *pquenumber = quenumber;
-      return result;
+      // 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;
+
+  if (b->verbose > 2) {
+    printf("    Queueing bad tet: (%d, %d, %d, %d), ratio %g, qnum %d.\n",
+           pointmark(newbadtet->forg), pointmark(newbadtet->fdest),
+           pointmark(newbadtet->fapex), pointmark(newbadtet->foppo),
+           sqrt(ratio2), queuenumber);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dequeuebadtet()    Remove a tetrahedron from the front of the queue.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+tetgenmesh::badface* tetgenmesh::topbadtetra()
+{
+  // 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;
+  } else {
+    // Return the first tetrahedron of the highest-priority queue.
+    return tetquefront[firstnonemptyq];
+  }
+}
+
+void tetgenmesh::dequeuebadtet()
+{
+  badface *deadbadtet;
+  int i;
+
+  // 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];
+      }
+    }
+    // Return the bad tetrahedron to the pool.
+    badfacedealloc(badtetrahedrons, deadbadtet);
   }
-  return (badface *) NULL;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -25343,6 +28389,7 @@ bool tetgenmesh::checkseg4encroach(face* testseg, point testpt, point* prefpt,
   bool enq;
   int hitbdry;
 
+  enq = false;
   eorg = sorg(*testseg);
   edest = sdest(*testseg);
   cent[0] = 0.5 * (eorg[0] + edest[0]);
@@ -25350,50 +28397,55 @@ bool tetgenmesh::checkseg4encroach(face* testseg, point testpt, point* prefpt,
   cent[2] = 0.5 * (eorg[2] + edest[2]);
   radius = distance(cent, eorg);
 
-  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;
+  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;
           }
-        } 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) {
@@ -25430,31 +28482,57 @@ bool tetgenmesh::checkseg4encroach(face* testseg, point testpt, point* prefpt,
 bool tetgenmesh::checksub4encroach(face* testsub, point testpt, bool enqflag)
 {
   triface abuttet;
-  point forg, fdest, fapex, encpt;
-  REAL cent[3];
+  point pa, pb, pc, encpt;
+  REAL A[4][4], rhs[4], D;
+  REAL cent[3], area;
   REAL radius, dist, diff;
-  bool enq, ncollinear;
+  bool enq;
+  int indx[4];
   int quenumber;
   
-  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.
-  
   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);
+  radius = 0.0;
+  encpt = (point) NULL;
+
+  pa = sorg(*testsub);
+  pb = sdest(*testsub);
+  pc = sapex(*testsub);
+  
+  // 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.
     }
-    if (!enq) {
-      sesymself(*testsub);
+  }
+
+  // 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) {
       stpivot(*testsub, abuttet);
       if (abuttet.tet != dummytet) {
         dist = distance(cent, oppo(abuttet));
@@ -25463,190 +28541,30 @@ bool tetgenmesh::checksub4encroach(face* testsub, point testpt, bool enqflag)
         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);
+      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 {
-      assert(testpt);
-      projpt2face(testpt, forg, fdest, fapex, prj);
+      dist = distance(cent, testpt);
+      diff = dist - radius;
+      if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
+      enq = (diff <= 0.0);
     }
-    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) {
-    if (b->verbose > 2) {
-      printf("    Queuing badqual subsegment (%d, %d).\n",
-             pointmark(eorg), pointmark(edest));
+    if (enq) {
+      quenumber = 0; // A queue of encroached subfaces.
     }
-    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);
+  if (enq && enqflag) {
+    enqueueencsub(testsub, encpt, quenumber, cent);    
   }
 
   return enq;
@@ -25664,19 +28582,17 @@ bool tetgenmesh::checksub4badqual(face* testsub, bool enqflag)
 
 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, q, cosd;
+  REAL volume, L, 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];
@@ -25684,10 +28600,6 @@ bool tetgenmesh::checktet4badqual(triface* testtet, bool enqflag)
   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];
@@ -25703,135 +28615,118 @@ bool tetgenmesh::checktet4badqual(triface* testtet, bool enqflag)
   // 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;
-  // Compare the volume to average edge length of abcd.
+  // 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.
   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);
-  
-  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?
+  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) {
-    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;
-          }
+    // 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) || ((cosd < cosmaxdihed)));
+      }
+      // 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;
         }
-        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: 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.
+    // }
+  } 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.
     for (i = 0; i < 3; i++) {
-      circumcent[i] = 0.25 * (pa[i] + pb[i] + pc[i] + pd[i]);
+      offcent[i] = bicent[i] + split * (circumcent[i] - bicent[i]);
     }
-    ratio2 = 0.0;
   }
 
   if (!enq && (b->varvolume || b->fixedvolume)) {
-    // The tet is in good shape.
-    ratio2 = 0.0;
+    // Check if the tet has too big volume.
     enq = b->fixedvolume && (volume > b->maxvolume);
     if (!enq && b->varvolume) {
       enq = (volume > volumebound(testtet->tet)) &&
             (volumebound(testtet->tet) > 0.0);
     }
   }
+
   if (!enq) {
-    // The tet is in good shape.
-    ratio2 = 0.0;
-    if (b->bgmesh && (b->alpha1 > 0.0)) {
+    // Check if the user-defined sizing function is satisfied. 
+    if (b->metric) {
+      // assert(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[3]; // dist = b->alpha1 * pa[pointlfsindex];
+        dist = pa[pointmtrindex]; // dist = b->alpha1 * pa[pointmtrindex];
         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).
@@ -25839,44 +28734,14 @@ bool tetgenmesh::checktet4badqual(triface* testtet, bool enqflag)
       }
       // *** Experiment !
       // enq = (i == 4); // Does c lies outside all sparse-ball?
-    }
+    } // if (b->metric)
   }
 
   if (enq && enqflag) {
-    // 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);
+    if (b->offcenter && (ratio2 > b->goodratio)) {
+      for (i = 0; i < 3; i++) circumcent[i] = offcent[i];
     }
+    enqueuebadtet(testtet, ratio2, circumcent);
   }
 
   return enq;
@@ -25892,28 +28757,23 @@ bool tetgenmesh::checktet4badqual(triface* testtet, bool enqflag)
 // 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 (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.                                     //
+// 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.                                                 //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 bool tetgenmesh::acceptsegpt(point segpt, point refpt, face* splitseg)
 {
-  triface spintet;
-  face parentsh, spinsh;
-  point pa, pb, pc;
-  REAL ablen, palen, pblen;
-  REAL V, A;
+  point p[2];
+  REAL L, lfs;
+  int i, j;
 
   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);
@@ -25928,73 +28788,26 @@ bool tetgenmesh::acceptsegpt(point segpt, point refpt, face* splitseg)
     return false;
   }
   
-  pa = sorg(*splitseg);
-  pb = sdest(*splitseg);
-  ablen = distance(pa, pb);
-  if (varconstraint) {
-    A = areabound(*splitseg);
-    if ((A > 0.0) && (ablen > A)) {
+  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) {
       return true; // case (1)
     }
   }
 
-  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)
+  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 (j == 0) return true; // case (3).
 
   // If 'refpt' != NULL, force p to be inserted.
   if (refpt != (point) NULL) {
@@ -26017,26 +28830,20 @@ bool tetgenmesh::acceptsegpt(point segpt, point refpt, face* splitseg)
 // 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 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.    //
+// p can be inserted if |p - v| > \alpha_2 H(v), for all v \in V.            //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 bool tetgenmesh::acceptfacpt(point facpt, list* subceillist, list* verlist)
 {
-  triface testtet;
   face *testsh;
-  point p[3];
-  REAL L, L2, L3, lfs;
+  point p[2], ploop;
+  REAL L, 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) {
@@ -26062,76 +28869,23 @@ bool tetgenmesh::acceptfacpt(point facpt, list* subceillist, list* verlist)
       }
     }
   }
-  // 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 (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);
-        }
-      }
-    }
-  }
 
-  // Check if p is inside the protect balls of vertices of V.
+  j = 0; // Use j to count the number of inside balls.
   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];
+    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.
     }
-    L = distance(p[0], facpt);
-    if (L < lfs) break; // p is inside ball.
   }
-  if (i == verlist->len()) return true; // case (3).
+  verlist->clear();
+
+  if (j == 0) return true; // case (3).
 
   rejsubpts++;
   return false;
@@ -26144,17 +28898,15 @@ bool tetgenmesh::acceptfacpt(point facpt, list* subceillist, list* verlist)
 // 'ceillist' is B(p).  'verlist' (V) is empty on input, it returns the set  //
 // of vertices of B(p).                                                      //
 //                                                                           //
-// 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.                        //
+// p can be split 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[4];
-  REAL L, vol, lfs;
+  point p[3], ploop;
+  REAL L, lfs;
   int idx, i, j;
 
   // Collect the vertices of CBC(p), save them in V.
@@ -26171,45 +28923,23 @@ bool tetgenmesh::acceptvolpt(point volpt, list* ceillist, list* verlist)
       }
     }
   }
-  // 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)
-        }
-      }
-    }
-  }
 
-  // Check if p is inside the protect balls of vertices of V.
+  j = 0; // Use j to counte the number of inside balls.
   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];
+    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.
     }
-    L = distance(p[0], volpt);
-    if (L < lfs) break; // p is inside ball.
   }
-  if (i == verlist->len()) return true; // case (2).
+  verlist->clear();
+  
+  if (j == 0) return true; // case (2).
 
   rejtetpts++;
   return false;
@@ -26267,17 +28997,27 @@ void tetgenmesh::getsplitpoint(point e1, point e2, point refpt, point newpt)
       // Add a random perturbation on newpt.
       d1 = distance(ei, newpt);
       d2 = distance(newpt, refpt);
-      ps = randgenerator(d2 * b->epsilon2);
+      ps = randgenerator(d2 * b->epsilon2 * 1e+2);
       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]);
   }
 }
 
@@ -26310,10 +29050,10 @@ void tetgenmesh::shepardinterpolate(point newpt, list *verlist)
     sumweight += weights[i];
   }
   // Interpolate.
-  newpt[pointlfsindex] = 0.0;
+  newpt[pointmtrindex] = 0.0;
   for (i = 0; i < verlist->len(); i++) {
     neipt = * (point *)(* verlist)[i];
-    newpt[pointlfsindex] += (weights[i] * neipt[pointlfsindex]) / sumweight;
+    newpt[pointmtrindex] += (weights[i] * neipt[pointmtrindex]) / sumweight;
   }
 
   delete [] weights;
@@ -26324,22 +29064,33 @@ void tetgenmesh::shepardinterpolate(point newpt, list *verlist)
 // 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 sizes of the adjacent vertices of p.              //
+// (b->bgmesh) or from the two input endpoints.                              //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::setnewpointsize(point newpt, list* verlist)
+void tetgenmesh::setnewpointsize(point newpt, point e1, point e2)
 {
-  if (b->bgmesh) {
+  if (b->metric) {
+    // Interpolate the point size in a background mesh.
     triface bgmtet;
-    point pa;
     // Get a tet in background mesh for locating p.
-    pa = * (point *)(* verlist)[0];
-    decode(point2bgmtet(pa), bgmtet);
-    interpolatepointsize(newpt, &bgmtet, NULL);
+    decode(point2bgmtet(e1), bgmtet);
+    p1interpolatebgm(newpt, &bgmtet, NULL);
   } else {
-    // Interpolate a local size for p using Shepard interpolation.
-    shepardinterpolate(newpt, verlist);
+    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];
+    }
   }
 }
 
@@ -26350,82 +29101,93 @@ void tetgenmesh::setnewpointsize(point newpt, list* verlist)
 ///////////////////////////////////////////////////////////////////////////////
 
 void tetgenmesh::splitencseg(point newpt, face* splitseg, list* tetlist,
-  list* sublist, list* verlist, queue* flipque, bool chkencsub, bool chkbadtet)
+  list* sublist, list* verlist, queue* flipque, bool chkencsub, bool chkbadtet,
+  bool optflag)
 {
+  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);
+  flip(flipque, NULL); // lawson(NULL, flipque);
   
-  // 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 (!optflag) { 
+    // Check the two new subsegs to see if they're encroached (not by p).
+    for (i = 0; i < 2; i++) {
       if (!shell2badface(*splitseg)) {
-        if (varconstraint && (areabound(*splitseg) > 0.0)) {
-          checkseg4badqual(splitseg, true);
-        }
+        checkseg4encroach(splitseg, NULL, NULL, 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];
-        if (!shell2badface(checksh)) {
-          checksub4encroach(&checksh, NULL, true);
+      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)) {
-            if (varconstraint && (areabound(checksh) > 0.0)) {
-              checksub4badqual(&checksh, true);
-            }
+            checksub4encroach(&checksh, NULL, true);
           }
         }
-      }
-      sublist->clear();
-      verlist->clear();
-      spivotself(spinsh);
-    } while (spinsh.sh != startsh.sh);
-  }
-  
+        sublist->clear();
+        if (verlist) verlist->clear();
+        spivotself(spinsh);
+      } while (spinsh.sh != startsh.sh);
+    }
+  } // if (!optflag)  
+
   // Collect the new tets connecting at p.
   sstpivot(splitseg, &starttet);
   tetlist->append(&starttet);
   formstarpolyhedron(newpt, tetlist, verlist, true);
 
-  // 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.
+  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.
     for (i = 0; i < tetlist->len(); i++) {
       starttet = * (triface *)(* tetlist)[i];
-      checktet4badqual(&starttet, true);
+      checktet4opt(&starttet, true);
     }
+    delete mytetlist;
+    delete myflipque;
   }
-  tetlist->clear();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -26465,11 +29227,6 @@ bool tetgenmesh::tallencsegs(point testpt, int n, list **ceillists)
             // 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);
@@ -26484,11 +29241,6 @@ bool tetgenmesh::tallencsegs(point testpt, int n, list **ceillists)
       // 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);
     }
@@ -26532,11 +29284,6 @@ bool tetgenmesh::tallencsubs(point testpt, int n, list** ceillists)
           // 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);
-              }
-            }
           }
         }
       }
@@ -26549,11 +29296,6 @@ bool tetgenmesh::tallencsubs(point testpt, int n, list** ceillists)
       // 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);
     }
@@ -26598,18 +29340,17 @@ void tetgenmesh::repairencsegs(bool chkencsub, bool chkbadtet)
 {
   list **tetlists, **ceillists;
   list **sublists, **subceillists;
-  list *tetlist, *sublist, *verlist;
+  list *tetlist, *sublist;
   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];
@@ -26618,9 +29359,6 @@ void tetgenmesh::repairencsegs(bool chkencsub, bool chkbadtet)
   } 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));
   }
 
@@ -26647,9 +29385,6 @@ void tetgenmesh::repairencsegs(bool chkencsub, bool chkbadtet)
         }
         // 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));
@@ -26668,6 +29403,13 @@ void tetgenmesh::repairencsegs(bool chkencsub, bool chkbadtet)
                   // 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,
@@ -26676,9 +29418,9 @@ void tetgenmesh::repairencsegs(bool chkencsub, bool chkbadtet)
                     if (trimbowatcavity(sympt, &symsplitseg, n, sublists,
                           subceillists, tetlists, ceillists, -1.0)) {
                       bowatinsertsite(sympt, &symsplitseg, n, sublists,
-                        subceillists, tetlists, ceillists, verlist, flipque,
+                        subceillists, tetlists, ceillists, NULL, flipque,
                         true, chkencsub, chkbadtet);
-                      setnewpointsize(sympt, verlist);
+                      setnewpointsize(sympt, e1, e2);
                       if (steinerleft > 0) steinerleft--;
                     } else {
                       // p did not insert for invalid BC(symp).
@@ -26688,12 +29430,11 @@ void tetgenmesh::repairencsegs(bool chkencsub, bool chkbadtet)
                     releasebowatcavity(&symsplitseg, n, sublists, subceillists,
                                        tetlists, ceillists);
                   } else {
-                    splitencseg(sympt, &symsplitseg, tetlist, sublist, verlist,
-                                flipque, chkencsub, chkbadtet);
-                    setnewpointsize(sympt, verlist);
+                    splitencseg(sympt, &symsplitseg, tetlist, sublist, NULL,
+                                flipque, chkencsub, chkbadtet, false);
+                    setnewpointsize(sympt, e1, e2);
                     if (steinerleft > 0) steinerleft--;
                   }
-                  verlist->clear();
                 } else {
                   // The sympt are on the same segment. It is possible when
                   //   splitseg is the symmetric rotating axes.
@@ -26710,6 +29451,13 @@ void tetgenmesh::repairencsegs(bool chkencsub, bool chkbadtet)
               }
             } // 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,
@@ -26718,9 +29466,9 @@ void tetgenmesh::repairencsegs(bool chkencsub, bool chkbadtet)
             if (trimbowatcavity(newpt, &splitseg, n, sublists, subceillists, 
                                 tetlists, ceillists, -1.0)) {
               bowatinsertsite(newpt, &splitseg, n, sublists, subceillists,
-                              tetlists, ceillists, verlist, flipque, true,
+                              tetlists, ceillists, NULL, flipque, true,
                               chkencsub, chkbadtet);
-              setnewpointsize(newpt, verlist);
+              setnewpointsize(newpt, e1, e2);
               if (steinerleft > 0) steinerleft--;
             } else {
               // p did not insert for invalid B(p).
@@ -26730,12 +29478,11 @@ void tetgenmesh::repairencsegs(bool chkencsub, bool chkbadtet)
             releasebowatcavity(&splitseg, n, sublists, subceillists, tetlists,
                                ceillists);
           } else {
-            splitencseg(newpt, &splitseg, tetlist, sublist, verlist, flipque,
-                        chkencsub, chkbadtet);
-            setnewpointsize(newpt, verlist);
+            splitencseg(newpt, &splitseg, tetlist, sublist, NULL, flipque,
+                        chkencsub, chkbadtet, false);
+            setnewpointsize(newpt, e1, e2);
             if (steinerleft > 0) steinerleft--;
           }
-          verlist->clear();
         } else {
           // p did not accept for insertion.
           pointdealloc(newpt);
@@ -26754,9 +29501,6 @@ void tetgenmesh::repairencsegs(bool chkencsub, bool chkbadtet)
   } else {
     delete tetlist;
     delete sublist;
-  }
-  delete verlist;
-  if (b->fliprepair) {
     delete flipque;
   }
 }
@@ -26781,7 +29525,7 @@ void tetgenmesh::repairencsubs(bool chkbadtet)
   list *verlist;
   badface *encloop;
   face splitsub, symsplitsub;
-  point newpt, sympt;
+  point newpt, sympt, e1;
   enum locateresult loc, symloc;
   bool reject;
   long oldptnum;
@@ -26801,21 +29545,17 @@ void tetgenmesh::repairencsubs(bool chkbadtet)
     // 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.
+      // Create a new point p at the circumcenter of f.
       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));
@@ -26831,12 +29571,11 @@ void tetgenmesh::repairencsubs(bool chkbadtet)
         // Form BC(p), B(p), CBC(p) and C(p).
         formbowatcavity(newpt, NULL, &splitsub, &n, NULL, &sublist,
                         &subceillist, tetlists, ceillists);
-        // Check for encroaching subsegments (on B(p)).
+        // Check for encroached 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.
@@ -26866,7 +29605,6 @@ void tetgenmesh::repairencsubs(bool chkbadtet)
                 reject = tallencsegs(sympt, 2, ceillists);
                 if (!reject) {
                   reject = !acceptfacpt(sympt, subceillist, verlist);
-                  verlist->clear();
                 }
                 if (!reject) {
                   reject = !trimbowatcavity(sympt,NULL,n,&sublist,&subceillist,
@@ -26878,21 +29616,23 @@ void tetgenmesh::repairencsubs(bool chkbadtet)
                   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,verlist,NULL,false,true,chkbadtet);
-                  setnewpointsize(sympt, verlist);
-                  verlist->clear();
+                     tetlists,ceillists,NULL,NULL,false,true,chkbadtet);
+                  setnewpointsize(sympt, e1, NULL);
                   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);
@@ -26913,10 +29653,11 @@ void tetgenmesh::repairencsubs(bool chkbadtet)
                               ceillists, -1.0);
             }
           }
+          // Save a point for size interpolation.
+          e1 = sorg(splitsub);
           bowatinsertsite(newpt, NULL, n, &sublist, &subceillist, tetlists,
-                          ceillists, verlist, NULL, true, true, chkbadtet);
-          setnewpointsize(newpt, verlist);
-          verlist->clear();
+                          ceillists, NULL, NULL, true, true, chkbadtet);
+          setnewpointsize(newpt, e1, NULL);
           if (steinerleft > 0) steinerleft--;
         } else {
           // p is rejected for the one of the following reasons:
@@ -26928,8 +29669,7 @@ void tetgenmesh::repairencsubs(bool chkbadtet)
           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) {
@@ -26942,11 +29682,6 @@ void tetgenmesh::repairencsubs(bool chkbadtet)
               if (!isdead(&splitsub)) {
                 if (!shell2badface(splitsub)) {
                   checksub4encroach(&splitsub, NULL, true);
-                  if (!shell2badface(splitsub)) {
-                    if (varconstraint && (areabound(splitsub) > 0.0)) {
-                      checksub4badqual(&splitsub, true);
-                    }
-                  }
                 }
               }
             }
@@ -26980,11 +29715,6 @@ void tetgenmesh::repairencsubs(bool chkbadtet)
       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.
@@ -27012,7 +29742,7 @@ void tetgenmesh::repairbadtets()
   list *verlist;
   badface *badtet;
   triface starttet;
-  point newpt;
+  point newpt, e1;
   enum locateresult loc;
   bool reject;
   long oldptnum;
@@ -27026,14 +29756,20 @@ void tetgenmesh::repairbadtets()
   //   if an unlimited number of Steiner points is allowed.
   while ((badtetrahedrons->items > 0) && (steinerleft != 0)) {
     // Get a bad-quality tet t.
-    badtet = dequeuebadtet();
+    badtet = topbadtetra();
     // 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(&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.
+    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).
       makepoint(&newpt);
       for (i = 0; i < 3; i++) newpt[i] = badtet->cent[i];
       setpointtype(newpt, FREEVOLVERTEX);
@@ -27051,8 +29787,9 @@ void tetgenmesh::repairbadtets()
           // 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) {
@@ -27068,10 +29805,12 @@ void tetgenmesh::repairbadtets()
           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, verlist);
+          setnewpointsize(newpt, e1, NULL);
           if (steinerleft > 0) steinerleft--;
         } else {
           // p is rejected for one of the following reasons:
@@ -27089,7 +29828,6 @@ void tetgenmesh::repairbadtets()
         }
         tetlist->clear();
         ceillist->clear();
-        verlist->clear();
         // Split encroached subsegments/subfaces if there are.
         if (reject) {
           oldptnum = points->items;
@@ -27100,7 +29838,8 @@ void tetgenmesh::repairbadtets()
             repairencsubs(true);
           }
           if (points->items > oldptnum) {
-            // Some encroaching subsegments/subfaces have been split.
+            // Some encroaching subsegments/subfaces got split. Re-queue the
+            //   tet if it is still alive.
             starttet = badtet->tt;
             if (!isdead(&starttet)) {
               checktet4badqual(&starttet, true);
@@ -27133,8 +29872,8 @@ void tetgenmesh::repairbadtets()
         pointdealloc(newpt);
       } // if ((loc != ONVERTEX) && (loc != OUTSIDE))
     } // if (!isdead(&badtet->tt) && org(badtet->tt) == badtet->forg &&
-    // Remove the tet from the pool.
-    badfacedealloc(badtetrahedrons, badtet);
+    // Remove the tet from the queue.
+    dequeuebadtet();
   } // while ((badtetrahedrons->items > 0) && (steinerleft != 0))
 
   delete tetlist;
@@ -27162,18 +29901,17 @@ void tetgenmesh::enforcequality()
     r2count = r3count = 0l;
   }
 
-  if (b->refine) {
-    // Mark segment vertices (acute or not).
-    markacutevertices(89.0);
+  // If both '-D' and '-r' options are used. 
+  if (b->conformdel && b->refine) {
+    markacutevertices(65.0);
   }
-  if (!b->bgmesh) {
-    // Calculate the node local feature sizes.
-    calclocalfeaturesizes();
+  // If '-m' is not used.
+  if (!b->metric) {
+    // Find and mark all sharp segments.
+    marksharpsegments(65.0);
+    // Decide the sizes for feature points.
+    decidefeaturepointsizes();
   }
-  // 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);
@@ -27216,8 +29954,11 @@ void tetgenmesh::enforcequality()
     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;
-    for (i = 0; i < 64; i++) tetquetail[i] = &tetquefront[i];
+    firstnonemptyq = -1;
+    recentq = -1;
     // 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");
@@ -27244,9 +29985,36 @@ void tetgenmesh::enforcequality()
 //
 
 //
-// Begin of mesh smoothing routines
+// Begin of mesh optimization 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.                    //
@@ -27278,10 +30046,15 @@ bool tetgenmesh::checktet4ill(triface* testtet, bool enqflag)
         fnext(*testtet, checktet);
         tspivot(checktet, checksh2);
         if (checksh2.sh != dummysh) {
-          // Two subfaces share this edge. It should be a segment.
+          // Two subfaces share this edge.
           sspivot(checksh1, checkseg);
           if (checkseg.sh == dummysh) {
-            illflag = true; break;
+            // 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;
           }
         }
         enextself(*testtet);
@@ -27295,7 +30068,7 @@ bool tetgenmesh::checktet4ill(triface* testtet, bool enqflag)
     // Allocate space for the bad tetrahedron.
     newbadtet = (badface *) badtetrahedrons->alloc();
     newbadtet->tt = *testtet;
-    newbadtet->key = 0.0;
+    newbadtet->key = -1.0; // = 180 degree.
     for (i = 0; i < 3; i++) newbadtet->cent[i] = 0.0;
     newbadtet->forg = org(*testtet);
     newbadtet->fdest = dest(*testtet);
@@ -27314,38 +30087,38 @@ bool tetgenmesh::checktet4ill(triface* testtet, bool enqflag)
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// checktet4sliver()    Check a tet to see if it is a sliver.                //
+// checktet4opt()    Check a tet to see if it needs to be optimized.         //
 //                                                                           //
-// 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.                 //
+// 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.                                                                   //
 //                                                                           //
-// 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.                                      //
+// 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.                                       //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::checktet4sliver(triface* testtet, bool chkill, bool enqflag)
+bool tetgenmesh::checktet4opt(triface* testtet, bool enqflag)
 {
   badface *newbadtet;
   point pa, pb, pc, pd;
-  REAL N[4][3], volume, len;
-  REAL cosd, smallcosd;
+  REAL N[4][3], len;
+  REAL cosd;
   bool enq;
-  int edgeno, i, j;
+  int 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);
+  // 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]));
@@ -27353,70 +30126,60 @@ bool tetgenmesh::checktet4sliver(triface* testtet, bool chkill, bool enqflag)
       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.
+  // 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 (edgeno) {
-    case 0: break; // edge ab
+    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;
     }
-    // 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);
+    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;
     }
   }
 
@@ -27425,481 +30188,406 @@ bool tetgenmesh::checktet4sliver(triface* testtet, bool chkill, bool enqflag)
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// 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);
-}
-
-///////////////////////////////////////////////////////////////////////////////
+// removeedge()    Remove an edge                                            //
 //                                                                           //
-// removetetbyflip32()    Remove a tet by a 3-to-2 flip.                     //
+// '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.                                                       //
 //                                                                           //
-// '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.   //
+// 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'.           //
 //                                                                           //
-// 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 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 '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.                   //
+// 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'.                                      //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::removetetbyflip32(triface *fliptet, bool enq, bool chkill)
+bool tetgenmesh::removeedge(badface* remedge, bool optflag)
 {
-  triface abcd, badc;
-  triface cdab, dcba;
+  triface abcd, badc;  // Tet configuration at edge ab.
   triface baccasing, abdcasing;
-  triface dcacasing, cdbcasing;
-  face abc, bad;
-  REAL attrib, volume;
-  int i;  
+  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) {
+      fnext(abcd, badc);
+      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");
+          }
+          optcount[0]++;
+          return true;
+        }
+      }
+    }
+    // Check if the oppsite edge cd is on the hull.
+    enext2fnextself(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));
 
-  if (b->verbose > 1) {
-    printf("    by a 3-to-2 flip.\n");
+  remflag = false;
+  key = remedge->key;
+
+  if (subflag && optflag) {
+    abcd = remedge->tt;
+    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);
+        }
+        optcount[1]++;
+        return true;
+      }
+    } // if (j = 0; j < 2; j++)
+    // Faces are not flipable. Return.
+    return false;
   }
 
-   fliptetcount++;
+  // 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");
+    }
+  } 
 
-  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 (!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);
+        }
+      }
+      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);
+        }
+        printf("\n");
+      }
     }
-    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.
-
-  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);
+  }
+
+  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);
+      }
     }
   }
+
+  return remflag;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// removetetbyrecon()    Remove a tet by local reconnection.                 //
+// smoothsliver()    Remove a sliver by smoothing a vertex of it.            //
 //                                                                           //
-// '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).   //
-//                                                                           //
-// abcd is removable if it is not a segment, and either it can be stripped   //
-// off or it can be flipped away.                                            //
-//                                                                           //
-// The return value indicates abcd is remveable or not. Note, although abcd  //
-// is removeable but it may not be removed when 'chkill' is FALSE.           //
+// The 'slivtet' represents a sliver abcd, and ab is the current edge which  //
+// has a large dihedral angle (close to 180 degree).                         //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::removetetbyrecon(badface* remtet, bool chkill)
+bool tetgenmesh::smoothsliver(badface* remedge, list *starlist)
 {
-  triface abcd, badc;  // Tet configuration at edge ab.
-  triface baccasing, abdcasing;
-  face abseg;
-  point pa, pb, pc, pd, pe;
-  REAL ori1, ori2;
-  REAL cosmaxd1, cosmaxd2;
-  bool remflag;
-  int i;
+  triface checktet;
+  point smthpt;
+  bool smthed;
+  int idx, i, j;
 
-  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);
-      // 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.
+  // 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();
       }
-    } // 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);
-  } // for (i = 0; i < 2; i++)
+    }
+  } 
 
-  return remflag;
+  /* 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();
+        }
+      }
+    }
+  }
+  */
+
+  return smthed;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// removetetbysplit()    Remove a tet by inserting a point in it.            //
+// 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).                         //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::removetetbysplit(badface* remtet)
+bool tetgenmesh::splitsliver(badface *remedge, list *tetlist, list *ceillist)
 {
-  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);
-    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);
-        }
-      }
-    }
-  }
-
-  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);
-        }
-      }
-      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);
-        }
+  triface starttet;
+  face checkseg;
+  point newpt, pt[4];
+  bool remflag;
+  int i;
+
+  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);
       }
-      smoothsubpt++;
-    } else {
-      // The local quality will not be improved. Do not insert p.
-      pointdealloc(newpt);
-      newpt = (point) NULL;
-      unsmoothsubpt++;
+      ceillist->clear();
+      return 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,
+  }
+
+  // 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);
+
+  // 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, verlist);
-      // Check if there are new slivers at p.
+      setnewpointsize(newpt, pt[0], NULL);
+      if (steinerleft > 0) steinerleft--;
+      // Queue new slivers.
       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);
+        checktet4opt(&starttet, true);
       }
-      unsmoothvolpt++;
+      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);
     }
-    delete tetlist;
-    delete ceillist;
-    delete verlist;
   }
+  tetlist->clear();
+  ceillist->clear();
 
-  return newpt != (point) NULL;
+  return remflag;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -27908,19 +30596,17 @@ bool tetgenmesh::removetetbysplit(badface* remtet)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::tallslivers(bool chkill)
+void tetgenmesh::tallslivers(bool optflag)
 {
   triface tetloop;
 
   tetrahedrons->traversalinit();
   tetloop.tet = tetrahedrontraverse();
   while (tetloop.tet != (tetrahedron *) NULL) {
-    if (chkill) {
-      if (!checktet4sliver(&tetloop, true, true)) {
-        checktet4ill(&tetloop, true);
-      }
+    if (optflag) {
+      checktet4opt(&tetloop, true);
     } else {
-      checktet4sliver(&tetloop, false, true);
+      checktet4ill(&tetloop, true);
     }
     tetloop.tet = tetrahedrontraverse();
   }
@@ -27928,26 +30614,62 @@ void tetgenmesh::tallslivers(bool chkill)
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// repairmesh()    Remove illegal tets in the mesh.                          //
+// 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.  //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::repairmesh()
+void tetgenmesh::optimizemesh(bool optflag)
 {
-  badface *remtet, *lastunrementry;
+  list *splittetlist, *tetlist, *ceillist;
+  badface *remtet, *lastentry;
+  REAL maxdihed, objdihed, curdihed;
+  long oldnum;
+  int iter, i;
 
   if (!b->quiet) {
-    printf("Repairing mesh.\n");
+    if (optflag) {
+      printf("Optimizing mesh.\n");
+    } else {
+      printf("Repairing mesh.\n");
+    }
   }
 
-  // Initialize the pool of bad tets
-  badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0);
-  lastunrementry = (badface *) NULL;
-  striptetcount = fliptetcount = unimprovecount = 0l;
+#ifdef SELF_CHECK
+  if (optflag && (b->verbose)) {
+    printf("  level = %d.\n", b->optlevel);
+  }
+#endif
 
-  // Looking for illegal tets.
-  tallslivers(true);
-  
+  // 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.
+
+  // Perform edge flip to improve quality.
+  lastentry = (badface *) NULL;
   // Loop until pool 'badtetrahedrons' is empty.
   while (badtetrahedrons->items > 0) {
     badtetrahedrons->traversalinit();
@@ -27960,21 +30682,22 @@ void tetgenmesh::repairmesh()
           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));
+          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);
         }
-        if (!removetetbyrecon(remtet, true)) {
+        if (!removeedge(remtet, optflag)) {
           // An unremoveable tet. Check if it forms a loop.
-          if (lastunrementry != (badface *) NULL) {
-            if (remtet == lastunrementry) break;
+          if (lastentry != (badface *) NULL) {
+            if (remtet == lastentry) break;
           } else {
             // Remember this tet as a breakpoint.
-            lastunrementry = remtet;
+            lastentry = remtet;
           }
         } else {
           // Clear the breakpoint.
-          lastunrementry = (badface *) NULL;
+          lastentry = (badface *) NULL;
           // Remove the entry from the queue.
           badfacedealloc(badtetrahedrons, remtet);
         }
@@ -27989,153 +30712,97 @@ void tetgenmesh::repairmesh()
   }
 
   if (b->verbose) {
-    if (striptetcount > 0l) {
-      printf("  %ld tets are stripped off.\n", striptetcount);
+    if (optcount[0] > 0l) {
+      printf("  %ld tets are peeled off.\n", optcount[0]);
     }
-    if (fliptetcount > 0l) {
-      printf("  %ld tets are flipped away.\n", fliptetcount);
+    if (optcount[1] > 0l) {
+      printf("  %ld faces are flipped.\n", optcount[1]);
     }
-    if (badtetrahedrons->items > 0l) {
-      printf("  %ld tets are unremoveable.\n", badtetrahedrons->items);
+    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);
+    // }
   }
 
-  delete badtetrahedrons;
-  badtetrahedrons = (memorypool *) NULL;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// smoothmesh()    Smooth the mesh.                                          //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-void tetgenmesh::smoothmesh()
-{
-  badface *remtet, *lastunrementry;
-
-  if (!b->quiet) {
-    printf("Smoothing mesh.\n");
-  }
+  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;
 
-  // Initialize the pool of bad tets
-  badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0);
-  cosmaxdihed = cos(b->maxdihedral * PI / 180.0);
-  cosmindihed = 1.0;
-  striptetcount = fliptetcount = unimprovecount = 0l;
-  smoothcdtsegpt = smoothsegpt = smoothsubpt = smoothvolpt = 0l;
-  unsmoothcdtsegpt = unsmoothsegpt = unsmoothsubpt = unsmoothvolpt = 0l;
-
-  // Looking for bad tets.
-  tallslivers(false);
-  
-  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. 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 {
+    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);
-    }
-    // Stop if the above loop was out by force.
-    if (remtet != (badface *) NULL) break;
-  }
-
-  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);
-    }
-  }
-
-  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;
+        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);
+              }
             }
-          } 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);
       }
-      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);
+      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);
+      // }
     }
+    delete tetlist;
+    delete ceillist;
+    delete splittetlist;
   }
 
   delete badtetrahedrons;
@@ -28143,7 +30810,7 @@ void tetgenmesh::smoothmesh()
 }
 
 //
-// End of mesh smoothing routines
+// End of mesh optimization routines
 //
 
 //
@@ -28167,11 +30834,13 @@ void tetgenmesh::transfernodes()
   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.
@@ -28182,6 +30851,10 @@ void tetgenmesh::transfernodes()
     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;
@@ -28197,7 +30870,6 @@ void tetgenmesh::transfernodes()
     }
   }
   // '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;
@@ -28206,6 +30878,7 @@ void tetgenmesh::transfernodes()
     printf("Error:  The point set is trivial.\n");
     terminatetetgen(1);
   }
+  // Two identical points are distinguished by 'lengthlimit'.
   lengthlimit = longest * b->epsilon * 1e+2;
 }
 
@@ -28296,15 +30969,6 @@ void tetgenmesh::highorder()
   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");
   }
@@ -28347,44 +31011,21 @@ void tetgenmesh::highorder()
   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 = 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);
-        }
+        worktet.loc = edge2locver[i][0];
+        worktet.ver = edge2locver[i][1];
         // 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.
@@ -28399,7 +31040,7 @@ void tetgenmesh::highorder()
             // Get the extra node list of 'spintet'.
             adjextralist = (point *) spintet.tet[highorderindex];
             // Find the index of its extra node list.
-            j = edgeindexmap[spintet.loc][spintet.ver];
+            j = locver2edge[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) {
@@ -28457,8 +31098,7 @@ void tetgenmesh::outnodes(tetgenio* out)
     }
   }
 
-  // nextras = in->numberofpointattributes;
-  nextras = 0; // After version 1.4.0, don't output point attributes.
+  nextras = in->numberofpointattributes;
   bmark = !b->nobound && in->pointmarkerlist;
 
   // Avoid compile warnings.
@@ -28642,8 +31282,11 @@ void tetgenmesh::outmetrics(tetgenio* out)
 {
   FILE *outfile;
   char outmtrfilename[FILENAMESIZE];
-  point pointloop;
-  int nextras, attribindex;
+  list *tetlist, *ptlist;
+  triface tetloop;
+  point ptloop, neipt;
+  REAL lave, len; // lmin, lmax, 
+  int mtrindex;
   int i;  
 
   if (out == (tetgenio *) NULL) {
@@ -28661,53 +31304,103 @@ void tetgenmesh::outmetrics(tetgenio* out)
 
   // Avoid compile warnings.
   outfile = (FILE *) NULL;
-  attribindex = 0;
+  mtrindex = 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 attributes,
-    fprintf(outfile, "%ld  %d\n", points->items, nextras);
+    // 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 '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);
-      }
+    // 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);
     }
-    out->numberofpointattributes = nextras;
-    attribindex = 0;
+    out->numberofpointmtrs = 1; // (sizeoftensor + 3);
+    mtrindex = 0;
   }
   
+  // Initialize the point2tet field of each point.
   points->traversalinit();
-  pointloop = pointtraverse();
-  while (pointloop != (point) NULL) {
+  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();
+    }
     if (out == (tetgenio *) NULL) {
-      for (i = 0; i < nextras; i++) {
-        // Write an attribute.
-        fprintf(outfile, "%-22.17e ", pointloop[3 + i]);
+      // 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");
       }
       fprintf(outfile, "\n");
     } else {
-      for (i = 0; i < nextras; i++) {
-        // Output an attribute.
-        out->pointattributelist[attribindex++] = pointloop[3 + i];
+      // 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;
       }
     }
-    pointloop = pointtraverse();
+    tetlist->clear();
+    ptlist->clear();
+    ptloop = pointtraverse();
   }
 
+  delete tetlist;
+  delete ptlist;
+
   if (out == (tetgenio *) NULL) {
     fprintf(outfile, "# Generated by %s\n", b->commandline);
     fclose(outfile);
@@ -28874,6 +31567,7 @@ void tetgenmesh::outfaces(tetgenio* out)
   char facefilename[FILENAMESIZE];
   int *elist;
   int *emlist;
+  int neigh1, neigh2;
   int index;
   triface tface, tsymface;
   face checkmark;
@@ -28927,6 +31621,14 @@ void tetgenmesh::outfaces(tetgenio* out)
         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;
@@ -28973,6 +31675,15 @@ void tetgenmesh::outfaces(tetgenio* out)
             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,
@@ -28982,6 +31693,9 @@ void tetgenmesh::outfaces(tetgenio* out)
             // 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.
@@ -28991,6 +31705,10 @@ void tetgenmesh::outfaces(tetgenio* out)
           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++;
       }
@@ -29125,7 +31843,7 @@ void tetgenmesh::outsubfaces(tetgenio* out)
   char facefilename[FILENAMESIZE];
   int *elist;
   int *emlist;
-  int index;
+  int index, index1, index2;
   triface abuttingtet;
   face faceloop;
   point torg, tdest, tapex;
@@ -29151,7 +31869,8 @@ void tetgenmesh::outsubfaces(tetgenio* out)
   outfile = (FILE *) NULL;
   elist = (int *) NULL;
   emlist = (int *) NULL;
-  index = marker = 0;
+  index = index1 = index2 = 0;
+  faceid = marker = 0;
   neigh1 = neigh2 = 0;
 
   bmark = !b->nobound && in->facetmarkerlist;
@@ -29190,7 +31909,6 @@ void tetgenmesh::outsubfaces(tetgenio* out)
     out->numberoftrifaces = subfaces->items;
     elist = out->trifacelist;
     emlist = out->trifacemarkerlist;
-    index = 0;
   }
 
   // Determine the first index (0 or 1).
@@ -29258,15 +31976,163 @@ void tetgenmesh::outsubfaces(tetgenio* out)
       elist[index++] = pointmark(tdest) - shift;
       elist[index++] = pointmark(tapex) - shift;
       if (bmark) {
-        emlist[facenumber - in->firstnumber] = marker;
+        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 (b->neighout > 1) {
-        out->adjtetlist[(facenumber - in->firstnumber) * 2]     = neigh1;
-        out->adjtetlist[(facenumber - in->firstnumber) * 2 + 1] = neigh2;
+      // 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++;
       }
     }
-    facenumber++;
-    faceloop.sh = shellfacetraverse(subfaces);
+    tetloop.tet = tetrahedrontraverse();
   }
 
   if (out == (tetgenio *) NULL) {
@@ -29301,7 +32167,7 @@ void tetgenmesh::outsubsegments(tetgenio* out)
     if (out == (tetgenio *) NULL) {
       printf("Writing %s.\n", edgefilename);
     } else {
-      printf("Writing faces.\n");
+      printf("Writing edges.\n");
     }
   }
 
@@ -29327,7 +32193,6 @@ void tetgenmesh::outsubsegments(tetgenio* out)
     }
     out->numberofedges = subsegs->items;
     elist = out->edgelist;
-    index = 0;
   }
 
   // Determine the first index (0 or 1).
@@ -29351,102 +32216,545 @@ void tetgenmesh::outsubsegments(tetgenio* out)
       elist[index++] = pointmark(torg) - shift;
       elist[index++] = pointmark(tdest) - shift;
     }
-    edgenumber++;
-    edgeloop.sh = shellfacetraverse(subsegs);
+    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);
+    }
+  }
+
+  // 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();
   }
 
   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(neighborfilename, b->outfilename);
-    strcat(neighborfilename, ".neigh");
+    strcpy(outfilename, b->outfilename);
+    strcat(outfilename, ".v.cell");
   }
-
+  
   if (!b->quiet) {
     if (out == (tetgenio *) NULL) {
-      printf("Writing %s.\n", neighborfilename);
+      printf("Writing %s.\n", outfilename);
     } else {
-      printf("Writing neighbors.\n");
+      printf("Writing Voronoi cells.\n");
     }
   }
 
-  // Avoid compile warnings.
-  outfile = (FILE *) NULL;
-  nlist = (int *) NULL;
-  index = 0;
-
   if (out == (tetgenio *) NULL) {
-    outfile = fopen(neighborfilename, "w");
+    outfile = fopen(outfilename, "w");
     if (outfile == (FILE *) NULL) {
-      printf("File I/O Error:  Cannot create file %s.\n", neighborfilename);
+      printf("File I/O Error:  Cannot create file %s.\n", outfilename);
       terminatetetgen(1);
     }
-    // Number of tetrahedra, four faces per tetrahedron.
-    fprintf(outfile, "%ld  %d\n", tetrahedrons->items, 4);
+    // Number of Voronoi cells.
+    fprintf(outfile, "%ld\n", points->items);
   } else {
-    // Allocate memory for 'neighborlist'.
-    out->neighborlist = new int[tetrahedrons->items * 4];
-    if (out->neighborlist == (int *) NULL) {
+    out->numberofvcells = points->items;
+    out->vcelllist = new int*[out->numberofvcells];
+    if (out->vcelllist == (int **) NULL) {
       printf("Error:  Out of memory.\n");
       terminatetetgen(1);
     }
-    nlist = out->neighborlist;
-    index = 0;
   }
 
-  // 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;
+  // 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++;
     }
-    tetloop.tet = tetrahedrontraverse();
-    elementnumber++;
+    tetlist->clear();
+    ptlist->clear();
+    ptloop = pointtraverse();
   }
+  delete tetlist;
+  delete ptlist;
+  delete [] tetfaceindexarray;
+  delete [] tetedgeindexarray;
 
   if (out == (tetgenio *) NULL) {
     fprintf(outfile, "# Generated by %s\n", b->commandline);
@@ -29779,7 +33087,7 @@ void tetgenmesh::outmesh2medit(char* mfilename)
   tetrahedron* tetptr;
   triface tface, tsymface;
   face segloop, checkmark;
-  point pointloop, p1, p2, p3, p4;
+  point ptloop, p1, p2, p3, p4;
   long faces;
   int pointnumber;
   int i;
@@ -29813,20 +33121,19 @@ void tetgenmesh::outmesh2medit(char* mfilename)
   fprintf(outfile, "%ld\n", points->items);
 
   points->traversalinit();
-  pointloop = pointtraverse();
+  ptloop = pointtraverse();
   pointnumber = 1;                        // Medit need start number form 1.
-  while (pointloop != (point) NULL) {
+  while (ptloop != (point) NULL) {
     // Point coordinates.
-    fprintf(outfile, "%.17g  %.17g  %.17g",
-            pointloop[0], pointloop[1], pointloop[2]);
+    fprintf(outfile, "%.17g  %.17g  %.17g", ptloop[0], ptloop[1], ptloop[2]);
     if (in->numberofpointattributes > 0) {
       // Write an attribute, ignore others if more than one.
-      fprintf(outfile, "  %.17g\n", pointloop[3]);
+      fprintf(outfile, "  %.17g\n", ptloop[3]);
     } else {
       fprintf(outfile, "    0\n");
     }
-    setpointmark(pointloop, pointnumber);
-    pointloop = pointtraverse();
+    setpointmark(ptloop, pointnumber);
+    ptloop = pointtraverse();
     pointnumber++;
   }
 
@@ -29927,7 +33234,7 @@ void tetgenmesh::outmesh2gid(char* gfilename)
   tetrahedron* tetptr;
   triface tface, tsymface;
   face sface;
-  point pointloop, p1, p2, p3, p4;
+  point ptloop, p1, p2, p3, p4;
   int pointnumber;
   int elementnumber;
 
@@ -29953,19 +33260,19 @@ void tetgenmesh::outmesh2gid(char* gfilename)
   fprintf(outfile, "coordinates\n");
 
   points->traversalinit();
-  pointloop = pointtraverse();
+  ptloop = pointtraverse();
   pointnumber = 1;                        // Gid need start number form 1.
-  while (pointloop != (point) NULL) {
+  while (ptloop != (point) NULL) {
     // Point coordinates.
     fprintf(outfile, "%4d  %.17g %.17g %.17g", pointnumber,
-            pointloop[0], pointloop[1], pointloop[2]);
+            ptloop[0], ptloop[1], ptloop[2]);
     if (in->numberofpointattributes > 0) {
       // Write an attribute, ignore others if more than one.
-      fprintf(outfile, "  %.17g", pointloop[3]);
+      fprintf(outfile, "  %.17g", ptloop[3]);
     }
     fprintf(outfile, "\n");
-    setpointmark(pointloop, pointnumber);
-    pointloop = pointtraverse();
+    setpointmark(ptloop, pointnumber);
+    ptloop = pointtraverse();
     pointnumber++;
   }
 
@@ -30015,19 +33322,19 @@ void tetgenmesh::outmesh2gid(char* gfilename)
   fprintf(outfile, "coordinates\n");
 
   points->traversalinit();
-  pointloop = pointtraverse();
+  ptloop = pointtraverse();
   pointnumber = 1;                        // Gid need start number form 1.
-  while (pointloop != (point) NULL) {
+  while (ptloop != (point) NULL) {
     // Point coordinates.
     fprintf(outfile, "%4d  %.17g %.17g %.17g", pointnumber,
-            pointloop[0], pointloop[1], pointloop[2]);
+            ptloop[0], ptloop[1], ptloop[2]);
     if (in->numberofpointattributes > 0) {
       // Write an attribute, ignore others if more than one.
-      fprintf(outfile, "  %.17g", pointloop[3]);
+      fprintf(outfile, "  %.17g", ptloop[3]);
     }
     fprintf(outfile, "\n");
-    setpointmark(pointloop, pointnumber);
-    pointloop = pointtraverse();
+    setpointmark(ptloop, pointnumber);
+    ptloop = pointtraverse();
     pointnumber++;
   }
 
@@ -30081,7 +33388,7 @@ void tetgenmesh::outmesh2off(char* ofilename)
   FILE *outfile;
   char offfilename[FILENAMESIZE];
   triface tface, tsymface;
-  point pointloop, p1, p2, p3;
+  point ptloop, p1, p2, p3;
   long faces;
   int shift;
 
@@ -30111,11 +33418,10 @@ void tetgenmesh::outmesh2off(char* ofilename)
 
   // Write the points.
   points->traversalinit();
-  pointloop = pointtraverse();
-  while (pointloop != (point) NULL) {
-    fprintf(outfile, " %.17g  %.17g  %.17g\n", pointloop[0], pointloop[1],
-            pointloop[2]);
-    pointloop = pointtraverse();
+  ptloop = pointtraverse();
+  while (ptloop != (point) NULL) {
+    fprintf(outfile, " %.17g  %.17g  %.17g\n",ptloop[0], ptloop[1], ptloop[2]);
+    ptloop = pointtraverse();
   }
 
   // OFF always use zero as the first index.
@@ -30527,10 +33833,10 @@ void tetgenmesh::checkdelaunay(REAL eps, queue* flipqueue)
             case T32: printf("\"T32\""); break;
             case T22: printf("\"T22\""); break;
             case T44: printf("\"T44\""); break;
-            case UNFLIPABLE: printf("\"UNFLIPABLE\""); break;
+            case N32: printf("\"N32\""); break;
+            case N40: printf("\"N40\""); break;
             case FORBIDDENFACE:printf("\"FORBIDDENFACE\""); break;
             case FORBIDDENEDGE:printf("\"FORBIDDENEDGE\""); break;
-            case NONCONVEX:printf("\"NONCONVEX\""); break;
             }
             printf("\n");
           }
@@ -30552,69 +33858,6 @@ void tetgenmesh::checkdelaunay(REAL eps, queue* flipqueue)
   }
 }
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// 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.         //
@@ -30673,9 +33916,14 @@ void tetgenmesh::checkconforming()
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
+#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);
   }
@@ -30684,12 +33932,11 @@ void tetgenmesh::algorithmicstatistics()
            r3count);
   }
   if (b->quality) {
-    printf("  Bowyer-Watson counts (seg, sub, vol)\n");
-    printf("    Insert vertices: %ld, %ld, %ld\n",
+    printf("  Bowyer-Watson insertions: seg %ld, sub %ld, vol %ld.\n",
            bowatsegcount, bowatsubcount, bowatvolcount);
-    printf("    Update cavities: %ld, %ld, %ld\n",
+    printf("  Bowyer-Watson corrections: seg %ld, sub %ld, vol %ld\n",
            updsegcount, updsubcount, updvolcount);
-    printf("    Failed cavities: %ld, %ld, %ld\n",
+    printf("  Bowyer-Watson failures: seg %ld, sub %ld, vol %ld\n",
            failsegcount, failsubcount, failvolcount);
     printf("  Number of repair flips: %ld.\n", repairflipcount);
     printf("  Number of circumcenters outside Bowat-cav.: %ld.\n",
@@ -30698,25 +33945,21 @@ void tetgenmesh::algorithmicstatistics()
       printf("  Segment split rules: R2 %ld, R3 %ld\n", r2count, r3count);
       printf("  Number of CDT enforcement points: %ld.\n", cdtenforcesegpts);
     }
-    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("  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("\n");
+  */
 }
 
+#endif // #ifdef SELF_CHECK
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // qualitystatistics()    Print statistics about the quality of the mesh.    //
@@ -30725,25 +33968,28 @@ void tetgenmesh::algorithmicstatistics()
 
 void tetgenmesh::qualitystatistics()
 {
-  triface tetloop;
+  triface tetloop, neightet;
   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];
+  REAL edgelength[6], alldihed[6], faceangle[3];
   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;
@@ -30773,6 +34019,7 @@ void tetgenmesh::qualitystatistics()
   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;
@@ -30780,8 +34027,8 @@ void tetgenmesh::qualitystatistics()
   longest = 0.0;
   smallestvolume = minaltitude;
   biggestvolume = 0.0;
-  smallestdiangle = 180.0;
-  biggestdiangle = 0.0;
+  smallestdiangle = smallestfaangle = 180.0;
+  biggestdiangle = biggestfaangle = 0.0;
 
   // Loop all elements, calculate quality parameters for each element.
   tetrahedrons->traversalinit();
@@ -30925,6 +34172,45 @@ void tetgenmesh::qualitystatistics()
     }
     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);
@@ -30951,6 +34237,12 @@ void tetgenmesh::qualitystatistics()
          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';
@@ -30958,6 +34250,7 @@ void tetgenmesh::qualitystatistics()
   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],
@@ -30974,6 +34267,7 @@ void tetgenmesh::qualitystatistics()
   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",
@@ -30992,6 +34286,18 @@ void tetgenmesh::qualitystatistics()
   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",
@@ -31009,7 +34315,10 @@ void tetgenmesh::qualitystatistics()
          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");
 }
 
@@ -31028,6 +34337,7 @@ void tetgenmesh::statistics()
   }
   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);
   }
@@ -31035,20 +34345,35 @@ void tetgenmesh::statistics()
   printf("\n  Mesh points: %ld\n", points->items);
   printf("  Mesh tetrahedra: %ld\n", tetrahedrons->items);
   if (b->plc || b->refine) {
-    printf("  Mesh faces: %ld\n", (4l * tetrahedrons->items + hullsize) / 2l);
+    printf("  Mesh triangles: %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 faces: %ld\n\n", hullsize);
+    printf("  Convex hull triangles: %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");
   }
 }
 
@@ -31144,7 +34469,7 @@ tetgenmesh::tetgenmesh()
   longest = 0.0;
   hullsize = 0l;
   insegments = 0l;
-  pointlfsindex = 0;
+  pointmtrindex = 0;
   pointmarkindex = 0;
   point2simindex = 0;
   point2pbcptindex = 0;
@@ -31154,6 +34479,7 @@ tetgenmesh::tetgenmesh()
   shmarkindex = 0;
   areaboundindex = 0;
   checksubfaces = 0;
+  checksubsegs = 0;
   checkpbcs = 0;
   varconstraint = 0;
   nonconvex = 0;
@@ -31164,10 +34490,11 @@ tetgenmesh::tetgenmesh()
   collapverts = 0;
   unsupverts = 0;
   jettisoninverts = 0;
-  symbolic = 0;
+  symbolic = 1;
   samples = 0l;
-  randomseed = 0l;
+  randomseed = 1l;
   macheps = 0.0;
+  minfaceang = minfacetdihed = PI;
   maxcavfaces = maxcavverts = 0;
   expcavcount = 0;
   abovecount = 0l;
@@ -31176,10 +34503,11 @@ tetgenmesh::tetgenmesh()
   repairflipcount = 0l;
   outbowatcircumcount = 0l;
   failvolcount = failsubcount = failsegcount = 0l;
-  r1count = r2count = r3count = r4count = 0l;
+  r1count = r2count = r3count = 0l;
   cdtenforcesegpts = 0l;
   rejsegpts = rejsubpts = rejtetpts = 0l;
   flip23s = flip32s = flip22s = flip44s = 0l;
+  tloctime = tfliptime = 0.0;
 }
 
 //
@@ -31214,31 +34542,29 @@ tetgenmesh::tetgenmesh()
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-#include <time.h>           // Defined type clock_t, constant CLOCKS_PER_SEC.
-
 void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
-  tetgenio *bgmesh)
+  tetgenio *addin, tetgenio *bgmin)
 {
   tetgenmesh m;
-  clock_t tv0, tv1, tv2, tv3, tv4, tv5, tv6, tv7, tv8, tv9, tv10, tv11;
+  // Variables for timing the performance of TetGen (defined in time.h).
+  clock_t tv[14];
 
-  tv0 = clock();
+  tv[0] = clock();
  
   m.b = b;
   m.in = in;
   m.macheps = exactinit();
   m.steinerleft = b->steiner;
-  if (b->bgmesh) {
-    // '-m' switch
+  if (b->metric) {
     m.bgm = new tetgenmesh();
     m.bgm->b = b;
-    m.bgm->in = bgmesh;
+    m.bgm->in = bgmin;
     m.bgm->macheps = exactinit();
   }
   m.initializepools();
   m.transfernodes();
 
-  tv1 = clock();
+  tv[1] = clock();
 
   if (b->refine) {
     m.reconstructmesh();
@@ -31246,103 +34572,149 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
     m.delaunizevertices();
   }
 
-  tv2 = clock();
+  tv[2] = clock();
+
   if (!b->quiet) {
     if (b->refine) {
-      printf("Mesh reconstruction seconds:  %g\n",
-             (tv2 - tv1) / (REAL) CLOCKS_PER_SEC);
+      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();
     } else {
-      printf("Delaunay seconds:  %g\n", (tv2 - tv1) / (REAL) CLOCKS_PER_SEC);
+      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);
     }
   }
 
   if (b->useshelles && !b->refine) {
-    m.insegments = m.meshsurface();
+    m.meshsurface();
     if (b->diagnose != 1) {
-      m.incrperturbvertices(b->epsilon); // '-p' switch.
+      m.markacutevertices(89.0);
+      m.incrperturbvertices(b->epsilon);
       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(); // '-d' switch.
+      m.detectinterfaces();
     }
   }
 
-  tv3 = clock();
+  tv[4] = clock();
+
   if (!b->quiet) {
     if (b->useshelles && !b->refine) {
       if (b->diagnose != 1) {
-        printf("Segment and facet seconds:  %g\n",
-               (tv3 - tv2) / (REAL) CLOCKS_PER_SEC);
+        printf("Segment and facet ");
       } else {
-        printf("Intersection seconds:  %g\n", 
-               (tv3 - tv2) / (REAL) CLOCKS_PER_SEC);  
+        printf("Intersection "); 
       }
-    } 
+      printf("seconds:  %g\n", (tv[4] - tv[3]) / (REAL) CLOCKS_PER_SEC);
+    }
   }
 
   if (b->plc && !(b->diagnose == 1)) {
     m.carveholes();
   }
 
-  tv4 = clock();
+  tv[5] = clock();
+
   if (!b->quiet) {
     if (b->plc && !(b->diagnose == 1)) {
-      printf("Hole seconds:  %g\n", (tv4 - tv3) / (REAL) CLOCKS_PER_SEC);
+      printf("Hole seconds:  %g\n", (tv[5] - tv[4]) / (REAL) CLOCKS_PER_SEC);
     }
   }
 
   if ((b->plc || b->refine) && !(b->diagnose == 1)) {
-    m.repairmesh(); 
+    m.optimizemesh(false); 
   }
 
-  tv5 = clock();
+  tv[6] = clock();
+
   if (!b->quiet) {
     if ((b->plc || b->refine) && !(b->diagnose == 1)) {
-      printf("Repair seconds:  %g\n", (tv5 - tv4) / (REAL) CLOCKS_PER_SEC);
+      printf("Repair seconds:  %g\n", (tv[6] - tv[5]) / (REAL) CLOCKS_PER_SEC);
     }
   }
 
   if ((b->plc && b->nobisect) && !(b->diagnose == 1)) {
-    m.removesteiners();
+    m.removesteiners(false);
   }
 
-  tv6 = clock();
+  tv[7] = clock();
+
   if (!b->quiet) {
     if ((b->plc && b->nobisect) && !(b->diagnose == 1)) {
       printf("Steiner removal seconds:  %g\n",
-             (tv6 - tv5) / (REAL) CLOCKS_PER_SEC);
+             (tv[7] - tv[6]) / (REAL) CLOCKS_PER_SEC);
     }
   }
 
-  if (b->insertaddpoints) {
-    if (in->numberofaddpoints == 0) {
-      in->load_addnodes(b->infilename);
-    }
-    if (in->numberofaddpoints > 0) {
-      m.insertaddpoints(); 
+  if (b->insertaddpoints && (addin != (tetgenio *) NULL)) {
+    if (addin->numberofpoints > 0) {
+      m.insertconstrainedpoints(addin); 
     }
   }
 
-  tv7 = clock();
+  tv[8] = clock();
+
   if (!b->quiet) {
-    if ((b->plc || b->refine) && (in->numberofaddpoints > 0)) {
-      printf("Add points seconds:  %g\n", (tv7 - tv6) / (REAL) CLOCKS_PER_SEC);
+    if ((b->plc || b->refine) && (b->insertaddpoints)) {
+      printf("Constrained points seconds:  %g\n", 
+             (tv[8] - tv[7]) / (REAL) CLOCKS_PER_SEC);
     }
   }
 
-  if (b->bgmesh) {
-    // '-b' switch
-    m.bgm->initializepools();
-    m.bgm->transfernodes();
-    m.bgm->reconstructmesh();
+  if (b->metric) {
     m.interpolatesizemap();
   }
 
-  tv8 = clock();
+  tv[9] = clock();
+
+  if (!b->quiet) {
+    if (b->metric) {
+      printf("Size interpolating seconds:  %g\n",
+             (tv[9] - tv[8]) / (REAL) CLOCKS_PER_SEC);
+    }
+  }
+
+  if (b->coarse) {
+    m.removesteiners(true);
+  }
+
+  tv[10] = clock();
+
   if (!b->quiet) {
-    if (b->bgmesh) {
-      printf("Background mesh reconstruct seconds:  %g\n",
-             (tv8 - tv7) / (REAL) CLOCKS_PER_SEC);
+    if (b->coarse) {
+      printf("Mesh coarsening seconds:  %g\n",
+             (tv[10] - tv[9]) / (REAL) CLOCKS_PER_SEC);
     }
   }
 
@@ -31350,21 +34722,25 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
     m.enforcequality();
   }
 
-  tv9 = clock();
+  tv[11] = clock();
+
   if (!b->quiet) {
     if (b->quality) {
-      printf("Quality seconds:  %g\n", (tv9 - tv8) / (REAL) CLOCKS_PER_SEC);
+      printf("Quality seconds:  %g\n",
+             (tv[11] - tv[10]) / (REAL) CLOCKS_PER_SEC);
     }
   }
 
-  if (b->quality && b->smooth) {
-    m.smoothmesh();
+  if (b->quality && (b->optlevel > 0)) {
+    m.optimizemesh(true);
   }
 
-  tv10 = clock();
+  tv[12] = clock();
+
   if (!b->quiet) {
-    if (b->quality && b->smooth) {
-      printf("Smooth seconds:  %g\n", (tv10 - tv9) / (REAL) CLOCKS_PER_SEC);
+    if (b->quality && (b->optlevel > 0)) {
+      printf("Optimize seconds:  %g\n",
+             (tv[12] - tv[11]) / (REAL) CLOCKS_PER_SEC);
     }
   }
 
@@ -31393,13 +34769,12 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
   } else {
     if (b->diagnose == 1) {
       if (m.subfaces->items > 0l) {
-        // Only output when there are intersecting faces.
-        m.outnodes(out);
+        m.outnodes(out);  // Only output when self-intersecting faces exist.
       }
     } else {
       m.outnodes(out);
-      if (b->metric) {
-        m.outmetrics(out);
+      if (b->quality || b->metric) {
+        // m.outmetrics(out);
       }
     }
   }
@@ -31423,24 +34798,20 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
   } else {
     if (b->facesout) {
       if (m.tetrahedrons->items > 0l) {
-        // Output all faces.
-        m.outfaces(out);
+        m.outfaces(out);  // Output all faces.
       }
     } else {
       if (b->diagnose == 1) {
         if (m.subfaces->items > 0l) {
-          // Only output when there are intersecting faces.
-          m.outsubfaces(out);
+          m.outsubfaces(out); // Only output self-intersecting faces.
         }
       } else if (b->plc || b->refine) {
         if (m.subfaces->items > 0l) {
-          // Output boundary faces.
-          m.outsubfaces(out); 
+          m.outsubfaces(out); // Output boundary faces.
         }
       } else {
         if (m.tetrahedrons->items > 0l) {
-          // Output convex hull faces.
-          m.outhullfaces(out); 
+          m.outhullfaces(out); // Output convex hull faces.
         }
       }
     }
@@ -31450,9 +34821,11 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
     m.outpbcnodes(out);
   }
 
-  if (b->edgesout && b->plc) {
-    if (m.subsegs->items > 0l) {
-      m.outsubsegments(out); 
+  if (b->edgesout) {
+    if (b->edgesout > 1) {
+      m.outedges(out); // -ee, output all mesh edges. 
+    } else {
+      m.outsubsegments(out); // -e, only output subsegments.
     }
   }
 
@@ -31479,11 +34852,17 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
     m.outneighbors(out);
   }
 
-  tv11 = clock();
+  if (b->voroout) {
+    m.outvoronoi(out);
+  }
+
+  tv[13] = clock();
+
   if (!b->quiet) {
-    printf("\nOutput seconds:  %g\n", (tv11 - tv10) / (REAL) CLOCKS_PER_SEC);
+    printf("\nOutput seconds:  %g\n",
+           (tv[13] - tv[12]) / (REAL) CLOCKS_PER_SEC);
     printf("Total running seconds:  %g\n",
-           (tv11 - tv0) / (REAL) CLOCKS_PER_SEC);
+           (tv[13] - tv[0]) / (REAL) CLOCKS_PER_SEC);
   }
 
   if (b->docheck) {
@@ -31505,7 +34884,7 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
     m.statistics();
   }
 
-  if (bgmesh) {
+  if (b->metric) {
     delete m.bgm;
   }
 }
@@ -31529,7 +34908,7 @@ int main(int argc, char *argv[])
 ///////////////////////////////////////////////////////////////////////////////
 
 void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
-  tetgenio *bgmesh)
+  tetgenio *addin, tetgenio *bgmin)
 
 #endif // not TETLIBRARY
 
@@ -31538,7 +34917,7 @@ void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
 
 #ifndef TETLIBRARY
 
-  tetgenio in, bgmesh;
+  tetgenio in, addin, bgmin;
   
   if (!b.parse_commandline(argc, argv)) {
     terminatetetgen(1);
@@ -31552,16 +34931,21 @@ void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
       terminatetetgen(1);
     }
   }
-  if (b.bgmesh) {
-    if (!bgmesh.load_tetmesh(b.bgmeshfilename)) {
-      bgmesh.numberoftetrahedra = 0l;
+  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 (bgmesh.numberoftetrahedra > 0l) {
-    tetrahedralize(&b, &in, NULL, &bgmesh);
+  if (bgmin.numberoftetrahedra > 0l) {
+    tetrahedralize(&b, &in, NULL, &addin, &bgmin);
   } else {
-    tetrahedralize(&b, &in, NULL, NULL);
+    tetrahedralize(&b, &in, NULL, &addin, NULL);
   }
 
   return 0;
@@ -31571,7 +34955,7 @@ void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
   if (!b.parse_commandline(switches)) {
     terminatetetgen(1);
   }
-  tetrahedralize(&b, in, out, bgmesh);
+  tetrahedralize(&b, in, out, addin, bgmin);
 
 #endif // not TETLIBRARY
 }
diff --git a/contrib/Tetgen/tetgen.h b/contrib/Tetgen/tetgen.h
index 55b8f3a604..74106f9260 100644
--- a/contrib/Tetgen/tetgen.h
+++ b/contrib/Tetgen/tetgen.h
@@ -5,16 +5,22 @@
 // A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator         //
 //                                                                           //
 // Version 1.4                                                               //
-// January 14, 2006                                                          //
+// April 16, 2007                                                            //
 //                                                                           //
-// Copyright 2002, 2004, 2005, 2006                                          //
+// Copyright (C) 2002--2007                                                  //
 // Hang Si                                                                   //
-// Rathausstr. 9, 10178 Berlin, Germany                                      //
+// Research Group Numerical Mathematics and Scientific Computing             //
+// Weierstrass Institute for Applied Analysis and Stochastics                //
+// Mohrenstr. 39, 10117 Berlin, Germany                                      //
 // si@wias-berlin.de                                                         //
 //                                                                           //
-// 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 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.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // TetGen computes Delaunay tetrahedralizations, constrained Delaunay tetra- //
 //   hedralizations, and quality Delaunay tetrahedral meshes. The latter are //
@@ -28,26 +34,25 @@
 //                                                                           //
 //   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 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 refinement algorithm is from:  Hang Si, "Adaptive Tetrahedral  //
+//   Mesh Generation by Constrained Delaunay Refinement". WIAS Preprint No.  //
+//   1176, Berlin 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.  Both data structures have //
-//   a set of fast mesh manipulation primitives.                             //
+//   boundary elements: subfaces and subsegments.                            //
 //                                                                           //
 //   J. R. Shewchuk, "Delaunay Refinement Mesh Generation". PhD thesis,      //
-//   Carnegie Mellon University, 1997.                                       //
+//   Carnegie Mellon University, Pittsburgh, PA, 1997.                       //
 //                                                                           //
 //   E. P. Muecke, "Shapes and Implementations in Three-Dimensional          //
 //   Geometry". PhD thesis, Univ. of Illinois, Urbana, Illinois, 1993.       //
@@ -74,6 +79,15 @@
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
+// 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                                                   //
@@ -128,40 +142,30 @@
   #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>
- 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// The tetgenio data type                                                    //
+// tetgenio    Passing data into and out of the library of TetGen.           //
 //                                                                           //
-// Used to pass data into and out of the library of TetGen.                  //
+// 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.    //
 //                                                                           //
 // If you want to program with the library of TetGen, it's necessary for you //
-// 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 any array is stored starting at index [0].//
+// 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().                                                           //
+//                                                                           //
+// In all cases, the first item in an 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'.        //
@@ -218,6 +222,30 @@ class tetgenio {
       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
@@ -236,27 +264,27 @@ class tetgenio {
 
     // 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. 
-    // 'addpointlist':  An array of additional point coordinates.
-    // 'addpointattributelist':  An array of attributes for addition points.
+    // '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.
     // `pointmarkerlist':  An array of point markers; one int per point.
     REAL *pointlist;
     REAL *pointattributelist;
-    REAL *addpointlist;
-    REAL *addpointattributelist;
+    REAL *pointmtrlist;
     int *pointmarkerlist;
     int numberofpoints;
     int numberofpointattributes;
-    int numberofaddpoints;
+    int numberofpointmtrs;
  
     // `elementlist':  An array of element (triangle or tetrahedron) corners. 
     //   The first element's first corner is at index [0], followed by its
@@ -314,13 +342,6 @@ class tetgenio {
     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;
@@ -331,7 +352,7 @@ class tetgenio {
     // `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 '-n'
+    //   indicates outside (no adj. tet). This list is output when '-nn'
     //   switch is used.
     // `trifacemarkerlist':  An array of face markers; one int per face.
     int *trifacelist;
@@ -347,6 +368,21 @@ class tetgenio {
     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.
@@ -356,7 +392,6 @@ class tetgenio {
     // 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);
@@ -367,6 +402,7 @@ class tetgenio {
     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);
@@ -387,9 +423,7 @@ class tetgenio {
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// The tetgenbehavior data type                                              //
-//                                                                           //
-// Used to parse command line switches and file names.                       //
+// tetgenbehavior    Parsing 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  //
@@ -425,28 +459,29 @@ class tetgenbehavior {
 
     enum objecttype {NONE, NODES, POLY, OFF, PLY, STL, MEDIT, MESH};
 
-    // 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.
+    // 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.
 
     int plc;                                              // '-p' switch, 0.
-    int refine;                                           // '-r' switch, 0.
     int quality;                                          // '-q' switch, 0.
-    int smooth;                                           // '-s' switch, 0.
+    int refine;                                           // '-r' switch, 0.
+    int coarse;                                           // '-R' 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.
@@ -455,26 +490,27 @@ class tetgenbehavior {
     int noelewritten;                                     // '-E' switch, 0.
     int nofacewritten;                                    // '-F' switch, 0.
     int noiterationnum;                                   // '-I' switch, 0.
-    int nomerge;           // count of how often '-M' switch is selected, 0.
+    int nomerge;                                          // '-M',switch, 0.
     int nobisect;          // count of how often '-Y' switch is selected, 0.
-    int noflip;                     // do not perform flips. '-Y' switch. 0.
+    int noflip;                     // do not perform flips. '-X' 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 tol;               // count of how often '-T' switch is selected, 0.
-    int useshelles;            // '-p', '-r', '-q', '-d', or '-c' switch, 0.
+    int useshelles;            // '-p', '-r', '-q', '-d', or '-R' 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 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 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 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.
@@ -483,6 +519,7 @@ class tetgenbehavior {
     char commandline[1024];
     char infilename[1024];
     char outfilename[1024];
+    char addinfilename[1024];
     char bgmeshfilename[1024];
 
     tetgenbehavior();
@@ -505,9 +542,8 @@ class tetgenbehavior {
 //                                                                           //
 // 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 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).                            //
+// are basic units for implmenting geometric algorithms.  TetGen uses two 3D //
+// geometric predicates: the orientation and in-sphere tests.                //
 //                                                                           //
 // 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 //
@@ -590,20 +626,15 @@ class tetgenmesh {
     //   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, FACETVERTEX, FREESUBVERTEX, VOLVERTEX,
-                   FREEVOLVERTEX, DEADVERTEX = -32768};
+           FREESEGVERTEX, FREESUBVERTEX, FREEVOLVERTEX, DEADVERTEX = -32768};
  
-    // 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 a subface/subsegment.
+    enum shestype {NSHARP, SHARP};
 
     // 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 UNFLIPABLE, NONCONVEX are unflipable.
-    enum fliptype {T23, T32, T22, T44, UNFLIPABLE, FORBIDDENFACE,
-                   FORBIDDENEDGE, NONCONVEX};
+    //   Types N32, N40 are unflipable.
+    enum fliptype {T23, T32, T22, T44, N32, N40, FORBIDDENFACE, FORBIDDENEDGE};
 
     // Labels that signify the result of triangle-triangle intersection test.
     //   Two triangles are DISJOINT, or adjoint at a vertex SHAREVERTEX, or
@@ -767,7 +798,7 @@ class tetgenmesh {
     // 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 REAL of local feature sizes (optional -p switch);
+    //   - a list of REALs of a user-defined metric tensor (optional);
     //   - 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);
@@ -913,61 +944,6 @@ class tetgenmesh {
       REAL transmat[2][4][4];
     };
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// 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                                  //
@@ -998,12 +974,8 @@ class tetgenmesh {
     //   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
@@ -1196,7 +1168,7 @@ class tetgenmesh {
         bool locate(int pos);
         void *add(void* newitem);
         void *insert(int pos, void* insitem);
-        void *del(void* delitem);
+        void *deletenode(void** delnode);
         void *del(int pos);
         void *getitem();
         void *getnitem(int pos);
@@ -1207,7 +1179,7 @@ class tetgenmesh {
 //                                                                           //
 // Queue data structure.                                                     //
 //                                                                           //
-// A 'queue' is a basically a link.  Following is an image of a queue.       //
+// A 'queue' is basically a link.  Following is an image of a queue.         //
 //              ___________     ___________     ___________                  //
 //   Pop() <-- |_         _|<--|_         _|<--|_         _| <-- Push()      //
 //             |_  Data0  _|   |_  Data1  _|   |_  Data2  _|                 //
@@ -1221,12 +1193,27 @@ class tetgenmesh {
       public:
 
         queue(int bytes, int count = 256) : link(bytes, NULL, count) {}
-        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); }
+        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);
+        }
     };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1287,7 +1274,9 @@ class tetgenmesh {
     //   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];
+    badface *tetquefront[64], *tetquetail[64];
+    int nextnonemptyq[64];
+    int firstnonemptyq, recentq;
 
     // Pointer to a recently visited tetrahedron. Improves point location
     //   if proximate points are inserted sequentially.
@@ -1299,7 +1288,8 @@ class tetgenmesh {
     long hullsize;                        // Number of faces of convex hull.
     long insegments;                            // Number of input segments.
     int steinerleft;               // Number of Steiner points not yet used.
-    int pointlfsindex;   // Index to find the local feature size of a point.
+    int sizeoftensor;                  // Number of REALs per metric tensor.
+    int pointmtrindex;        // Index to find the metric tensor 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.
@@ -1310,6 +1300,7 @@ class tetgenmesh {
     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?
@@ -1319,12 +1310,15 @@ class tetgenmesh {
     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.
@@ -1333,13 +1327,12 @@ class tetgenmesh {
     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, r4count;   // Number of rules performed.
+    long r1count, r2count, r3count;      // Numbers of edge splitting rules.
     long cdtenforcesegpts;              // Number of CDT enforcement points.
     long rejsegpts, rejsubpts, rejtetpts;      // Number of rejected points.
-    long striptetcount, fliptetcount, unimprovecount; // Mesh smooth counts.
-    long smoothcdtsegpt, smoothsegpt, smoothsubpt, smoothvolpt; 
-    long unsmoothcdtsegpt, unsmoothsegpt, unsmoothsubpt, unsmoothvolpt;
+    long optcount[10];          // Numbers of various optimizing operations.
     long flip23s, flip32s, flip22s, flip44s;   // Number of flips performed.
+    REAL tloctime, tfliptime;      // Time (microseconds) of point location.
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
@@ -1383,6 +1376,10 @@ class tetgenmesh {
     //   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];
@@ -1476,7 +1473,7 @@ class tetgenmesh {
     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.
@@ -1484,6 +1481,10 @@ class tetgenmesh {
     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);
@@ -1509,7 +1510,6 @@ class tetgenmesh {
     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,16 +1544,14 @@ class tetgenmesh {
     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);
@@ -1576,6 +1574,7 @@ class tetgenmesh {
     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);
@@ -1611,6 +1610,7 @@ class tetgenmesh {
     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,8 +1635,15 @@ class tetgenmesh {
     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);
@@ -1652,6 +1659,8 @@ class tetgenmesh {
                                      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*);
@@ -1674,8 +1683,6 @@ class tetgenmesh {
     // 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();
 
@@ -1698,7 +1705,7 @@ class tetgenmesh {
                      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.
@@ -1732,6 +1739,8 @@ class tetgenmesh {
     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.
@@ -1791,46 +1800,43 @@ class tetgenmesh {
     void restorepolyhedron(list* oldtetlist);
     bool suppressfacetpoint(face* supsh, list* frontlist, list* misfrontlist,
                             list* ptlist, list* conlist, memorypool* viri,
-                            queue* flipque);
+                            queue* flipque, bool noreloc, bool optflag);
     bool suppresssegpoint(face* supseg, list* spinshlist, list* newsegshlist,
                           list* frontlist, list* misfrontlist, list* ptlist,
-                          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 rotuines.
+                          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);
+
+    // Mesh reconstruction routines.
     long reconstructmesh();
-    bool intettest(point testpt, triface* testtet, REAL eps);
-    void insertaddpoints();
-
+    // Constrained points insertion routines.
+    void insertconstrainedpoints(tetgenio *addio);
     // Background mesh operations.
-    bool interpolatepointsize(point pt, triface* bgmtet, long *scount);
-    void searchpointrecursive(triface *curtet, long *scount);
+    bool p1interpolatebgm(point pt, triface* bgmtet, long *scount);
     void interpolatesizemap();
+    void duplicatebgmesh();
 
     // Delaunay refinement routines.
-    void calclocalfeaturesizes();
-    void marksharpsubsegs(REAL dihedbound);
-    void markskinnysubfaces(REAL anglebound);
-    void enqueuebadtet(triface* tt, REAL key, REAL* cent);
+    void marksharpsegments(REAL sharpangle);
+    void decidefeaturepointsizes();
     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, list* verlist);
-    void splitencseg(point, face*, list*, list*, list*, queue*, bool, bool);
+    void setnewpointsize(point newpt, point e1, point e2);
+    void splitencseg(point, face*, list*, list*, list*,queue*,bool,bool,bool);
     bool tallencsegs(point testpt, int n, list** ceillists);
     bool tallencsubs(point testpt, int n, list** ceillists);
     void tallbadtetrahedrons();
@@ -1839,16 +1845,15 @@ class tetgenmesh {
     void repairbadtets();
     void enforcequality();
 
-    // Mesh Smoothing routines.
+    // Mesh optimization routines.
+    void dumpbadtets();
     bool checktet4ill(triface* testtet, bool enqflag);
-    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();
+    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);
 
     // I/O routines
     void transfernodes();
@@ -1860,8 +1865,10 @@ class tetgenmesh {
     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);
@@ -1873,7 +1880,6 @@ class tetgenmesh {
     void checkmesh();
     void checkshells();
     void checkdelaunay(REAL eps, queue* flipqueue);
-    void checkdegeneracy(REAL eps);
     void checkconforming();
     void algorithmicstatistics();
     void qualitystatistics();
@@ -1893,23 +1899,18 @@ class tetgenmesh {
 //                     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).                                                         //
+// saved to file(s). If 'bgmin' != NULL, it contains a background mesh which //
+// defines a mesh size distruction function.                                 //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, 
-                    tetgenio *bgmesh = NULL);
+                    tetgenio *addin = NULL, tetgenio *bgmin = NULL);
 void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
-                    tetgenio *bgmesh = NULL);
+                    tetgenio *addin = NULL, tetgenio *bgmin = NULL);
 
 #endif // #ifndef tetgenH
-- 
GitLab