diff --git a/Fltk/GUI.cpp b/Fltk/GUI.cpp
index a2115bc8dc39b7618e8169d03a236584deef2af6..eea14c491f21c27de5b9d34ac745fbfd0008bc68 100644
--- a/Fltk/GUI.cpp
+++ b/Fltk/GUI.cpp
@@ -1,4 +1,4 @@
-// $Id: GUI.cpp,v 1.578 2006-12-03 04:00:18 geuzaine Exp $
+// $Id: GUI.cpp,v 1.579 2006-12-03 17:45:37 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -3947,37 +3947,41 @@ void GUI::create_visibility_window()
     vis_group[2] = new Fl_Group(WB, 2 * WB + 2 * BH, width - 2 * WB, height - 4 * WB - 2 * BH, "Interactive");
     vis_group[2]->resizable(NULL);
 
-    Fl_Box *b2 = new Fl_Box(FL_NO_BOX, 2 * WB, 3 * WB + 2 * BH, brw, BH, "Hide with the mouse:");
-    b2->align(FL_ALIGN_INSIDE|FL_ALIGN_LEFT);
+    int ll = width/2 - BH - WB - IW;
 
-    Fl_Button *butt1 = new Fl_Button(2*WB, 3 * WB + 3 * BH, IW, BH, "Elements");
+    Fl_Box *b2 = new Fl_Box(FL_NO_BOX, ll, 3 * WB + 2 * BH, IW, BH, 
+			    "Hide with the mouse:");
+    b2->align(FL_ALIGN_INSIDE|FL_ALIGN_CENTER);
+
+    Fl_Button *butt1 = new Fl_Button(ll, 3 * WB + 3 * BH, IW, BH, "Elements");
     butt1->callback(visibility_interactive_cb, (void *)"hide_elements");
-    Fl_Button *butt2 = new Fl_Button(2*WB, 3 * WB + 4 * BH, IW, BH, "Points");
+    Fl_Button *butt2 = new Fl_Button(ll, 3 * WB + 4 * BH, IW, BH, "Points");
     butt2->callback(visibility_interactive_cb, (void *)"hide_points");
-    Fl_Button *butt3 = new Fl_Button(2*WB, 3 * WB + 5 * BH, IW, BH, "Lines");
+    Fl_Button *butt3 = new Fl_Button(ll, 3 * WB + 5 * BH, IW, BH, "Lines");
     butt3->callback(visibility_interactive_cb, (void *)"hide_lines");
-    Fl_Button *butt4 = new Fl_Button(2*WB, 3 * WB + 6 * BH, IW, BH, "Surfaces");
+    Fl_Button *butt4 = new Fl_Button(ll, 3 * WB + 6 * BH, IW, BH, "Surfaces");
     butt4->callback(visibility_interactive_cb, (void *)"hide_surfaces");
-    Fl_Button *butt5 = new Fl_Button(2*WB, 3 * WB + 7 * BH, IW, BH, "Volumes");
+    Fl_Button *butt5 = new Fl_Button(ll, 3 * WB + 7 * BH, IW, BH, "Volumes");
     butt5->callback(visibility_interactive_cb, (void *)"hide_volumes");
 
-    Fl_Button *butt6 = new Fl_Button(3*WB + IW, 3 * WB + 3 * BH, 2 * BH, 5*BH, "Show\nAll");
+    Fl_Button *butt6 = new Fl_Button(ll + IW + WB, 3 * WB + 3 * BH, 2 * BH, 5*BH, "Show\nAll");
     butt6->callback(visibility_interactive_cb, (void *)"show_all");
 
-    int ww = 4*WB + IW + 2*BH;
+    int ll2 = ll + IW + WB + 2*BH + WB;
 
-    Fl_Box *b12 = new Fl_Box(FL_NO_BOX, ww, 3 * WB + 2 * BH, brw, BH, "Show with the mouse:");
-    b12->align(FL_ALIGN_INSIDE|FL_ALIGN_LEFT);
+    Fl_Box *b12 = new Fl_Box(FL_NO_BOX, ll2, 3 * WB + 2 * BH, IW, BH, 
+			     "Show with the mouse:");
+    b12->align(FL_ALIGN_INSIDE|FL_ALIGN_CENTER);
 
-    Fl_Button *butt11 = new Fl_Button(ww, 3 * WB + 3 * BH, IW, BH, "Elements");
+    Fl_Button *butt11 = new Fl_Button(ll2, 3 * WB + 3 * BH, IW, BH, "Elements");
     butt11->callback(visibility_interactive_cb, (void *)"show_elements");
-    Fl_Button *butt12 = new Fl_Button(ww, 3 * WB + 4 * BH, IW, BH, "Points");
+    Fl_Button *butt12 = new Fl_Button(ll2, 3 * WB + 4 * BH, IW, BH, "Points");
     butt12->callback(visibility_interactive_cb, (void *)"show_points");
-    Fl_Button *butt13 = new Fl_Button(ww, 3 * WB + 5 * BH, IW, BH, "Lines");
+    Fl_Button *butt13 = new Fl_Button(ll2, 3 * WB + 5 * BH, IW, BH, "Lines");
     butt13->callback(visibility_interactive_cb, (void *)"show_lines");
-    Fl_Button *butt14 = new Fl_Button(ww, 3 * WB + 6 * BH, IW, BH, "Surfaces");
+    Fl_Button *butt14 = new Fl_Button(ll2, 3 * WB + 6 * BH, IW, BH, "Surfaces");
     butt14->callback(visibility_interactive_cb, (void *)"show_surfaces");
-    Fl_Button *butt15 = new Fl_Button(ww, 3 * WB + 7 * BH, IW, BH, "Volumes");
+    Fl_Button *butt15 = new Fl_Button(ll2, 3 * WB + 7 * BH, IW, BH, "Volumes");
     butt15->callback(visibility_interactive_cb, (void *)"show_volumes");
     
     vis_group[2]->end();
diff --git a/Geo/gmshFace.cpp b/Geo/gmshFace.cpp
index c614a49208ca48af9fdfafa174b1e9b66dc4b8ac..a4485bbf9f8c70604c5f9edf4ec1128d51b1391e 100644
--- a/Geo/gmshFace.cpp
+++ b/Geo/gmshFace.cpp
@@ -1,4 +1,4 @@
-// $Id: gmshFace.cpp,v 1.29 2006-12-03 03:19:55 geuzaine Exp $
+// $Id: gmshFace.cpp,v 1.30 2006-12-03 17:45:37 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -109,6 +109,9 @@ SVector3 gmshFace::normal(const SPoint2 &param) const
     // We cannot use InterpolateSurface() for plane surfaces since it
     // relies on the mean plane, which does not respect the
     // orientation
+
+    // FIXME: move this test at the end of the MeanPlane computation
+    // routine--and store the correct normal, damn it!
     GPoint p = point(param);
     double n[3] = {meanPlane.a, meanPlane.b, meanPlane.c};
     norme(n);
diff --git a/contrib/Tetgen/LICENSE b/contrib/Tetgen/LICENSE
index 6dd5c8c11e8cbc6eb26452051a714c95aa775496..65e5262522bd3faa6a85ec43002263fc1557455e 100644
--- a/contrib/Tetgen/LICENSE
+++ b/contrib/Tetgen/LICENSE
@@ -27,9 +27,10 @@ For details, see http://tetgen.berlios.de
 
 TetGen
 A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator
-Version 1.3 (Released on June 13, 2004).
+Version 1.4 (Released on January 14, 2006).
 
-Copyright 2002, 2004  Hang Si
+Copyright 2002, 2004, 2005, 2006 
+Hang Si
 Rathausstr. 9, 10178 Berlin, Germany
 si@wias-berlin.de
 
@@ -62,4 +63,4 @@ CLAIM, DAMAGES OR  OTHER LIABILITY, WHETHER IN AN  ACTION OF CONTRACT,
 TORT  OR OTHERWISE, ARISING  FROM, OUT  OF OR  IN CONNECTION  WITH THE
 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
-==============================================================================
+==============================================================================
\ No newline at end of file
diff --git a/contrib/Tetgen/README b/contrib/Tetgen/README
new file mode 100644
index 0000000000000000000000000000000000000000..429553ab848bb8e9a55cc5405fec9b0b9e348a0d
--- /dev/null
+++ b/contrib/Tetgen/README
@@ -0,0 +1,14 @@
+This is TetGen version 1.4.1 (released on July 28, 2006)
+
+Please see the user's manul (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.
+
+Please send bugs/comments to Hang Si <si@wias-berlin.de>
+
+Hang Si
+July 28, 2006
diff --git a/contrib/Tetgen/tetgen.cxx b/contrib/Tetgen/tetgen.cxx
index 13a08e99eaf5190e20f71d5c76d8912f058bfa70..348a256569c9319e6c970e3fff9bbd50fff39f6b 100644
--- a/contrib/Tetgen/tetgen.cxx
+++ b/contrib/Tetgen/tetgen.cxx
@@ -4,10 +4,10 @@
 //                                                                           //
 // A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator         //
 //                                                                           //
-// Version 1.3.4                                                             //
-// June 13, 2005                                                             //
+// Version 1.4                                                               //
+// January 14, 2006                                                          //
 //                                                                           //
-// Copyright 2002, 2004, 2005                                                //
+// Copyright 2002, 2004, 2005, 2006                                          //
 // Hang Si                                                                   //
 // Rathausstr. 9, 10178 Berlin, Germany                                      //
 // si@wias-berlin.de                                                         //
@@ -28,6 +28,21 @@
 
 #include "tetgen.h"
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// terminatetetgen()    Terminate TetGen with a given exit code.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void terminatetetgen(int x)
+{
+#ifdef TETLIBRARY
+  throw x;
+#else
+  exit(x);
+#endif // #ifdef TETLIBRARY
+}
+
 //
 // Begin of class 'tetgenio' implementation
 //
@@ -53,6 +68,7 @@ void tetgenio::initialize()
   pointlist = (REAL *) NULL;
   pointattributelist = (REAL *) NULL;
   addpointlist = (REAL *) NULL;
+  addpointattributelist = (REAL *) NULL;
   pointmarkerlist = (int *) NULL;
   numberofpoints = 0;
   numberofpointattributes = 0;
@@ -67,6 +83,7 @@ void tetgenio::initialize()
   numberoftetrahedronattributes = 0;
 
   trifacelist = (int *) NULL;
+  adjtetlist = (int *) NULL;
   trifacemarkerlist = (int *) NULL;
   numberoftrifaces = 0; 
 
@@ -86,10 +103,8 @@ void tetgenio::initialize()
 
   facetconstraintlist = (REAL *) NULL;
   numberoffacetconstraints = 0;
-
   segmentconstraintlist = (REAL *) NULL;
   numberofsegmentconstraints = 0;
-
   nodeconstraintlist = (REAL *) NULL;
   numberofnodeconstraints = 0;
 
@@ -128,6 +143,9 @@ void tetgenio::deinitialize()
   if (addpointlist != (REAL *) NULL) {
     delete [] addpointlist;
   }
+  if (addpointattributelist != (REAL *) NULL) {
+    delete [] addpointattributelist;
+  }
   if (pointmarkerlist != (int *) NULL) {
     delete [] pointmarkerlist;
   }
@@ -148,6 +166,9 @@ void tetgenio::deinitialize()
   if (trifacelist != (int *) NULL) {
     delete [] trifacelist;
   }
+  if (adjtetlist != (int *) NULL) {
+    delete [] adjtetlist;
+  }
   if (trifacemarkerlist != (int *) NULL) {
     delete [] trifacemarkerlist;
   }
@@ -228,23 +249,23 @@ bool tetgenio::load_node_call(FILE* infile, int markers, char* infilename)
   int i, j;
 
   // Initialize 'pointlist', 'pointattributelist', and 'pointmarkerlist'.
-  pointlist = new REAL[numberofpoints * mesh_dim];
+  pointlist = new REAL[numberofpoints * 3];
   if (pointlist == (REAL *) NULL) {
     printf("Error:  Out of memory.\n");
-    exit(1);
+    terminatetetgen(1);
   }
   if (numberofpointattributes > 0) {
     pointattributelist = new REAL[numberofpoints * numberofpointattributes];
     if (pointattributelist == (REAL *) NULL) {
       printf("Error:  Out of memory.\n");
-      exit(1);
+      terminatetetgen(1);
     }
   }
   if (markers) {
     pointmarkerlist = new int[numberofpoints];
     if (pointmarkerlist == (int *) NULL) {
       printf("Error:  Out of memory.\n");
-      exit(1);
+      terminatetetgen(1);
     }
   }
 
@@ -271,12 +292,16 @@ bool tetgenio::load_node_call(FILE* infile, int markers, char* infilename)
       break;
     }
     y = (REAL) strtod(stringptr, &stringptr);
-    stringptr = findnextnumber(stringptr);
-    if (*stringptr == '\0') {
-      printf("Error:  Point %d has no z coordinate.\n", firstnumber + i);
-      break;
+    if (mesh_dim == 3) {
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  Point %d has no z coordinate.\n", firstnumber + i);
+        break;
+      }
+      z = (REAL) strtod(stringptr, &stringptr);
+    } else {
+      z = 0.0; // mesh_dim == 2;
     }
-    z = (REAL) strtod(stringptr, &stringptr);
     pointlist[index++] = x;
     pointlist[index++] = y;
     pointlist[index++] = z;
@@ -370,13 +395,13 @@ bool tetgenio::load_node(char* filename)
     markers = (int) strtol (stringptr, &stringptr, 0);
   }
 
-  if (mesh_dim != 3) {
-    printf("Error:  load_node() only works for 3D points.\n");
+  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 < 4) {
-    printf("File I/O error:  There should have at least 4 points.\n");
+  if (numberofpoints < (mesh_dim + 1)) {
+    printf("Input error:  TetGen needs at least %d points.\n", mesh_dim + 1);
     fclose(infile);
     return false;
   }
@@ -434,7 +459,7 @@ bool tetgenio::load_addnodes(char* filename)
   addpointlist = new REAL[numberofaddpoints * mesh_dim];
   if (addpointlist == (REAL *) NULL) {
     printf("Error:  Out of memory.\n");
-    exit(1);
+    terminatetetgen(1);
   }
 
   // Read the list of additional points.
@@ -517,10 +542,6 @@ bool tetgenio::load_pbc(char* filename)
   }
   // Initialize 'pbcgrouplist';
   pbcgrouplist = new pbcgroup[numberofpbcgroups];
-  if (pbcgrouplist == (pbcgroup *) NULL) {
-    printf("Error:  Out of memory.\n");
-    exit(1);
-  }
 
   // Read the list of pbc groups.
   for (i = 0; i < numberofpbcgroups; i++) {
@@ -591,8 +612,6 @@ bool tetgenio::load_pbc(char* filename)
 // 'filename' is the filename of the original inputfile without suffix. The  //
 // constraints are found in file 'filename.var'.                             //
 //                                                                           //
-// This routine will be called both in load_poly() and load_tetmesh().       //
-//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 bool tetgenio::load_var(char* filename)
@@ -738,6 +757,77 @@ bool tetgenio::load_var(char* filename)
   return true;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_mtr()    Load a size specification map from file.                    //
+//                                                                           //
+// 'filename' is the filename of the original inputfile without suffix. The  //
+// size map is found in file 'filename.mtr'.                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_mtr(char* filename)
+{
+  FILE *infile;
+  char mtrfilename[FILENAMESIZE];
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  REAL attrib;
+  int attribindex;
+  int i, j;
+
+  strcpy(mtrfilename, filename);
+  strcat(mtrfilename, ".mtr");
+  infile = fopen(mtrfilename, "r");
+  if (infile != (FILE *) NULL) {
+    printf("Opening %s.\n", mtrfilename);
+  } else {
+    // No such file. Return.
+    return false;
+  }
+
+  // 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;
+  }
+
+  // Metric tensors are saved in pointattributelist.
+  if (pointattributelist != (REAL *) NULL) {
+    delete [] pointattributelist;
+    pointattributelist = (REAL *) NULL;
+  }
+  numberofpointattributes = i;
+  // Allocate space for pointattributelist.
+  pointattributelist = new REAL[numberofpoints * numberofpointattributes];
+  if (pointattributelist == (REAL *) NULL) {
+    printf("Error:  Out of memory.\n");
+    terminatetetgen(1);
+  }
+  attribindex = 0;
+  for (i = 0; i < numberofpoints; i++) {
+    // Read metrics.
+    stringptr = readnumberline(inputline, infile, mtrfilename);
+    for (j = 0; j < numberofpointattributes; j++) {
+      // stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  Metric %d is missing value #%d in %s.\n",
+               i + firstnumber, j + 1, mtrfilename);
+        terminatetetgen(1);
+      }
+      attrib = (REAL) strtod(stringptr, &stringptr);
+      pointattributelist[attribindex++] = attrib;
+    }
+  }
+
+  fclose(infile);
+  return true;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // load_poly()    Load a piecewise linear complex from a .poly or .smesh.    //
@@ -851,13 +941,13 @@ bool tetgenio::load_poly(char* filename)
     }
   }
 
-  if (mesh_dim != 3) {
-    printf("Error:  load_poly() only works for 3D points.\n");
+  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 < 4) {
-    printf("File I/O error:  There should have at least 4 points.\n");
+  if (numberofpoints < (mesh_dim + 1)) {
+    printf("Input error:  TetGen needs at least %d points.\n", mesh_dim + 1);
     fclose(infile);
     return false;
   }
@@ -872,76 +962,158 @@ bool tetgenio::load_poly(char* filename)
     fclose(infile);
   }
 
-  // Read number of facets and number of boundary markers.
-  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
-  numberoffacets = (int) strtol (stringptr, &stringptr, 0);
-  if (numberoffacets <= 0) {
-    // No facet list, return.
-    fclose(polyfile);
-    return true;
-  }
-  stringptr = findnextnumber(stringptr);
-  if (*stringptr == '\0') {
-    markers = 0;  // no boundary marker.
-  } else {
-    markers = (int) strtol (stringptr, &stringptr, 0);
-  }
-
-  // Initialize the 'facetlist', 'facetmarkerlist'.
-  facetlist = new facet[numberoffacets];
-  if (markers == 1) {
-    facetmarkerlist = new int[numberoffacets];
-  }
-
   facet *f;
   polygon *p;
 
-  // Read data into 'facetlist', 'facetmarkerlist'.
-  if (smesh == 0) {
-    // Facets are in .poly file format.
-    for (i = 1; i <= numberoffacets; i++) {
-      f = &(facetlist[i - 1]);
-      init(f);
-      f->numberofholes = 0;
-      currentmarker = 0;
-      // Read number of polygons, number of holes, and a boundary marker.
-      stringptr = readnumberline(inputline, polyfile, inpolyfilename);
-      f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
-      stringptr = findnextnumber(stringptr);
-      if (*stringptr != '\0') {
-        f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
+  if (mesh_dim == 3) {
+
+    // Read number of facets and number of boundary markers.
+    stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+    numberoffacets = (int) strtol (stringptr, &stringptr, 0);
+    if (numberoffacets <= 0) {
+      // No facet list, return.
+      fclose(polyfile);
+      return true;
+    }
+    stringptr = findnextnumber(stringptr);
+    if (*stringptr == '\0') {
+      markers = 0;  // no boundary marker.
+    } else {
+      markers = (int) strtol (stringptr, &stringptr, 0);
+    }
+
+    // Initialize the 'facetlist', 'facetmarkerlist'.
+    facetlist = new facet[numberoffacets];
+    if (markers == 1) {
+      facetmarkerlist = new int[numberoffacets];
+    }
+
+    // Read data into 'facetlist', 'facetmarkerlist'.
+    if (smesh == 0) {
+      // Facets are in .poly file format.
+      for (i = 1; i <= numberoffacets; i++) {
+        f = &(facetlist[i - 1]);
+        init(f);
+        f->numberofholes = 0;
+        currentmarker = 0;
+        // Read number of polygons, number of holes, and a boundary marker.
+        stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+        f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr != '\0') {
+          f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
+          if (markers == 1) {
+            stringptr = findnextnumber(stringptr);
+            if (*stringptr != '\0') {
+              currentmarker = (int) strtol(stringptr, &stringptr, 0);
+            }
+          }
+        }
+        // Initialize facetmarker if it needs.
         if (markers == 1) {
-          stringptr = findnextnumber(stringptr);
-          if (*stringptr != '\0') {
-            currentmarker = (int) strtol(stringptr, &stringptr, 0);
-          } 
+          facetmarkerlist[i - 1] = currentmarker; 
+        }
+        // Each facet should has at least one polygon.
+        if (f->numberofpolygons <= 0) {
+          printf("Error:  Wrong number of polygon in %d facet.\n", i);
+          break; 
+        }
+        // Initialize the 'f->polygonlist'.
+        f->polygonlist = new polygon[f->numberofpolygons];
+        // Go through all polygons, read in their vertices.
+        for (j = 1; j <= f->numberofpolygons; j++) {
+          p = &(f->polygonlist[j - 1]);
+          init(p);
+          // Read number of vertices of this polygon.
+          stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+          p->numberofvertices = (int) strtol(stringptr, &stringptr, 0);
+          if (p->numberofvertices < 1) {
+            printf("Error:  Wrong polygon %d in facet %d\n", j, i);
+            break;
+          }
+          // Initialize 'p->vertexlist'.
+          p->vertexlist = new int[p->numberofvertices];
+          // Read all vertices of this polygon.
+          for (k = 1; k <= p->numberofvertices; k++) {
+            stringptr = findnextnumber(stringptr);
+            if (*stringptr == '\0') {
+              // Try to load another non-empty line and continue to read the
+              //   rest of vertices.
+              stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+              if (*stringptr == '\0') {
+                printf("Error: Missing %d endpoints of polygon %d in facet %d",
+                       p->numberofvertices - k, j, i);
+                break;
+              }
+            }
+            p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
+          }
+        } 
+        if (j <= f->numberofpolygons) {
+          // This must be caused by an error. However, there're j - 1
+          //   polygons have been read. Reset the 'f->numberofpolygon'.
+          if (j == 1) {
+            // This is the first polygon.
+            delete [] f->polygonlist;
+          }
+          f->numberofpolygons = j - 1;
+          // No hole will be read even it exists.
+          f->numberofholes = 0;
+          break;
+        }
+        // If this facet has hole pints defined, read them.
+        if (f->numberofholes > 0) {
+          // Initialize 'f->holelist'.
+          f->holelist = new REAL[f->numberofholes * 3];
+          // Read the holes' coordinates.
+          index = 0;
+          for (j = 1; j <= f->numberofholes; j++) {
+            stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+            for (k = 1; k <= 3; k++) {
+              stringptr = findnextnumber(stringptr);
+              if (*stringptr == '\0') {
+                printf("Error:  Hole %d in facet %d has no coordinates", j, i);
+                break;
+              }
+              f->holelist[index++] = (REAL) strtod (stringptr, &stringptr);
+            }
+            if (k <= 3) {
+              // This must be caused by an error.
+              break;
+            }
+          }
+          if (j <= f->numberofholes) {
+            // This must be caused by an error.
+            break;
+          }
         }
-      } 
-      // Initialize facetmarker if it needs.
-      if (markers == 1) {
-        facetmarkerlist[i - 1] = currentmarker; 
       }
-      // Each facet should has at least one polygon.
-      if (f->numberofpolygons <= 0) {
-        printf("Error:  Wrong number of polygon in %d facet.\n", i);
-        break; 
+      if (i <= numberoffacets) {
+        // This must be caused by an error.
+        numberoffacets = i - 1;
+        fclose(polyfile);
+        return false;
       }
-      // Initialize the 'f->polygonlist'.
-      f->polygonlist = new polygon[f->numberofpolygons];
-      // Go through all polygons, read in their vertices.
-      for (j = 1; j <= f->numberofpolygons; j++) {
-        p = &(f->polygonlist[j - 1]);
+    } else { // poly == 0
+      // Read the facets from a .smesh file.
+      for (i = 1; i <= numberoffacets; i++) {
+        f = &(facetlist[i - 1]);
+        init(f);
+        // Initialize 'f->facetlist'. In a .smesh file, each facetlist only
+        //   contains exactly one polygon, no hole.
+        f->numberofpolygons = 1;
+        f->polygonlist = new polygon[f->numberofpolygons];
+        p = &(f->polygonlist[0]);
         init(p);
         // Read number of vertices of this polygon.
-        stringptr = readnumberline(inputline, polyfile, inpolyfilename);
-        p->numberofvertices = (int) strtol(stringptr, &stringptr, 0);
+        stringptr = readnumberline(inputline, polyfile, insmeshfilename);
+        p->numberofvertices = (int) strtol (stringptr, &stringptr, 0);
         if (p->numberofvertices < 1) {
-          printf("Error:  Wrong polygon %d in facet %d\n", j, i);
+          printf("Error:  Wrong number of vertex in facet %d\n", i);
           break;
         }
         // Initialize 'p->vertexlist'.
         p->vertexlist = new int[p->numberofvertices];
-        // Read all vertices of this polygon.
         for (k = 1; k <= p->numberofvertices; k++) {
           stringptr = findnextnumber(stringptr);
           if (*stringptr == '\0') {
@@ -949,223 +1121,196 @@ bool tetgenio::load_poly(char* filename)
             //   rest of vertices.
             stringptr = readnumberline(inputline, polyfile, inpolyfilename);
             if (*stringptr == '\0') {
-              printf("Error:  Missing %d endpoints of polygon %d in facet %d",
-                     p->numberofvertices - k, j, i);
+              printf("Error:  Missing %d endpoints in facet %d",
+                     p->numberofvertices - k, i);
               break;
             }
           }
           p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
         }
-      } 
-      if (j <= f->numberofpolygons) {
-        // This must be caused by an error. However, there're j - 1 polygons
-        //   have been read. Reset the 'f->numberofpolygon'.
-        if (j == 1) {
-          // This is the first polygon.
-          delete [] f->polygonlist;
-        }
-        f->numberofpolygons = j - 1;
-        // No hole will be read even it exists.
-        f->numberofholes = 0;
-        break;
-      }
-      // If this facet has holes pints defined, read them.
-      if (f->numberofholes > 0) {
-        // Initialize 'f->holelist'.
-        f->holelist = new REAL[f->numberofholes * 3];
-        // Read the holes' coordinates.
-        index = 0;
-        for (j = 1; j <= f->numberofholes; j++) {
-          stringptr = readnumberline(inputline, polyfile, inpolyfilename);
-          for (k = 1; k <= 3; k++) {
-            stringptr = findnextnumber(stringptr);
-            if (*stringptr == '\0') {
-              printf("Error:  Hole %d in facet %d has no coordinates", j, i);
-              break;
-            }
-            f->holelist[index++] = (REAL) strtod (stringptr, &stringptr);
-          }
-          if (k <= 3) {
-            // This must be caused by an error.
-            break;
-          }
-        }
-        if (j <= f->numberofholes) {
+        if (k <= p->numberofvertices) {
           // This must be caused by an error.
           break;
         }
+        // Read facet's boundary marker at last.
+        if (markers == 1) {
+          stringptr = findnextnumber(stringptr);
+          if (*stringptr == '\0') {
+            currentmarker = 0;
+          } else {
+            currentmarker = (int) strtol(stringptr, &stringptr, 0);
+          }
+          facetmarkerlist[i - 1] = currentmarker;
+        }
       }
-    } 
-    if (i <= numberoffacets) {
-      // This must be caused by an error.
-      numberoffacets = i - 1;
-      fclose(polyfile);
-      return false;
-    }
-  } else { // poly == 0
-    // Read the facets from a .smesh file.
-    for (i = 1; i <= numberoffacets; i++) {
-      f = &(facetlist[i - 1]);
-      init(f);
-      // Initialize 'f->facetlist'. In a .smesh file, each facetlist only
-      //   contains exactly one polygon, no hole.
-      f->numberofpolygons = 1;
-      f->polygonlist = new polygon[f->numberofpolygons];
-      p = &(f->polygonlist[0]);
-      init(p);
-      // Read number of vertices of this polygon.
-      stringptr = readnumberline(inputline, polyfile, insmeshfilename);
-      p->numberofvertices = (int) strtol (stringptr, &stringptr, 0);
-      if (p->numberofvertices < 1) {
-        printf("Error:  Wrong number of vertex in facet %d\n", i);
-        break;
+      if (i <= numberoffacets) {
+        // This must be caused by an error.
+        numberoffacets = i - 1;
+        fclose(polyfile);
+        return false;
       }
-      // Initialize 'p->vertexlist'.
-      p->vertexlist = new int[p->numberofvertices];
-      for (k = 1; k <= p->numberofvertices; k++) {
+    }
+
+    // Read the hole section.
+    stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+    if (*stringptr != '\0') {
+      numberofholes = (int) strtol (stringptr, &stringptr, 0);
+    } else {
+      numberofholes = 0;
+    }
+    if (numberofholes > 0) {
+      // Initialize 'holelist'.
+      holelist = new REAL[numberofholes * 3];
+      for (i = 0; i < 3 * numberofholes; i += 3) {
+        stringptr = readnumberline(inputline, polyfile, inpolyfilename);
         stringptr = findnextnumber(stringptr);
         if (*stringptr == '\0') {
-          // Try to load another non-empty line and continue to read the
-          //   rest of vertices.
-          stringptr = readnumberline(inputline, polyfile, inpolyfilename);
-          if (*stringptr == '\0') {
-            printf("Error:  Missing %d endpoints in facet %d",
-                   p->numberofvertices - k, i);
-            break;
-          }
+          printf("Error:  Hole %d has no x coord.\n", firstnumber + (i / 3));
+          break;
+        } else {
+          holelist[i] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Hole %d has no y coord.\n", firstnumber + (i / 3));
+          break;
+        } else {
+          holelist[i + 1] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Hole %d has no z coord.\n", firstnumber + (i / 3));
+          break;
+        } else {
+          holelist[i + 2] = (REAL) strtod(stringptr, &stringptr);
         }
-        p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
       }
-      if (k <= p->numberofvertices) {
+      if (i < 3 * numberofholes) {
         // This must be caused by an error.
-        break;
+        fclose(polyfile);
+        return false;
       }
-      // Read facet's boundary marker at last.
-      if (markers == 1) {
+    }
+
+    // Read the region section.  The 'region' section is optional, if we
+    //   don't reach the end-of-file, try read it in.
+    stringptr = readnumberline(inputline, polyfile, NULL);
+    if (stringptr != (char *) NULL && *stringptr != '\0') {
+      numberofregions = (int) strtol (stringptr, &stringptr, 0);
+    } else {
+      numberofregions = 0;
+    }
+    if (numberofregions > 0) {
+      // Initialize 'regionlist'.
+      regionlist = new REAL[numberofregions * 5];
+      index = 0;
+      for (i = 0; i < numberofregions; i++) {
+        stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Region %d has no x coordinate.\n", firstnumber + i);
+          break;
+        } else {
+          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Region %d has no y coordinate.\n", firstnumber + i);
+          break;
+        } else {
+          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Region %d has no z coordinate.\n", firstnumber + i);
+          break;
+        } else {
+          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Region %d has no region attrib.\n", firstnumber + i);
+          break;
+        } else {
+          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
+        }
         stringptr = findnextnumber(stringptr);
         if (*stringptr == '\0') {
-          currentmarker = 0;
+          regionlist[index] = regionlist[index - 1];
         } else {
-          currentmarker = (int) strtol(stringptr, &stringptr, 0);
+          regionlist[index] = (REAL) strtod(stringptr, &stringptr);
         }
-        facetmarkerlist[i - 1] = currentmarker;
+        index++;
+      }
+      if (i < numberofregions) {
+        // This must be caused by an error.
+        fclose(polyfile);
+        return false;
       }
-    } 
-    if (i <= numberoffacets) {
-      // This must be caused by an error.
-      numberoffacets = i - 1;
-      fclose(polyfile);
-      return false;
     }
-  }
 
-  // Read the hole section.
-  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
-  if (*stringptr != '\0') {
-    numberofholes = (int) strtol (stringptr, &stringptr, 0);
   } else {
-    numberofholes = 0;
-  }
-  if (numberofholes > 0) {
-    // Initialize 'holelist'.
-    holelist = new REAL[numberofholes * 3];
-    for (i = 0; i < 3 * numberofholes; i += 3) {
+
+    // Read a PSLG from Triangle's poly file.
+    assert(mesh_dim == 2);
+    // A PSLG is a facet of a PLC.
+    numberoffacets = 1;
+    // Initialize the 'facetlist'.
+    facetlist = new facet[numberoffacets];
+    facetmarkerlist = (int *) NULL; // No facet markers.
+    f = &(facetlist[0]);
+    init(f);
+    // Read number of segments.
+    stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+    // Segments are degenerate polygons.
+    f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
+    if (f->numberofpolygons > 0) {
+      f->polygonlist = new polygon[f->numberofpolygons];
+    }
+    // Go through all segments, read in their vertices.
+    for (j = 0; j < f->numberofpolygons; j++) {
+      p = &(f->polygonlist[j]);
+      init(p);
+      // Read in a segment.
       stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+      stringptr = findnextnumber(stringptr); // Skip its index.
+      p->numberofvertices = 2; // A segment always has two vertices.
+      p->vertexlist = new int[p->numberofvertices];
+      p->vertexlist[0] = (int) strtol (stringptr, &stringptr, 0);
       stringptr = findnextnumber(stringptr);
-      if (*stringptr == '\0') {
-        printf("Error:  Hole %d has no x coord.\n", firstnumber + (i / 3));
-        break;
-      } else {
-        holelist[i] = (REAL) strtod(stringptr, &stringptr);
-      }
-      stringptr = findnextnumber(stringptr);
-      if (*stringptr == '\0') {
-        printf("Error:  Hole %d has no y coord.\n", firstnumber + (i / 3));
-        break;
-      } else {
-        holelist[i + 1] = (REAL) strtod(stringptr, &stringptr);
-      }
-      stringptr = findnextnumber(stringptr);
-      if (*stringptr == '\0') {
-        printf("Error:  Hole %d has no z coord.\n", firstnumber + (i / 3));
-        break;
-      } else {
-        holelist[i + 2] = (REAL) strtod(stringptr, &stringptr);
-      }
+      p->vertexlist[1] = (int) strtol (stringptr, &stringptr, 0);
     }
-    if (i < 3 * numberofholes) {
-      // This must be caused by an error.
-      fclose(polyfile);
-      return false;
-    }
-  }
-
-  // Read the region section.  The 'region' section is optional, if we don't
-  //   reach the end-of-file, try read it in.
-  stringptr = readnumberline(inputline, polyfile, NULL);
-  if (stringptr != (char *) NULL && *stringptr != '\0') {
-    numberofregions = (int) strtol (stringptr, &stringptr, 0);
-  } else {
-    numberofregions = 0;
-  }
-  if (numberofregions > 0) {
-    // Initialize 'regionlist'.
-    regionlist = new REAL[numberofregions * 5];
-    index = 0;
-    for (i = 0; i < numberofregions; i++) {
-      stringptr = readnumberline(inputline, polyfile, inpolyfilename);
-      stringptr = findnextnumber(stringptr);
-      if (*stringptr == '\0') {
-        printf("Error:  Region %d has no x coordinate.\n", firstnumber + i);
-        break;
-      } else {
-        regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
-      }
-      stringptr = findnextnumber(stringptr);
-      if (*stringptr == '\0') {
-        printf("Error:  Region %d has no y coordinate.\n", firstnumber + i);
-        break;
-      } else {
-        regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
-      }
-      stringptr = findnextnumber(stringptr);
-      if (*stringptr == '\0') {
-        printf("Error:  Region %d has no z coordinate.\n", firstnumber + i);
-        break;
-      } else {
-        regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
-      }
-      stringptr = findnextnumber(stringptr);
-      if (*stringptr == '\0') {
-        printf("Error:  Region %d has no region attrib.\n", firstnumber + i);
-        break;
-      } else {
-        regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
-      }
-      stringptr = findnextnumber(stringptr);
-      if (*stringptr == '\0') {
-        regionlist[index] = regionlist[index - 1];
-      } else {
-        regionlist[index] = (REAL) strtod(stringptr, &stringptr);
+    // Read number of holes.
+    stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+    f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
+    if (f->numberofholes > 0) {
+      // Initialize 'f->holelist'.
+      f->holelist = new REAL[f->numberofholes * 3];
+      // Read the holes' coordinates.
+      for (j = 0; j < f->numberofholes; j++) {
+        // Read a 2D hole point.
+        stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+        stringptr = findnextnumber(stringptr); // Skip its index.
+        f->holelist[j * 3] = (REAL) strtod (stringptr, &stringptr);
+        stringptr = findnextnumber(stringptr);
+        f->holelist[j * 3 + 1] = (REAL) strtod (stringptr, &stringptr);
+        f->holelist[j * 3 + 2] = 0.0; // The z-coord.
       }
-      index++;
-    }
-    if (i < numberofregions) {
-      // This must be caused by an error.
-      fclose(polyfile);
-      return false;
     }
+    // The regions are skipped.
+
   }
 
   // End of reading poly/smesh file.
   fclose(polyfile);
 
+  // Try to load a .var file if it exists.
+  load_var(filename);
+  // Try to load a .mtr file if it exists.
+  load_mtr(filename);
   // Try to read a .pbc file if it exists.
   load_pbc(filename);
 
-  // Try to load a .cons file if it exists.
-  load_var(filename);
-
   return true;
 }
 
@@ -1239,12 +1384,10 @@ bool tetgenio::load_off(char* filename)
         if (nverts > 0) {
           numberofpoints = nverts;
           pointlist = new REAL[nverts * 3];
-          assert(pointlist != NULL);
         }
         if (nfaces > 0) {        
           numberoffacets = nfaces;
           facetlist = new tetgenio::facet[nfaces];
-          assert(facetlist);
         }
       }
     } else if (iverts < nverts) {
@@ -1413,7 +1556,6 @@ bool tetgenio::load_ply(char* filename)
               if (nverts > 0) {
                 numberofpoints = nverts;
                 pointlist = new REAL[nverts * 3];
-                assert(pointlist != NULL);
               }
             }
           }
@@ -1434,7 +1576,6 @@ bool tetgenio::load_ply(char* filename)
               if (nfaces > 0) {        
                 numberoffacets = nfaces;
                 facetlist = new tetgenio::facet[nfaces];
-                assert(facetlist);
               }
             }
           }
@@ -1632,7 +1773,6 @@ bool tetgenio::load_stl(char* filename)
   }
   numberofpoints = nverts;
   pointlist = new REAL[nverts * 3];
-  assert(pointlist != NULL);
   for (i = 0; i < nverts; i++) {
     coord = (double *) (* plist)[i];
     iverts = i * 3;
@@ -1644,7 +1784,6 @@ bool tetgenio::load_stl(char* filename)
   nfaces = (int) (nverts / 3);
   numberoffacets = nfaces;
   facetlist = new tetgenio::facet[nfaces];
-  assert(facetlist != NULL);
 
   // Default use '1' as the array starting index.
   firstnumber = 1;
@@ -1692,6 +1831,7 @@ bool tetgenio::load_medit(char* filename)
   char buffer[INPUTLINESIZE];
   char *bufferp, *str;
   double *coord;
+  int dimension = 0;
   int nverts = 0;
   int nfaces = 0;
   int line_count = 0;
@@ -1719,6 +1859,28 @@ bool tetgenio::load_medit(char* filename)
 
   while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
     if (*bufferp == '#') continue;  // A comment line is skipped.
+    if (dimension == 0) {
+      // Find if it is the keyword "Dimension".
+      str = strstr(bufferp, "Dimension");
+      if (!str) str = strstr(bufferp, "dimension");
+      if (!str) str = strstr(bufferp, "DIMENSION");
+      if (str) {
+        // Read the dimensions
+        bufferp = findnextnumber(str); // Skip field "Dimension".
+        if (*bufferp == '\0') {
+          // Read a non-empty line.
+          bufferp = readline(buffer, fp, &line_count);
+        }
+        dimension = (int) strtol(bufferp, &bufferp, 0);
+        if (dimension != 2 && dimension != 3) {
+          printf("Unknown dimension in file on line %d in file %s\n",
+                 line_count, infilename);
+          fclose(fp);
+          return false;
+        }
+        mesh_dim = dimension;
+      }
+    }
     if (nverts == 0) {
       // Find if it is the keyword "Vertices".
       str = strstr(bufferp, "Vertices");
@@ -1736,7 +1898,6 @@ bool tetgenio::load_medit(char* filename)
         if (nverts > 0) {
           numberofpoints = nverts;
           pointlist = new REAL[nverts * 3];
-          assert(pointlist != NULL);
         }
         // Read the follwoing node list.
         for (i = 0; i < nverts; i++) {
@@ -1756,7 +1917,12 @@ bool tetgenio::load_medit(char* filename)
               fclose(fp);
               return false;
             }
-            coord[j] = (REAL) strtod(bufferp, &bufferp);
+            if ((j < 2) || (dimension == 3)) {
+              coord[j] = (REAL) strtod(bufferp, &bufferp);
+            } else {
+              assert((j == 2) && (dimension == 2));
+              coord[j] = 0.0;
+            }
             bufferp = findnextnumber(bufferp);
           }
         }
@@ -1790,9 +1956,7 @@ bool tetgenio::load_medit(char* filename)
         if (nfaces > 0) {        
           numberoffacets = nfaces;
           facetlist = new tetgenio::facet[nfaces];
-          assert(facetlist != NULL);
           facetmarkerlist = new int[nfaces];
-          assert(facetmarkerlist != NULL);
         }
         // Read the following list of faces.
         for (i = 0; i < nfaces; i++) {
@@ -1813,7 +1977,6 @@ bool tetgenio::load_medit(char* filename)
           p->numberofvertices = corners;
           // Allocate memory for face vertices
           p->vertexlist = new int[p->numberofvertices];
-          assert(p->vertexlist != NULL);
           // Read the vertices of the face.
           for (j = 0; j < corners; j++) {
             if (*bufferp == '\0') {
@@ -1968,12 +2131,13 @@ bool tetgenio::load_tetmesh(char* filename)
     fclose(infile);
     return false;
   }
+  fclose(infile);
 
-  // Read the elements from a .ele file.
+  // Read the elements from an .ele file.
   infilename = inelefilename;
-  printf("Opening %s.\n", infilename);
   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);
@@ -2001,7 +2165,7 @@ bool tetgenio::load_tetmesh(char* filename)
       tetrahedronlist = new int[numberoftetrahedra * numberofcorners]; 
       if (tetrahedronlist == (int *) NULL) {
         printf("Error:  Out of memory.\n");
-        exit(1);
+        terminatetetgen(1);
       }
       // Allocate memory for output tetrahedron attributes if necessary.
       if (numberoftetrahedronattributes > 0) {
@@ -2009,7 +2173,7 @@ bool tetgenio::load_tetmesh(char* filename)
                                         numberoftetrahedronattributes];
         if (tetrahedronattributelist == (REAL *) NULL) {
           printf("Error:  Out of memory.\n");
-          exit(1);
+          terminatetetgen(1);
         }
       }
     }
@@ -2024,13 +2188,13 @@ bool tetgenio::load_tetmesh(char* filename)
         if (*stringptr == '\0') {
           printf("Error:  Tetrahedron %d is missing vertex %d in %s.\n",
                  i + firstnumber, j + 1, infilename);
-          exit(1);
+          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);
-          exit(1);
+          terminatetetgen(1);
         }
         tetrahedronlist[index++] = corner;
       }
@@ -2066,13 +2230,13 @@ bool tetgenio::load_tetmesh(char* filename)
       trifacelist = new int[numberoftrifaces * 3];
       if (trifacelist == (int *) NULL) {
         printf("Error:  Out of memory.\n");
-        exit(1);
+        terminatetetgen(1);
       }
       if (markers) {
         trifacemarkerlist = new int[numberoftrifaces * 3];
         if (trifacemarkerlist == (int *) NULL) {
           printf("Error:  Out of memory.\n");
-          exit(1);
+          terminatetetgen(1);
         }
       }
     }
@@ -2086,13 +2250,13 @@ bool tetgenio::load_tetmesh(char* filename)
         if (*stringptr == '\0') {
           printf("Error:  Face %d is missing vertex %d in %s.\n",
                  i + firstnumber, j + 1, infilename);
-          exit(1);
+          terminatetetgen(1);
         }
         corner = (int) strtol(stringptr, &stringptr, 0);
         if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
           printf("Error:  Face %d has an invalid vertex index.\n",
                  i + firstnumber);
-          exit(1);
+          terminatetetgen(1);
         }
         trifacelist[index++] = corner;
       }
@@ -2122,7 +2286,7 @@ bool tetgenio::load_tetmesh(char* filename)
       edgelist = new int[numberofedges * 2];
       if (edgelist == (int *) NULL) {
         printf("Error:  Out of memory.\n");
-        exit(1);
+        terminatetetgen(1);
       }
     }
     // Read the list of faces.
@@ -2135,13 +2299,13 @@ bool tetgenio::load_tetmesh(char* filename)
         if (*stringptr == '\0') {
           printf("Error:  Edge %d is missing vertex %d in %s.\n",
                  i + firstnumber, j + 1, infilename);
-          exit(1);
+          terminatetetgen(1);
         }
         corner = (int) strtol(stringptr, &stringptr, 0);
         if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
           printf("Error:  Edge %d has an invalid vertex index.\n",
                  i + firstnumber);
-          exit(1);
+          terminatetetgen(1);
         }
         edgelist[index++] = corner;
       }
@@ -2166,7 +2330,7 @@ bool tetgenio::load_tetmesh(char* filename)
       tetrahedronvolumelist = new REAL[volelements];
       if (tetrahedronvolumelist == (REAL *) NULL) {
         printf("Error:  Out of memory.\n");
-        exit(1);
+        terminatetetgen(1);
       }
     }
     // Read the list of volume constraints.
@@ -2183,12 +2347,11 @@ bool tetgenio::load_tetmesh(char* filename)
     fclose(infile);
   }
 
+  // Try to load a .mtr file if it exists.
+  load_mtr(filename);
   // Try to read a .pbc file if it exists.
   load_pbc(filename);
 
-  // Try to load a .cons file if it exists.
-  load_var(filename);
-
   return true;
 }
 
@@ -2221,7 +2384,7 @@ void tetgenio::save_nodes(char* filename)
     }
     for (j = 0; j < numberofpointattributes; j++) {
       fprintf(fout, "  %.16g", 
-              pointattributelist[i * numberofpointattributes+j]);
+              pointattributelist[i * numberofpointattributes + j]);
     }
     if (pointmarkerlist != NULL) {
       fprintf(fout, "  %d", pointmarkerlist[i]);
@@ -2287,7 +2450,7 @@ void tetgenio::save_faces(char* filename)
           trifacemarkerlist != NULL ? 1 : 0);
   for (i = 0; i < numberoftrifaces; i++) {
     fprintf(fout, "%d  %5d  %5d  %5d", i + firstnumber, trifacelist[i * 3],
-            trifacelist[i * 3 + 1], trifacelist[i * 3 +2]);
+            trifacelist[i * 3 + 1], trifacelist[i * 3 + 2]);
     if (trifacemarkerlist != NULL) {
       fprintf(fout, "  %d", trifacemarkerlist[i]);
     }
@@ -2539,7 +2702,7 @@ char* tetgenio::readnumberline(char *string, FILE *infile, char *infilename)
     if (result == (char *) NULL) {
       if (infilename != (char *) NULL) {
         printf("  Error:  Unexpected end of file in %s.\n", infilename);
-        exit(1);
+        terminatetetgen(1);
       }
       return result;
     }
@@ -2610,17 +2773,26 @@ tetgenbehavior::tetgenbehavior()
   // Initialize command line switches.
   plc = 0;
   refine = 0;
-  quality = 0; 
+  quality = 0;
+  smooth = 1;
+  metric = 0;
+  bgmesh = 0;
   minratio = 2.0;
   goodratio = 0.0;
   minangle = 20.0;
   goodangle = 0.0;
+  maxdihedral = 170.0;
   varvolume = 0;
   fixedvolume = 0;
   maxvolume = -1.0;
   regionattrib = 0;
   insertaddpoints = 0;
-  detectinter = 0;
+  diagnose = 0;
+  offcenter = 0;
+  conformdel = 0;
+  alpha1 = sqrt(2.0);
+  alpha2 = 0.5;
+  alpha3 = 0.6;
   zeroindex = 0;
   facesout = 0;
   edgesout = 0;
@@ -2629,6 +2801,7 @@ tetgenbehavior::tetgenbehavior()
   gidview = 0;
   geomview = 0;
   order = 1;
+  nojettison = 0;
   nobound = 0;
   nonodewritten = 0;
   noelewritten = 0;
@@ -2637,20 +2810,21 @@ tetgenbehavior::tetgenbehavior()
   nobisect = 0;
   noflip = 0;
   steiner = -1;
-  dofullperturb = 0;
-  dopermute = 0;
-  srandseed = 1;
+  fliprepair = 1;
   nomerge = 0;
   docheck = 0;
   quiet = 0;
   verbose = 0;
+  tol = 0;
   useshelles = 0;
   epsilon = 1.0e-8;
+  epsilon2 = 1.0e-5;
   object = NONE;
   // Initialize strings
   commandline[0] = '\0';
   infilename[0] = '\0';
   outfilename[0] = '\0';
+  bgmeshfilename[0] = '\0';
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -2661,7 +2835,7 @@ tetgenbehavior::tetgenbehavior()
 
 void tetgenbehavior::versioninfo()
 {
-  printf("Version 1.3.4 (Released on June 13, 2005).\n");
+  printf("Version 1.4.1 (July 06, 2006).\n");
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -2672,28 +2846,31 @@ void tetgenbehavior::versioninfo()
 
 void tetgenbehavior::syntax()
 {
-  printf("  tetgen [-pq__a__AriMS__T__dzjo_fengGOBNEFICQVvh] input_file\n");
+  printf("  tetgen [-pq__a__AriMYS__T__dzjo_fengGOJBNEFICQVvh] input_file\n");
   printf("    -p  Tetrahedralizes a piecewise linear complex.\n");
   printf("    -q  Quality mesh generation. A minimum radius-edge ratio may\n");
   printf("        be specified (default 2.0).\n");
   printf("    -a  Applies a maximum tetrahedron volume constraint.\n");
-  printf("    -A  Assigns attributes to identify tetrahedra in certain ");
+  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  Detect intersections of PLC facets.\n");
+  printf("    -d  Diagnoses the validation of the input PLC.\n");
   printf("    -z  Numbers all output items starting from zero.\n");
   printf("    -o2 Generates second-order subparametric elements.\n");
-  printf("    -f  Outputs faces (including non-boundary faces) to .face ");
+  printf("    -P  Outputs triangulated PLC facets to .smesh file.\n");
+  printf("    -f  Outputs all faces (instead of boundary faces) to .face ");
   printf("file.\n");
   printf("    -e  Outputs subsegments to .edge file.\n");
   printf("    -n  Outputs tetrahedra neighbors to .neigh file.\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");
+  printf("    -J  No jettison of unused vertices from output .node file.\n");
   printf("    -B  Suppresses output of boundary information.\n");
   printf("    -N  Suppresses output of .node file.\n");
   printf("    -E  Suppresses output of .ele file.\n");
@@ -2719,7 +2896,7 @@ void tetgenbehavior::usage()
   printf("Triangulator\n");
   versioninfo();
   printf("\n");
-  printf("Copyright 2002, 2004, 2005\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");
@@ -2797,6 +2974,7 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
   int startindex;
   int increment;
   int meshnumber;
+  int Rcount;
   int i, j, k;
   char workstring[1024];
 
@@ -2811,6 +2989,9 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
     strcat(commandline, " ");
   }
   
+  // Rcount used to count the number of '-R' be used.
+  Rcount = 0;
+
   for (i = startindex; i < argc; i++) {
     // Remember the command line switches.
     strcat(commandline, argv[i]);
@@ -2830,6 +3011,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] == 'q') {
         quality = 1;
         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
@@ -2863,11 +3048,11 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
           varvolume = 1;
         }
       } else if (argv[i][j] == 'A') {
-        regionattrib = 1;
+        regionattrib++;
       } else if (argv[i][j] == 'i') {
         insertaddpoints = 1;
       } else if (argv[i][j] == 'd') {
-        detectinter = 1;
+        diagnose = 1;
       } else if (argv[i][j] == 'z') {
         zeroindex = 1;
       } else if (argv[i][j] == 'f') {
@@ -2875,13 +3060,19 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
       } else if (argv[i][j] == 'e') {
         edgesout = 1;
       } else if (argv[i][j] == 'n') {
-        neighout = 1;
+        neighout++;
       } else if (argv[i][j] == 'g') {
         meditview = 1;
       } else if (argv[i][j] == 'G') {
         gidview = 1;
       } else if (argv[i][j] == 'O') {
         geomview = 1;
+      } else if (argv[i][j] == 'M') {
+        nomerge = 1;
+      } else if (argv[i][j] == 'Y') {
+        nobisect++;
+      } else if (argv[i][j] == 'J') {
+        nojettison = 1;
       } else if (argv[i][j] == 'B') {
         nobound = 1;
       } else if (argv[i][j] == 'N') {
@@ -2897,8 +3088,6 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
           j++;
           order = 2;
         }
-      } else if (argv[i][j] == 'Y') {
-        noflip = 1; // nobisect++;
       } else if (argv[i][j] == 'S') {
         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
             (argv[i][j + 1] == '.')) {
@@ -2913,10 +3102,7 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
           workstring[k] = '\0';
           steiner = (int) strtol(workstring, (char **) NULL, 0);
         } 
-      } else if (argv[i][j] == 'P') {
-        dofullperturb = 1;
-        /*
-        dopermute = 1;
+      } else if (argv[i][j] == 's') {
         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
             (argv[i][j + 1] == '.')) {
           k = 0;
@@ -2928,12 +3114,34 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
             k++;
           }
           workstring[k] = '\0';
-          srandseed = (int) strtol(workstring, (char **) NULL, 0);
+          maxdihedral = (REAL) strtod(workstring, (char **) NULL);
+          if (maxdihedral >= 180.0) smooth = 0;
         }
-        */ 
-      } else if (argv[i][j] == 'M') {
-        nomerge = 1;
+      } else if (argv[i][j] == 'R') {
+        Rcount++;
+        if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+            (argv[i][j + 1] == '.')) {
+          k = 0;
+          while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+                 (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
+                 (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
+            j++;
+            workstring[k] = argv[i][j];
+            k++;
+          }
+          workstring[k] = '\0';
+          if (Rcount == 1) {
+            alpha1 = (REAL) strtod(workstring, (char **) NULL);
+          } else if (Rcount == 2) {
+            alpha2 = (REAL) strtod(workstring, (char **) NULL);
+          } else if (Rcount == 3) {
+            alpha3 = (REAL) strtod(workstring, (char **) NULL);
+          } 
+        }
+      } else if (argv[i][j] == 'D') {
+        conformdel++;
       } else if (argv[i][j] == 'T') {
+        tol++;
         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
             (argv[i][j + 1] == '.')) {
           k = 0;
@@ -2945,21 +3153,27 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
             k++;
           }
           workstring[k] = '\0';
-          epsilon = (REAL) strtod(workstring, (char **) NULL);
+          if (tol == 1) {
+            epsilon = (REAL) strtod(workstring, (char **) NULL);
+          } else if (tol == 2) {
+            epsilon2 = (REAL) strtod(workstring, (char **) NULL);
+          }
         } 
       } else if (argv[i][j] == 'C') {
         docheck++;
+      } else if (argv[i][j] == 'X') {
+        fliprepair = 0;
       } else if (argv[i][j] == 'Q') {
         quiet = 1;
       } else if (argv[i][j] == 'V') {
         verbose++;
       } else if (argv[i][j] == 'v') {
         versioninfo();
-        exit(0);
+        terminatetetgen(0);
       } else if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
                  (argv[i][j] == '?')) {
         usage();
-        exit(0);
+        terminatetetgen(0);
       } else {
         printf("Warning:  Unknown switch -%c.\n", argv[i][j]);
       }
@@ -2973,7 +3187,7 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
     if (infilename[0] == '\0') {
       // No input file name. Print the syntax and exit.
       syntax();
-      exit(0);
+      terminatetetgen(0);
     }
     // Recognize the object from file extension if it is available.
     if (!strcmp(&infilename[strlen(infilename) - 5], ".node")) {
@@ -3009,7 +3223,7 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
       refine = 1;
     }
   }
-  plc = plc || detectinter;
+  plc = plc || diagnose;
   useshelles = plc || refine || quality;
   goodratio = minratio;
   goodratio *= goodratio;
@@ -3024,7 +3238,7 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
            "-p, -d, -c, and -I");
     return false;
   }
-  if (detectinter && (quality || insertaddpoints || (order == 2) || neighout
+  if (diagnose && (quality || insertaddpoints || (order == 2) || neighout
       || docheck)) {
     printf("Error:  Switches %s cannot use together with -d.\n",
            "-q, -i, -o2, -n, and -C");
@@ -3077,6 +3291,9 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
     workstring[increment + 2] = '\0';
     sprintf(outfilename, workstring, meshnumber + 1);
   }
+  // Background filename has the form "*.b.ele", "*.b.node", ...
+  strcpy(bgmeshfilename, infilename);
+  strcat(bgmeshfilename, ".b");
 
   return true;
 }
@@ -3168,7 +3385,7 @@ void tetgenmesh::set_compfunc(char* str, int* itbytes, compfunc* pcomp)
   } else {
     // It is an unknown type.
     printf("Error in set_compfunc():  unknown type %s.\n", str);
-    exit(1);
+    terminatetetgen(1);
   }
 }
 
@@ -3185,8 +3402,9 @@ void tetgenmesh::set_compfunc(char* str, int* itbytes, compfunc* pcomp)
 void tetgenmesh::list::
 listinit(int itbytes, compfunc pcomp, int mitems,int exsize)
 {
+#ifdef SELF_CHECK
   assert(itbytes > 0 && mitems > 0 && exsize > 0);
-
+#endif
   itembytes = itbytes;
   comp = pcomp;
   maxitems = mitems;
@@ -3194,7 +3412,7 @@ listinit(int itbytes, compfunc pcomp, int mitems,int exsize)
   base = (char *) malloc(maxitems * itembytes); 
   if (base == (char *) NULL) {
     printf("Error:  Out of memory.\n");
-    exit(1);
+    terminatetetgen(1);
   }
   items = 0;
 }
@@ -3218,7 +3436,7 @@ void* tetgenmesh::list::append(void *appitem)
                                      itembytes);
     if (newbase == (char *) NULL) {
       printf("Error:  Out of memory.\n");
-      exit(1);
+      terminatetetgen(1);
     }
     base = newbase;
     maxitems += expandsize;
@@ -3252,7 +3470,7 @@ void* tetgenmesh::list::insert(int pos, void* insitem)
                                      itembytes);
     if (newbase == (char *) NULL) {
       printf("Error:  Out of memory.\n");
-      exit(1);
+      terminatetetgen(1);
     }
     base = newbase;
     maxitems += expandsize;
@@ -3273,19 +3491,28 @@ void* tetgenmesh::list::insert(int pos, void* insitem)
 //                                                                           //
 // del()    Delete an item at 'pos' (range from 0 to items - 1).             //
 //                                                                           //
-// The space at 'pos' will be overlapped by other items, that is, items lie  //
-// after pos will be moved one space upwords.                                //
+// The space at 'pos' will be overlapped by other item. If 'order' is 1, the //
+// remaining items of the list have the same order as usual, i.e., items lie //
+// after pos will be moved one space upwords. If 'order' is 0, the last item //
+// of the list will be moved up to pos.                                      //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::list::del(int pos)
+void tetgenmesh::list::del(int pos, int order)
 {
-  // If 'pos' is the last itemof the list, nothing need to do.
+  // If 'pos' is the last item of the list, nothing need to do.
   if (pos >= 0 && pos < items - 1) {
-    // Do block move.
-    memmove(base + pos * itembytes,       // dest
-            base + (pos + 1) * itembytes, // src
-            (items - pos - 1) * itembytes);
+    if (order == 1) {
+      // Do block move. 
+      memmove(base + pos * itembytes,       // dest
+              base + (pos + 1) * itembytes, // src
+              (items - pos - 1) * itembytes);
+    } else {
+      // Use the last item to overlap the del item.
+      memcpy(base + pos * itembytes, // item at pos
+             base + (items - 1) * itembytes, // item at last
+             itembytes);
+    }
   }
   if (items > 0) {
     items--;
@@ -3316,24 +3543,6 @@ int tetgenmesh::list::hasitem(void* checkitem)
   return -1;
 }
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// remove()    Remove an item (indicated by its pointer) from the list.      //
-//                                                                           //
-// If the list contains more than one copy of the pointer, only the first    //
-// copy is removed.  The returned value is the index of the removed item.    //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-int  tetgenmesh::list::remove(void* remitem)
-{
-  int pos = hasitem(remitem);
-  if (pos != -1) {
-    del(pos);
-  }
-  return pos;
-} 
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // sort()    Sort the items with respect to a linear order function.         //
@@ -3424,8 +3633,8 @@ poolinit(int bytecount, int itemcount, enum wordtype wtype, int alignment)
   } else {
     alignbytes = wordsize;
   }
-  if (sizeof(void *) > alignbytes) {
-    alignbytes = sizeof(void *);
+  if ((int) sizeof(void *) > alignbytes) {
+    alignbytes = (int) sizeof(void *);
   }
   itemwords = ((bytecount + alignbytes - 1) /  alignbytes)
             * (alignbytes / wordsize);
@@ -3439,7 +3648,7 @@ poolinit(int bytecount, int itemcount, enum wordtype wtype, int alignment)
                                 + alignbytes); 
   if (firstblock == (void **) NULL) {
     printf("Error:  Out of memory.\n");
-    exit(1);
+    terminatetetgen(1);
   }
   // Set the next block pointer to NULL.
   *(firstblock) = (void *) NULL;
@@ -3504,7 +3713,7 @@ void* tetgenmesh::memorypool::alloc()
                                     + alignbytes);
         if (newblock == (void **) NULL) {
           printf("Error:  Out of memory.\n");
-          exit(1);
+          terminatetetgen(1);
         }
         *nowblock = (void *) newblock;
         // The next block pointer is NULL.
@@ -3633,8 +3842,9 @@ void* tetgenmesh::memorypool::traverse()
 
 void tetgenmesh::link::linkinit(int bytecount, compfunc pcomp, int itemcount)
 {
-  assert(bytecount > 0 && itemcount > 0);  
-
+#ifdef SELF_CHECK
+  assert(bytecount > 0 && itemcount > 0);
+#endif
   // Remember the real size of each item.
   linkitembytes = bytecount;
   // Set the linear order function for this link.
@@ -3977,22 +4187,22 @@ int tetgenmesh::va[6] = { 2, 2, 0, 0, 1, 1 };
 //   'ver' as the second index.
 
 int tetgenmesh::locver2org[4][6]  = {
-  0, 1, 1, 2, 2, 0,
-  0, 3, 3, 1, 1, 0,
-  1, 3, 3, 2, 2, 1,
-  2, 3, 3, 0, 0, 2 
+  {0, 1, 1, 2, 2, 0},
+  {0, 3, 3, 1, 1, 0},
+  {1, 3, 3, 2, 2, 1},
+  {2, 3, 3, 0, 0, 2} 
 };
 int tetgenmesh::locver2dest[4][6] = { 
-  1, 0, 2, 1, 0, 2,
-  3, 0, 1, 3, 0, 1,
-  3, 1, 2, 3, 1, 2,
-  3, 2, 0, 3, 2, 0
+  {1, 0, 2, 1, 0, 2},
+  {3, 0, 1, 3, 0, 1},
+  {3, 1, 2, 3, 1, 2},
+  {3, 2, 0, 3, 2, 0}
 };
 int tetgenmesh::locver2apex[4][6] = { 
-  2, 2, 0, 0, 1, 1,
-  1, 1, 0, 0, 3, 3,
-  2, 2, 1, 1, 3, 3,
-  0, 0, 2, 2, 3, 3
+  {2, 2, 0, 0, 1, 1},
+  {1, 1, 0, 0, 3, 3},
+  {2, 2, 1, 1, 3, 3},
+  {0, 0, 2, 2, 3, 3}
 };
 
 // For oppo() primitives, use 'loc' as the index.
@@ -4520,7 +4730,8 @@ inline void tetgenmesh::setpointtype(point pt, enum verttype value) {
   ((int *) (pt))[pointmarkindex + 1] = (int) value;
 }
 
-// These two primitives set and read a pointer to a tetrahedron.
+// These following primitives set and read a pointer to a tetrahedron
+//   a subface/subsegment, a point, or a tet of background mesh.
 
 inline tetgenmesh::tetrahedron tetgenmesh::point2tet(point pt) {
   return ((tetrahedron *) (pt))[point2simindex];
@@ -4530,37 +4741,28 @@ inline void tetgenmesh::setpoint2tet(point pt, tetrahedron value) {
   ((tetrahedron *) (pt))[point2simindex] = value;
 }
 
-// These two primitives set and read a pointer to a subface/subsegment.
-//   Note: they use the same field as the above. Don't use them together.
-
 inline tetgenmesh::shellface tetgenmesh::point2sh(point pt) {
-  return (shellface) ((tetrahedron *) (pt))[point2simindex];
+  return (shellface) ((tetrahedron *) (pt))[point2simindex + 1];
 }
 
 inline void tetgenmesh::setpoint2sh(point pt, shellface value) {
-  ((tetrahedron *) (pt))[point2simindex] = (tetrahedron) value;
+  ((tetrahedron *) (pt))[point2simindex + 1] = (tetrahedron) value;
 }
 
-// These two primitives set and read a pointer to a point. 
-//   Note: they use the same field as the above. Don't use them together.
-
-inline tetgenmesh::point tetgenmesh::point2pt(point pt) {
-  return (point) ((tetrahedron *) (pt))[point2simindex];
+inline tetgenmesh::point tetgenmesh::point2ppt(point pt) {
+  return (point) ((tetrahedron *) (pt))[point2simindex + 2];
 }
 
-inline void tetgenmesh::setpoint2pt(point pt, point value) {
-  ((tetrahedron *) (pt))[point2simindex] = (tetrahedron) value;
+inline void tetgenmesh::setpoint2ppt(point pt, point value) {
+  ((tetrahedron *) (pt))[point2simindex + 2] = (tetrahedron) value;
 }
 
-// These primitives set and read a pointer to its parent point. They're used
-//   only in qulaity conforming Delaunay mesh algorithm.
-
-inline tetgenmesh::point tetgenmesh::point2ppt(point pt) {
-  return (point) ((tetrahedron *) (pt))[point2simindex + 1];
+inline tetgenmesh::tetrahedron tetgenmesh::point2bgmtet(point pt) {
+  return ((tetrahedron *) (pt))[point2simindex + 3];
 }
 
-inline void tetgenmesh::setpoint2ppt(point pt, point value) {
-  ((tetrahedron *) (pt))[point2simindex + 1] = (tetrahedron) value;
+inline void tetgenmesh::setpoint2bgmtet(point pt, tetrahedron value) {
+  ((tetrahedron *) (pt))[point2simindex + 3] = value;
 }
 
 // These primitives set and read a pointer to its pbc point.
@@ -4573,22 +4775,6 @@ inline void tetgenmesh::setpoint2pbcpt(point pt, point value) {
   ((tetrahedron *) (pt))[point2pbcptindex] = (tetrahedron) value;
 }
 
-// These primitives set and read a edge bound of this point.
-
-inline REAL tetgenmesh::edgebound(point pt) {
-  return ((REAL *) (pt))[edgeboundindex];
-}
-
-inline void tetgenmesh::setedgebound(point pt, REAL value) {
-  ((REAL *) (pt))[edgeboundindex] = value;
-}
-
-// Get the pre-calculated lifting point of a facet (specified by its mark).  
-
-inline tetgenmesh::point tetgenmesh::getliftpoint(int facetmark) {
-  return (point) &liftpointarray[(facetmark - 1) * 3];
-}
-
 //
 // End of primitives for points
 //
@@ -4626,7 +4812,12 @@ inline bool tetgenmesh::isdead(face* s) {
 }
 
 // isfacehaspoint() returns TRUE if the 'testpoint' is one of the vertices
-//   of the subface 's'.
+//   of the tetface 't' subface 's'.
+
+inline bool tetgenmesh::isfacehaspoint(triface* t, point testpoint) {
+  return ((org(*t) == testpoint) || (dest(*t) == testpoint) ||
+          (apex(*t) == testpoint));
+}
 
 inline bool tetgenmesh::isfacehaspoint(face* s, point testpoint) {
   return (s->sh[3] == (shellface) testpoint) || 
@@ -4670,7 +4861,8 @@ bool tetgenmesh::getnextface(triface* tface1, triface* tface2)
 
   // 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 (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.
@@ -4774,7 +4966,8 @@ void tetgenmesh::tsspivot(triface* checkedge, face* checkseg)
   hitbdry = 0;
   do {
     tspivot(spintet, parentsh);
-    if (parentsh.sh != dummysh) {
+    // Does spintet have a (non-fake) subface attached? 
+    if (parentsh.sh != dummysh && !isdead(&parentsh)) {
       // Find a subface!
       findedge(&parentsh, org(*checkedge), dest(*checkedge));
       sspivot(parentsh, *checkseg);
@@ -4817,13 +5010,17 @@ void tetgenmesh::sstpivot(face* checkseg, triface* retedge)
 
   // Get the subface which holds the subsegment.
   sdecode(checkseg->sh[0], parentsh);
+#ifdef SELF_CHECK
   assert(parentsh.sh != dummysh);
+#endif
   // Get a tetraheron to which the subface attches.
   stpivot(parentsh, *retedge);
   if (retedge->tet == dummytet) {
     sesymself(parentsh);
     stpivot(parentsh, *retedge);
+#ifdef SELF_CHECK
     assert(retedge->tet != dummytet);
+#endif
   }
   // Correct the edge direction before return.
   findedge(retedge, sorg(*checkseg), sdest(*checkseg));
@@ -4906,7 +5103,7 @@ void tetgenmesh::findedge(triface* tface, point eorg, point edest)
     } else {
       if (org(*tface) == edest) {
         if (dest(*tface) == eorg) {
-          // Edge is found, but need to inverse the direction.
+          // Edge is found, inverse the direction and return.
           esymself(*tface);
           return;
         }
@@ -4914,8 +5111,9 @@ void tetgenmesh::findedge(triface* tface, point eorg, point edest)
     }
     enextself(*tface);
   }
-  // It should not be here.
-  assert(i < 3);
+  // It should never be here.
+  printf("Internalerror in findedge():  Unable to find an edge in tet.\n");
+  internalerror();
 }
 
 void tetgenmesh::findedge(face* sface, point eorg, point edest)
@@ -4931,7 +5129,7 @@ void tetgenmesh::findedge(face* sface, point eorg, point edest)
     } else {
       if (sorg(*sface) == edest) {
         if (sdest(*sface) == eorg) {
-          // Edge is found, but need to inverse the direction.
+          // Edge is found, inverse the direction and return.
           sesymself(*sface);
           return;
         }
@@ -4939,8 +5137,8 @@ void tetgenmesh::findedge(face* sface, point eorg, point edest)
     }
     senextself(*sface);
   }
-  // It should not be here.
-  assert(i < 3);
+  printf("Internalerror in findedge():  Unable to find an edge in subface.\n");
+  internalerror();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -4971,11 +5169,11 @@ void tetgenmesh::findface(triface *fface, point forg, point fdest, point fapex)
   if (!isdead(fface)) {
     if (!findorg(fface, forg)) {
       // 'forg' is not a corner of 'fface', locate it.
-      preciselocate(forg, fface);
+      preciselocate(forg, fface, tetrahedrons->items);
     }
     // It is possible that forg is not found in a non-convex mesh.
     if (org(*fface) == forg) {
-      collinear = finddirection(fface, fdest);
+      collinear = finddirection(fface, fdest, tetrahedrons->items);
       if (collinear == RIGHTCOLLINEAR) {
         // fdest is just the destination.
       } else if (collinear == LEFTCOLLINEAR) {
@@ -5090,14 +5288,17 @@ void tetgenmesh::getonextseg(face* s, face* lseg)
     if (checkseg.sh != dummysh) break;
     // No segment! Go to the neighbor of this subface.
     spivotself(checksh);
+#ifdef SELF_CHECK
     // It should always meet a segment before come back.
     assert(checksh.sh != s->sh);
+#endif
     if (sorg(checksh) != forg) {
       sesymself(checksh);
+#ifdef SELF_CHECK
       assert(sorg(checksh) == forg);
+#endif
     }
   } while (true);
-  assert(checkseg.sh != dummysh);
   if (sorg(checkseg) != forg) sesymself(checkseg);
   *lseg = checkseg;
 }
@@ -5106,9 +5307,9 @@ void tetgenmesh::getonextseg(face* s, face* lseg)
 //                                                                           //
 // getseghasorg()    Get the segment containing the given point.             //
 //                                                                           //
-// On input we know 'dorg' is an endpoint of the segment containing 'sseg'.  //
-// This routine search along 'sseg' for the vertex 'dorg'. On return, 'sseg' //
-// contains 'dorg' as its origin.                                            //
+// 'dorg' is an endpoint of a segment S. 'sseg' is a subsegment of S. This   //
+// routine search a subsegment (along sseg) of S containing dorg. On return, //
+// 'sseg' contains 'dorg' as its origin.                                     //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -5145,8 +5346,9 @@ void tetgenmesh::getseghasorg(face* sseg, point dorg)
     sesym(nextseg, *sseg);
     return;
   }
-  // Should not be here.
-  assert(0);
+  // Should never be here.
+  printf("Internalerror in getseghasorg():  Unable to find the subseg.\n");
+  internalerror();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -5319,13 +5521,13 @@ void tetgenmesh::printsh(face* sface)
     printf(" (queued)");
   }
   if (sapex(*sface) != NULL) {
-    if (shelltype(*sface) == SHARPSUB) {
+    if (shelltype(*sface) == SHARP) {
       printf(" (sharp)");
-    } else if (shelltype(*sface) == SKINNYSUB) {
+    } else if (shelltype(*sface) == SKINNY) {
       printf(" (skinny)");
     }
   } else {
-    if (shelltype(*sface) == SHARPSUB) {
+    if (shelltype(*sface) == SHARP) {
       printf(" (sharp)");
     }
   }
@@ -5446,10 +5648,18 @@ void tetgenmesh::makepoint2tetmap()
   triface tetloop;
   point pointptr;
 
-  if (b->verbose) {
+  if (b->verbose > 0) {
     printf("  Constructing mapping from points to tetrahedra.\n");
   }
 
+  // Initialize the point2tet field of each point.
+  points->traversalinit();
+  pointptr = pointtraverse();
+  while (pointptr != (point) NULL) {
+    setpoint2tet(pointptr, (tetrahedron) NULL);
+    pointptr = pointtraverse();
+  }
+
   tetrahedrons->traversalinit();
   tetloop.tet = tetrahedrontraverse();
   while (tetloop.tet != (tetrahedron *) NULL) {
@@ -5484,7 +5694,7 @@ void tetgenmesh::makeindex2pointmap(point*& idx2verlist)
   point pointloop;
   int idx;
 
-  if (b->verbose) {
+  if (b->verbose > 0) {
     printf("  Constructing mapping from indices to points.\n");
   }
 
@@ -5518,21 +5728,18 @@ void tetgenmesh::makeindex2pointmap(point*& idx2verlist)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-makesegmentmap(int*& idx2seglist, shellface**& segsperverlist)
+void tetgenmesh::makesegmentmap(int*& idx2seglist, shellface**& segsperverlist)
 {
   shellface *shloop;
   int i, j, k;
 
-  if (b->verbose) {
+  if (b->verbose > 0) {
     printf("  Constructing mapping from points to segments.\n");
   }
 
   // Create and initialize 'idx2seglist'.
   idx2seglist = new int[points->items + 1];
-  for (i = 0; i < points->items + 1; i++) {
-    idx2seglist[i] = 0;
-  }
+  for (i = 0; i < points->items + 1; i++) idx2seglist[i] = 0;
 
   // Loop the set of segments once, counter the number of segments sharing
   //   each vertex.
@@ -5599,15 +5806,13 @@ makesubfacemap(int*& idx2facelist, shellface**& facesperverlist)
   shellface *shloop;
   int i, j, k;
 
-  if (b->verbose) {
+  if (b->verbose > 0) {
     printf("  Constructing mapping from points to subfaces.\n");
   }
 
   // Create and initialize 'idx2facelist'.
   idx2facelist = new int[points->items + 1];
-  for (i = 0; i < points->items + 1; i++) {
-    idx2facelist[i] = 0;
-  }
+  for (i = 0; i < points->items + 1; i++) idx2facelist[i] = 0;
 
   // Loop the set of subfaces once, counter the number of subfaces sharing
   //   each vertex.
@@ -5674,15 +5879,13 @@ maketetrahedronmap(int*& idx2tetlist, tetrahedron**& tetsperverlist)
   tetrahedron *tetloop;
   int i, j, k;
 
-  if (b->verbose) {
+  if (b->verbose > 0) {
     printf("  Constructing mapping from points to tetrahedra.\n");
   }
 
   // Create and initialize 'idx2tetlist'.
   idx2tetlist = new int[points->items + 1];
-  for (i = 0; i < points->items + 1; i++) {
-    idx2tetlist[i] = 0;
-  }
+  for (i = 0; i < points->items + 1; i++) idx2tetlist[i] = 0;
 
   // Loop the set of tetrahedra once, counter the number of tetrahedra
   //   sharing each vertex.
@@ -5750,11 +5953,11 @@ inline void tetgenmesh::cross(REAL* v1, REAL* v2, REAL* n)
 }
 
 // initm44() initializes a 4x4 matrix.
-void tetgenmesh::initm44(REAL a00, REAL a01, REAL a02, REAL a03,
-                         REAL a10, REAL a11, REAL a12, REAL a13,
-                         REAL a20, REAL a21, REAL a22, REAL a23,
-                         REAL a30, REAL a31, REAL a32, REAL a33,
-                         REAL M[4][4])
+static void initm44(REAL a00, REAL a01, REAL a02, REAL a03,
+                    REAL a10, REAL a11, REAL a12, REAL a13,
+                    REAL a20, REAL a21, REAL a22, REAL a23,
+                    REAL a30, REAL a31, REAL a32, REAL a33,
+                    REAL M[4][4])
 {
   M[0][0] = a00; M[0][1] = a01; M[0][2] = a02; M[0][3] = a03;
   M[1][0] = a10; M[1][1] = a11; M[1][2] = a12; M[1][3] = a13;
@@ -5763,7 +5966,7 @@ void tetgenmesh::initm44(REAL a00, REAL a01, REAL a02, REAL a03,
 }
 
 // m4xm4() multiplies 2 4x4 matrics:  m1 = m1 * m2.
-void tetgenmesh::m4xm4(REAL m1[4][4], REAL m2[4][4])
+static void m4xm4(REAL m1[4][4], REAL m2[4][4])
 {
   REAL tmp[4];
   int i, j;
@@ -5779,7 +5982,7 @@ void tetgenmesh::m4xm4(REAL m1[4][4], REAL m2[4][4])
 }
 
 // m4xv4() multiplies a 4x4 matrix and 4x1 vector: v2 = m * v1
-void tetgenmesh::m4xv4(REAL v2[4], REAL m[4][4], REAL v1[4])
+static void m4xv4(REAL v2[4], REAL m[4][4], REAL v1[4])
 {
   v2[0] = m[0][0]*v1[0] + m[0][1]*v1[1] + m[0][2]*v1[2] + m[0][3]*v1[3];
   v2[1] = m[1][0]*v1[0] + m[1][1]*v1[1] + m[1][2]*v1[2] + m[1][3]*v1[3];
@@ -5938,8 +6141,8 @@ void tetgenmesh::lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::interresult tetgenmesh::
-edge_vert_col_inter(REAL* A, REAL* B, REAL* P)
+enum tetgenmesh::interresult tetgenmesh::edge_vert_col_inter(REAL* A, REAL* B,
+  REAL* P)
 {
   int i = 0;
   do {
@@ -5980,7 +6183,6 @@ edge_vert_col_inter(REAL* A, REAL* B, REAL* P)
     i++;
   } while (i < 3);
   // Should never be here.
-  assert(i >= 3);
   return DISJOINT;
 }
 
@@ -6002,13 +6204,14 @@ edge_vert_col_inter(REAL* A, REAL* B, REAL* P)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::interresult tetgenmesh:: 
-edge_edge_cop_inter(REAL* A, REAL* B, REAL* P, REAL* Q, REAL* R)
+enum tetgenmesh::interresult tetgenmesh:: edge_edge_cop_inter(REAL* A, REAL* B,
+  REAL* P, REAL* Q, REAL* R)
 {
   REAL s1, s2, s3, s4;
 
+#ifdef SELF_CHECK
   assert(R != NULL);
-  
+#endif
   s1 = orient3d(A, B, R, P);
   s2 = orient3d(A, B, R, Q);
   if (s1 * s2 > 0.0) {
@@ -6059,16 +6262,22 @@ edge_edge_cop_inter(REAL* A, REAL* B, REAL* P, REAL* Q, REAL* R)
       }
       if (abp == SHAREVERTEX || abq == SHAREVERTEX) {
         // either p or q is coincident with a or b.
+#ifdef SELF_CHECK
         // ONLY one case is possible, otherwise, shoule be SHAREEDGE.
         assert(abp ^ abq);
+#endif
         return SHAREVERTEX;
       }
       // The last case. They are disjointed.
+#ifdef SELF_CHECK
       assert((abp == DISJOINT) && (abp == abq && abq == pqa && pqa == pqb));
+#endif
       return DISJOINT;
     } else {
       // p is collinear with ab. Case (1).
+#ifdef SELF_CHECK
       assert(abp == SHAREVERTEX || abp == DISJOINT);
+#endif
       return abp;
     }
   }
@@ -6076,7 +6285,9 @@ edge_edge_cop_inter(REAL* A, REAL* B, REAL* P, REAL* Q, REAL* R)
   if (s2 == 0.0) {
     // q is collinear with ab. Case (1).
     abq = edge_vert_col_inter(A, B, Q);
+#ifdef SELF_CHECK
     assert(abq == SHAREVERTEX || abq == DISJOINT || abq == INTERSECT);
+#endif
     return abq;
   }
 
@@ -6084,20 +6295,28 @@ edge_edge_cop_inter(REAL* A, REAL* B, REAL* P, REAL* Q, REAL* R)
   //   possible that a or b is collinear with pq (ONLY one of a and b).
   if (s3 == 0.0) {
     // a is collinear with pq. Case (3).
+#ifdef SELF_CHECK
     assert(s4 != 0.0);
+#endif
     pqa = edge_vert_col_inter(P, Q, A);
+#ifdef SELF_CHECK
     // This case should have been detected in above.
     assert(pqa != SHAREVERTEX);
     assert(pqa == INTERSECT || pqa == DISJOINT);
+#endif
     return pqa;
   }
   if (s4 == 0.0) {
     // b is collinear with pq. Case (3).
+#ifdef SELF_CHECK
     assert(s3 != 0.0);
+#endif
     pqb = edge_vert_col_inter(P, Q, B);
+#ifdef SELF_CHECK
     // This case should have been detected in above.
     assert(pqb != SHAREVERTEX);
     assert(pqb == INTERSECT || pqb == DISJOINT);
+#endif
     return pqb;
   }
 
@@ -6134,18 +6353,21 @@ edge_edge_cop_inter(REAL* A, REAL* B, REAL* P, REAL* Q, REAL* R)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::interresult tetgenmesh::
-tri_vert_cop_inter(REAL* A, REAL* B, REAL* C, REAL* P, REAL* R)
+enum tetgenmesh::interresult tetgenmesh::tri_vert_cop_inter(REAL* A, REAL* B,
+  REAL* C, REAL* P, REAL* R)
 {
   REAL s1, s2, s3;
   int sign;
 
+#ifdef SELF_CHECK
   assert(R != (REAL *) NULL);
-
+#endif
   // Adjust the orientation of a, b, c and r, so that we can assume that
   //   r is strictly in ABC- (i.e., r is above ABC wrt. right-hand rule).
   s1 = orient3d(A, B, C, R);
+#ifdef SELF_CHECK
   assert(s1 != 0.0);
+#endif
   sign = s1 < 0.0 ? 1 : -1;
 
   // Test starts from here.
@@ -6168,7 +6390,9 @@ tri_vert_cop_inter(REAL* A, REAL* B, REAL* C, REAL* P, REAL* R)
     // p is on ABR.
     if (s2 == 0.0) {
       // p is on BCR.
+#ifdef SELF_CHECK
       assert(s3 > 0.0);
+#endif
       // p is coincident with b.
       return SHAREVERTEX;
     }
@@ -6215,8 +6439,8 @@ tri_vert_cop_inter(REAL* A, REAL* B, REAL* C, REAL* P, REAL* R)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::interresult tetgenmesh::
-tri_edge_cop_inter(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q, REAL* R)
+enum tetgenmesh::interresult tetgenmesh::tri_edge_cop_inter(REAL* A, REAL* B,
+  REAL* C, REAL* P, REAL* Q, REAL* R)
 {
   enum interresult abpq, bcpq, capq;
   enum interresult abcp, abcq;
@@ -6249,17 +6473,23 @@ tri_edge_cop_inter(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q, REAL* R)
   //   to detect whether abc and pq are sharing vertex or disjointed.
   if (abpq == SHAREVERTEX) {
     // p or q is coincident with a or b.
+#ifdef SELF_CHECK
     assert(abcp ^ abcq);
+#endif
     return SHAREVERTEX;
   }
   if (bcpq == SHAREVERTEX) {
     // p or q is coincident with b or c.
+#ifdef SELF_CHECK
     assert(abcp ^ abcq);
+#endif
     return SHAREVERTEX;
   }
   if (capq == SHAREVERTEX) {
     // p or q is coincident with c or a.
+#ifdef SELF_CHECK
     assert(abcp ^ abcq);
+#endif
     return SHAREVERTEX;
   }
 
@@ -6281,9 +6511,8 @@ tri_edge_cop_inter(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q, REAL* R)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::interresult tetgenmesh::
-tri_edge_inter_tail(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q, REAL s1,
-                    REAL s2)
+enum tetgenmesh::interresult tetgenmesh::tri_edge_inter_tail(REAL* A, REAL* B,
+  REAL* C, REAL* P, REAL* Q, REAL s1, REAL s2)
 {
   REAL s3, s4, s5;
   int sign;
@@ -6317,7 +6546,9 @@ tri_edge_inter_tail(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q, REAL s1,
       // q is on ABP.
       if (s4 == 0.0) {
         // q is on BCP (and q must in CAP+).
+#ifdef SELF_CHECK
         assert(s5 > 0.0); 
+#endif
         // pq intersects abc at vertex b.
         return SHAREVERTEX;
       }
@@ -6356,11 +6587,15 @@ tri_edge_inter_tail(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q, REAL s1,
     // Either p or q is coplanar with abc. ONLY one of them is possible.
     if (s1 == 0.0) {
       // p is coplanar with abc, q can be used as reference point.
+#ifdef SELF_CHECK
       assert(s2 != 0.0);
+#endif
       return tri_vert_cop_inter(A, B, C, P, Q);
     } else {
       // q is coplanar with abc, p can be used as reference point.
+#ifdef SELF_CHECK
       assert(s2 == 0.0);
+#endif
       return tri_vert_cop_inter(A, B, C, Q, P);
     }
   }
@@ -6380,7 +6615,9 @@ tri_edge_inter_tail(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q, REAL s1,
   N[1] = az * bx - bz * ax;
   N[2] = ax * by - bx * ay;
   // The normal should not be a zero vector (otherwise, abc are collinear).
+#ifdef SELF_CHECK
   assert((fabs(N[0]) + fabs(N[1]) + fabs(N[2])) > 0.0);
+#endif
   // The reference point R is lifted from A to the normal direction with
   //   a distance d = average edge length of the triangle abc.
   R[0] = N[0] + A[0];
@@ -6392,7 +6629,9 @@ tri_edge_inter_tail(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q, REAL s1,
   if (R[0] == A[0] && R[1] == A[1] && R[2] == A[2]) {
     int i, j;
     for (i = 0; i < 3; i++) {
+#ifdef SELF_CHECK
       assert (R[i] == A[i]);
+#endif
       j = 2;
       do {
         if (N[i] > 0.0) {
@@ -6419,8 +6658,8 @@ tri_edge_inter_tail(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q, REAL s1,
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::interresult tetgenmesh::
-tri_edge_inter(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q)
+enum tetgenmesh::interresult tetgenmesh::tri_edge_inter(REAL* A, REAL* B,
+  REAL* C, REAL* P, REAL* Q)
 {
   REAL s1, s2;
 
@@ -6441,8 +6680,8 @@ tri_edge_inter(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::interresult tetgenmesh::
-tri_tri_inter(REAL* A, REAL* B, REAL* C, REAL* O, REAL* P, REAL* Q)
+enum tetgenmesh::interresult tetgenmesh::tri_tri_inter(REAL* A, REAL* B,
+  REAL* C, REAL* O, REAL* P, REAL* Q)
 {
   REAL s_o, s_p, s_q;
   REAL s_a, s_b, s_c;
@@ -6488,8 +6727,10 @@ tri_tri_inter(REAL* A, REAL* B, REAL* C, REAL* O, REAL* P, REAL* Q)
     // opq are coincident with abc.
     return SHAREFACE;
   }
+#ifdef SELF_CHECK
   // It is only possible either no share edge or one.
   assert(shareedge == 0 || shareedge == 1);
+#endif
 
   // Continue to detect whether opq and abc are intersecting or not.
   enum interresult opqab, opqbc, opqca;
@@ -6510,17 +6751,23 @@ tri_tri_inter(REAL* A, REAL* B, REAL* C, REAL* O, REAL* P, REAL* Q)
   // At this point, two triangles are not intersecting and not coincident.
   //   They may be share an edge, or share a vertex, or disjoint.
   if (abcop == SHAREEDGE) {
+#ifdef SELF_CHECK
     assert(abcpq == SHAREVERTEX && abcqo == SHAREVERTEX);
+#endif
     // op is coincident with an edge of abc.
     return SHAREEDGE;
   }
   if (abcpq == SHAREEDGE) {
+#ifdef SELF_CHECK
     assert(abcop == SHAREVERTEX && abcqo == SHAREVERTEX);
+#endif
     // pq is coincident with an edge of abc.
     return SHAREEDGE;
   }
   if (abcqo == SHAREEDGE) {
+#ifdef SELF_CHECK
     assert(abcop == SHAREVERTEX && abcpq == SHAREVERTEX);
+#endif
     // qo is coincident with an edge of abc.
     return SHAREEDGE;
   }
@@ -6530,16 +6777,22 @@ tri_tri_inter(REAL* A, REAL* B, REAL* C, REAL* O, REAL* P, REAL* Q)
     // o or p is coincident with a vertex of abc.
     if (abcpq == SHAREVERTEX) {
       // p is the coincident vertex.
+#ifdef SELF_CHECK
       assert(abcqo != SHAREVERTEX);
+#endif
     } else {
       // o is the coincident vertex.
+#ifdef SELF_CHECK
       assert(abcqo == SHAREVERTEX);
+#endif
     }
     return SHAREVERTEX;
   }
   if (abcpq == SHAREVERTEX) {
     // q is the coincident vertex.
+#ifdef SELF_CHECK
     assert(abcqo == SHAREVERTEX);
+#endif
     return SHAREVERTEX;
   }
 
@@ -6547,6 +6800,67 @@ tri_tri_inter(REAL* A, REAL* B, REAL* C, REAL* O, REAL* P, REAL* Q)
   return DISJOINT;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insphere_sos()    Insphere test with symbolic perturbation.               //
+//                                                                           //
+// The input points a, b, c, and d should be non-coplanar. They must be ord- //
+// ered so that they have a positive orientation (as defined by orient3d()), //
+// or the sign of the result will be reversed.                               //
+//                                                                           //
+// Return a positive value if the point e lies inside the circumsphere of a, //
+// b, c, and d; a negative value if it lies outside.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL tetgenmesh::insphere_sos(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe,
+  int ia, int ib, int ic, int id, int ie)
+{
+  REAL det;
+
+  det = insphere(pa, pb, pc, pd, pe);
+  if (det != 0.0) {
+    return det;
+  }
+  
+  // det = 0.0, use symbolic perturbation.
+  REAL *p[5], *tmpp;
+  REAL sign, det_c, det_d;
+  int idx[5], perm, tmp; 
+  int n, i, j; 
+
+  p[0] = pa; idx[0] = ia;
+  p[1] = pb; idx[1] = ib;
+  p[2] = pc; idx[2] = ic;
+  p[3] = pd; idx[3] = id;
+  p[4] = pe; idx[4] = ie;
+
+  // Bubble sort the points by the increasing order of the indices.
+  n = 5;
+  perm = 0; // The number of total swaps.
+  for (i = 0; i < n - 1; i++) {
+    for (j = 0; j < n - 1 - i; j++) {
+      if (idx[j + 1] < idx[j]) {  // compare the two neighbors.
+        tmp = idx[j];         // swap idx[j] and idx[j + 1]
+        idx[j] = idx[j + 1];
+        idx[j + 1] = tmp;
+        tmpp = p[j];         // swap p[j] and p[j + 1]
+        p[j] = p[j + 1];
+        p[j + 1] = tmpp;
+        perm++;
+      }
+    }
+  }
+
+  sign = (perm % 2 == 0) ? 1.0 : -1.0; 
+  det_c = orient3d(p[1], p[2], p[3], p[4]); // orient3d(b, c, d, e)
+  if (det_c != 0.0) {
+    return sign * det_c;
+  }
+  det_d = orient3d(p[0], p[2], p[3], p[4]); // orient3d(a, c, d, e)
+  return -sign * det_d;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // iscollinear()    Check if three points are approximately collinear.       //
@@ -6564,6 +6878,10 @@ bool tetgenmesh::iscollinear(REAL* A, REAL* B, REAL* C, REAL eps)
   REAL Lv, Lw, dd;
   REAL d, q;
 
+  // Limit of two closed points.
+  q = longest * eps;
+  q *= q;
+
   abx = A[0] - B[0];
   aby = A[1] - B[1];
   abz = A[2] - B[2];
@@ -6571,7 +6889,11 @@ bool tetgenmesh::iscollinear(REAL* A, REAL* B, REAL* C, REAL eps)
   acy = A[1] - C[1];
   acz = A[2] - C[2];
   Lv = abx * abx + aby * aby + abz * abz;
+  // Is AB (nearly) indentical?
+  if (Lv < q) return true;
   Lw = acx * acx + acy * acy + acz * acz;
+  // Is AC (nearly) indentical?
+  if (Lw < q) return true;
   dd = abx * acx + aby * acy + abz * acz;
   
   d = (dd * dd) / (Lv * Lw);
@@ -6598,6 +6920,8 @@ iscoplanar(REAL* k, REAL* l, REAL* m, REAL* n, REAL vol6, REAL eps)
   REAL L, q;
   REAL x, y, z;  
 
+  if (vol6 == 0.0) return true;
+
   x = k[0] - l[0];
   y = k[1] - l[1];
   z = k[2] - l[2];
@@ -6622,7 +6946,9 @@ iscoplanar(REAL* k, REAL* l, REAL* m, REAL* n, REAL vol6, REAL eps)
   y = m[1] - n[1];
   z = m[2] - n[2];
   L += sqrt(x * x + y * y + z * z);
+#ifdef SELF_CHECK
   assert(L > 0.0);
+#endif
   L /= 6.0;
   q = fabs(vol6) / (L * L * L);
   
@@ -6656,7 +6982,9 @@ iscospheric(REAL* k, REAL* l, REAL* m, REAL* n, REAL* o, REAL vol24, REAL eps)
   L += distance(l, o);
   L += distance(m, o);
   L += distance(n, o);
+#ifdef SELF_CHECK
   assert(L > 0.0);
+#endif
   L /= 10.0;
   q = fabs(vol24) / (L * L * L * L);
 
@@ -6706,7 +7034,9 @@ REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2)
   v2[2] = p[2] - e1[2];
 
   len = sqrt(dot(v1, v1));
+#ifdef SELF_CHECK
   assert(len != 0.0);
+#endif
   v1[0] /= len;
   v1[1] /= len;
   v1[2] /= len;
@@ -6715,6 +7045,20 @@ REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2)
   return sqrt(dot(v2, v2) - l_p * l_p);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// shortdistance()    Returns the shortest distance from point p to a face.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2, REAL* e3)
+{
+  REAL prj[3];
+
+  projpt2face(p, e1, e2, e3, prj);
+  return distance(p, prj);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // interiorangle()    Return the interior angle (0 - 2 * PI) between vectors //
@@ -6744,7 +7088,9 @@ REAL tetgenmesh::interiorangle(REAL* o, REAL* p1, REAL* p2, REAL* n)
   len1 = sqrt(dot(v1, v1));
   len2 = sqrt(dot(v2, v2));
   lenlen = len1 * len2;
+#ifdef SELF_CHECK
   assert(lenlen != 0.0);
+#endif
   costheta = dot(v1, v2) / lenlen;
   if (costheta > 1.0) {
     costheta = 1.0; // Roundoff. 
@@ -6786,7 +7132,9 @@ void tetgenmesh::projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj)
   v2[2] = p[2] - e1[2];
 
   len = sqrt(dot(v1, v1));
+#ifdef SELF_CHECK
   assert(len != 0.0);
+#endif
   v1[0] /= len;
   v1[1] /= len;
   v1[2] /= len;
@@ -6810,7 +7158,9 @@ void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj)
 
   // Get the unit face normal.
   facenormal(f1, f2, f3, fnormal, &len);
+#ifdef SELF_CHECK
   assert(len > 0.0);
+#endif
   fnormal[0] /= len;
   fnormal[1] /= len;
   fnormal[2] /= len;
@@ -6820,7 +7170,6 @@ void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj)
   v1[2] = p[2] - f1[2];
   // Get the project distance.
   dist = dot(fnormal, v1);
-  assert(fabs(dist) >= b->epsilon);
   
   // Get the project point.
   prj[0] = p[0] - dist * fnormal[0];
@@ -6934,62 +7283,86 @@ REAL tetgenmesh::facedihedral(REAL* pa, REAL* pb, REAL* pc1, REAL* pc2)
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// tetalldihedral()    Get all(six) dihedral angles in tetrahedron formed by //
-//                     vertices a, b, c and d. Return by array adDihed[6].   //
+// tetalldihedral()    Get all (six) dihedral angles of a tet.               //
 //                                                                           //
-// The order in which the dihedrals are assigned matters for computation of  //
-// solid angles. The way they're currently set up, combining them as (0,1,2),//
-// (0,3,4), (1,3,5), (2,4,5) gives (in order) solid angles at vertices a, b, //
-// c and d.                                                                  //
+// The tet is given by its four corners a, b, c, and d. If 'cosdd' is not    //
+// NULL, it returns the cosines of the 6 dihedral angles, the corresponding  //
+// edges are: ab, bc, ca, ad, bd, and cd. If 'cosmaxd' (or 'cosmind') is not //
+// NULL, it returns the cosine of the maximal (or minimal) dihedral angle.   //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-tetalldihedral(point pa, point pb, point pc, point pd, REAL dihed[6])
+void tetgenmesh::tetalldihedral(point pa, point pb, point pc, point pd,
+  REAL* cosdd, REAL* cosmaxd, REAL* cosmind)
 {
-  REAL n0[3], n1[3], n2[3], n3[3];
-  REAL n0len, n1len, n2len, n3len;
-  REAL dotp;
-  
-  facenormal(pc, pb, pd, n0, &n0len);
-  facenormal(pa, pc, pd, n1, &n1len);
-  facenormal(pb, pa, pd, n2, &n2len);
-  facenormal(pa, pb, pc, n3, &n3len);
-  
-  n0[0] /= n0len; n0[1] /= n0len; n0[2] /= n0len;
-  n1[0] /= n1len; n1[1] /= n1len; n1[2] /= n1len;
-  n2[0] /= n2len; n2[1] /= n2len; n2[2] /= n2len;
-  n3[0] /= n3len; n3[1] /= n3len; n3[2] /= n3len;
-
-  dotp = -dot(n0, n1);
-  if (dotp > 1.) dotp = 1.;
-  else if (dotp < -1.) dotp = -1.;
-  dihed[5] = acos(dotp); // Edge CD
-
-  dotp = -dot(n0, n2);
-  if (dotp > 1.) dotp = 1.;
-  else if (dotp < -1.) dotp = -1.;
-  dihed[4] = acos(dotp); // Edge BD
-
-  dotp = -dot(n0, n3);
-  if (dotp > 1.) dotp = 1.;
-  else if (dotp < -1.) dotp = -1.;
-  dihed[3] = acos(dotp); // Edge BC
+  REAL N[4][3], cosd, len;
+  int f1, f2, i, j;
 
-  dotp = -dot(n1, n2);
-  if (dotp > 1.) dotp = 1.;
-  else if (dotp < -1.) dotp = -1.;
-  dihed[2] = acos(dotp); // Edge AD
-
-  dotp = -dot(n1, n3);
-  if (dotp > 1.) dotp = 1.;
-  else if (dotp < -1.) dotp = -1.;
-  dihed[1] = acos(dotp); // Edge AC
+  // Get four normals of faces of the tet.
+  tetallnormal(pa, pb, pc, pd, N, NULL);
+  // Normalize the normals.
+  for (i = 0; i < 4; i++) {
+    len = sqrt(dot(N[i], N[i]));
+    if (len != 0.0) {
+      for (j = 0; j < 3; j++) N[i][j] /= len;
+    }
+  }
 
-  dotp = -dot(n2, n3);
-  if (dotp > 1.) dotp = 1.;
-  else if (dotp < -1.) dotp = -1.;
-  dihed[0] = acos(dotp); // Edge AB
+  for (i = 0; i < 6; i++) {
+    switch (i) {
+    case 0: f1 = 2; f2 = 3; break; // edge ab.
+    case 1: f1 = 0; f2 = 3; break; // edge bc.
+    case 2: f1 = 1; f2 = 3; break; // edge ca.
+    case 3: f1 = 1; f2 = 2; break; // edge ad.
+    case 4: f1 = 2; f2 = 0; break; // edge bd.
+    case 5: f1 = 0; f2 = 1; break; // edge cd.
+    }
+    cosd = -dot(N[f1], N[f2]);
+    if (cosdd) cosdd[i] = cosd;
+    if (i == 0) {
+      if (cosmaxd) *cosmaxd = cosd;
+      if (cosmind) *cosmind = cosd;
+    } else {
+      if (cosmaxd) *cosmaxd = cosd < *cosmaxd ? cosd : *cosmaxd;
+      if (cosmind) *cosmind = cosd > *cosmind ? cosd : *cosmind;
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetallnormal()    Get the in-noramls of the four faces of a given tet.    //
+//                                                                           //
+// Let tet be abcd. N[4][3] returns the four normals, which are: N[0] cbd,   //
+// N[1] acd, N[2] bad, N[3] abc. These normals are unnormalized.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::tetallnormal(point pa, point pb, point pc, point pd,
+  REAL N[4][3], REAL* volume)
+{
+  REAL A[4][4], rhs[4], D;
+  int indx[4];
+  int i, j;
+
+  // get the entries of A[3][3].
+  for (i = 0; i < 3; i++) A[0][i] = pa[i] - pd[i];  // d->a vec
+  for (i = 0; i < 3; i++) A[1][i] = pb[i] - pd[i];  // d->b vec
+  for (i = 0; i < 3; i++) A[2][i] = pc[i] - pd[i];  // d->c vec
+  // Compute the inverse of matrix A, to get 3 normals of the 4 faces.
+  lu_decmp(A, 3, indx, &D, 0);     // Decompose the matrix just once.
+  if (volume != NULL) {
+    // Get the volume of the tet.
+    *volume = fabs((A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2])) / 6.0;
+  }
+  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];
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -7078,42 +7451,18 @@ circumsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* cent, REAL* radius)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-inscribedsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* cent, 
-                REAL* radius)
+void tetgenmesh::inscribedsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd,
+  REAL* cent, REAL* radius)
 {
-  REAL A[4][4], rhs[4], D;
-  REAL N[3][4], H[4];  // Normals (colume vectors) and heights of each face.
+  REAL N[4][3], H[4]; // Normals (colume vectors) and heights of each face.
   REAL rd;
-  int indx[4], i, j;  
-
-  // Compute the normals of 4 faces.
-  A[0][0] = pa[0] - pd[0];
-  A[0][1] = pa[1] - pd[1];
-  A[0][2] = pa[2] - pd[2];
-  A[1][0] = pb[0] - pd[0];
-  A[1][1] = pb[1] - pd[1];
-  A[1][2] = pb[2] - pd[2];
-  A[2][0] = pc[0] - pd[0];
-  A[2][1] = pc[1] - pd[1];
-  A[2][2] = pc[2] - pd[2];
-  // Compute inverse of matrix A, to get the 3 normals of 4 faces.
-  lu_decmp(A, 3, indx, &D, 0);     // Decompose the matrix just once.
-  for (j = 0; j < 3; j++) {
-    for (i = 0; i < 3; i++) rhs[i] = 0.0;
-    rhs[j] = -1.0;
-    lu_solve(A, 3, indx, rhs, 0);
-    for (i = 0; i < 3; i++) N[i][j] = rhs[i];
-  }
-  // Compute the last normal by summing 3 computed vectors, because sum over 
-  //   a closed sufrace is 0.
-  N[0][3] = - N[0][0] - N[0][1] - N[0][2];
-  N[1][3] = - N[1][0] - N[1][1] - N[1][2];
-  N[2][3] = - N[2][0] - N[2][1] - N[2][2];
-  // Compute the length of  normals.
+  int i;  
+
+  // Get the all normals of the tet.
+  tetallnormal(pa, pb, pc, pd, N, NULL);
   for (i = 0; i < 4; i++) {
     // H[i] is the inverse of height of its corresponding face.
-    H[i] = sqrt(N[0][i] * N[0][i] + N[1][i] * N[1][i] + N[2][i] * N[2][i]);
+    H[i] = sqrt(dot(N[i], N[i]));
   }
   // Compute the radius use eq. (1).
   rd = 1.0 / (H[0] + H[1] + H[2] + H[3]);
@@ -7289,7 +7638,6 @@ void tetgenmesh::spherelineint(REAL* p1, REAL* p2, REAL* C, REAL R, REAL p[7])
     p[2] = y1 + mu * (y2 - y1);
     p[3] = z1 + mu * (z2 - z1);
   } else {
-    assert(i > 0.0);
     // two intersections
     p[0] = 2.0;
     // first intersection
@@ -7307,14 +7655,13 @@ void tetgenmesh::spherelineint(REAL* p1, REAL* p2, REAL* C, REAL R, REAL p[7])
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// linelineint()    Calculate The shortest line between two lines in 3D.     //
+// linelineint()    Calculate the shortest line between two lines in 3D.     //
 //                                                                           //
 // Two 3D lines generally don't intersect at a point, they may be parallel ( //
-// no intersections), or they may be coincident (infinite intersections) but //
-// most often only their projection onto a plane intersect.  When they don't //
-// exactly intersect at a point they can be connected by a line segment, the //
-// shortest line segment is unique and is often considered to be their inter-//
-// section in 3D.                                                            //
+// no intersections), or coincident (infinite intersections) but most often  //
+// only their projections onto a plane intersect. If they don't exactly int- //
+// ersect at a point they can be connected by a line segment, the shortest   //
+// segment is unique and is often considered to be their intersection in 3D. //
 //                                                                           //
 // The following code are adapted from: http://astronomy.swin.edu.au/pbourke //
 // /geometry/lineline3d. Paul Bourke pbourke@swin.edu.au                     //
@@ -7376,6 +7723,52 @@ void tetgenmesh::linelineint(REAL *p1,REAL *p2, REAL *p3, REAL *p4, REAL p[7])
   p[6] = p3[2] + mub * p43[2];
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// planelineint()    Calculate the intersection of a line and a plane.       //
+//                                                                           //
+// The equation of a plane (points P are on the plane with normal N and P3   //
+// on the plane) can be written as: N dot (P - P3) = 0. The equation of the  //
+// line (points P on the line passing through P1 and P2) can be written as:  //
+// P = P1 + u (P2 - P1). The intersection of these two occurs when:          //
+//   N dot (P1 + u (P2 - P1)) = N dot P3.                                    //
+// Solving for u gives:                                                      //
+//         N dot (P3 - P1)                                                   //
+//   u = ------------------.                                                 //
+//         N dot (P2 - P1)                                                   //
+// If the denominator is 0 then N (the normal to the plane) is perpendicular //
+// to the line.  Thus the line is either parallel to the plane and there are //
+// no solutions or the line is on the plane in which case there are an infi- //
+// nite number of solutions.                                                 //
+//                                                                           //
+// The plane is given by three points pa, pb, and pc, e1 and e2 defines the  //
+// line. If u is non-zero, The intersection point (if exists) returns in ip. //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::planelineint(REAL* pa, REAL* pb, REAL* pc, REAL* e1, REAL* e2,
+  REAL* ip, REAL* u)
+{
+  REAL n[3], det, det1;
+
+  // Calculate N.
+  facenormal(pa, pb, pc, n, NULL);
+  // Calculate N dot (e2 - e1).
+  det = n[0] * (e2[0] - e1[0]) + n[1] * (e2[1] - e1[1])
+      + n[2] * (e2[2] - e1[2]);
+  if (det != 0.0) {
+    // Calculate N dot (pa - e1)
+    det1 = n[0] * (pa[0] - e1[0]) + n[1] * (pa[1] - e1[1])
+         + n[2] * (pa[2] - e1[2]);
+    *u = det1 / det;
+    ip[0] = e1[0] + *u * (e2[0] - e1[0]);
+    ip[1] = e1[1] + *u * (e2[1] - e1[1]);
+    ip[2] = e1[2] + *u * (e2[2] - e1[2]);
+  } else {
+    *u = 0.0;
+  }
+}
+
 //
 // End of Geometric quantities calculators
 //
@@ -7494,33 +7887,42 @@ void tetgenmesh::initializepools()
     checkpbcs = 1;
   }
   // Default varconstraint = 0;
-  if (b->quality && (in->nodeconstraintlist || in->segmentconstraintlist ||
-                     in->facetconstraintlist)) {
+  if (in->segmentconstraintlist || in->facetconstraintlist) {
     varconstraint = 1;
   }
 
-  // The index within each point at which the constraint is found, where the
-  //   index is measured in REALs.
-  edgeboundindex = 3 + in->numberofpointattributes;
-  // The index within each point at which a element pointer is found. Ensure
-  //   the index is aligned to a sizeof(tetrahedron)-byte address.
-  point2simindex = ((edgeboundindex + varconstraint) * sizeof(REAL) +
-                    sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
+  // The index within each point at which its local feature size is found.
+  //   It is saved directly after the list of point attributes.
+  if (b->bgmesh && (bgm != (tetgenmesh *) NULL)) {
+    // A background mesh is in use. That point attributes should be the
+    //   same as that of the background mesh.
+    pointlfsindex = 3 + bgm->in->numberofpointattributes; 
+  } else {
+    pointlfsindex = 3 + in->numberofpointattributes; 
+  }
+  // The index within each point at which a element pointer is found, where
+  //   the index is measured in pointers. Ensure the index is aligned to a
+  //   sizeof(tetrahedron)-byte address.
+  point2simindex = ((pointlfsindex + b->quality) * sizeof(REAL) 
+                 + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
   if (b->plc || b->refine) {
-    // Increase the point size by one pointer points to a simplex, which
-    //   may be one of the followings:
-    //   - a tetrahedron containing it, read by point2tet();
-    //   - a subface containing it, read by point2sh();
-    //   - a (sharp) subsegment it relates, read by point2sh();
-    //   - a (duplicated) point of it, read by point2pt();
-    //   Optionally, increase the point size one pointer points another
-    //   point (its parent, read by point2ppt()) when b->quality == 1.
-    pointsize = (point2simindex + 1 + b->quality) * sizeof(tetrahedron);
+    // 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.
+      pointsize = (point2simindex + 4) * sizeof(tetrahedron);
+    }
     // The index within each point at which a pbc point is found.
-    point2pbcptindex = (pointsize + sizeof(int) - 1) / sizeof(int);
-    // Increase one pointer points to another point (its corresponding pbc
-    //   point, read by point2pbcpt()) when checkpbcs == 1.
-    pointsize = (point2pbcptindex + checkpbcs) * sizeof(int);
+    point2pbcptindex = (pointsize + sizeof(tetrahedron) - 1)
+                     / sizeof(tetrahedron);
+    if (checkpbcs) {
+      // Increase the size by one pointer to a corresponding pbc point,
+      //   read by point2pbcpt().
+      pointsize = (point2pbcptindex + 1) * sizeof(tetrahedron);
+    }
   } else {
     pointsize = point2simindex * sizeof(tetrahedron);
   }
@@ -7547,7 +7949,7 @@ void tetgenmesh::initializepools()
   //   found, where the index is measured in REALs.  Note that if the
   //   `b->regionattrib' flag is set, an additional attribute will be added.
   volumeboundindex = elemattribindex + in->numberoftetrahedronattributes
-                   + b->regionattrib;
+                   + (b->regionattrib > 0);
   // If element attributes or an constraint are needed, increase the number
   //   of bytes occupied by an element.
   if (b->varvolume) {
@@ -7555,18 +7957,17 @@ void tetgenmesh::initializepools()
   } else if (in->numberoftetrahedronattributes + b->regionattrib > 0) {
     elesize = volumeboundindex * sizeof(REAL);
   }
-  // If the high order elements are required (-o2 switch is used), an
-  //   additional pointer pointed to the list of extra nodes is allocated
-  //   for each element.
-  if (b->order == 2) {
-    highorderindex = (elesize + sizeof(int) - 1) / sizeof(int);
-    elesize = (highorderindex + 1) * sizeof(int);
+  // 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);
+    elesize = (elemmarkerindex + 1) * sizeof(int);
   }
-  // If element neighbor graph is requested, make sure there's room to
-  //   store an integer index in each element.  This integer index can
-  //   occupy the same space as the subface pointers.
-  if (b->neighout && (elesize <= 8 * sizeof(tetrahedron))) {
-    elesize = 8 * sizeof(tetrahedron) + sizeof(int);
+  // If -o2 switch is used, an additional pointer pointed to the list of
+  //   higher order nodes is allocated for each element.
+  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.
   tetrahedrons = new memorypool(elesize, ELEPERBLOCK, POINTER, 8);
@@ -7843,19 +8244,22 @@ void tetgenmesh::makepoint(point* pnewpoint)
   (*pnewpoint)[1] = 0.0;
   (*pnewpoint)[2] = 0.0;
   // Initialize the list of user-defined attributes.
-  for (i = 0; i < in->numberofpointattributes; i++) {
-    (*pnewpoint)[3 + i] = 0.0;
+  if (bgm != (tetgenmesh *) NULL) {
+    for (i = 0; i < bgm->in->numberofpointattributes; i++) {
+      (*pnewpoint)[3 + i] = 0.0;
+    } 
+  } else {
+    for (i = 0; i < in->numberofpointattributes; i++) {
+      (*pnewpoint)[3 + i] = 0.0;
+    }
   }
   if (b->plc || b->refine) {
-    // Initialize the point-to-tetrahedron filed.
+    // Initialize the point-to-simplex filed.
     setpoint2tet(*pnewpoint, NULL);
-    if (b->quality) {
-      // Initialize the other pointer to its parent point.
-      setpoint2ppt(*pnewpoint, NULL);
-    }
-    if (b->quality && varconstraint) {
-      // Initialize the maximum edge length bound.
-      setedgebound(*pnewpoint, 0.0);
+    setpoint2sh(*pnewpoint, NULL);
+    setpoint2ppt(*pnewpoint, NULL);
+    if (bgm != (tetgenmesh *) NULL) {
+      setpoint2bgmtet(*pnewpoint, NULL);
     }
     if (checkpbcs) {
       // Initialize the other pointer to its pbc point.
@@ -7937,10 +8341,13 @@ REAL tetgenmesh::distance2(tetrahedron* tetptr, point p)
 // WARNING: This routine is designed for convex triangulations, and will not //
 // generally work after the holes and concavities have been carved.          //
 //                                                                           //
+// If 'maxtetnumber' > 0, stop the searching process if the number of passed //
+// tets is larger than it and return OUTSIDE.                                //
+//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::locateresult tetgenmesh::
-preciselocate(point searchpt, triface* searchtet)
+enum tetgenmesh::locateresult tetgenmesh::preciselocate(point searchpt,
+  triface* searchtet, long maxtetnumber)
 {
   triface backtracetet;
   triface walkthroface;
@@ -7949,13 +8356,15 @@ preciselocate(point searchpt, triface* searchtet)
   long tetnumber;
   int side;
 
-  // 'searchtet' should be a valid tetrahedron.
+  if (isdead(searchtet)) searchtet->tet = dummytet;
   if (searchtet->tet == dummytet) {
     searchtet->loc = 0;
     symself(*searchtet);
-    assert(searchtet->tet != dummytet);
   }
-  assert(!isdead(searchtet));
+  // 'searchtet' should be a valid tetrahedron now.
+#ifdef SELF_CHECK
+  assert(!isdead(searchtet) && (searchtet->tet != dummytet));
+#endif
 
   searchtet->ver = 0; // Keep in CCW edge ring.
   // Find a face of 'searchtet' such that the 'searchpt' lies strictly
@@ -7967,11 +8376,13 @@ preciselocate(point searchpt, triface* searchtet)
     ori1 = orient3d(forg, fdest, fapex, searchpt);
     if (ori1 < 0.0) break;
   }
+#ifdef SELF_CHECK
   assert(searchtet->loc < 4);
+#endif
 
   // Define 'tetnumber' for exit the loop when it's running endless.
   tetnumber = 0l;
-  while (tetnumber <= tetrahedrons->items) {
+  while ((maxtetnumber > 0l) && (tetnumber <= maxtetnumber)) {
     // Check if we are reaching the boundary of the triangulation.
     if (searchtet->tet == dummytet) {
       *searchtet = backtracetet;
@@ -8009,7 +8420,9 @@ preciselocate(point searchpt, triface* searchtet)
         }
         // Remember, ori1 < 0.0, which means 'searchpt' will not on edge
         //   (forg, fdest) or on vertex forg or fdest.
+#ifdef SELF_CHECK
         assert(ori1 < 0.0);
+#endif
         // The rest possible cases are: 
         //   (1) 'searchpt' lies on edge (fdest, toppo);
         //   (2) 'searchpt' lies on edge (toppo, forg);
@@ -8047,7 +8460,9 @@ preciselocate(point searchpt, triface* searchtet)
       return INTETRAHEDRON;
     }
     // We walk through the face 'walkthroface' and continue the searching.
+#ifdef SELF_CHECK
     assert(walkthroface.tet != (tetrahedron *) NULL);
+#endif
     // Store the face handle in 'backtracetet' before we take the real walk.
     //   So we are able to restore the handle to 'searchtet' if we are
     //   reaching the outer boundary.
@@ -8103,7 +8518,9 @@ locate(point searchpt, triface *searchtet)
     searchtet->loc = 0;
     symself(*searchtet);
   }
+#ifdef SELF_CHECK
   assert(!isdead(searchtet));
+#endif
   
   // Get the distance from the suggested starting tet to the point we seek.
   searchdist = distance2(searchtet->tet, searchpt);
@@ -8119,10 +8536,11 @@ locate(point searchpt, triface *searchtet)
   }
 
   // Select "good" candidate using k random samples, taking the closest one.
-  //   The number of random samples taken is proportional to the cube root
+  //   The number of random samples taken is proportional to the fourth root
   //   of the number of tetrahedra in the mesh. The next bit of code assumes
   //   that the number of tetrahedra increases monotonically.
-  while (SAMPLEFACTOR * samples * samples * samples < tetrahedrons->items) {
+  while (SAMPLEFACTOR * samples * samples * samples * samples <
+         tetrahedrons->items) {
     samples++;
   }
   // Find how much blocks in current tet pool.
@@ -8158,7 +8576,7 @@ locate(point searchpt, triface *searchtet)
   }
   
   // Call simple walk-through to locate the point.
-  return preciselocate(searchpt, searchtet); 
+  return preciselocate(searchpt, searchtet, tetrahedrons->items); 
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -8335,11124 +8753,15183 @@ adjustlocate(point searchpt, triface* searchtet, enum locateresult precise,
   return INTETRAHEDRON;
 }
 
-//
-// End of point location routines
-//
-
-//
-// Begin of mesh transformation routines
-//
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// categorizeface()    Determine the flip type of a given face.              //
+// locatesub()    Find a point in the surface mesh of a facet.               //
 //                                                                           //
-// 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'.                                                           //
+// Searching begins from the input 'searchsh', it should be a handle on the  //
+// convex hull of the facet triangulation.                                   //
 //                                                                           //
-// 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. //
+// If 'stopatseg' is nonzero, the search will stop if it tries to walk       //
+// through a subsegment, and will return OUTSIDE.                            //
 //                                                                           //
-// 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  //
-// doing five orientation tests: two tests for determining that d, e lie on  //
-// the different sides of abc, three tests for determining if the edge de    //
-// intersects the face abc.  However, if we use the neighbor information of  //
-// the mesh data structure, we can reduce the five orientation tests to at   //
-// most three tests, that is, the two tests for determining whether d and e  //
-// lie on the different sides of abc can be saved.                           //
+// On completion, 'searchsh' is a subface that contains 'searchpt'.          //
+//   - Returns ONVERTEX if the point lies on an existing vertex. 'searchsh'  //
+//     is a handle whose origin is the existing vertex.                      //
+//   - Returns ONEDGE if the point lies on a mesh edge.  'searchsh' is a     //
+//     handle whose primary edge is the edge on which the point lies.        //
+//   - Returns ONFACE if the point lies strictly within a subface.           //
+//     'searchsh' is a handle on which the point lies.                       //
+//   - Returns OUTSIDE if the point lies outside the triangulation.          //
+//                                                                           //
+// WARNING: This routine is designed for convex triangulations, and will not //
+// not generally work after the holes and concavities have been carved.      //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
+enum tetgenmesh::locateresult tetgenmesh::locatesub(point searchpt,
+  face* searchsh, int stopatseg, REAL epspp)
 {
-  triface symhoriz, casing;
-  face checksh, checkseg;
-  face cassh1, cassh2;
-  point pa, pb, pc, pd, pe, pf, pg;
-  point abdoppo, bcdoppo, cadoppo;
-  REAL ori1, ori2, ori3;
-  int adjtet;
+  face backtracksh, spinsh, checkedge;
+  point forg, fdest, fapex;
+  REAL orgori, destori;
+  REAL ori, sign;
+  int moveleft, i;
 
-  sym(horiz, symhoriz);
-  if (symhoriz.tet == dummytet) {
-    // A hull face is unflipable and locally Delaunay.
-    return NONCONVEX;
+  if (searchsh->sh == dummysh) {
+    searchsh->shver = 0;
+    spivotself(*searchsh);
+#ifdef SELF_CHECK
+    assert(searchsh->sh != dummysh);
+#endif
   }
-  
-  adjustedgering(horiz, CCW);
-  findedge(&symhoriz, dest(horiz), org(horiz));
-  pa = org(horiz);
-  pb = dest(horiz);
-  pc = apex(horiz);
-  pd = oppo(horiz);
-  pe = oppo(symhoriz);
+  // Find the sign to simulate that abovepoint is 'above' the facet.
+  adjustedgering(*searchsh, CCW);
+  forg = sorg(*searchsh);
+  fdest = sdest(*searchsh);
+  fapex = sapex(*searchsh);
+  ori = orient3d(forg, fdest, fapex, abovepoint);
+  sign = ori > 0.0 ? -1 : 1;
 
-  // Find the number of adjacent tetrahedra of abc, which have d, e, and one
-  //   of corners of abc as their corners. This number can be 0, 1 and 2.
-  abdoppo = bcdoppo = cadoppo = (point) NULL;
-  adjtet = 0;
-  fnext(horiz, casing); // at edge 'ab'.
-  symself(casing);
-  if (casing.tet != dummytet) {
-    abdoppo = oppo(casing);
-    if (abdoppo == pe) adjtet++;
-  }
-  enextfnext(horiz, casing); // at edge 'bc'.
-  symself(casing);
-  if (casing.tet != dummytet) {
-    bcdoppo = oppo(casing);
-    if (bcdoppo == pe) adjtet++;
-  }
-  enext2fnext(horiz, casing); // at edge 'ca'.
-  symself(casing);
-  if (casing.tet != dummytet) {
-    cadoppo = oppo(casing);
-    if (cadoppo == pe) adjtet++;
+  // Orient 'searchsh' so that 'searchpt' is below it (i.e., searchpt has
+  //   CCW orientation with respect to searchsh in plane).  Such edge
+  //   should always exist. Save it as (forg, fdest).
+  for (i = 0; i < 3; i++) {
+    forg = sorg(*searchsh);
+    fdest = sdest(*searchsh);
+    ori = orient3d(forg, fdest, abovepoint, searchpt) * sign;
+    if (ori > 0.0) break;
+    senextself(*searchsh);
   }
+#ifdef SELF_CHECK
+  assert(i < 3);
+#endif
   
-  if (adjtet == 0) {
-    // No adjacent tetrahedron. Types T23, T22 and T44 are possible. 
-    ori1 = orient3d(pa, pb, pd, pe);
-    if (checksubfaces && ori1 != 0.0) {
-      // Check if abd and abe are both boundary faces?
-      fnext(horiz, casing);
-      tspivot(casing, cassh1);
-      fnext(symhoriz, casing);
-      tspivot(casing, cassh2);
-      if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
-        // abd and abe are both boundary faces. Check if ab is a segment.
-        findedge(&cassh1, pa, pb);
-        sspivot(cassh1, checkseg);
-        if (checkseg.sh == dummysh) {
-          // ab is not a segment - abd and abe belong to the same facet.
-          //   The four points are forced to be coplanar.
-          ori1 = 0.0;
-        } else {
-          // ab is a segment - abd and abe belong to two different facets.
-          //   In principle, a, b, c and d can form a tetrahedron (since
-          //   ori1 != 0.0).  However, we should avoid to create a very
-          //   flat one which may induce to form a sequence of extremely
-          //   badly-shaped or even wrong orientational tetrahedra. Hence,
-          //   we use a larger epsilon to test if they're coplanar.
-          if (iscoplanar(pa, pb, pd, pe, ori1, b->epsilon * 1e+2)) ori1 = 0.0;
-        }
-      } else {
-        // abd and abe are not both boundary faces. Check if abd and bae
-        //   are approximately coplanar with respect to the epsilon.
-        if (iscoplanar(pa, pb, pd, pe, ori1, b->epsilon)) ori1 = 0.0;
-      }
+  while (1) {
+    fapex = sapex(*searchsh);
+    // Check whether the apex is the point we seek.
+    if (fapex[0] == searchpt[0] && fapex[1] == searchpt[1] &&
+        fapex[2] == searchpt[2]) {
+      senext2self(*searchsh);
+      return ONVERTEX;
     }
-    if (ori1 < 0.0) {
-      // e lies above abd, unflipable, tet abde is not present.
-#ifdef SELF_CHECK
-      if (!nonconvex) {
-        // abd and abe should not be hull faces, check it.
-        fnext(horiz, casing);
-        symself(casing);
-        assert(casing.tet != dummytet);
-        fnext(symhoriz, casing);
-        symself(casing);
-        assert(casing.tet != dummytet);
+    // Does the point lie on the other side of the line defined by the
+    //   triangle edge opposite the triangle's destination?
+    destori = orient3d(forg, fapex, abovepoint, searchpt) * sign;
+    if (epspp > 0.0) {
+      if (iscoplanar(forg, fapex, abovepoint, searchpt, destori, epspp)) {
+        destori = 0.0;
       }
-#endif
-      if (checksubfaces) {
-        // The nonconvexbility may be casued by existing an subsegment.
-        tsspivot(&horiz, &checkseg);
-        if (checkseg.sh != dummysh) {
-          return FORBIDDENEDGE;
-        }
+    }
+    // Does the point lie on the other side of the line defined by the
+    //   triangle edge opposite the triangle's origin? 
+    orgori = orient3d(fapex, fdest, abovepoint, searchpt) * sign;
+    if (epspp > 0.0) {
+      if (iscoplanar(fapex, fdest, abovepoint, searchpt, orgori, epspp)) {
+        orgori = 0.0;
       }
-      return UNFLIPABLE;
     }
-    ori2 = orient3d(pb, pc, pd, pe);
-    if (checksubfaces && ori2 != 0.0) {
-      // Check if bcd and cbe are both boundary faces.
-      enextfnext(horiz, casing);
-      tspivot(casing, cassh1);
-      enext2fnext(symhoriz, casing);
-      tspivot(casing, cassh2);
-      if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
-        // bcd and cbe are both boundary faces. Check if bc is a segment.
-        findedge(&cassh1, pb, pc);
-        sspivot(cassh1, checkseg);
-        if (checkseg.sh == dummysh) {
-          // bc is not a segment - bcd and cbe belong to the same facet.
-          //   The four points are forced to be coplanar.
-          ori2 = 0.0;
-        } else {
-          // bc is a segment - bcd and cbe belong to two different facets.
-          //   In principle, b, c, d and e can form a tetrahedron (since
-          //   ori2 != 0.0). Use a larger eps to test if they're coplanar.
-          if (iscoplanar(pb, pc, pd, pe, ori2, b->epsilon * 1e+2)) ori2 = 0.0;
-        } 
+    if (destori > 0.0) {
+      moveleft = 1;
+    } else {
+      if (orgori > 0.0) {
+        moveleft = 0;
       } else {
-        //  bcd and cbe are not both boundary faces. Check if bcd and cbe
-        //   are approximately coplanar with respect to the epsilon.
-        if (iscoplanar(pb, pc, pd, pe, ori2, b->epsilon)) ori2 = 0.0;
-      }
-    }
-    if (ori2 < 0.0) {
-      // e lies above bcd, unflipable, tet bcde is not present.
-#ifdef SELF_CHECK
-      if (!nonconvex) {
-        // bcd and cbe should not be hull faces, check it.
-        enextfnext(horiz, casing);
-        symself(casing);
-        assert(casing.tet != dummytet);
-        enext2fnext(symhoriz, casing);
-        symself(casing);
-        assert(casing.tet != dummytet);
-      }
-#endif
-      enextself(horiz);
-      if (checksubfaces) {
-        // The nonconvexbility may be casued by existing an subsegment.
-        tsspivot(&horiz, &checkseg);
-        if (checkseg.sh != dummysh) {
-          return FORBIDDENEDGE;
-        }
-      }
-      return UNFLIPABLE;
-    } 
-    ori3 = orient3d(pc, pa, pd, pe);
-    if (checksubfaces && ori3 != 0.0) {
-      // Check if cad and ace are both boundary faces.
-      enext2fnext(horiz, casing);
-      tspivot(casing, cassh1);
-      enextfnext(symhoriz, casing);
-      tspivot(casing, cassh2);
-      if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
-        // cad and ace are both boundary faces. Check if ca is a segment.
-        findedge(&cassh1, pc, pa);
-        sspivot(cassh1, checkseg);
-        if (checkseg.sh == dummysh) {
-          // ca is not a segment - cad and ace belong to the same facet.
-          //   The four points are forced to be coplanar.
-          ori3 = 0.0;
-        } else {
-          // ca is a segment - cad and ace belong to two different facets.
-          //   In principle, c, a, d and e can form a tetrahedron (since
-          //   ori3 != 0.0). Use a larger eps to test if they're coplanar.
-          if (iscoplanar(pc, pa, pd, pe, ori3, b->epsilon * 1e+2)) ori3 = 0.0;
+        // The point must be on the boundary of or inside this triangle.
+        if (destori == 0.0) {
+          senext2self(*searchsh);
+          return ONEDGE;
         } 
-      } else {
-        // cad and ace are not both boundary faces. Check if cad and ace
-        //   are approximately coplanar with respect to the epsilon.
-        if (iscoplanar(pc, pa, pd, pe, ori3, b->epsilon)) ori3 = 0.0;
-      }
-    }
-    if (ori3 < 0.0) {
-      // e lies above cad, unflipable, tet cade is not present.
-#ifdef SELF_CHECK
-      if (!nonconvex) {
-        // cad and ace should not be hull faces, check it.
-        enext2fnext(horiz, casing);
-        symself(casing);
-        assert(casing.tet != dummytet);
-        enextfnext(symhoriz, casing);
-        symself(casing);
-        assert(casing.tet != dummytet);
-      }
-#endif
-      enext2self(horiz);
-      if (checksubfaces) {
-        // The nonconvexbility may be casued by existing an subsegment.
-        tsspivot(&horiz, &checkseg);
-        if (checkseg.sh != dummysh) {
-          return FORBIDDENEDGE;
+        if (orgori == 0.0) {
+          senextself(*searchsh);
+          return ONEDGE;
         }
+        return ONFACE;
       }
-      return UNFLIPABLE;
     }
-    if (ori1 == 0.0) {
-      // e is coplanar with abd.
-      if (ori2 * ori3 == 0.0) {
-        // only one zero is possible.
-        // 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;
-      }
-    } else if (ori2 == 0.0) {
-      // e is coplanar with bcd.
-      if (ori1 * ori3 == 0.0) {
-        // only one zero is possible.
-        // 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;
-      }
-      // Adjust 'horiz' and 'symhoriz' be the edge bc.
-      enextself(horiz);
-      enext2self(symhoriz);
-    } else if (ori3 == 0.0) {
-      // e is coplanar with cad.
-      if (ori1 * ori2 == 0.0) {
-        // only one zero is possible.
-        // 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;
-      }
-      // Adjust 'horiz' and 'symhoriz' be the edge ca.
-      enext2self(horiz);
-      enextself(symhoriz);
+    // Move to another triangle.  Leave a trace `backtracksh' in case
+    //   walking off a boundary of the triangulation.
+    if (moveleft) {
+      senext2(*searchsh, backtracksh);
+      fdest = fapex;
     } else {
-      // e lies below all three faces, flipable.
-      if (checksubfaces) {
-        tspivot(horiz, checksh);
-        if (checksh.sh != dummysh) {
-          // To flip a subface is forbidden.
-          return FORBIDDENFACE;
-        }
-      }
-      return T23;
+      senext(*searchsh, backtracksh);
+      forg = fapex;
     }
-    // Four points are coplanar, T22 or T44 is possible.
-    if (checksubfaces) {
-      tsspivot(&horiz, &checkseg);
-      if (checkseg.sh != dummysh) {
-        // To flip a subsegment is forbidden.
-        return FORBIDDENEDGE;
-      }
-      tspivot(horiz, checksh);
-      if (checksh.sh != dummysh) {
-        // To flip a subface is forbidden.
-        return FORBIDDENFACE;
+    // Check if we meet a segment.
+    sspivot(backtracksh, checkedge);
+    if (checkedge.sh != dummysh) {
+      if (stopatseg) {
+        // The flag indicates we should not cross a segment. Stop.
+        *searchsh = backtracksh;
+        return OUTSIDE;
       }
-    }
-    // Assume the four coplanar points are a, b, d, e, abd and abe are two
-    //   coplanar faces. If both abd and abe are hull faces, flipable(T22).
-    //   If they are interior faces, get the opposite tetrahedra abdf and
-    //   abeg, if f = g, flipable (T44). Otherwise, unflipable.
-    pf = pg = (point) NULL;
-    fnext(horiz, casing);
-    symself(casing);
-    if (casing.tet != dummytet) {
-      pf = oppo(casing);
-    }
-    fnext(symhoriz, casing);
-    symself(casing);
-    if (casing.tet != dummytet) {
-      pg = oppo(casing);
-    }
-    if (pf == pg) {
-      // Either T22 (pf == pg == NULL) or T44 (pf and pg) is possible.
-      if (checksubfaces) {
-        // Retreat the corner points a, b, and c.
-        pa = org(horiz);
-        pb = dest(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;
-        ori1 = orient3d(pd, pc, pe, pb);
-        if (ori1 <= 0) return NONCONVEX;
-        if (pf != (point) NULL) {
-          ori1 = orient3d(pd, pf, pe, pa);
-          if (ori1 <= 0) return NONCONVEX;
-          ori1 = orient3d(pf, pd, pe, pb);
-          if (ori1 <= 0) return NONCONVEX;
+      // Try to walk through a segment. We need to find a coplanar subface
+      //   sharing this segment to get into.
+      spinsh = backtracksh;
+      do {
+        spivotself(spinsh);
+        if (spinsh.sh == backtracksh.sh) {
+          // Turn back, no coplanar subface is found.
+          break;
         }
-      }
-      if (pf == (point) NULL) {
-        // abd and abe are hull faces, flipable.
-        return T22;
-      } else {
-        // abd and abe are interior faces, flipable.
-        assert(pf != (point) NULL);
-        return T44;
-      }
+        // Are they belong to the same facet.
+        if (shellmark(spinsh) == shellmark(backtracksh)) {
+          // Find a coplanar subface. Walk into it.
+          *searchsh = spinsh;
+          break;
+        }
+        // Are they (nearly) coplanar?
+        ori = orient3d(forg, fdest, sapex(backtracksh), sapex(spinsh));
+        if (iscoplanar(forg, fdest, sapex(backtracksh), sapex(spinsh), ori,
+                       b->epsilon)) {
+          // Find a coplanar subface. Walk into it.
+          *searchsh = spinsh;
+          break;
+        }
+      } while (spinsh.sh != backtracksh.sh);
     } else {
-      // ab has more than four faces around it, unflipable.
-      return UNFLIPABLE;
+      spivot(backtracksh, *searchsh);
     }
-  } else if (adjtet == 1) {
-    // One of its three edges is locally non-convex. Type T32 is possible.
-    // Adjust current configuration so that edge ab is non-convex.
-    if (bcdoppo == pe) {
-      // Edge bc is non-convex. Adjust 'horiz' and 'symhoriz' be edge bc.
-      enextself(horiz);
-      enext2self(symhoriz);
-      pa = org(horiz);
-      pb = dest(horiz);
-      pc = apex(horiz);
-    } else if (cadoppo == pe) {
-      // Edge ca is non-convex. Adjust 'horiz' and 'symhoriz' be edge ca.
-      enext2self(horiz);
-      enextself(symhoriz);
-      pa = org(horiz);
-      pb = dest(horiz);
-      pc = apex(horiz);
-    } else {
-      // Edge ab is non-convex.
-      assert(abdoppo == pe);
-    } // Now ab is the non-convex edge.
-    // In order to be flipable, ab should cross face cde. Check it.
-    ori1 = orient3d(pc, pd, pe, pa);
-    if (checksubfaces && ori1 != 0.0) {
-      // Check if cad and ace are both boundary faces.
-      enext2fnext(horiz, casing);
-      tspivot(casing, cassh1);
-      enextfnext(symhoriz, casing);
-      tspivot(casing, cassh2);
-      if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
-        // cad and ace are both boundary faces. Check if ca is a segment.
-        findedge(&cassh1, pc, pa);
-        sspivot(cassh1, checkseg);
-        if (checkseg.sh == dummysh) {
-          // ca is not a segment. cad and ace belong to the same facet.
-          //   The four points are forced to be coplanar.
-          ori1 = 0.0;
+    // Check for walking right out of the triangulation.
+    if ((searchsh->sh == dummysh) || (searchsh->sh == backtracksh.sh)) {
+      // Go back to the last triangle.
+      *searchsh = backtracksh;
+      return OUTSIDE;
+    }
+    // To keep the same orientation wrt abovepoint.
+    if (sorg(*searchsh) != forg) sesymself(*searchsh);
+#ifdef SELF_CHECK
+    assert((sorg(*searchsh) == forg) && (sdest(*searchsh) == fdest));
+#endif
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// adjustlocatesub()    Adjust the precise location of a vertex.             //
+//                                                                           //
+// 'precise' is the precise location (returned from locatesub()) of 'searcht'//
+// with respect to 'searchsh'. 'epspp' is the given relative tolerance.      //
+//                                                                           //
+// This routine re-evaluates the orientations of 'searchpt' with respect to  //
+// the three edges of 'searchsh'. Detects the collinearities by additinal    //
+// tests based on the given tolerance. If 'precise' is ONEDGE, one can save  //
+// one orientation test for the current edge of 'searchsh'.                  //
+//                                                                           //
+// On completion, 'searchsh' is a subface contains 'searchpt'. The returned  //
+// value indicates one of the following cases:                               //
+//   - Returns ONVERTEX if the point lies on an existing vertex. 'searchsh'  //
+//     is a handle whose origin is the existing vertex.                      //
+//   - Returns ONEDGE if the point lies on a mesh edge.  'searchsh' is a     //
+//     handle whose primary edge is the edge on which the point lies.        //
+//   - Returns ONFACE if the point lies strictly within a subface.           //
+//     'searchsh' is a handle on which the point lies.                       //
+//   - Returns OUTSIDE if the point lies outside 'searchsh'.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::locateresult tetgenmesh::
+adjustlocatesub(point searchpt, face* searchsh, enum locateresult precise,
+                REAL epspp)
+{
+  point pa, pb, pc;
+  bool s1, s2, s3;
+
+  pa = sorg(*searchsh);
+  pb = sdest(*searchsh);
+  pc = sapex(*searchsh);
+
+  if (precise == ONEDGE) {
+    s1 = true;
+  } else {
+    s1 = iscollinear(pa, pb, searchpt, epspp);
+  }
+  s2 = iscollinear(pb, pc, searchpt, epspp);
+  s3 = iscollinear(pc, pa, searchpt, epspp);
+  if (s1) {
+    if (s2) {
+      // on vertex pb.
+#ifdef SELF_CHECK
+      assert(!s3);
+#endif
+      senextself(*searchsh);
+      return ONVERTEX;
+    } else if (s3) {
+      // on vertex pa.
+      return ONVERTEX;
+    } else {
+      // on edge pa->pb.
+      return ONEDGE;
+    }
+  } else if (s2) {
+    if (s3) {
+      // on vertex pc.
+      senext2self(*searchsh);
+      return ONVERTEX;
+    } else {
+      // on edge pb->pc.
+      senextself(*searchsh);
+      return ONEDGE;
+    }
+  } else if (s3) {
+    // on edge pc->pa.
+    senext2self(*searchsh);
+    return ONEDGE;
+  } else {
+    return precise;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// locateseg()    Find a point in subsegments.                               //
+//                                                                           //
+// Searching begins from the input 'searchseg', it should be a subsegment of //
+// the whole segment.                                                        //
+//                                                                           //
+// On completion, 'searchseg' is a subsegment that contains 'searchpt'.      //
+//   - Returns ONVERTEX if the point lies on an existing vertex. 'searchseg' //
+//     is a handle whose origin is the existing vertex.                      //
+//   - Returns ONEDGE if the point lies inside 'searchseg'.                  //
+//   - Returns OUTSIDE if the point lies outside the segment.                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::locateresult tetgenmesh::
+locateseg(point searchpt, face* searchseg)
+{
+  face backtraceseg;
+  point pa, pb;
+  REAL dx, dy, dz;
+  int moveleft;
+  int i;
+
+  moveleft = 0;
+  while (1) {
+    searchseg->shver = 0;
+    pa = sorg(*searchseg);
+    pb = sdest(*searchseg);
+    // Find the biggest difference in x, y, and z coordinates of a and b.
+    dx = fabs(pb[0] - pa[0]);
+    dy = fabs(pb[1] - pa[1]);
+    dz = fabs(pb[2] - pa[2]);
+    if (dx > dy) {
+      if (dx > dz) {
+        i = 0;
+      } else {
+        i = 2;
+      }
+    } else {
+      if (dy > dz) {
+        i = 1;
+      } else {
+        i = 2;
+      }
+    }
+    if (pa[i] < pb[i]) {
+      if (searchpt[i] < pa[i]) {
+        moveleft = 1;
+      } else if (searchpt[i] > pa[i]) {
+        if (searchpt[i] < pb[i]) {
+          return ONEDGE;
+        } else if (searchpt[i] > pb[i]) {
+          moveleft = 0;
         } else {
-          // ca is a segment. cad and ace belong to different facets.
-          //   In principle, c, d, e, and a can form a tetrahedron (since
-          //   ori1 != 0.0).  However, we should avoid to create a very
-          //   flat tet. Use a larger epsilon to test if they're coplanar.
-          if (iscoplanar(pc, pd, pe, pa, ori1, b->epsilon * 1e+2)) ori1 = 0.0;
+#ifdef SELF_CHECK
+          assert(searchpt[i] == pb[i]);
+#endif
+          sesymself(*searchseg);
+          return ONVERTEX;
         }
       } else {
-        // Check if c, d, e, and a are approximately coplanar.
-        if (iscoplanar(pc, pd, pe, pa, ori1, b->epsilon)) ori1 = 0.0;
+#ifdef SELF_CHECK
+        assert(searchpt[i] == pa[i]);
+#endif
+        return ONVERTEX;
       }
-    }
-    if (ori1 <= 0.0) {
-      // a lies above or is coplanar cde, abc is locally Delaunay.
-      return NONCONVEX;
-    }
-    ori2 = orient3d(pd, pc, pe, pb);
-    if (checksubfaces && ori2 != 0.0) {
-      // Check if bcd and cbe are both boundary faces.
-      enextfnext(horiz, casing);
-      tspivot(casing, cassh1);
-      enext2fnext(symhoriz, casing);
-      tspivot(casing, cassh2);
-      if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
-        // bcd and cbe are both boundary faces. Check if bc is a segment.
-        findedge(&cassh1, pb, pc);
-        sspivot(cassh1, checkseg);
-        if (checkseg.sh == dummysh) {
-          // bc is not a segment. bcd and cbe belong to the same facet.
-          //   The four points are forced to be coplanar.
-          ori2 = 0.0;
+    } else if (pa[i] > pb[i]) {
+      if (searchpt[i] < pb[i]) {
+        moveleft = 0;
+      } else if (searchpt[i] > pb[i]) {
+        if (searchpt[i] < pa[i]) {
+          return ONEDGE;
+        } else if (searchpt[i] > pa[i]) {
+          moveleft = 1;
         } else {
-          // bc is a segment. bcd and cbe belong to different facets.
-          //   In principle, d, c, e, and b can form a tetrahedron (since
-          //   ori2 != 0.0).  However, we should avoid to create a very
-          //   flat tet. Use a larger epsilon to test if they're coplanar.
-          if (iscoplanar(pd, pc, pe, pb, ori2, b->epsilon * 1e+2)) ori2 = 0.0;
+#ifdef SELF_CHECK
+          assert(searchpt[i] == pa[i]);
+#endif
+          return ONVERTEX;
         }
       } else {
-        // Check if d, c, e, and b are approximately coplanar.
-        if (iscoplanar(pd, pc, pe, pb, ori2, b->epsilon)) ori2 = 0.0;
+#ifdef SELF_CHECK
+        assert(searchpt[i] == pb[i]);
+#endif
+        sesymself(*searchseg);
+        return ONVERTEX;
       }
     }
-    if (ori2 <= 0.0) {
-      // b lies above dce, unflipable, and abc is locally Delaunay.
-      return NONCONVEX;
+    backtraceseg = *searchseg;
+    if (moveleft) {
+      senext2self(*searchseg);
+    } else {
+      senextself(*searchseg);
+    }
+    spivotself(*searchseg);
+    if (searchseg->sh == dummysh) {
+      *searchseg = backtraceseg;
+      break;
+    }
+  }
+
+  return OUTSIDE;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// adjustlocateseg()    Adjust the precise location of a vertex on segment.  //
+//                                                                           //
+// 'searchpt' is either inside or ouside the segment 'searchseg'. It will be //
+// adjusted to on vertex if it is very close to an endpoint of 'searchseg'.  //
+// 'epspp' is the given relative tolerance.                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::locateresult tetgenmesh::
+adjustlocateseg(point searchpt, face* searchseg, enum locateresult precise,
+                REAL epspp)
+{
+  point pa, pb;
+  REAL L, d, r;
+
+  pa = sorg(*searchseg);
+  pb = sdest(*searchseg);
+  L = distance(pa, pb);
+
+  // Is searchpt approximate to pa?
+  d = distance(pa, searchpt);
+  r = d / L;
+  if (r <= epspp) {
+    return ONVERTEX;
+  }
+  // Is searchpt approximate to pb?
+  d = distance(pb, searchpt);
+  r = d / L;
+  if (r <= epspp) {
+    sesymself(*searchseg);
+    return ONVERTEX;
+  }
+
+  return precise;
+}
+
+//
+// End of point location routines
+//
+
+//
+// Begin of mesh transformation routines
+//
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Flip operations                                                           //
+//                                                                           //
+// If abc is a hull face, it is unflipable, and is locally Delaunay.  In the //
+// following, we assume abc is an interior face, and the other tetrahedron   //
+// adjoining at abc is bace.                                                 //
+//                                                                           //
+// If the convex hull CH of the set {a, b, c, d, e} only has four vertices,  //
+// i.e., one vertex lies inside CH, then abc is unflipable, and is locally   //
+// Delaunay. If CH is the vertex set itself, we have the following cases to  //
+// determine whether abc is flipable or not.                                 //
+//                                                                           //
+// If no four points of {a, b, c, d, e} are coplanar, a 2-to-3 flip can be   //
+// applied to abc if the edge de crosses the triangle abc; a 3-to-2 flip can //
+// be applied to abc if ab crosses cde, and abde exists, otherwise, face abc //
+// is unflipable, i.e., the tetrahedron abde is not present.                 //
+//                                                                           //
+// If four points of {a, b, c, d, e} are coplanar (two faces are coplanar).  //
+// Assume faces abd and abe are coplanar (it is impossible be abc). If a, b, //
+// d, e form a non-convex quadrilateral, then abc is unflipable, furthermore,//
+// it is locally Delaunay.  Assume they are convex quadrilateral, if abd and //
+// abe are hull faces, a 2-to-2 flip can be applied to abc;  if abd and abe  //
+// are interior faces,  assume two tetrahedra adjoining abd and abe at the   //
+// opposite sides are abdg and abef, respectively.  If g = f, a 4-to-4 flip  //
+// can be applied to abc, otherwise, abc is unflipable.                      //
+//                                                                           //
+// There are other cases which can cause abc unflipable. If abc is a subface,//
+// a 2-to-3 flip is forbidden;  if ab is a subsegment, flips 3-to-2, 2-to-2, //
+// and 4-to-4 are forbidden.                                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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'.                                                           //
+//                                                                           //
+// 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. //
+//                                                                           //
+// 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  //
+// doing five orientation tests: two tests for determining that d, e lie on  //
+// the different sides of abc, three tests for determining if the edge de    //
+// intersects the face abc.  However, if we use the neighbor information of  //
+// the mesh data structure, we can reduce the five orientation tests to at   //
+// most three tests, that is, the two tests for determining whether d and e  //
+// lie on the different sides of abc can be saved.                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
+{
+  triface symhoriz, casing;
+  face checksh, checkseg;
+  face cassh1, cassh2;
+  point pa, pb, pc, pd, pe, pf, pg;
+  point abdoppo, bcdoppo, cadoppo;
+  REAL ori1, ori2, ori3;
+  int adjtet;
+
+  sym(horiz, symhoriz);
+  if (symhoriz.tet == dummytet) {
+    // A hull face is unflipable and locally Delaunay.
+    return NONCONVEX;
+  }
+  
+  adjustedgering(horiz, CCW);
+  findedge(&symhoriz, dest(horiz), org(horiz));
+  pa = org(horiz);
+  pb = dest(horiz);
+  pc = apex(horiz);
+  pd = oppo(horiz);
+  pe = oppo(symhoriz);
+
+  // Find the number of adjacent tetrahedra of abc, which have d, e, and one
+  //   of corners of abc as their corners. This number can be 0, 1 and 2.
+  abdoppo = bcdoppo = cadoppo = (point) NULL;
+  adjtet = 0;
+  fnext(horiz, casing); // at edge 'ab'.
+  symself(casing);
+  if (casing.tet != dummytet) {
+    abdoppo = oppo(casing);
+    if (abdoppo == pe) adjtet++;
+  }
+  enextfnext(horiz, casing); // at edge 'bc'.
+  symself(casing);
+  if (casing.tet != dummytet) {
+    bcdoppo = oppo(casing);
+    if (bcdoppo == pe) adjtet++;
+  }
+  enext2fnext(horiz, casing); // at edge 'ca'.
+  symself(casing);
+  if (casing.tet != dummytet) {
+    cadoppo = oppo(casing);
+    if (cadoppo == pe) adjtet++;
+  }
+  
+  if (adjtet == 0) {
+    // No adjacent tetrahedron. Types T23, T22 and T44 are possible. 
+    ori1 = orient3d(pa, pb, pd, pe);
+    if (checksubfaces && ori1 != 0.0) {
+      // Check if abd and abe are both boundary faces?
+      fnext(horiz, casing);
+      tspivot(casing, cassh1);
+      fnext(symhoriz, casing);
+      tspivot(casing, cassh2);
+      if ((cassh1.sh != dummysh) && (cassh2.sh != dummysh)) {
+        // abd and abe are both boundary faces. Check if ab is a segment.
+        findedge(&cassh1, pa, pb);
+        sspivot(cassh1, checkseg);
+        if (checkseg.sh == dummysh) {
+          // ab is not a segment - abd and abe belong to the same facet.
+          //   The four points are forced to be coplanar.
+          ori1 = 0.0;
+        } else {
+          // ab is a segment - abd and abe belong to two different facets.
+          //   In principle, a, b, c and d can form a tetrahedron (since
+          //   ori1 != 0.0).  However, we should avoid to create a very
+          //   flat one which may form a sequence of extremely badly-shaped
+          //   or even wrong orientational tets. Test with a larger epsilon.
+          if (iscoplanar(pa, pb, pd, pe, ori1, b->epsilon * 1e+2)) ori1 = 0.0;
+        }
+      } else {
+        // abd and abe are not both boundary faces. Check if abd and bae
+        //   are approximately coplanar with respect to the epsilon.
+        if (iscoplanar(pa, pb, pd, pe, ori1, b->epsilon)) ori1 = 0.0;
+      }
+    }
+    if (ori1 < 0.0) {
+      // e lies above abd, unflipable, tet abde is not present.
+#ifdef SELF_CHECK
+      if (!nonconvex) {
+        // abd and abe should not be hull faces, check it.
+        fnext(horiz, casing);
+        symself(casing);
+        assert(casing.tet != dummytet);
+        fnext(symhoriz, casing);
+        symself(casing);
+        assert(casing.tet != dummytet);
+      }
+#endif
+      if (checksubfaces) {
+        // The nonconvexbility may be casued by existing an subsegment.
+        tsspivot(&horiz, &checkseg);
+        if (checkseg.sh != dummysh) {
+          return FORBIDDENEDGE;
+        }
+      }
+      return UNFLIPABLE;
+    }
+    ori2 = orient3d(pb, pc, pd, pe);
+    if (checksubfaces && ori2 != 0.0) {
+      // Check if bcd and cbe are both boundary faces.
+      enextfnext(horiz, casing);
+      tspivot(casing, cassh1);
+      enext2fnext(symhoriz, casing);
+      tspivot(casing, cassh2);
+      if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
+        // bcd and cbe are both boundary faces. Check if bc is a segment.
+        findedge(&cassh1, pb, pc);
+        sspivot(cassh1, checkseg);
+        if (checkseg.sh == dummysh) {
+          // bc is not a segment - bcd and cbe belong to the same facet.
+          //   The four points are forced to be coplanar.
+          ori2 = 0.0;
+        } else {
+          if (iscoplanar(pb, pc, pd, pe, ori2, b->epsilon * 1e+2)) ori2 = 0.0;
+        } 
+      } else {
+        //  bcd and cbe are not both boundary faces. Check if bcd and cbe
+        //   are approximately coplanar with respect to the epsilon.
+        if (iscoplanar(pb, pc, pd, pe, ori2, b->epsilon)) ori2 = 0.0;
+      }
+    }
+    if (ori2 < 0.0) {
+      // e lies above bcd, unflipable, tet bcde is not present.
+#ifdef SELF_CHECK
+      if (!nonconvex) {
+        // bcd and cbe should not be hull faces, check it.
+        enextfnext(horiz, casing);
+        symself(casing);
+        assert(casing.tet != dummytet);
+        enext2fnext(symhoriz, casing);
+        symself(casing);
+        assert(casing.tet != dummytet);
+      }
+#endif
+      enextself(horiz);
+      if (checksubfaces) {
+        // The nonconvexbility may be casued by existing an subsegment.
+        tsspivot(&horiz, &checkseg);
+        if (checkseg.sh != dummysh) {
+          return FORBIDDENEDGE;
+        }
+      }
+      return UNFLIPABLE;
+    } 
+    ori3 = orient3d(pc, pa, pd, pe);
+    if (checksubfaces && ori3 != 0.0) {
+      // Check if cad and ace are both boundary faces.
+      enext2fnext(horiz, casing);
+      tspivot(casing, cassh1);
+      enextfnext(symhoriz, casing);
+      tspivot(casing, cassh2);
+      if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
+        // cad and ace are both boundary faces. Check if ca is a segment.
+        findedge(&cassh1, pc, pa);
+        sspivot(cassh1, checkseg);
+        if (checkseg.sh == dummysh) {
+          // ca is not a segment - cad and ace belong to the same facet.
+          //   The four points are forced to be coplanar.
+          ori3 = 0.0;
+        } else {
+          // ca is a segment - cad and ace belong to two different facets.
+          //   In principle, c, a, d and e can form a tetrahedron (since
+          //   ori3 != 0.0). Use a larger eps to test if they're coplanar.
+          if (iscoplanar(pc, pa, pd, pe, ori3, b->epsilon * 1e+2)) ori3 = 0.0;
+        } 
+      } else {
+        // cad and ace are not both boundary faces. Check if cad and ace
+        //   are approximately coplanar with respect to the epsilon.
+        if (iscoplanar(pc, pa, pd, pe, ori3, b->epsilon)) ori3 = 0.0;
+      }
+    }
+    if (ori3 < 0.0) {
+      // e lies above cad, unflipable, tet cade is not present.
+#ifdef SELF_CHECK
+      if (!nonconvex) {
+        // cad and ace should not be hull faces, check it.
+        enext2fnext(horiz, casing);
+        symself(casing);
+        assert(casing.tet != dummytet);
+        enextfnext(symhoriz, casing);
+        symself(casing);
+        assert(casing.tet != dummytet);
+      }
+#endif
+      enext2self(horiz);
+      if (checksubfaces) {
+        // The nonconvexbility may be casued by existing an subsegment.
+        tsspivot(&horiz, &checkseg);
+        if (checkseg.sh != dummysh) {
+          return FORBIDDENEDGE;
+        }
+      }
+      return UNFLIPABLE;
+    }
+    if (ori1 == 0.0) {
+      // e is coplanar with abd.
+      if (ori2 * ori3 == 0.0) {
+        // only one zero is possible.
+        // 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;
+      }
+    } else if (ori2 == 0.0) {
+      // e is coplanar with bcd.
+      if (ori1 * ori3 == 0.0) {
+        // only one zero is possible.
+        // 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;
+      }
+      // Adjust 'horiz' and 'symhoriz' be the edge bc.
+      enextself(horiz);
+      enext2self(symhoriz);
+    } else if (ori3 == 0.0) {
+      // e is coplanar with cad.
+      if (ori1 * ori2 == 0.0) {
+        // only one zero is possible.
+        // 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;
+      }
+      // Adjust 'horiz' and 'symhoriz' be the edge ca.
+      enext2self(horiz);
+      enextself(symhoriz);
+    } else {
+      // e lies below all three faces, flipable.
+      if (checksubfaces) {
+        tspivot(horiz, checksh);
+        if (checksh.sh != dummysh) {
+          // To flip a subface is forbidden.
+          return FORBIDDENFACE;
+        }
+      }
+      return T23;
+    }
+    // Four points are coplanar, T22 or T44 is possible.
+    if (checksubfaces) {
+      tsspivot(&horiz, &checkseg);
+      if (checkseg.sh != dummysh) {
+        // To flip a subsegment is forbidden.
+        return FORBIDDENEDGE;
+      }
+      tspivot(horiz, checksh);
+      if (checksh.sh != dummysh) {
+        // To flip a subface is forbidden.
+        return FORBIDDENFACE;
+      }
+    }
+    // Assume the four coplanar points are a, b, d, e, abd and abe are two
+    //   coplanar faces. If both abd and abe are hull faces, flipable(T22).
+    //   If they are interior faces, get the opposite tetrahedra abdf and
+    //   abeg, if f = g, flipable (T44). Otherwise, unflipable.
+    pf = pg = (point) NULL;
+    fnext(horiz, casing);
+    symself(casing);
+    if (casing.tet != dummytet) {
+      pf = oppo(casing);
+    }
+    fnext(symhoriz, casing);
+    symself(casing);
+    if (casing.tet != dummytet) {
+      pg = oppo(casing);
+    }
+    if (pf == pg) {
+      // Either T22 (pf == pg == NULL) or T44 (pf and pg) is possible.
+      if (checksubfaces) {
+        // Retreat the corner points a, b, and c.
+        pa = org(horiz);
+        pb = dest(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;
+        ori1 = orient3d(pd, pc, pe, pb);
+        if (ori1 <= 0) return NONCONVEX;
+        if (pf != (point) NULL) {
+          ori1 = orient3d(pd, pf, pe, pa);
+          if (ori1 <= 0) return NONCONVEX;
+          ori1 = orient3d(pf, pd, pe, pb);
+          if (ori1 <= 0) return NONCONVEX;
+        }
+      }
+      if (pf == (point) NULL) {
+        // abd and abe are hull faces, flipable.
+        return T22;
+      } else {
+        // abd and abe are interior faces, flipable.
+#ifdef SELF_CHECK
+        assert(pf != (point) NULL);
+#endif
+        return T44;
+      }
+    } else {
+      // ab has more than four faces around it, unflipable.
+      return UNFLIPABLE;
+    }
+  } else if (adjtet == 1) {
+    // One of its three edges is locally non-convex. Type T32 is possible.
+    // Adjust current configuration so that edge ab is non-convex.
+    if (bcdoppo == pe) {
+      // Edge bc is non-convex. Adjust 'horiz' and 'symhoriz' be edge bc.
+      enextself(horiz);
+      enext2self(symhoriz);
+      pa = org(horiz);
+      pb = dest(horiz);
+      pc = apex(horiz);
+    } else if (cadoppo == pe) {
+      // Edge ca is non-convex. Adjust 'horiz' and 'symhoriz' be edge ca.
+      enext2self(horiz);
+      enextself(symhoriz);
+      pa = org(horiz);
+      pb = dest(horiz);
+      pc = apex(horiz);
+    } else {
+      // Edge ab is non-convex.
+#ifdef SELF_CHECK
+      assert(abdoppo == pe);
+#endif
+    } // Now ab is the non-convex edge.
+    // In order to be flipable, ab should cross face cde. Check it.
+    ori1 = orient3d(pc, pd, pe, pa);
+    if (checksubfaces && ori1 != 0.0) {
+      // Check if cad and ace are both boundary faces.
+      enext2fnext(horiz, casing);
+      tspivot(casing, cassh1);
+      enextfnext(symhoriz, casing);
+      tspivot(casing, cassh2);
+      if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
+        // cad and ace are both boundary faces. Check if ca is a segment.
+        findedge(&cassh1, pc, pa);
+        sspivot(cassh1, checkseg);
+        if (checkseg.sh == dummysh) {
+          // ca is not a segment. cad and ace belong to the same facet.
+          //   The four points are forced to be coplanar.
+          ori1 = 0.0;
+        } else {
+          // ca is a segment. cad and ace belong to different facets.
+          //   In principle, c, d, e, and a can form a tetrahedron (since
+          //   ori1 != 0.0).  However, we should avoid to create a very
+          //   flat tet. Use a larger epsilon to test if they're coplanar.
+          if (iscoplanar(pc, pd, pe, pa, ori1, b->epsilon * 1e+2)) ori1 = 0.0;
+        }
+      } else {
+        // Check if c, d, e, and a are approximately coplanar.
+        if (iscoplanar(pc, pd, pe, pa, ori1, b->epsilon)) ori1 = 0.0;
+      }
+    }
+    if (ori1 <= 0.0) {
+      // a lies above or is coplanar cde, abc is locally Delaunay.
+      return NONCONVEX;
+    }
+    ori2 = orient3d(pd, pc, pe, pb);
+    if (checksubfaces && ori2 != 0.0) {
+      // Check if bcd and cbe are both boundary faces.
+      enextfnext(horiz, casing);
+      tspivot(casing, cassh1);
+      enext2fnext(symhoriz, casing);
+      tspivot(casing, cassh2);
+      if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
+        // bcd and cbe are both boundary faces. Check if bc is a segment.
+        findedge(&cassh1, pb, pc);
+        sspivot(cassh1, checkseg);
+        if (checkseg.sh == dummysh) {
+          // bc is not a segment. bcd and cbe belong to the same facet.
+          //   The four points are forced to be coplanar.
+          ori2 = 0.0;
+        } else {
+          // bc is a segment. bcd and cbe belong to different facets.
+          //   In principle, d, c, e, and b can form a tetrahedron (since
+          //   ori2 != 0.0).  However, we should avoid to create a very
+          //   flat tet. Use a larger epsilon to test if they're coplanar.
+          if (iscoplanar(pd, pc, pe, pb, ori2, b->epsilon * 1e+2)) ori2 = 0.0;
+        }
+      } else {
+        // Check if d, c, e, and b are approximately coplanar.
+        if (iscoplanar(pd, pc, pe, pb, ori2, b->epsilon)) ori2 = 0.0;
+      }
+    }
+    if (ori2 <= 0.0) {
+      // b lies above dce, unflipable, and abc is locally Delaunay.
+      return NONCONVEX;
+    }
+    // Edge ab crosses face cde properly.
+    if (checksubfaces) {
+      // If abc is subface, then ab must be a subsegment (because abde is
+      //   a tetrahedron and ab crosses cde properly). 
+      tsspivot(&horiz, &checkseg);
+      if (checkseg.sh != dummysh) {
+        // To flip a subsegment is forbidden.
+        return FORBIDDENEDGE;
+      }
+      // Both abd and bae should not be subfaces (because they're not
+      //   coplanar and ab is not a subsegment). However, they may be
+      //   subfaces and belong to a facet (created during facet recovery),
+      //   that is, abde is an invalid tetrahedron. Find this case out.
+      fnext(horiz, casing);
+      tspivot(casing, cassh1);
+      fnext(symhoriz, casing);
+      tspivot(casing, cassh2); 
+      if (cassh1.sh != dummysh || cassh2.sh != dummysh) {
+        if (!b->quiet) {
+          // Unfortunately, they're subfaces. Corrections need be done here.
+          printf("Warning:  A tetrahedron spans two subfaces of a facet.\n");
+        }
+        // Temporarily, let it be there.
+        return UNFLIPABLE;
+      }
+    }
+    return T32;
+  } else {
+    // The convex hull of {a, b, c, d, e} has only four vertices, abc is
+    //   unflipable, furthermore, it is locally Delaunay.
+    return NONCONVEX;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// enqueueflipface(), enqueueflipedge()    Queue a face (or an edge).        //
+//                                                                           //
+// The face (or edge) may be non-locally Delaunay. It is queued for process- //
+// ing in flip() (or flipsub()). The vertices of the face (edge) are stored  //
+// seperatly to ensure the face (or edge) is still the same one when we save //
+// it since other flips will cause this face (or edge) be changed or dead.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::enqueueflipface(triface& checkface, queue* flipqueue)
+{
+  badface *queface;
+
+  queface = (badface *) flipqueue->push((void *) NULL);
+  queface->tt = checkface;
+  queface->forg = org(checkface);
+  queface->fdest = dest(checkface);
+  queface->fapex = apex(checkface);
+}
+
+void tetgenmesh::enqueueflipedge(face& checkedge, queue* flipqueue)
+{
+  badface *queface;
+
+  queface = (badface *) flipqueue->push((void *) NULL);
+  queface->ss = checkedge;
+  queface->forg = sorg(checkedge);
+  queface->fdest = sdest(checkedge);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip23()    Perform a 2-to-3 flip.                                        //
+//                                                                           //
+// On input, 'flipface' represents the face will be flipped.  Let it is abc, //
+// the two tetrahedra sharing abc are abcd, bace. abc is not a subface.      //
+//                                                                           //
+// A 2-to-3 flip is to change two tetrahedra abcd, bace to three tetrahedra  //
+// edab, edbc, and edca.  As a result, face abc has been removed and three   //
+// new faces eda, edb and edc have been created.                             //
+//                                                                           //
+// On completion, 'flipface' returns edab.  If 'flipqueue' is not NULL, all  //
+// possibly non-Delaunay faces are added into it.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+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;
+  face baesh, cbesh, acesh;
+  triface edab, edbc, edca;                            // New configuration.
+  point pa, pb, pc, pd, pe;
+  REAL attrib, volume;
+  int i;
+
+  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);
+  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));
+  }
+  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);
+  enext2fnext(abcd, oldcad);
+  fnext(bace, oldbae);
+  enext2fnext(bace, oldcbe);
+  enextfnext(bace, oldace);
+  sym(oldabd, abdcasing);
+  sym(oldbcd, bcdcasing);
+  sym(oldcad, cadcasing);
+  sym(oldbae, baecasing);
+  sym(oldcbe, cbecasing);
+  sym(oldace, acecasing);
+  if (checksubfaces) {
+    tspivot(oldabd, abdsh);
+    tspivot(oldbcd, bcdsh);
+    tspivot(oldcad, cadsh);
+    tspivot(oldbae, baesh);
+    tspivot(oldcbe, cbesh);
+    tspivot(oldace, acesh);
+  }
+
+  // Creating the new configuration inside the convex hull.
+  edab.tet = abcd.tet; // Update abcd to be edab.
+  setorg (edab, pe);
+  setdest(edab, pd);
+  setapex(edab, pa);
+  setoppo(edab, pb);
+  edbc.tet = bace.tet; // Update bace to be edbc.
+  setorg (edbc, pe);
+  setdest(edbc, pd);
+  setapex(edbc, pb);
+  setoppo(edbc, pc);
+  maketetrahedron(&edca); // Create edca.
+  setorg (edca, pe);
+  setdest(edca, pd);
+  setapex(edca, pc);
+  setoppo(edca, pa);
+  // Set the element attributes of the new tetrahedron 'edca'.
+  for (i = 0; i < in->numberoftetrahedronattributes; i++) {
+    attrib = elemattribute(abcd.tet, i);
+    setelemattribute(edca.tet, i, attrib);
+  }
+  // Set the volume constraint of the new tetrahedron 'edca' if the -ra
+  //   switches are not used together. In -ra case, the various volume
+  //   constraints can be spreaded very far.
+  if (b->varvolume && !b->refine) {
+    volume = volumebound(abcd.tet);
+    setvolumebound(edca.tet, volume);
+  }
+
+  // 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);
+  }
+  // Bond the faces inside the convex hull.
+  edab.loc = 0;
+  edca.loc = 1;
+  bond(edab, edca);
+  edab.loc = 1;
+  edbc.loc = 0;
+  bond(edab, edbc);
+  edbc.loc = 1;
+  edca.loc = 0;
+  bond(edbc, edca);
+  // Bond the faces on the convex hull.
+  edab.loc = 2;
+  bond(edab, abdcasing);
+  edab.loc = 3;
+  bond(edab, baecasing);
+  edbc.loc = 2;
+  bond(edbc, bcdcasing);
+  edbc.loc = 3;
+  bond(edbc, cbecasing);
+  edca.loc = 2;
+  bond(edca, cadcasing);
+  edca.loc = 3;
+  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).
+    for (i = 0; i < 4; i ++) {
+      edab.loc = i;
+      tsdissolve(edab);
+      edbc.loc = i;
+      tsdissolve(edbc);
+    }
+    if (abdsh.sh != dummysh) {
+      edab.loc = 2; 
+      tsbond(edab, abdsh);
+    }
+    if (baesh.sh != dummysh) {
+      edab.loc = 3; 
+      tsbond(edab, baesh);
+    }
+    if (bcdsh.sh != dummysh) {
+      edbc.loc = 2; 
+      tsbond(edbc, bcdsh);
+    }
+    if (cbesh.sh != dummysh) {
+      edbc.loc = 3; 
+      tsbond(edbc, cbesh);
+    }
+    if (cadsh.sh != dummysh) {
+      edca.loc = 2; 
+      tsbond(edca, cadsh);
+    }
+    if (acesh.sh != dummysh) {
+      edca.loc = 3; 
+      tsbond(edca, acesh);
+    }
+  }
+
+  edab.loc = 0;
+  edbc.loc = 0;
+  edca.loc = 0;
+  if (b->verbose > 3) {
+    printf("    Updating edab ");
+    printtet(&edab);
+    printf("    Updating edbc ");
+    printtet(&edbc);
+    printf("    Creating edca ");
+    printtet(&edca);
+  }
+
+  if (flipqueue != (queue *) NULL) {
+    enextfnext(edab, abdcasing);
+    enqueueflipface(abdcasing, flipqueue);
+    enext2fnext(edab, baecasing);
+    enqueueflipface(baecasing, flipqueue);
+    enextfnext(edbc, bcdcasing);
+    enqueueflipface(bcdcasing, flipqueue);
+    enext2fnext(edbc, cbecasing);
+    enqueueflipface(cbecasing, flipqueue);
+    enextfnext(edca, cadcasing);
+    enqueueflipface(cadcasing, flipqueue);
+    enext2fnext(edca, acecasing);
+    enqueueflipface(acecasing, flipqueue);  
+  }
+
+  // Save a live handle in 'recenttet'.
+  recenttet = edbc;
+  // Set the return handle be edab.
+  *flipface = edab;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip32()    Perform a 3-to-2 flip.                                        //
+//                                                                           //
+// On input, 'flipface' represents the face will be flipped.  Let it is eda, //
+// where edge ed is locally non-convex. Three tetrahedra sharing ed are edab,//
+// edbc, and edca.  ed is not a subsegment.                                  //
+//                                                                           //
+// A 3-to-2 flip is to change the three tetrahedra edab, edbc, and edca into //
+// another two tetrahedra abcd and bace.  As a result, the edge ed has been  //
+// removed and the face abc has been created.                                //
+//                                                                           //
+// On completion, 'flipface' returns abcd.  If 'flipqueue' is not NULL, all  //
+// possibly non-Delaunay faces are added into it.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+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;
+  face baesh, cbesh, acesh;
+  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);
+
+  if (b->verbose > 2) {
+    printf("    Do T32 on face (%d, %d, %d, %d).\n",
+           pointmark(pe), pointmark(pd), pointmark(pa), pointmark(pb));
+  }
+  flip32s++;
+
+#ifdef SELF_CHECK
+  // Edge de must cross face abc properly.
+  // assert(orient3d(pa, pb, pc, pd) <= 0.0);
+  // assert(orient3d(pb, pa, pc, pe) <= 0.0);
+#endif
+
+  // Storing the old configuration outside the convex hull.
+  enextfnext(edab, oldabd);
+  enext2fnext(edab, oldbae);
+  enextfnext(edbc, oldbcd);
+  enext2fnext(edbc, oldcbe);
+  enextfnext(edca, oldcad);
+  enext2fnext(edca, oldace);
+  sym(oldabd, abdcasing);
+  sym(oldbcd, bcdcasing);
+  sym(oldcad, cadcasing);
+  sym(oldbae, baecasing);
+  sym(oldcbe, cbecasing);
+  sym(oldace, acecasing);
+  if (checksubfaces) {
+    tspivot(oldabd, abdsh);
+    tspivot(oldbcd, bcdsh);
+    tspivot(oldcad, cadsh);
+    tspivot(oldbae, baesh);
+    tspivot(oldcbe, cbesh);
+    tspivot(oldace, acesh);
+  }
+
+  // Creating the new configuration inside the convex hull.
+  abcd.tet = edab.tet; // Update edab to be abcd.
+  setorg (abcd, pa);
+  setdest(abcd, pb);
+  setapex(abcd, pc);
+  setoppo(abcd, pd);
+  bace.tet = edbc.tet; // Update edbc to be bace.
+  setorg (bace, pb);
+  setdest(bace, pa);
+  setapex(bace, pc);
+  setoppo(bace, pe);
+  // Dealloc a redundant tetrahedron (edca).
+  tetrahedrondealloc(edca.tet); 
+
+  // 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);
+  }
+  // Bond the inside face of the convex hull.
+  abcd.loc = 0;
+  bace.loc = 0;
+  bond(abcd, bace);
+  // Bond the outside faces of the convex hull.
+  abcd.loc = 1;
+  bond(abcd, abdcasing);
+  abcd.loc = 2;
+  bond(abcd, bcdcasing);
+  abcd.loc = 3;
+  bond(abcd, cadcasing);
+  bace.loc = 1;
+  bond(bace, baecasing);
+  bace.loc = 3;
+  bond(bace, cbecasing);
+  bace.loc = 2;
+  bond(bace, acecasing);
+  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);
+    }
+    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 (acesh.sh != dummysh) {
+      bace.loc = 2;
+      tsbond(bace, acesh);
+    }
+  }
+
+  abcd.loc = 0;
+  bace.loc = 0;
+  if (b->verbose > 3) {
+    printf("    Updating abcd ");
+    printtet(&abcd);
+    printf("    Updating bace ");
+    printtet(&bace);
+    printf("    Deleting edca ");
+    // printtet(&edca);
+  }
+
+  if (flipqueue != (queue *) NULL) { 
+    fnext(abcd, abdcasing);
+    enqueueflipface(abdcasing, flipqueue);
+    fnext(bace, baecasing);
+    enqueueflipface(baecasing, flipqueue);
+    enextfnext(abcd, bcdcasing);
+    enqueueflipface(bcdcasing, flipqueue);
+    enextfnext(bace, cbecasing);
+    enqueueflipface(cbecasing, flipqueue);
+    enext2fnext(abcd, cadcasing);
+    enqueueflipface(cadcasing, flipqueue);
+    enext2fnext(bace, acecasing);
+    enqueueflipface(acecasing, flipqueue);  
+  }
+
+  // Save a live handle in 'recenttet'.
+  recenttet = abcd;
+  // Set the return handle be abcd.
+  *flipface = abcd;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip22()    Perform a 2-to-2 (or 4-to-4) flip.                            //
+//                                                                           //
+// On input, 'flipface' represents the face will be flipped.  Let it is abe, //
+// ab is the flipable edge, the two tetrahedra sharing abe are abce and bade,//
+// hence a, b, c and d are coplanar. If abc, bad are interior faces, the two //
+// tetrahedra opposite to e are bacf and abdf.  ab is not a subsegment.      //
+//                                                                           //
+// A 2-to-2 flip is to change two tetrahedra abce and bade into another two  //
+// tetrahedra dcae and cdbe. If bacf and abdf exist, they're changed to cdaf //
+// and dcbf, thus a 4-to-4 flip.  As a result, two or four tetrahedra have   //
+// rotated counterclockwise (using right-hand rule with thumb points to e):  //
+// abce->dcae, bade->cdbe, and bacf->cdaf, abdf->dcbf.                       //
+//                                                                           //
+// If abc and bad are subfaces, a 2-to-2 flip is performed simultaneously by //
+// calling routine flip22sub(), hence abc->dca, bad->cdb.  The edge rings of //
+// the flipped subfaces dca and cdb have the same orientation as abc and bad.//
+// Hence, they have the same orientation as other subfaces of the facet with //
+// respect to the lift point of this facet.                                  //
+//                                                                           //
+// On completion, 'flipface' holds edge dc of tetrahedron dcae. 'flipqueue'  //
+// contains all possibly non-Delaunay faces if it is not NULL.               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flip22(triface* flipface, queue* flipqueue)
+{
+  triface abce, bade;
+  triface oldbce, oldcae, oldade, olddbe;
+  triface bcecasing, caecasing, adecasing, dbecasing;
+  face bcesh, caesh, adesh, dbesh;
+  triface bacf, abdf;
+  triface oldacf, oldcbf, oldbdf, olddaf;
+  triface acfcasing, cbfcasing, bdfcasing, dafcasing;
+  face acfsh, cbfsh, bdfsh, dafsh;
+  face abc, bad;
+  point pa, pb, pc, pd, pe, pf;
+  int mirrorflag;
+
+  adjustedgering(*flipface, CCW); // 'flipface' is bae.
+  fnext(*flipface, abce);
+  esymself(abce);
+  adjustedgering(*flipface, CW); // 'flipface' is abe.
+  fnext(*flipface, bade);
+#ifdef SELF_CHECK
+  assert(bade.tet != dummytet);
+#endif
+  esymself(bade);
+  pa = org(abce);
+  pb = dest(abce);
+  pc = apex(abce);
+  pd = apex(bade);
+  pe = oppo(bade);
+#ifdef SELF_CHECK
+  assert(oppo(abce) == pe);
+#endif
+  sym(abce, bacf);
+  mirrorflag = bacf.tet != dummytet;
+  if (mirrorflag) {
+    findedge(&bacf, pb, pa);
+    sym(bade, abdf);
+#ifdef SELF_CHECK
+    assert(abdf.tet != dummytet);
+#endif
+    findedge(&abdf, pa, pb);
+    pf = oppo(bacf);
+#ifdef SELF_CHECK
+    assert(oppo(abdf) == pf);
+#endif
+  } 
+
+  if (b->verbose > 2) {
+    printf("    Do %s on edge (%d, %d).\n", mirrorflag ? "T44" : "T22",
+           pointmark(pa), pointmark(pb));
+  }
+  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);
+  enextfnext(bade, oldade);
+  enext2fnext(bade, olddbe);
+  sym(oldbce, bcecasing);
+  sym(oldcae, caecasing);
+  sym(oldade, adecasing);
+  sym(olddbe, dbecasing);
+  if (checksubfaces) {
+    tspivot(oldbce, bcesh);
+    tspivot(oldcae, caesh);
+    tspivot(oldade, adesh);
+    tspivot(olddbe, dbesh);
+    tspivot(abce, abc);
+    tspivot(bade, bad);
+  }
+  if (mirrorflag) {
+    enextfnext(bacf, oldacf);
+    enext2fnext(bacf, oldcbf);
+    enextfnext(abdf, oldbdf);
+    enext2fnext(abdf, olddaf);
+    sym(oldacf, acfcasing);
+    sym(oldcbf, cbfcasing);
+    sym(oldbdf, bdfcasing);
+    sym(olddaf, dafcasing);
+    if (checksubfaces) {
+      tspivot(oldacf, acfsh);
+      tspivot(oldcbf, cbfsh);
+      tspivot(oldbdf, bdfsh);
+      tspivot(olddaf, dafsh);
+    }
+  }
+
+  // Rotate abce, bade one-quarter turn counterclockwise.
+  bond(oldbce, caecasing);
+  bond(oldcae, adecasing);
+  bond(oldade, dbecasing);
+  bond(olddbe, bcecasing);
+  if (checksubfaces) {
+    // Check for subfaces and rebond them to the rotated tets.
+    if (caesh.sh == dummysh) {
+      tsdissolve(oldbce);
+    } else {
+      tsbond(oldbce, caesh);
+    }
+    if (adesh.sh == dummysh) {
+      tsdissolve(oldcae);
+    } else {
+      tsbond(oldcae, adesh);
+    }
+    if (dbesh.sh == dummysh) {
+      tsdissolve(oldade);
+    } else {
+      tsbond(oldade, dbesh);
+    }
+    if (bcesh.sh == dummysh) {
+      tsdissolve(olddbe);
+    } else {
+      tsbond(olddbe, bcesh);
+    }
+  }
+  if (mirrorflag) {
+    // Rotate bacf, abdf one-quarter turn counterclockwise.
+    bond(oldcbf, acfcasing);
+    bond(oldacf, dafcasing);
+    bond(olddaf, bdfcasing);
+    bond(oldbdf, cbfcasing);
+    if (checksubfaces) {
+      // Check for subfaces and rebond them to the rotated tets.
+      if (acfsh.sh == dummysh) {
+        tsdissolve(oldcbf);
+      } else {
+        tsbond(oldcbf, acfsh);
+      }
+      if (dafsh.sh == dummysh) {
+        tsdissolve(oldacf);
+      } else {
+        tsbond(oldacf, dafsh);
+      }
+      if (bdfsh.sh == dummysh) {
+        tsdissolve(olddaf);
+      } else {
+        tsbond(olddaf, bdfsh);
+      }
+      if (cbfsh.sh == dummysh) {
+        tsdissolve(oldbdf);
+      } else {
+        tsbond(oldbdf, cbfsh);
+      }
+    }
+  }
+
+  // New vertex assignments for the rotated tetrahedra.
+  setorg(abce, pd); // Update abce to dcae
+  setdest(abce, pc);
+  setapex(abce, pa);
+  setorg(bade, pc); // Update bade to cdbe
+  setdest(bade, pd);
+  setapex(bade, pb);
+  if (mirrorflag) {
+    setorg(bacf, pc); // Update bacf to cdaf
+    setdest(bacf, pd);
+    setapex(bacf, pa);
+    setorg(abdf, pd); // Update abdf to dcbf
+    setdest(abdf, pc);
+    setapex(abdf, pb);
+  }
+
+  // Are there subfaces need to be flipped?
+  if (checksubfaces && abc.sh != dummysh) {
+#ifdef SELF_CHECK
+    assert(bad.sh != dummysh);
+#endif
+    // Adjust the edge be ab, so the rotation of subfaces is according with
+    //   the rotation of tetrahedra.
+    findedge(&abc, pa, pb);
+    // Flip an edge of two subfaces, ignore non-Delaunay edges.
+    flip22sub(&abc, NULL);
+  }
+
+  if (b->verbose > 3) {
+    printf("    Updating abce ");
+    printtet(&abce);
+    printf("    Updating bade ");
+    printtet(&bade);
+    if (mirrorflag) {
+      printf("    Updating bacf ");
+      printtet(&bacf);
+      printf("    Updating abdf ");
+      printtet(&abdf);
+    }
+  }
+
+  if (flipqueue != (queue *) NULL) { 
+    enextfnext(abce, bcecasing);
+    enqueueflipface(bcecasing, flipqueue);
+    enext2fnext(abce, caecasing);
+    enqueueflipface(caecasing, flipqueue);
+    enextfnext(bade, adecasing);
+    enqueueflipface(adecasing, flipqueue);
+    enext2fnext(bade, dbecasing);
+    enqueueflipface(dbecasing, flipqueue);
+    if (mirrorflag) {
+      enextfnext(bacf, acfcasing);
+      enqueueflipface(acfcasing, flipqueue);
+      enext2fnext(bacf, cbfcasing);
+      enqueueflipface(cbfcasing, flipqueue);
+      enextfnext(abdf, bdfcasing);
+      enqueueflipface(bdfcasing, flipqueue);
+      enext2fnext(abdf, dafcasing);
+      enqueueflipface(dafcasing, flipqueue);
+    }
+    // The two new faces dcae (abce), cdbe (bade) may still not be locally
+    //   Delaunay, and may need be flipped (flip23).  On the other hand, in
+    //   conforming Delaunay algorithm, two new subfaces dca (abc), and cdb
+    //   (bad) may be non-conforming Delaunay, they need be queued if they
+    //   are locally Delaunay but non-conforming Delaunay.
+    enqueueflipface(abce, flipqueue);
+    enqueueflipface(bade, flipqueue);
+  }
+
+  // Save a live handle in 'recenttet'.
+  recenttet = abce;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip22sub()    Perform a 2-to-2 flip on a subface edge.                   //
+//                                                                           //
+// The flip edge is given by subface 'flipedge'.  Let it is abc, where ab is //
+// the flipping edge.  The other subface is bad,  where a, b, c, d form a    //
+// convex quadrilateral.  ab is not a subsegment.                            //
+//                                                                           //
+// A 2-to-2 subface flip is to change two subfaces abc and bad to another    //
+// two subfaces dca and cdb.  Hence, edge ab has been removed and dc becomes //
+// an edge. If a point e is above abc, this flip is equal to rotate abc and  //
+// bad counterclockwise using right-hand rule with thumb points to e. It is  //
+// important to know that the edge rings of the flipped subfaces dca and cdb //
+// are keeping the same orientation as their original subfaces. So they have //
+// the same orientation with respect to the lift point of this facet.        //
+//                                                                           //
+// During rotating, the face rings of the four edges bc, ca, ad, and de need //
+// be re-connected. If the edge is not a subsegment, then its face ring has  //
+// only two faces, a sbond() will bond them together. If it is a subsegment, //
+// one should use sbond1() twice to bond two different handles to the rotat- //
+// ing subface, one is predecssor (-casin), another is successor (-casout).  //
+//                                                                           //
+// If 'flipqueue' is not NULL, it returns four edges bc, ca, ad, de, which   //
+// may be non-Delaunay.                                                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flip22sub(face* flipedge, queue* flipqueue)
+{
+  face abc, bad;
+  face oldbc, oldca, oldad, olddb;
+  face bccasin, bccasout, cacasin, cacasout;
+  face adcasin, adcasout, dbcasin, dbcasout;
+  face bc, ca, ad, db;
+  face spinsh;
+  point pa, pb, pc, pd;
+
+  abc = *flipedge;
+  spivot(abc, bad);
+  if (sorg(bad) != sdest(abc)) {
+    sesymself(bad);
+  }
+  pa = sorg(abc);
+  pb = sdest(abc);
+  pc = sapex(abc);
+  pd = sapex(bad);
+
+  if (b->verbose > 2) {
+    printf("    Flip sub edge (%d, %d).\n", pointmark(pa), pointmark(pb));
+  }
+
+  // Save the old configuration outside the quadrilateral.  
+  senext(abc, oldbc);
+  senext2(abc, oldca);
+  senext(bad, oldad);
+  senext2(bad, olddb);
+  // Get the outside connection. Becareful if there is a subsegment on the
+  //   quadrilateral, two casings (casin and casout) are needed to save for
+  //   keeping the face link.
+  spivot(oldbc, bccasout);
+  sspivot(oldbc, bc);
+  if (bc.sh != dummysh) {
+    // 'bc' is a subsegment.
+    if (bccasout.sh != dummysh) {
+      if (oldbc.sh != bccasout.sh) {
+        // 'oldbc' is not self-bonded.
+        spinsh = bccasout;
+        do {
+          bccasin = spinsh;
+          spivotself(spinsh);
+        } while (spinsh.sh != oldbc.sh);
+      } else {
+        bccasout.sh = dummysh;
+      }
+    }
+    ssdissolve(oldbc);
+  }
+  spivot(oldca, cacasout);
+  sspivot(oldca, ca);
+  if (ca.sh != dummysh) {
+    // 'ca' is a subsegment.
+    if (cacasout.sh != dummysh) {
+      if (oldca.sh != cacasout.sh) {
+        // 'oldca' is not self-bonded.
+        spinsh = cacasout;
+        do {
+          cacasin = spinsh;
+          spivotself(spinsh);
+        } while (spinsh.sh != oldca.sh);
+      } else {
+        cacasout.sh = dummysh;
+      }
+    }
+    ssdissolve(oldca);
+  }
+  spivot(oldad, adcasout);
+  sspivot(oldad, ad);
+  if (ad.sh != dummysh) {
+    // 'ad' is a subsegment. 
+    if (adcasout.sh != dummysh) {
+      if (oldad.sh != adcasout.sh) {
+        // 'adcasout' is not self-bonded.
+        spinsh = adcasout;
+        do {
+          adcasin = spinsh;
+          spivotself(spinsh);
+        } while (spinsh.sh != oldad.sh);
+      } else {
+        adcasout.sh = dummysh;
+      }
+    }
+    ssdissolve(oldad);
+  }
+  spivot(olddb, dbcasout);
+  sspivot(olddb, db);
+  if (db.sh != dummysh) {
+    // 'db' is a subsegment.
+    if (dbcasout.sh != dummysh) {
+      if (olddb.sh != dbcasout.sh) {
+        // 'dbcasout' is not self-bonded.
+        spinsh = dbcasout;
+        do {
+          dbcasin = spinsh;
+          spivotself(spinsh);
+        } while (spinsh.sh != olddb.sh);
+      } else {
+        dbcasout.sh = dummysh;
+      }
+    }
+    ssdissolve(olddb);
+  }
+
+  // Rotate abc and bad one-quarter turn counterclockwise.
+  if (ca.sh != dummysh) {
+    if (cacasout.sh != dummysh) {
+      sbond1(cacasin, oldbc);
+      sbond1(oldbc, cacasout);
+    } else {
+      // Bond 'oldbc' to itself.
+      sbond(oldbc, oldbc);
+      // Make sure that dummysh always correctly bonded.
+      dummysh[0] = sencode(oldbc);
+    }
+    ssbond(oldbc, ca);
+  } else {
+    sbond(oldbc, cacasout);
+  }
+  if (ad.sh != dummysh) {
+    if (adcasout.sh != dummysh) {
+      sbond1(adcasin, oldca);
+      sbond1(oldca, adcasout);
+    } else {
+      // Bond 'oldca' to itself.
+      sbond(oldca, oldca);
+      // Make sure that dummysh always correctly bonded.
+      dummysh[0] = sencode(oldca);
+    }
+    ssbond(oldca, ad);
+  } else {
+    sbond(oldca, adcasout);
+  }
+  if (db.sh != dummysh) {
+    if (dbcasout.sh != dummysh) {
+      sbond1(dbcasin, oldad);
+      sbond1(oldad, dbcasout);
+    } else {
+      // Bond 'oldad' to itself.
+      sbond(oldad, oldad);
+      // Make sure that dummysh always correctly bonded.
+      dummysh[0] = sencode(oldad);
+    }
+    ssbond(oldad, db);
+  } else {
+    sbond(oldad, dbcasout);
+  }
+  if (bc.sh != dummysh) {
+    if (bccasout.sh != dummysh) {
+      sbond1(bccasin, olddb);
+      sbond1(olddb, bccasout);
+    } else {
+      // Bond 'olddb' to itself.
+      sbond(olddb, olddb);
+      // Make sure that dummysh always correctly bonded.
+      dummysh[0] = sencode(olddb);
+    }
+    ssbond(olddb, bc);
+  } else {
+    sbond(olddb, bccasout);
+  }
+
+  // New vertex assignments for the rotated subfaces.
+  setsorg(abc, pd);  // Update abc to dca.
+  setsdest(abc, pc);
+  setsapex(abc, pa);
+  setsorg(bad, pc);  // Update bad to cdb.
+  setsdest(bad, pd);
+  setsapex(bad, pb);
+
+  if (flipqueue != (queue *) NULL) {
+    enqueueflipedge(bccasout, flipqueue);
+    enqueueflipedge(cacasout, flipqueue);
+    enqueueflipedge(adcasout, flipqueue);
+    enqueueflipedge(dbcasout, flipqueue);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip()    Flips non-locally Delaunay faces in flipqueue until it is empty.//
+//                                                                           //
+// Assumpation:  Current tetrahedralization is non-Delaunay after inserting  //
+// a point or performing a flip operation, all possibly non-Delaunay faces   //
+// are in 'flipqueue'.                                                       //
+//                                                                           //
+// If 'plastflip' is not NULL,  it is used to return a stack of recently     //
+// flipped faces.  This stack will be used to reverse the flips done in this //
+// routine later for removing a newly inserted point because it encroaches   //
+// any subfaces or subsegments.                                              //
+//                                                                           //
+// The return value is the total number of flips done during this invocation.//
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+long tetgenmesh::flip(queue* flipqueue, badface **plastflip)
+{
+  badface *qface, *newflip;
+  triface flipface, symface;
+  point pa, pb, pc, pd, pe;
+  enum fliptype fc;
+  REAL sign, bakepsilon;
+  long flipcount, maxfaces;
+  int epscount, fcount;
+  int ia, ib, ic, id, ie;
+
+  if (b->verbose > 1) {
+    printf("    Do flipface queue: %ld faces.\n", flipqueue->len());
+  }
+
+  flipcount = flip23s + flip32s + flip22s + flip44s;
+  if (checksubfaces) {
+    maxfaces = (4l * tetrahedrons->items + hullsize) / 2l;
+    fcount = 0;
+  }
+
+  if (plastflip != (badface **) NULL) {
+    // Initialize the stack of the flip sequence.
+    flipstackers->restart();
+    *plastflip = (badface *) NULL;
+  }
+
+  // Loop until the queue is empty.
+  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;
+    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) {
+      // For positive orientation that insphere() test requires.
+      adjustedgering(flipface, CW);
+      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(pa, pb, pc, pd, pe, ia, ib, ic, id, ie);
+        assert(sign != 0.0);
+      // } else {  
+      //   sign = insphere(pa, pb, pc, pd, pe);
+      // }
+    } else {
+      sign = -1.0; // A hull face is locally Delaunay.
+    }
+    if (sign > 0.0) {
+      // 'flipface' is non-locally Delaunay, try to flip it.     
+      if (checksubfaces) {
+        fcount++;
+        bakepsilon = b->epsilon;
+        epscount = 0;
+        while (epscount < 32) {
+          fc = categorizeface(flipface);
+          if (fc == NONCONVEX) {
+            b->epsilon *= 1e-1;
+            epscount++;
+            continue;
+          }
+          break;
+        }
+        b->epsilon = bakepsilon;
+        if (epscount >= 32) {
+          if (b->verbose > 0) {
+            printf("Warning:  Can't flip a degenerate tetrahedron.\n");
+          }
+          fc = NONCONVEX;
+        }
+      } else {
+        fc = categorizeface(flipface);
+#ifdef SELF_CHECK
+        assert(fc != NONCONVEX);
+#endif
+      }
+      switch (fc) {
+      // The following face types are flipable.
+      case T44:
+      case T22:
+        flip22(&flipface, flipqueue); 
+        break;
+      case T23:
+        flip23(&flipface, flipqueue); 
+        break;
+      case T32:
+        flip32(&flipface, flipqueue); 
+        break;
+      // The following face types are unflipable.
+      case UNFLIPABLE:
+        break;
+      case FORBIDDENFACE:
+        break;
+      case FORBIDDENEDGE:
+        break;
+      // This case is only possible when the domain is nonconvex.
+      case NONCONVEX:
+        // assert(nonconvex);
+        break;
+      }
+      if (plastflip != (badface **) NULL) {
+        if ((fc == T44) || (fc == T22) || (fc == T23) || (fc == T32)) { 
+          // Push the flipped face into stack.
+          newflip = (badface *) flipstackers->alloc();
+          newflip->tt = flipface;
+          newflip->key = (REAL) fc;
+          newflip->forg = org(flipface);
+          newflip->fdest = dest(flipface);
+          newflip->fapex = apex(flipface);
+          newflip->previtem = *plastflip;
+          *plastflip = newflip; 
+        }
+      }
+    }
+  }
+
+  flipcount = flip23s + flip32s + flip22s + flip44s - flipcount;
+  if (b->verbose > 1) {
+    printf("    %ld flips.\n", flipcount);
+  }
+
+  return flipcount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// undoflip()    Undo the most recent flip sequence induced by flip().       //
+//                                                                           //
+// 'lastflip' is the stack of recently flipped faces. Walks through the list //
+// of flips, in the reverse of the order in which they were done, and undoes //
+// them.                                                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::undoflip(badface *lastflip)
+{
+  enum fliptype fc;
+
+  while (lastflip != (badface *) NULL) {
+    // Get the right flipped face.
+    findface(&lastflip->tt, lastflip->forg, lastflip->fdest, lastflip->fapex);
+    fc = (enum fliptype) (int) lastflip->key;
+    switch (fc) {
+    case T23:
+      // The reverse operation of T23 is T32.
+      flip32(&lastflip->tt, NULL);
+      break;
+    case T32:
+      // The reverse operation of T32 is T23.
+      flip23(&lastflip->tt, NULL);
+      break;
+    case T22:
+    case T44:
+      // The reverse operation of T22 or T44 is again T22 or T44.
+      flip22(&lastflip->tt, NULL);
+      break;
+    default: // To omit compile warnings.
+      break;
+    }
+    // Go on and process the next transformation.
+    lastflip = lastflip->previtem;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flipsub()    Flip non-Delaunay edges in a queue of (coplanar) subfaces.   //
+//                                                                           //
+// Assumpation:  Current triangulation T contains non-Delaunay edges (after  //
+// inserting a point or performing a flip). Non-Delaunay edges are queued in //
+// 'facequeue'. Returns the total number of flips done during this call.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+long tetgenmesh::flipsub(queue* flipqueue)
+{
+  badface *qedge;
+  face flipedge, symedge;
+  face checkseg;
+  point pa, pb, pc, pd;
+  REAL vab[3], vac[3], vad[3];
+  REAL dot1, dot2, lac, lad; 
+  REAL sign, ori;
+  int edgeflips;
+  int i;
+
+  if (b->verbose > 1) {
+    printf("  Start do edge queue: %ld edges.\n", flipqueue->len());
+  }
+
+  edgeflips = 0;
+
+  while ((qedge = (badface *) flipqueue->pop()) != NULL) {
+    flipedge = qedge->ss;
+    if (flipedge.sh == dummysh) continue;
+    if ((sorg(flipedge) != qedge->forg) || 
+        (sdest(flipedge) != qedge->fdest)) continue; 
+    sspivot(flipedge, checkseg);
+    if (checkseg.sh != dummysh) continue;  // Can't flip a subsegment.
+    spivot(flipedge, symedge);
+    if (symedge.sh == dummysh) continue; // Can't flip a hull edge.
+    pa = sorg(flipedge);
+    pb = sdest(flipedge);
+    pc = sapex(flipedge);
+    pd = sapex(symedge);
+    // Choose the triangle abc or abd as the base depending on the angle1
+    //   (Vac, Vab) and angle2 (Vad, Vab).
+    for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i];
+    for (i = 0; i < 3; i++) vac[i] = pc[i] - pa[i];
+    for (i = 0; i < 3; i++) vad[i] = pd[i] - pa[i];
+    dot1 = dot(vac, vab);
+    dot2 = dot(vad, vab);
+    dot1 *= dot1;
+    dot2 *= dot2;
+    lac = dot(vac, vac);
+    lad = dot(vad, vad);
+    if (lad * dot1 <= lac * dot2) {
+      // angle1 is closer to 90 than angle2, choose abc (flipedge).
+      abovepoint = facetabovepointarray[shellmark(flipedge)];
+      if (abovepoint == (point) NULL) {
+        getfacetabovepoint(&flipedge);
+      }
+      sign = insphere(pa, pb, pc, abovepoint, pd);
+      ori = orient3d(pa, pb, pc, abovepoint);
+    } else {
+      // angle2 is closer to 90 than angle1, choose abd (symedge).
+      abovepoint = facetabovepointarray[shellmark(symedge)];
+      if (abovepoint == (point) NULL) {
+        getfacetabovepoint(&symedge);
+      }
+      sign = insphere(pa, pb, pd, abovepoint, pc);
+      ori = orient3d(pa, pb, pd, abovepoint);
+    }
+    // Correct the sign.
+    sign = ori > 0.0 ? sign : -sign;
+    if (sign > 0.0) {
+      // Flip the non-Delaunay edge.
+      flip22sub(&flipedge, flipqueue);
+      edgeflips++;
+    }
+  }
+
+  if (b->verbose > 1) {
+    printf("  Total %d flips.\n", edgeflips);
+  }
+
+  return edgeflips;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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.
+  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);
+  sym(oldbcd, bcdcasing);
+  sym(oldcad, cadcasing);
+  maketetrahedron(&badv);
+  maketetrahedron(&cbdv);
+  maketetrahedron(&acdv);
+
+  // Set 'badv' vertices.
+  setorg (badv, pb);
+  setdest(badv, pa);
+  setapex(badv, pd);
+  setoppo(badv, newpoint);
+  // Set 'cbdv' vertices.
+  setorg (cbdv, pc);
+  setdest(cbdv, pb);
+  setapex(cbdv, pd);
+  setoppo(cbdv, newpoint);
+  // Set 'acdv' vertices.
+  setorg (acdv, pa);
+  setdest(acdv, pc);
+  setapex(acdv, pd);
+  setoppo(acdv, newpoint);
+  // Set 'abcv' vertices
+  setoppo(abcv, newpoint);
+
+  // Set the element attributes of the new tetrahedra.
+  for (i = 0; i < in->numberoftetrahedronattributes; i++) {
+    attrib = elemattribute(abcv.tet, i);
+    setelemattribute(badv.tet, i, attrib);
+    setelemattribute(cbdv.tet, i, attrib);
+    setelemattribute(acdv.tet, i, attrib);
+  }
+  // Set the volume constraint of the new tetrahedra.
+  if (b->varvolume) {
+    volume = volumebound(abcv.tet);
+    setvolumebound(badv.tet, volume);
+    setvolumebound(cbdv.tet, volume);
+    setvolumebound(acdv.tet, volume);
+  }
+
+  // Bond the new triangles to the surrounding tetrahedron.
+  bond(badv, abdcasing);
+  bond(cbdv, bcdcasing);
+  bond(acdv, cadcasing);
+  // There may exist subfaces need to be bonded to the new tetrahedra.
+  if (checksubfaces) {
+    tspivot(oldabd, abdsh);
+    if (abdsh.sh != dummysh) {
+      tsdissolve(oldabd);
+      tsbond(badv, abdsh);
+    }
+    tspivot(oldbcd, bcdsh);
+    if (bcdsh.sh != dummysh) {
+      tsdissolve(oldbcd);
+      tsbond(cbdv, bcdsh);
+    }
+    tspivot(oldcad, cadsh);
+    if (cadsh.sh != dummysh) {
+      tsdissolve(oldcad);
+      tsbond(acdv, cadsh);
+    }
+  }
+  badv.loc = 3; 
+  cbdv.loc = 2;
+  bond(badv, cbdv);
+  cbdv.loc = 3; 
+  acdv.loc = 2;
+  bond(cbdv, acdv);
+  acdv.loc = 3; 
+  badv.loc = 2;
+  bond(acdv, badv);
+  badv.loc = 1; 
+  bond(badv, oldabd);
+  cbdv.loc = 1; 
+  bond(cbdv, oldbcd);
+  acdv.loc = 1; 
+  bond(acdv, oldcad);
+  
+  badv.loc = 0;
+  cbdv.loc = 0;
+  acdv.loc = 0;
+  if (b->verbose > 3) {
+    printf("    Updating abcv ");
+    printtet(&abcv);
+    printf("    Creating badv ");
+    printtet(&badv);
+    printf("    Creating cbdv ");
+    printtet(&cbdv);
+    printf("    Creating acdv ");
+    printtet(&acdv);
+  }
+
+  if (flipqueue != (queue *) NULL) {
+    enqueueflipface(abcv, flipqueue);
+    enqueueflipface(badv, flipqueue);
+    enqueueflipface(cbdv, flipqueue);
+    enqueueflipface(acdv, flipqueue);
+  }
+
+  // Save a handle for quick point location.
+  recenttet = abcv;
+  // Set the return handle be abcv.
+  *splittet = abcv;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// unsplittetrahedron()    Reverse the operation of inserting a point into a //
+//                         tetrahedron, so as to remove the newly inserted   //
+//                         point from the mesh.                              //
+//                                                                           //
+// Assume the origional tetrahedron is abcd, it was split by v into four     //
+// tetrahedra abcv, badv, cbdv, and acdv. 'splittet' represents face abc of  //
+// abcv (i.e., its opposite is v).                                           //
+//                                                                           //
+// Point v is removed by expanding abcv to abcd, deleting three tetrahedra   //
+// badv, cbdv and acdv.  On return, point v is not deleted in this routine.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::unsplittetrahedron(triface* splittet)
+{
+  triface abcv, badv, cbdv, acdv;
+  triface oldabv, oldbcv, oldcav;
+  triface badcasing, cbdcasing, acdcasing;
+  face badsh, cbdsh, acdsh;
+
+  abcv = *splittet;
+  adjustedgering(abcv, CCW);  // for sure.
+  fnext(abcv, oldabv);
+  fnext(oldabv, badv);
+  esymself(badv);
+  enextfnext(abcv, oldbcv);
+  fnext(oldbcv, cbdv);
+  esymself(cbdv);
+  enext2fnext(abcv, oldcav);
+  fnext(oldcav, acdv);
+  esymself(acdv);
+
+  if (b->verbose > 1) {
+    printf("  Removing point %d in tetrahedron (%d, %d, %d, %d).\n",
+           pointmark(oppo(abcv)), pointmark(org(abcv)), pointmark(dest(abcv)),
+           pointmark(apex(abcv)), pointmark(apex(badv)));
+  }
+
+  sym(badv, badcasing);
+  tspivot(badv, badsh);
+  sym(cbdv, cbdcasing);
+  tspivot(cbdv, cbdsh);
+  sym(acdv, acdcasing);
+  tspivot(acdv, acdsh);
+
+  // Expanding abcv to abcd.
+  setoppo(abcv, apex(badv));
+  bond(oldabv, badcasing);
+  if (badsh.sh != dummysh) {
+    tsbond(oldabv, badsh);
+  }
+  bond(oldbcv, cbdcasing);
+  if (cbdsh.sh != dummysh) {
+    tsbond(oldbcv, cbdsh);
+  }
+  bond(oldcav, acdcasing);
+  if (acdsh.sh != dummysh) {
+    tsbond(oldcav, acdsh);
+  }
+
+  // Delete the three split-out tetrahedra.
+  tetrahedrondealloc(badv.tet);
+  tetrahedrondealloc(cbdv.tet);
+  tetrahedrondealloc(acdv.tet);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// splittetface()    Insert a point on a face of a mesh.                     //
+//                                                                           //
+// 'splittet' is the splitting face.  Let it is abcd, where abc is the face  //
+// will be split. If abc is not a hull face, abce is the tetrahedron at the  //
+// opposite of d.                                                            //
+//                                                                           //
+// To split face abc by a point v is to shrink the tetrahedra abcd to abvd,  //
+// create two new tetrahedra bcvd, cavd.  If abc is not a hull face, shrink  //
+// the tetrahedra bace to bave, create two new tetrahedra cbve, acve.        //
+//                                                                           //
+// If abc is a subface, it is split into three subfaces simultaneously by    //
+// calling routine splitsubface(), hence, abv, bcv, cav.  The edge rings of  //
+// the split subfaces have the same orientation as abc's.                    //
+//                                                                           //
+// On completion, 'splittet' returns abvd.  If 'flipqueue' is not NULL, it   //
+// contains all possibly non-locally Delaunay faces.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+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.
+  point pa, pb, pc, pd, pe;
+  REAL attrib, volume;
+  bool mirrorflag;
+  int i;
+
+  abcd = *splittet;
+  // abcd.ver = 0; // Adjust to be CCW edge ring.
+  adjustedgering(abcd, CCW);
+  pa = org(abcd);
+  pb = dest(abcd);
+  pc = apex(abcd);
+  pd = oppo(abcd);
+  pe = (point) NULL; // avoid a compile warning.
+  // Is there a second tetrahderon?
+  mirrorflag = issymexist(&abcd);
+  if (mirrorflag) {
+    // This is an interior face.
+    sym(abcd, bace);
+    findedge(&bace, dest(abcd), org(abcd));
+    pe = oppo(bace);
+  }
+  if (checksubfaces) {
+    // Is there a subface need to be split together?
+    tspivot(abcd, abcsh);
+    if (abcsh.sh != dummysh) {
+      // Exists! Keep the edge ab of both handles be the same.
+      findedge(&abcsh, org(abcd), dest(abcd));
+    }
+  }
+
+  if (b->verbose > 1) {
+    printf("  Inserting point %d on face (%d, %d, %d).\n", pointmark(newpoint),
+           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);
+  sym(oldbcd, bcdcasing);
+  sym(oldcad, cadcasing);
+  // Create two new tetrahedra.
+  maketetrahedron(&bcvd);
+  maketetrahedron(&cavd);
+  if (mirrorflag) {
+    // Save the old configuration at faces bce and cae.
+    enextfnext(bace, oldace);
+    enext2fnext(bace, oldcbe);
+    sym(oldace, acecasing);
+    sym(oldcbe, cbecasing);
+    // Create two new tetrahedra.
+    maketetrahedron(&acve);
+    maketetrahedron(&cbve);
+  } else {
+    // Splitting a boundary face increases the number of boundary faces.
+    hullsize += 2;
+  }
+
+  // Set vertices to the changed tetrahedron and new tetrahedra.
+  abvd = abcd;  // Update 'abcd' to 'abvd'.
+  setapex(abvd, newpoint);
+  setorg (bcvd, pb);  // Set 'bcvd'.
+  setdest(bcvd, pc);
+  setapex(bcvd, newpoint);
+  setoppo(bcvd, pd);
+  setorg (cavd, pc);  // Set 'cavd'.
+  setdest(cavd, pa);
+  setapex(cavd, newpoint);
+  setoppo(cavd, pd);
+  // Set the element attributes of the new tetrahedra.
+  for (i = 0; i < in->numberoftetrahedronattributes; i++) {
+    attrib = elemattribute(abvd.tet, i);
+    setelemattribute(bcvd.tet, i, attrib);
+    setelemattribute(cavd.tet, i, attrib);
+  }
+  if (b->varvolume) {
+    // Set the area constraint of the new tetrahedra.
+    volume = volumebound(abvd.tet);
+    setvolumebound(bcvd.tet, volume);
+    setvolumebound(cavd.tet, volume);
+  }
+  if (mirrorflag) {
+    bave = bace;  // Update 'bace' to 'bave'.
+    setapex(bave, newpoint);
+    setorg (acve, pa);  // Set 'acve'.
+    setdest(acve, pc);
+    setapex(acve, newpoint);
+    setoppo(acve, pe);
+    setorg (cbve, pc);  // Set 'cbve'.
+    setdest(cbve, pb);
+    setapex(cbve, newpoint);
+    setoppo(cbve, pe);
+    // Set the element attributes of the new tetrahedra.
+    for (i = 0; i < in->numberoftetrahedronattributes; i++) {
+      attrib = elemattribute(bave.tet, i);
+      setelemattribute(acve.tet, i, attrib);
+      setelemattribute(cbve.tet, i, attrib);
+    }
+    if (b->varvolume) {
+      // Set the area constraint of the new tetrahedra.
+      volume = volumebound(bave.tet);
+      setvolumebound(acve.tet, volume);
+      setvolumebound(cbve.tet, volume);
+    }
+  }
+
+  // Bond the new tetrahedra to the surrounding tetrahedra.
+  bcvd.loc = 1;
+  bond(bcvd, bcdcasing); 
+  cavd.loc = 1;
+  bond(cavd, cadcasing); 
+  bcvd.loc = 3;
+  bond(bcvd, oldbcd);
+  cavd.loc = 2;
+  bond(cavd, oldcad);
+  bcvd.loc = 2;
+  cavd.loc = 3;
+  bond(bcvd, cavd);  
+  if (mirrorflag) {
+    acve.loc = 1;
+    bond(acve, acecasing);
+    cbve.loc = 1;
+    bond(cbve, cbecasing);
+    acve.loc = 3;
+    bond(acve, oldace);
+    cbve.loc = 2;
+    bond(cbve, oldcbe);
+    acve.loc = 2;
+    cbve.loc = 3;
+    bond(acve, cbve);
+    // Bond two new coplanar facets.
+    bcvd.loc = 0;
+    cbve.loc = 0;
+    bond(bcvd, cbve);
+    cavd.loc = 0;
+    acve.loc = 0;
+    bond(cavd, acve);
+  }
+
+  // There may exist subface needed to be bonded to the new tetrahedra.
+  if (checksubfaces) {
+    tspivot(oldbcd, bcdsh);
+    if (bcdsh.sh != dummysh) {
+      tsdissolve(oldbcd);
+      bcvd.loc = 1;
+      tsbond(bcvd, bcdsh);
+    }
+    tspivot(oldcad, cadsh);
+    if (cadsh.sh != dummysh) {
+      tsdissolve(oldcad);
+      cavd.loc = 1;
+      tsbond(cavd, cadsh);
+    }
+    if (mirrorflag) {
+      tspivot(oldace, acesh);
+      if (acesh.sh != dummysh) {
+        tsdissolve(oldace);
+        acve.loc = 1;
+        tsbond(acve, acesh);
+      }
+      tspivot(oldcbe, cbesh);
+      if (cbesh.sh != dummysh) {
+        tsdissolve(oldcbe);
+        cbve.loc = 1;
+        tsbond(cbve, cbesh);
+      }
+    }
+    // Is there a subface needs to be split together?
+    if (abcsh.sh != dummysh) {
+      // Split this subface 'abc' into three i.e, abv, bcv, cav.
+      splitsubface(newpoint, &abcsh, (queue *) NULL);
+    }  
+  }
+
+  // Save a handle for quick point location.
+  recenttet = abvd;
+  // Set the return handle be abvd.
+  *splittet = abvd;
+
+  bcvd.loc = 0;
+  cavd.loc = 0;
+  if (mirrorflag) {
+    cbve.loc = 0;
+    acve.loc = 0;
+  }
+  if (b->verbose > 3) {
+    printf("    Updating abvd ");
+    printtet(&abvd);
+    printf("    Creating bcvd ");
+    printtet(&bcvd);
+    printf("    Creating cavd ");
+    printtet(&cavd);
+    if (mirrorflag) {
+      printf("    Updating bave ");
+      printtet(&bave);
+      printf("    Creating cbve ");
+      printtet(&cbve);
+      printf("    Creating acve ");
+      printtet(&acve);
+    }
+  }
+
+  if (flipqueue != (queue *) NULL) {
+    fnextself(abvd);
+    enqueueflipface(abvd, flipqueue);
+    fnextself(bcvd);
+    enqueueflipface(bcvd, flipqueue);
+    fnextself(cavd);
+    enqueueflipface(cavd, flipqueue);
+    if (mirrorflag) {
+      fnextself(bave);
+      enqueueflipface(bave, flipqueue);
+      fnextself(cbve);
+      enqueueflipface(cbve, flipqueue);
+      fnextself(acve);
+      enqueueflipface(acve, flipqueue);
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// unsplittetface()    Reverse the operation of inserting a point on a face, //
+//                     so as to remove the newly inserted point.             //
+//                                                                           //
+// Assume the original face is abc, the tetrahedron containing abc is abcd.  //
+// If abc is not a hull face, bace is the tetrahedron at the opposite of d.  //
+// After face abc was split by a point v, tetrahedron abcd had been split    //
+// into three tetrahedra, abvd, bcvd, cavd, and bace (if it exists) had been //
+// split into bave, cbve, acve. 'splittet' represents abvd (its apex is v).  //
+//                                                                           //
+// Point v is removed by expanding abvd to abcd, deleting two tetrahedra     //
+// bcvd, cavd. Expanding bave(if it exists) to bace, deleting two tetrahedra //
+// cbve, acve.  If abv is a subface, routine unsplitsubface() will be called //
+// to reverse the operation of splitting a subface. On completion, point v   //
+// is not deleted in this routine.                                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::unsplittetface(triface* splittet)
+{
+  triface abvd, bcvd, cavd, bave, cbve, acve;
+  triface oldbvd, oldvad, oldvbe, oldave;
+  triface bcdcasing, cadcasing, cbecasing, acecasing;
+  face bcdsh, cadsh, cbesh, acesh;
+  face abvsh;
+  bool mirrorflag;
+
+  abvd = *splittet;
+  adjustedgering(abvd, CCW); // for sure.
+  enextfnext(abvd, oldbvd);
+  fnext(oldbvd, bcvd);
+  esymself(bcvd);
+  enextself(bcvd);
+  enext2fnext(abvd, oldvad);
+  fnext(oldvad, cavd);
+  esymself(cavd);
+  enext2self(cavd);
+  // Is there a second tetrahedron?
+  sym(abvd, bave);
+  mirrorflag = bave.tet != dummytet;
+  if (mirrorflag) {
+    findedge(&bave, dest(abvd), org(abvd));
+    enextfnext(bave, oldave);  
+    fnext(oldave, acve);
+    esymself(acve);
+    enextself(acve);
+    enext2fnext(bave, oldvbe);  
+    fnext(oldvbe, cbve);
+    esymself(cbve);
+    enext2self(cbve);
+  } else {
+    // Unsplit a hull face decrease the number of boundary faces.
+    hullsize -= 2;
+  }
+  // Is there a subface at abv.
+  tspivot(abvd, abvsh);
+  if (abvsh.sh != dummysh) {
+    // Exists! Keep the edge ab of both handles be the same.
+    findedge(&abvsh, org(abvd), dest(abvd));
+  }
+
+  if (b->verbose > 1) {
+    printf("  Removing point %d on face (%d, %d, %d).\n",
+           pointmark(apex(abvd)), pointmark(org(abvd)), pointmark(dest(abvd)),
+           pointmark(dest(bcvd)));
+  }
+
+  fnextself(bcvd); // bcvd has changed to bcdv.
+  sym(bcvd, bcdcasing);
+  tspivot(bcvd, bcdsh);
+  fnextself(cavd); // cavd has changed to cadv.
+  sym(cavd, cadcasing);
+  tspivot(cavd, cadsh);
+  if (mirrorflag) {
+    fnextself(acve); // acve has changed to acev.
+    sym(acve, acecasing);
+    tspivot(acve, acesh);
+    fnextself(cbve); // cbve has changed to cbev.
+    sym(cbve, cbecasing);
+    tspivot(cbve, cbesh);
+  }
+
+  // Expand abvd to abcd.
+  setapex(abvd, dest(bcvd));
+  bond(oldbvd, bcdcasing);
+  if (bcdsh.sh != dummysh) {
+    tsbond(oldbvd, bcdsh);
+  }
+  bond(oldvad, cadcasing);
+  if (cadsh.sh != dummysh) {
+    tsbond(oldvad, cadsh);
+  }
+  if (mirrorflag) {
+    // Expanding bave to bace.
+    setapex(bave, dest(acve));
+    bond(oldave, acecasing);
+    if (acesh.sh != dummysh) {
+      tsbond(oldave, acesh);
+    }
+    bond(oldvbe, cbecasing);
+    if (cbesh.sh != dummysh) {
+      tsbond(oldvbe, cbesh);
+    }
+  }
+
+  // Unsplit a subface if there exists.
+  if (abvsh.sh != dummysh) {
+    unsplitsubface(&abvsh);
+  }
+
+  // Delete the split-out tetrahedra.
+  tetrahedrondealloc(bcvd.tet);
+  tetrahedrondealloc(cavd.tet);
+  if (mirrorflag) {
+    tetrahedrondealloc(acve.tet);
+    tetrahedrondealloc(cbve.tet);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// splitsubface()    Insert a point on a subface, split it into three.       //
+//                                                                           //
+// The subface is 'splitface'.  Let it is abc. The inserting point 'newpoint'//
+// v should lie inside abc.  If the neighbor tetrahedra of abc exist, i.e.,  //
+// abcd and bace, they should have been split by routine splittetface()      //
+// before calling this routine, so the connection between the new tetrahedra //
+// and new subfaces can be correctly set.                                    //
+//                                                                           //
+// To split subface abc by point v is to shrink abc to abv, create two new   //
+// subfaces bcv and cav.  Set the connection between updated and new created //
+// subfaces. If there is a subsegment at edge bc or ca, connection of new    //
+// subface (bcv or cav) to its casing subfaces is a face link, 'casingin' is //
+// the predecessor and 'casingout' is the successor. It is important to keep //
+// the orientations of the edge rings of the updated and created subfaces be //
+// the same as abc's. So they have the same orientation as other subfaces of //
+// this facet with respect to the lift point of this facet.                  //
+//                                                                           //
+// On completion, 'splitface' returns abv.  If 'flipqueue' is not NULL, it   //
+// returns all possibly non-Delaunay edges.                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::
+splitsubface(point newpoint, face* splitface, queue* flipqueue)
+{
+  triface abvd, bcvd, cavd, bave, cbve, acve;
+  face abc, oldbc, oldca, bc, ca, spinsh;
+  face bccasin, bccasout, cacasin, cacasout;
+  face abv, bcv, cav;
+  point pa, pb, pc;
+  
+  abc = *splitface;
+  // The newly created subfaces will have the same edge ring as abc.
+  adjustedgering(abc, CCW);
+  pa = sorg(abc);
+  pb = sdest(abc);
+  pc = sapex(abc);
+
+  if (b->verbose > 1) {
+    printf("  Inserting point %d on subface (%d, %d, %d).\n",
+           pointmark(newpoint), pointmark(pa), pointmark(pb), pointmark(pc));
+  }
+
+  // Save the old configuration at edge bc and ca.  Subsegments may appear
+  //   at both sides, save the face links and dissolve them.
+  senext(abc, oldbc);
+  senext2(abc, oldca);
+  spivot(oldbc, bccasout);
+  sspivot(oldbc, bc);
+  if (bc.sh != dummysh) {
+    if (oldbc.sh != bccasout.sh) {
+      // 'oldbc' is not self-bonded.
+      spinsh = bccasout;
+      do {
+        bccasin = spinsh;
+        spivotself(spinsh);
+      } while (spinsh.sh != oldbc.sh);
+    } else {
+      bccasout.sh = dummysh;
+    }
+    ssdissolve(oldbc);
+  } 
+  spivot(oldca, cacasout);
+  sspivot(oldca, ca);
+  if (ca.sh != dummysh) {
+    if (oldca.sh != cacasout.sh) {
+      // 'oldca' is not self-bonded.
+      spinsh = cacasout;
+      do {
+        cacasin = spinsh;
+        spivotself(spinsh);
+      } while (spinsh.sh != oldca.sh);
+    } else {
+      cacasout.sh = dummysh;
+    }
+    ssdissolve(oldca);
+  }
+  // Create two new subfaces.
+  makeshellface(subfaces, &bcv);
+  makeshellface(subfaces, &cav);
+
+  // Set the vertices of changed and new subfaces.
+  abv = abc;  // Update 'abc' to 'abv'.
+  setsapex(abv, newpoint);
+  setsorg(bcv, pb);  // Set 'bcv'.
+  setsdest(bcv, pc);
+  setsapex(bcv, newpoint);
+  setsorg(cav, pc);  // Set 'cav'.
+  setsdest(cav, pa);
+  setsapex(cav, newpoint);
+  if (b->quality && varconstraint) {
+    // Copy yhr area bound into the new subfaces.
+    setareabound(bcv, areabound(abv));
+    setareabound(cav, areabound(abv));
+  }
+  // Copy the boundary mark into the new subfaces.
+  setshellmark(bcv, shellmark(abv));
+  setshellmark(cav, shellmark(abv));  
+  // Copy the subface type into the new subfaces.
+  setshelltype(bcv, shelltype(abv));
+  setshelltype(cav, shelltype(abv));
+  if (checkpbcs) {
+    // Copy the pbcgroup into the new subfaces.
+    setshellpbcgroup(bcv, shellpbcgroup(abv));
+    setshellpbcgroup(cav, shellpbcgroup(abv));
+  }
+  // Bond the new subfaces to the surrounding subfaces.
+  if (bc.sh != dummysh) {
+    if (bccasout.sh != dummysh) {
+      sbond1(bccasin, bcv);
+      sbond1(bcv, bccasout);
+    } else {
+      // Bond 'bcv' to itsself.
+      sbond(bcv, bcv);
+    }
+    ssbond(bcv, bc);
+  } else {
+    sbond(bcv, bccasout);
+  }
+  if (ca.sh != dummysh) {
+    if (cacasout.sh != dummysh) {
+      sbond1(cacasin, cav);
+      sbond1(cav, cacasout);
+    } else {
+      // Bond 'cav' to itself.
+      sbond(cav, cav);
+    }
+    ssbond(cav, ca);
+  } else {
+    sbond(cav, cacasout);
+  }
+  senext2self(bcv);
+  sbond(bcv, oldbc);
+  senextself(cav);
+  sbond(cav, oldca);
+  senext2self(bcv);
+  senextself(cav);
+  sbond(bcv, cav);
+
+  // Bond the new subfaces to the new tetrahedra if they exist.
+  stpivot(abv, abvd);
+  if (abvd.tet != dummytet) {
+    // Get two new tetrahedra and their syms.
+    findedge(&abvd, sorg(abv), sdest(abv));
+    enextfnext(abvd, bcvd);
+#ifdef SELF_CHECK
+    assert(bcvd.tet != dummytet);
+#endif
+    fnextself(bcvd);
+    enext2fnext(abvd, cavd);
+#ifdef SELF_CHECK
+    assert(cavd.tet != dummytet);
+#endif
+    fnextself(cavd);
+    // Bond two new subfaces to the two new tetrahedra.
+    tsbond(bcvd, bcv);
+    tsbond(cavd, cav);
+  }
+  // Set the connection at the other sides if the tetrahedra exist.
+  sesymself(abv);  // bav
+  stpivot(abv, bave);
+  if (bave.tet != dummytet) {
+    sesymself(bcv);  // cbv
+    sesymself(cav);  // acv
+    // Get two new tetrahedra and their syms.
+    findedge(&bave, sorg(abv), sdest(abv));
+    enextfnext(bave, acve);
+#ifdef SELF_CHECK
+    assert(acve.tet != dummytet);
+#endif
+    fnextself(acve);
+    enext2fnext(bave, cbve);
+#ifdef SELF_CHECK
+    assert(cbve.tet != dummytet);
+#endif
+    fnextself(cbve);
+    // Bond two new subfaces to the two new tetrahedra.
+    tsbond(acve, cav);
+    tsbond(cbve, bcv);
+  }
+
+  bcv.shver = 0;
+  cav.shver = 0;
+  if (b->verbose > 3) {
+    printf("    Updating abv ");
+    printsh(&abv);
+    printf("    Creating bcv ");
+    printsh(&bcv);
+    printf("    Creating cav ");
+    printsh(&cav);
+  }
+
+  if (flipqueue != (queue *) NULL) {
+    enqueueflipedge(abv, flipqueue);
+    enqueueflipedge(bcv, flipqueue);
+    enqueueflipedge(cav, flipqueue);
+  }
+
+  // Set the return handle be abv.
+  *splitface = abv;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// unsplitsubface()    Reverse the operation of inserting a point on a       //
+//                     subface, so as to remove the newly inserted point.    //
+//                                                                           //
+// Assume the original subface is abc, it was split by a point v into three  //
+// subfaces abv, bcv and cav.  'splitsh' represents abv.                     //
+//                                                                           //
+// To remove point v is to expand abv to abc, delete bcv and cav. If edge bc //
+// or ca is a subsegment,  the connection at a subsegment is a subface link, //
+// '-casin' and '-casout' are used to save the predecessor and successor of  //
+// bcv or cav.  On completion, point v is not deleted in this routine.       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::unsplitsubface(face* splitsh)
+{
+  face abv, bcv, cav;
+  face oldbv, oldva, bc, ca, spinsh;
+  face bccasin, bccasout, cacasin, cacasout;
+
+  abv = *splitsh;
+  senext(abv, oldbv);
+  spivot(oldbv, bcv);
+  if (sorg(bcv) != sdest(oldbv)) {
+    sesymself(bcv);
+  }
+  senextself(bcv);
+  senext2(abv, oldva);
+  spivot(oldva, cav);
+  if (sorg(cav) != sdest(oldva)) {
+    sesymself(cav);
+  }
+  senext2self(cav);
+
+  if (b->verbose > 1) {
+    printf("  Removing point %d on subface (%d, %d, %d).\n",
+           pointmark(sapex(abv)), pointmark(sorg(abv)), pointmark(sdest(abv)),
+           pointmark(sdest(bcv)));
+  }
+
+  spivot(bcv, bccasout);
+  sspivot(bcv, bc);
+  if (bc.sh != dummysh) {
+    if (bcv.sh != bccasout.sh) {
+      // 'bcv' is not self-bonded.
+      spinsh = bccasout;
+      do {
+        bccasin = spinsh;
+        spivotself(spinsh);
+      } while (spinsh.sh != bcv.sh);
+    } else {
+      bccasout.sh = dummysh;
+    }
+  }
+  spivot(cav, cacasout);
+  sspivot(cav, ca);
+  if (ca.sh != dummysh) {
+    if (cav.sh != cacasout.sh) {
+      // 'cav' is not self-bonded.
+      spinsh = cacasout;
+      do {
+       cacasin = spinsh;
+       spivotself(spinsh);
+      } while (spinsh.sh != cav.sh);
+    } else {
+      cacasout.sh = dummysh;
+    }
+  }
+
+  // Expand abv to abc.
+  setsapex(abv, sdest(bcv));
+  if (bc.sh != dummysh) {
+    if (bccasout.sh != dummysh) {
+      sbond1(bccasin, oldbv);
+      sbond1(oldbv, bccasout);
+    } else {
+      // Bond 'oldbv' to itself.
+      sbond(oldbv, oldbv);
     }
-    // Edge ab crosses face cde properly.
-    if (checksubfaces) {
-      // If abc is subface, then ab must be a subsegment (because abde is
-      //   a tetrahedron and ab crosses cde properly). 
-      tsspivot(&horiz, &checkseg);
-      if (checkseg.sh != dummysh) {
-        // To flip a subsegment is forbidden.
-        return FORBIDDENEDGE;
-      }
-      // Both abd and bae should not be subfaces (because they're not
-      //   coplanar and ab is not a subsegment). However, they may be
-      //   subfaces and belong to a facet (created during facet recovery),
-      //   that is, abde is an invalid tetrahedron. Find this case out.
-      fnext(horiz, casing);
-      tspivot(casing, cassh1);
-      fnext(symhoriz, casing);
-      tspivot(casing, cassh2); 
-      if (cassh1.sh != dummysh || cassh2.sh != dummysh) {
-        // Unfortunately, they're subfaces. Corrections need be done here.
-        printf("Warning:  A tetrahedron spans two subfaces of a facet.\n");
-        // Temporarily, let it be there.
-        return UNFLIPABLE;
-      }
+    ssbond(oldbv, bc);
+  } else {
+    sbond(oldbv, bccasout);
+  } 
+  if (ca.sh != dummysh) {
+    if (cacasout.sh != dummysh) {
+      sbond1(cacasin, oldva);
+      sbond1(oldva, cacasout);
+    } else {
+      // Bond 'oldva' to itself.
+      sbond(oldva, oldva);
     }
-    return T32;
+    ssbond(oldva, ca);
   } else {
-    assert(adjtet == 2);
-    // The convex hull of {a, b, c, d, e} has only four vertices, abc is
-    //   unflipable, furthermore, it is locally Delaunay.
-    return NONCONVEX;
+    sbond(oldva, cacasout);
   }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// enqueueflipface(), enqueueflipedge()    Add a face or an edge to the end  //
-//                                         of a queue.                       //
-//                                                                           //
-// This face or edge may be non-Delaunay and will be checked.  Corresponding //
-// flip operation will be applied on it if it is non-Delaunay.  The vertices //
-// of the face or edge are stored seperatly used to ensure the face or edge  //
-// is still the same one when we save it.  Sometimes, other flipping will    //
-// cause this face or edge be changed or dead.                               //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::enqueueflipface(triface& checkface, queue* flipqueue)
-{
-  badface *queface;
-
-  queface = (badface *) flipqueue->push((void *) NULL);
-  queface->tt = checkface;
-  queface->forg = org(checkface);
-  queface->fdest = dest(checkface);
-  queface->fapex = apex(checkface);
-}
-
-void tetgenmesh::enqueueflipedge(face& checkedge, queue* flipqueue)
-{
-  badface *queface;
-
-  queface = (badface *) flipqueue->push((void *) NULL);
-  queface->ss = checkedge;
-  queface->forg = sorg(checkedge);
-  queface->fdest = sdest(checkedge);
+  // Delete two split-out subfaces.
+  shellfacedealloc(subfaces, bcv.sh);
+  shellfacedealloc(subfaces, cav.sh);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// flip23()    Perform a 2-to-3 flip.                                        //
+// splittetedge()    Insert a point on an edge of the mesh.                  //
 //                                                                           //
-// On input, 'flipface' represents the face will be flipped.  Let it is abc, //
-// the two tetrahedra sharing abc are abcd, bace. abc is not a subface.      //
+// The edge is given by 'splittet'. Assume its four corners are a, b, n1 and //
+// n2, where ab is the edge will be split. Around ab may exist any number of //
+// tetrahedra. For convenience, they're ordered in a sequence following the  //
+// right-hand rule with your thumb points from a to b. Let the vertex set of //
+// these tetrahedra be {a, b, n1, n2, ..., n(i)}. NOTE the tetrahedra around //
+// ab may not connect to each other (can only happen when ab is a subsegment,//
+// hence some faces abn(i) are subfaces).  If ab is a subsegment, abn1 must  //
+// be a subface.                                                             //
 //                                                                           //
-// A 2-to-3 flip is to change two tetrahedra abcd, bace to three tetrahedra  //
-// edab, edbc, and edca.  As a result, face abc has been removed and three   //
-// new faces eda, edb and edc have been created.                             //
+// To split edge ab by a point v is to split all tetrahedra containing ab by //
+// v.  More specifically, for each such tetrahedron, an1n2b, it is shrunk to //
+// an1n2v, and a new tetrahedra bn2n1v is created. If ab is a subsegment, or //
+// some faces of the splitting tetrahedra are subfaces, they must be split   //
+// either by calling routine 'splitsubedge()'.                               //
 //                                                                           //
-// On completion, 'flipface' returns edab.  If 'flipqueue' is not NULL, all  //
-// possibly non-Delaunay faces are added into it.                            //
+// On completion, 'splittet' returns avn1n2.  If 'flipqueue' is not NULL, it //
+// returns all faces which may become non-Delaunay after this operation.     //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::flip23(triface* flipface, queue* flipqueue)
+void tetgenmesh::
+splittetedge(point newpoint, triface* splittet, 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;
-  face baesh, cbesh, acesh;
-  triface edab, edbc, edca;                            // New configuration.
-  point pa, pb, pc, pd, pe;
+  triface *bots, *newtops;
+  triface oldtop, topcasing;
+  triface spintet, tmpbond0, tmpbond1;
+  face abseg, splitsh, topsh, spinsh;
+  point pa, pb, n1, n2;
   REAL attrib, volume;
-  int i;
+  int wrapcount, hitbdry;
+  int i, j;
 
-  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);
-  pe = oppo(bace);
+  if (checksubfaces) {
+    // Is there a subsegment need to be split together?
+    tsspivot(splittet, &abseg);
+    if (abseg.sh != dummysh) {
+      abseg.shver = 0;
+      // Orient the edge direction of 'splittet' be abseg.
+      if (org(*splittet) != sorg(abseg)) {
+        esymself(*splittet);
+      }
+    }
+  } 
+  spintet = *splittet;
+  pa = org(spintet);
+  pb = dest(spintet);
 
-  if (b->verbose > 2) {
-    printf("    Do T23 on face (%d, %d, %d, %d).\n", pointmark(pa),
-           pointmark(pb), pointmark(pc), pointmark(pd));
+  if (b->verbose > 1) {
+    printf("  Inserting point %d on edge (%d, %d).\n", 
+           pointmark(newpoint), pointmark(pa), pointmark(pb));
   }
-  flip23s++;
 
+  // Collect the tetrahedra containing the splitting edge (ab).
+  n1 = apex(spintet);
+  hitbdry = 0;
+  wrapcount = 1;
+  if (checksubfaces && abseg.sh != dummysh) {
+    // It may happen that some tetrahedra containing ab (a subsegment) are
+    //   completely disconnected with others. If it happens, use the face
+    //   link of ab to cross the boundary. 
+    while (true) {
+      if (!fnextself(spintet)) {
+        // Meet a boundary, walk through it.
+        hitbdry ++;
+        tspivot(spintet, spinsh);
 #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);
+        assert(spinsh.sh != dummysh);
 #endif
-
-  // Storing the old configuration outside the convex hull.
-  fnext(abcd, oldabd);
-  enextfnext(abcd, oldbcd);
-  enext2fnext(abcd, oldcad);
-  fnext(bace, oldbae);
-  enext2fnext(bace, oldcbe);
-  enextfnext(bace, oldace);
-  sym(oldabd, abdcasing);
-  sym(oldbcd, bcdcasing);
-  sym(oldcad, cadcasing);
-  sym(oldbae, baecasing);
-  sym(oldcbe, cbecasing);
-  sym(oldace, acecasing);
-  if (checksubfaces) {
-    tspivot(oldabd, abdsh);
-    tspivot(oldbcd, bcdsh);
-    tspivot(oldcad, cadsh);
-    tspivot(oldbae, baesh);
-    tspivot(oldcbe, cbesh);
-    tspivot(oldace, acesh);
-  }
-
-  // Creating the new configuration inside the convex hull.
-  edab.tet = abcd.tet; // Update abcd to be edab.
-  setorg (edab, pe);
-  setdest(edab, pd);
-  setapex(edab, pa);
-  setoppo(edab, pb);
-  edbc.tet = bace.tet; // Update bace to be edbc.
-  setorg (edbc, pe);
-  setdest(edbc, pd);
-  setapex(edbc, pb);
-  setoppo(edbc, pc);
-  maketetrahedron(&edca); // Create edca.
-  setorg (edca, pe);
-  setdest(edca, pd);
-  setapex(edca, pc);
-  setoppo(edca, pa);
-  // Set the element attributes of the new tetrahedron 'edca'.
-  for (i = 0; i < in->numberoftetrahedronattributes; i++) {
-    attrib = elemattribute(abcd.tet, i);
-    setelemattribute(edca.tet, i, attrib);
-  }
-  // Set the volume constraint of the new tetrahedron 'edca' if the -ra
-  //   switches are not used together. In -ra case, the various volume
-  //   constraints can be spreaded very far.
-  if (b->varvolume && !b->refine) {
-    volume = volumebound(abcd.tet);
-    setvolumebound(edca.tet, volume);
-  }
-
-  // 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);
-  }
-  // Bond the faces inside the convex hull.
-  edab.loc = 0;
-  edca.loc = 1;
-  bond(edab, edca);
-  edab.loc = 1;
-  edbc.loc = 0;
-  bond(edab, edbc);
-  edbc.loc = 1;
-  edca.loc = 0;
-  bond(edbc, edca);
-  // Bond the faces on the convex hull.
-  edab.loc = 2;
-  bond(edab, abdcasing);
-  edab.loc = 3;
-  bond(edab, baecasing);
-  edbc.loc = 2;
-  bond(edbc, bcdcasing);
-  edbc.loc = 3;
-  bond(edbc, cbecasing);
-  edca.loc = 2;
-  bond(edca, cadcasing);
-  edca.loc = 3;
-  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).
-    for (i = 0; i < 4; i ++) {
-      edab.loc = i;
-      tsdissolve(edab);
-      edbc.loc = i;
-      tsdissolve(edbc);
+        findedge(&spinsh, pa, pb);
+        sfnextself(spinsh);
+        stpivot(spinsh, spintet);
+#ifdef SELF_CHECK
+        assert(spintet.tet != dummytet);
+#endif
+        findedge(&spintet, pa, pb);
+        // Remember this position (hull face) in 'splittet'.
+        *splittet = spintet;
+        // Split two hull faces increase the hull size;
+        hullsize += 2;
+      }
+      if (apex(spintet) == n1) break;
+      wrapcount ++;
     }
-    if (abdsh.sh != dummysh) {
-      edab.loc = 2; 
-      tsbond(edab, abdsh);
+    if (hitbdry > 0) {
+      wrapcount -= hitbdry;
     }
-    if (baesh.sh != dummysh) {
-      edab.loc = 3; 
-      tsbond(edab, baesh);
+  } else {
+    // All the tetrahedra containing ab are connected together. If there
+    //   are subfaces, 'splitsh' keeps one of them.
+    splitsh.sh = dummysh;
+    while (hitbdry < 2) {
+      if (checksubfaces && splitsh.sh == dummysh) {
+        tspivot(spintet, splitsh);
+      }
+      if (fnextself(spintet)) {
+        if (apex(spintet) == n1) break;
+        wrapcount++;
+      } else {
+        hitbdry ++;
+        if (hitbdry < 2) {
+          esym(*splittet, spintet);
+        }
+      }
     }
-    if (bcdsh.sh != dummysh) {
-      edbc.loc = 2; 
-      tsbond(edbc, bcdsh);
+    if (hitbdry > 0) {
+      // ab is on the hull.
+      wrapcount -= 1;
+      // 'spintet' now is a hull face, inverse its edge direction.
+      esym(spintet, *splittet);
+      // Split two hull faces increases the number of hull faces.
+      hullsize += 2;
     }
-    if (cbesh.sh != dummysh) {
-      edbc.loc = 3; 
-      tsbond(edbc, cbesh);
+  }
+  
+  // Make arrays of updating (bot, oldtop) and new (newtop) tetrahedra.
+  bots = new triface[wrapcount];
+  newtops = new triface[wrapcount];
+  // Spin around ab, gather tetrahedra and set up new tetrahedra. 
+  spintet = *splittet;
+  for (i = 0; i < wrapcount; i++) {
+    // Get 'bots[i] = an1n2b'.
+    enext2fnext(spintet, bots[i]);
+    esymself(bots[i]);
+    // Create 'newtops[i]'.
+    maketetrahedron(&(newtops[i]));
+    // Go to the next.
+    fnextself(spintet);
+    if (checksubfaces && abseg.sh != dummysh) {
+      if (!issymexist(&spintet)) {
+        // We meet a hull face, walk through it.
+        tspivot(spintet, spinsh);
+#ifdef SELF_CHECK
+        assert(spinsh.sh != dummysh);
+#endif
+        findedge(&spinsh, pa, pb);
+        sfnextself(spinsh);
+        stpivot(spinsh, spintet);
+#ifdef SELF_CHECK
+        assert(spintet.tet != dummytet);
+#endif
+        findedge(&spintet, pa, pb);
+      }
     }
-    if (cadsh.sh != dummysh) {
-      edca.loc = 2; 
-      tsbond(edca, cadsh);
+  }
+  
+  // Set the vertices of updated and new tetrahedra.
+  for (i = 0; i < wrapcount; i++) {
+    // Update 'bots[i] = an1n2v'.
+    setoppo(bots[i], newpoint);
+    // Set 'newtops[i] = bn2n1v'.
+    n1 = dest(bots[i]);
+    n2 = apex(bots[i]);
+    // Set 'newtops[i]'.
+    setorg(newtops[i], pb);
+    setdest(newtops[i], n2);
+    setapex(newtops[i], n1);
+    setoppo(newtops[i], newpoint);
+    // Set the element attributes of a new tetrahedron.
+    for (j = 0; j < in->numberoftetrahedronattributes; j++) {
+      attrib = elemattribute(bots[i].tet, j);
+      setelemattribute(newtops[i].tet, j, attrib);
     }
-    if (acesh.sh != dummysh) {
-      edca.loc = 3; 
-      tsbond(edca, acesh);
+    if (b->varvolume) {
+      // Set the area constraint of a new tetrahedron.
+      volume = volumebound(bots[i].tet);
+      setvolumebound(newtops[i].tet, volume);
+    }
+#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);
     }
+#endif
   }
 
-  edab.loc = 0;
-  edbc.loc = 0;
-  edca.loc = 0;
-  if (b->verbose > 3) {
-    printf("    Updating edab ");
-    printtet(&edab);
-    printf("    Updating edbc ");
-    printtet(&edbc);
-    printf("    Creating edca ");
-    printtet(&edca);
+  // Bond newtops to topcasings and bots.
+  for (i = 0; i < wrapcount; i++) {
+    // Get 'oldtop = n1n2va' from 'bots[i]'.
+    enextfnext(bots[i], oldtop);
+    sym(oldtop, topcasing);
+    bond(newtops[i], topcasing);
+    if (checksubfaces) {
+      tspivot(oldtop, topsh);
+      if (topsh.sh != dummysh) {
+        tsdissolve(oldtop);
+        tsbond(newtops[i], topsh);
+      }
+    }
+    enextfnext(newtops[i], tmpbond0);
+    bond(oldtop, tmpbond0);
   }
-
-  if (flipqueue != (queue *) NULL) { 
-    enextfnext(edab, abdcasing);
-    enqueueflipface(abdcasing, flipqueue);
-    enext2fnext(edab, baecasing);
-    enqueueflipface(baecasing, flipqueue);
-    enextfnext(edbc, bcdcasing);
-    enqueueflipface(bcdcasing, flipqueue);
-    enext2fnext(edbc, cbecasing);
-    enqueueflipface(cbecasing, flipqueue);
-    enextfnext(edca, cadcasing);
-    enqueueflipface(cadcasing, flipqueue);
-    enext2fnext(edca, acecasing);
-    enqueueflipface(acecasing, flipqueue);  
+  // Bond between newtops.
+  fnext(newtops[0], tmpbond0);
+  enext2fnext(bots[0], spintet); 
+  for (i = 1; i < wrapcount; i ++) {
+    if (issymexist(&spintet)) {
+      enext2fnext(newtops[i], tmpbond1);
+      bond(tmpbond0, tmpbond1);
+    }
+    fnext(newtops[i], tmpbond0);
+    enext2fnext(bots[i], spintet); 
   }
-
-  // Save a live handle in 'recenttet'.
-  recenttet = edbc;
-  // Set the return handle be edab.
-  *flipface = edab;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// flip32()    Perform a 3-to-2 flip.                                        //
-//                                                                           //
-// On input, 'flipface' represents the face will be flipped.  Let it is eda, //
-// where edge ed is locally non-convex. Three tetrahedra sharing ed are edab,//
-// edbc, and edca.  ed is not a subsegment.                                  //
-//                                                                           //
-// A 3-to-2 flip is to change the three tetrahedra edab, edbc, and edca into //
-// another two tetrahedra abcd and bace.  As a result, the edge ed has been  //
-// removed and the face abc has been created.                                //
-//                                                                           //
-// On completion, 'flipface' returns abcd.  If 'flipqueue' is not NULL, all  //
-// possibly non-Delaunay faces are added into it.                            //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-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;
-  face baesh, cbesh, acesh;
-  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);
-
-  if (b->verbose > 2) {
-    printf("    Do T32 on face (%d, %d, %d, %d).\n",
-           pointmark(pe), pointmark(pd), pointmark(pa), pointmark(pb));
+  // Bond the last to the first if no boundary.
+  if (issymexist(&spintet)) {
+    enext2fnext(newtops[0], tmpbond1);
+    bond(tmpbond0, tmpbond1);
   }
-  flip32s++;
 
+  // Is there exist subfaces and subsegment need to be split?
+  if (checksubfaces) {
+    if (abseg.sh != dummysh) {
+      // A subsegment needs be split.
+      spivot(abseg, splitsh);
 #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);
+      assert(splitsh.sh != dummysh);
 #endif
+    }
+    if (splitsh.sh != dummysh) {
+      // Split subfaces (and subsegment).
+      findedge(&splitsh, pa, pb);
+      splitsubedge(newpoint, &splitsh, (queue *) NULL);
+    }
+  }
 
-  // Storing the old configuration outside the convex hull.
-  enextfnext(edab, oldabd);
-  enext2fnext(edab, oldbae);
-  enextfnext(edbc, oldbcd);
-  enext2fnext(edbc, oldcbe);
-  enextfnext(edca, oldcad);
-  enext2fnext(edca, oldace);
-  sym(oldabd, abdcasing);
-  sym(oldbcd, bcdcasing);
-  sym(oldcad, cadcasing);
-  sym(oldbae, baecasing);
-  sym(oldcbe, cbecasing);
-  sym(oldace, acecasing);
-  if (checksubfaces) {
-    tspivot(oldabd, abdsh);
-    tspivot(oldbcd, bcdsh);
-    tspivot(oldcad, cadsh);
-    tspivot(oldbae, baesh);
-    tspivot(oldcbe, cbesh);
-    tspivot(oldace, acesh);
+  if (b->verbose > 3) {
+    for (i = 0; i < wrapcount; i++) {
+      printf("    Updating bots[%i] ", i);
+      printtet(&(bots[i]));
+      printf("    Creating newtops[%i] ", i);
+      printtet(&(newtops[i]));
+    }
   }
 
-  // Creating the new configuration inside the convex hull.
-  abcd.tet = edab.tet; // Update edab to be abcd.
-  setorg (abcd, pa);
-  setdest(abcd, pb);
-  setapex(abcd, pc);
-  setoppo(abcd, pd);
-  bace.tet = edbc.tet; // Update edbc to be bace.
-  setorg (bace, pb);
-  setdest(bace, pa);
-  setapex(bace, pc);
-  setoppo(bace, pe);
-  // Dealloc a redundant tetrahedron (edca).
-  tetrahedrondealloc(edca.tet); 
-
-  // 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);
+  if (flipqueue != (queue *) NULL) {
+    for (i = 0; i < wrapcount; i++) {
+      enqueueflipface(bots[i], flipqueue);
+      enqueueflipface(newtops[i], flipqueue);
+    }
   }
-  // Bond the inside face of the convex hull.
-  abcd.loc = 0;
-  bace.loc = 0;
-  bond(abcd, bace);
-  // Bond the outside faces of the convex hull.
-  abcd.loc = 1;
-  bond(abcd, abdcasing);
-  abcd.loc = 2;
-  bond(abcd, bcdcasing);
-  abcd.loc = 3;
-  bond(abcd, cadcasing);
-  bace.loc = 1;
-  bond(bace, baecasing);
-  bace.loc = 3;
-  bond(bace, cbecasing);
-  bace.loc = 2;
-  bond(bace, acecasing);
+
+  // Set the return handle be avn1n2.  It is got by transforming from
+  //   'bots[0]' (which is an1n2v).
+  fnext(bots[0], spintet); // spintet is an1vn2.
+  esymself(spintet); // spintet is n1avn2.
+  enextself(spintet); // spintet is avn1n2.
+  *splittet = spintet;
+
+  delete [] bots;
+  delete [] newtops;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// unsplittetedge()    Reverse the operation of splitting an edge, so as to  //
+//                     remove the newly inserted point.                      //
+//                                                                           //
+// Assume the original edge is ab, the tetrahedron containing ab is abn1n2.  //
+// After ab was split by a point v, every tetrahedron containing ab (e.g.,   //
+// abn1n2) has been split into two (e.g., an1n2v and bn2n1v). 'splittet'     //
+// represents avn1n2 (i.e., its destination is v).                           //
+//                                                                           //
+// To remove point v is to expand each split tetrahedron containing ab (e.g.,//
+// (avn1n2 to abn1n2), then delete the redundant one(e.g., vbn1n2). If there //
+// exists any subface around ab, routine unsplitsubedge() will be called to  //
+// reverse the operation of splitting a edge (or a subsegment) of subfaces.  //
+// On completion, point v is not deleted in this routine.                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::unsplittetedge(triface* splittet)
+{
+  triface *bots, *newtops;
+  triface oldtop, topcasing;
+  triface spintet;
+  face avseg, splitsh, topsh, spinsh;
+  point pa, pv, n1;
+  int wrapcount, hitbdry;
+  int i;
+
+  spintet = *splittet;
+  pa = org(spintet);
+  pv = dest(spintet);
   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);
-    }
-    if (abdsh.sh != dummysh) {
-      abcd.loc = 1;
-      tsbond(abcd, abdsh);
+    // Is there a subsegment need to be unsplit together?
+    tsspivot(splittet, &avseg);
+    if (avseg.sh != dummysh) {
+      // The subsegment's direction should conform to 'splittet'.
+      if (sorg(avseg) != pa) {
+        sesymself(avseg);
+      }
     }
-    if (baesh.sh != dummysh) {
-      bace.loc = 1;
-      tsbond(bace, baesh);
+  } 
+
+  n1 = apex(spintet);
+  hitbdry = 0;
+  wrapcount = 1;
+  if (checksubfaces && avseg.sh != dummysh) {
+    // It may happen that some tetrahedra containing ab (a subsegment) are
+    //   completely disconnected with others. If it happens, use the face
+    //   link of ab to cross the boundary. 
+    while (true) {    
+      if (!fnextself(spintet)) {
+        // Meet a boundary, walk through it.
+        hitbdry ++;
+        tspivot(spintet, spinsh);
+#ifdef SELF_CHECK
+        assert(spinsh.sh != dummysh);
+#endif
+        findedge(&spinsh, pa, pv);
+        sfnextself(spinsh);
+        stpivot(spinsh, spintet);
+#ifdef SELF_CHECK
+        assert(spintet.tet != dummytet);
+#endif
+        findedge(&spintet, pa, pv);
+        // Remember this position (hull face) in 'splittet'.
+        *splittet = spintet;
+        // Split two hull faces increase the hull size;
+        hullsize += 2;
+      }
+      if (apex(spintet) == n1) break;
+      wrapcount ++;
     }
-    if (bcdsh.sh != dummysh) {
-      abcd.loc = 2;
-      tsbond(abcd, bcdsh);
+    if (hitbdry > 0) {
+      wrapcount -= hitbdry;
     }
-    if (cbesh.sh != dummysh) {
-      bace.loc = 3;
-      tsbond(bace, cbesh);
+  } else {
+    // All the tetrahedra containing ab are connected together. If there
+    //   are subfaces, 'splitsh' keeps one of them.
+    splitsh.sh = dummysh;
+    while (hitbdry < 2) {
+      if (checksubfaces && splitsh.sh == dummysh) {
+        tspivot(spintet, splitsh);
+      }
+      if (fnextself(spintet)) {
+        if (apex(spintet) == n1) break;
+        wrapcount++;
+      } else {
+        hitbdry ++;
+        if (hitbdry < 2) {
+          esym(*splittet, spintet);
+        }
+      }
     }
-    if (cadsh.sh != dummysh) {
-      abcd.loc = 3;
-      tsbond(abcd, cadsh);
+    if (hitbdry > 0) {
+      // ab is on the hull.
+      wrapcount -= 1;
+      // 'spintet' now is a hull face, inverse its edge direction.
+      esym(spintet, *splittet);
+      // Split two hull faces increases the number of hull faces.
+      hullsize += 2;
     }
-    if (acesh.sh != dummysh) {
-      bace.loc = 2;
-      tsbond(bace, acesh);
+  }
+  
+  // Make arrays of updating (bot, oldtop) and new (newtop) tetrahedra.
+  bots = new triface[wrapcount];
+  newtops = new triface[wrapcount];
+  // Spin around av, gather tetrahedra and set up new tetrahedra. 
+  spintet = *splittet;
+  for (i = 0; i < wrapcount; i++) {
+    // Get 'bots[i] = an1n2v'.
+    enext2fnext(spintet, bots[i]);
+    esymself(bots[i]);
+    // Get 'oldtop = n1n2va'.
+    enextfnext(bots[i], oldtop);
+    // Get 'newtops[i] = 'bn1n2v'
+    fnext(oldtop, newtops[i]); // newtop = n1n2bv
+    esymself(newtops[i]); // newtop = n2n1bv
+    enext2self(newtops[i]); // newtop = bn2n1v
+    // Go to the next.
+    fnextself(spintet);
+    if (checksubfaces && avseg.sh != dummysh) {
+      if (!issymexist(&spintet)) {
+        // We meet a hull face, walk through it.
+        tspivot(spintet, spinsh);
+#ifdef SELF_CHECK
+        assert(spinsh.sh != dummysh);
+#endif
+        findedge(&spinsh, pa, pv);
+        sfnextself(spinsh);
+        stpivot(spinsh, spintet);
+#ifdef SELF_CHECK
+        assert(spintet.tet != dummytet);
+#endif
+        findedge(&spintet, pa, pv);
+      }
     }
   }
 
-  abcd.loc = 0;
-  bace.loc = 0;
-  if (b->verbose > 3) {
-    printf("    Updating abcd ");
-    printtet(&abcd);
-    printf("    Updating bace ");
-    printtet(&bace);
-    printf("    Deleting edca ");
-    printtet(&edca);
+  if (b->verbose > 1) {
+    printf("  Removing point %d from edge (%d, %d).\n", 
+           pointmark(oppo(bots[0])), pointmark(org(bots[0])),
+           pointmark(org(newtops[0])));
   }
 
-  if (flipqueue != (queue *) NULL) { 
-    fnext(abcd, abdcasing);
-    enqueueflipface(abdcasing, flipqueue);
-    fnext(bace, baecasing);
-    enqueueflipface(baecasing, flipqueue);
-    enextfnext(abcd, bcdcasing);
-    enqueueflipface(bcdcasing, flipqueue);
-    enextfnext(bace, cbecasing);
-    enqueueflipface(cbecasing, flipqueue);
-    enext2fnext(abcd, cadcasing);
-    enqueueflipface(cadcasing, flipqueue);
-    enext2fnext(bace, acecasing);
-    enqueueflipface(acecasing, flipqueue);  
+  for (i = 0; i < wrapcount; i++) {
+    // Expand an1n2v to an1n2b.
+    setoppo(bots[i], org(newtops[i]));
+    // Get 'oldtop = n1n2va' from 'bot[i]'.
+    enextfnext(bots[i], oldtop);
+    // Get 'topcasing' from 'newtop[i]'
+    sym(newtops[i], topcasing);
+    // Bond them.
+    bond(oldtop, topcasing);
+    if (checksubfaces) {
+      tspivot(newtops[i], topsh);
+      if (topsh.sh != dummysh) {
+        tsbond(oldtop, topsh);
+      }
+    }
+    // Delete the tetrahedron above an1n2v.
+    tetrahedrondealloc(newtops[i].tet);
+  }
+
+  // If there exists any subface, unsplit them.
+  if (checksubfaces) {
+    if (avseg.sh != dummysh) {
+      spivot(avseg, splitsh);
+#ifdef SELF_CHECK
+      assert(splitsh.sh != dummysh);
+#endif
+    }
+    if (splitsh.sh != dummysh) {
+      findedge(&splitsh, pa, pv);
+      unsplitsubedge(&splitsh);
+    }
   }
 
-  // Save a live handle in 'recenttet'.
-  recenttet = abcd;
-  // Set the return handle be abcd.
-  *flipface = abcd;
+  delete [] bots;
+  delete [] newtops;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// flip22()    Perform a 2-to-2 (or 4-to-4) flip.                            //
+// splitsubedge()    Insert a point on an edge of the surface mesh.          //
 //                                                                           //
-// On input, 'flipface' represents the face will be flipped.  Let it is abe, //
-// ab is the flipable edge, the two tetrahedra sharing abe are abce and bade,//
-// hence a, b, c and d are coplanar. If abc, bad are interior faces, the two //
-// tetrahedra opposite to e are bacf and abdf.  ab is not a subsegment.      //
+// The splitting edge is given by 'splitsh'. Assume its three corners are a, //
+// b, c, where ab is the edge will be split. ab may be a subsegment.         //
 //                                                                           //
-// A 2-to-2 flip is to change two tetrahedra abce and bade into another two  //
-// tetrahedra dcae and cdbe. If bacf and abdf exist, they're changed to cdaf //
-// and dcbf, thus a 4-to-4 flip.  As a result, two or four tetrahedra have   //
-// rotated counterclockwise (using right-hand rule with thumb points to e):  //
-// abce->dcae, bade->cdbe, and bacf->cdaf, abdf->dcbf.                       //
+// To split edge ab is to split all subfaces conatining ab. If ab is not a   //
+// subsegment, there are only two subfaces need be split, otherwise, there   //
+// may have any number of subfaces need be split. Each splitting subface abc //
+// is shrunk to avc, a new subface vbc is created.  It is important to keep  //
+// the orientations of edge rings of avc and vbc be the same as abc's. If ab //
+// is a subsegment, it is shrunk to av and a new subsegment vb is created.   //
 //                                                                           //
-// If abc and bad are subfaces, a 2-to-2 flip is performed simultaneously by //
-// calling routine flip22sub(), hence abc->dca, bad->cdb.  The edge rings of //
-// the flipped subfaces dca and cdb have the same orientation as abc and bad.//
-// Hence, they have the same orientation as other subfaces of the facet with //
-// respect to the lift point of this facet.                                  //
+// If there are tetrahedra adjoining to the splitting subfaces, they should  //
+// be split before calling this routine, so the connection between the new   //
+// tetrahedra and the new subfaces can be correctly set.                     //
 //                                                                           //
-// On completion, 'flipface' holds edge dc of tetrahedron dcae. 'flipqueue'  //
-// contains all possibly non-Delaunay faces if it is not NULL.               //
+// On completion, 'splitsh' returns avc.  If 'flipqueue' is not NULL, it     //
+// returns all edges which may be non-Delaunay.                              //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::flip22(triface* flipface, queue* flipqueue)
+void tetgenmesh::splitsubedge(point newpoint, face* splitsh, queue* flipqueue)
 {
-  triface abce, bade;
-  triface oldbce, oldcae, oldade, olddbe;
-  triface bcecasing, caecasing, adecasing, dbecasing;
-  face bcesh, caesh, adesh, dbesh;
-  triface bacf, abdf;
-  triface oldacf, oldcbf, oldbdf, olddaf;
-  triface acfcasing, cbfcasing, bdfcasing, dafcasing;
-  face acfsh, cbfsh, bdfsh, dafsh;
-  face abc, bad;
-  point pa, pb, pc, pd, pe, pf;
-  int mirrorflag;
+  triface abcd, bace, vbcd, bvce;
+  face startabc, spinabc, spinsh;
+  face oldbc, bccasin, bccasout;
+  face ab, bc;
+  face avc, vbc, vbc1;
+  face av, vb;
+  point pa, pb;
 
-  adjustedgering(*flipface, CCW); // 'flipface' is bae.
-  fnext(*flipface, abce);
-  esymself(abce);
-  adjustedgering(*flipface, CW); // 'flipface' is abe.
-  fnext(*flipface, bade);
-  assert(bade.tet != dummytet);
-  esymself(bade);
-  pa = org(abce);
-  pb = dest(abce);
-  pc = apex(abce);
-  pd = apex(bade);
-  pe = oppo(bade);
-  assert(oppo(abce) == pe);
-  sym(abce, bacf);
-  mirrorflag = bacf.tet != dummytet;
-  if (mirrorflag) {
-    findedge(&bacf, pb, pa);
-    sym(bade, abdf);
-    assert(abdf.tet != dummytet);
-    findedge(&abdf, pa, pb);
-    pf = oppo(bacf);
-    assert(oppo(abdf) == pf);
-  } 
+  startabc = *splitsh;
+  // Is there a subsegment?
+  sspivot(startabc, ab);
+  if (ab.sh != dummysh) {
+    ab.shver = 0; 
+    if (sorg(startabc) != sorg(ab)) {
+      sesymself(startabc);
+    }
+  }
+  pa = sorg(startabc);
+  pb = sdest(startabc);
+  
+  if (b->verbose > 1) {
+    printf("  Inserting point %d on subedge (%d, %d) %s.\n",
+           pointmark(newpoint), pointmark(pa), pointmark(pb),
+           (ab.sh != dummysh ? "(seg)" : " "));
+  }
+  
+  // Spin arround ab, split every subface containing ab.
+  spinabc = startabc;
+  do {
+    // Adjust spinabc be edge ab.
+    if (sorg(spinabc) != pa) {
+      sesymself(spinabc);
+    }
+    // Save old configuration at edge bc, if bc has a subsegment, save the
+    //   face link of it and dissolve it from bc.
+    senext(spinabc, oldbc);
+    spivot(oldbc, bccasout);    
+    sspivot(oldbc, bc);
+    if (bc.sh != dummysh) {
+      if (spinabc.sh != bccasout.sh) {
+        // 'spinabc' is not self-bonded.
+        spinsh = bccasout;
+        do {
+          bccasin = spinsh;
+          spivotself(spinsh);
+        } while (spinsh.sh != oldbc.sh);
+      } else {
+        bccasout.sh = dummysh;
+      }
+      ssdissolve(oldbc);
+    }
+    // Create a new subface.
+    makeshellface(subfaces, &vbc);
+    // Split abc.
+    avc = spinabc;  // Update 'abc' to 'avc'.
+    setsdest(avc, newpoint);
+    // Make 'vbc' be in the same edge ring as 'avc'. 
+    vbc.shver = avc.shver; 
+    setsorg(vbc, newpoint); // Set 'vbc'.
+    setsdest(vbc, pb);
+    setsapex(vbc, sapex(avc));
+    if (b->quality && varconstraint) {
+      // Copy the area bound into the new subface.
+      setareabound(vbc, areabound(avc));
+    }
+    // Copy the shell marker and shell type into the new subface.
+    setshellmark(vbc, shellmark(avc));
+    setshelltype(vbc, shelltype(avc));
+    if (checkpbcs) {
+      // Copy the pbcgroup into the new subface.
+      setshellpbcgroup(vbc, shellpbcgroup(avc));
+    }
+    // Set the connection between updated and new subfaces.
+    senext2self(vbc);
+    sbond(vbc, oldbc);
+    // Set the connection between new subface and casings.
+    senext2self(vbc);
+    if (bc.sh != dummysh) {
+      if (bccasout.sh != dummysh) {
+        // Insert 'vbc' into face link.
+        sbond1(bccasin, vbc);
+        sbond1(vbc, bccasout);
+      } else {
+        // Bond 'vbc' to itself.
+        sbond(vbc, vbc);
+      }
+      ssbond(vbc, bc);
+    } else {
+      sbond(vbc, bccasout);
+    }
+    // Go to next subface at edge ab.
+    spivotself(spinabc);
+    if (spinabc.sh == dummysh) {
+      break; // 'ab' is a hull edge.
+    }
+  } while (spinabc.sh != startabc.sh);
 
-  if (b->verbose > 2) {
-    printf("    Do %s on edge (%d, %d).\n", mirrorflag ? "T44" : "T22",
-           pointmark(pa), pointmark(pb));
+  // Get the new subface vbc above the updated subface avc (= startabc).
+  senext(startabc, oldbc);
+  spivot(oldbc, vbc);
+  if (sorg(vbc) == newpoint) {
+    sesymself(vbc);
   }
-  mirrorflag ? flip44s++ : flip22s++;
+#ifdef SELF_CHECK
+  assert(sorg(vbc) == sdest(oldbc) && sdest(vbc) == sorg(oldbc));
+#endif
+  senextself(vbc);
+  // Set the face link for the new created subfaces around edge vb.
+  spinabc = startabc;
+  do {
+    // Go to the next subface at edge av.
+    spivotself(spinabc);
+    if (spinabc.sh == dummysh) {
+      break; // 'ab' is a hull edge.
+    }
+    if (sorg(spinabc) != pa) {
+      sesymself(spinabc);
+    }
+    // Get the new subface vbc1 above the updated subface avc (= spinabc).
+    senext(spinabc, oldbc);
+    spivot(oldbc, vbc1);
+    if (sorg(vbc1) == newpoint) {
+      sesymself(vbc1);
+    }
+#ifdef SELF_CHECK
+    assert(sorg(vbc1) == sdest(oldbc) && sdest(vbc1) == sorg(oldbc));
+#endif
+    senextself(vbc1);
+    // Set the connection: vbc->vbc1.
+    sbond1(vbc, vbc1);
+    // For the next connection.
+    vbc = vbc1;
+  } while (spinabc.sh != startabc.sh);
 
+  // Split ab if it is a subsegment.
+  if (ab.sh != dummysh) {
+    // Update subsegment ab to av.
+    av = ab;
+    setsdest(av, newpoint);
+    // Create a new subsegment vb.
+    makeshellface(subsegs, &vb);
+    setsorg(vb, newpoint);
+    setsdest(vb, pb);
+    // vb gets the same mark and segment type as av.
+    setshellmark(vb, shellmark(av));
+    setshelltype(vb, shelltype(av));
+    if (b->quality && varconstraint) {
+      // Copy the area bound into the new subsegment.
+      setareabound(vb, areabound(av));
+    }
+    // Save the old connection at ab (re-use the handles oldbc, bccasout).
+    senext(av, oldbc);
+    spivot(oldbc, bccasout);
+    // Bond av and vb (bonded at their "fake" edges).
+    senext2(vb, bccasin);
+    sbond(bccasin, oldbc);
+    if (bccasout.sh != dummysh) {
+      // There is a subsegment connecting with ab at b. It will connect
+      //   to vb at b after splitting.
+      bccasout.shver = 0;
+#ifdef SELF_CHECK
+      assert(sorg(bccasout) == pb); 
+#endif
+      senext2self(bccasout);
+      senext(vb, bccasin);
+      sbond(bccasin, bccasout);
+    }
+    // Bond all new subfaces (vbc) to vb. 
+    spinabc = startabc;
+    do {
+      // Adjust spinabc be edge av.
+      if (sorg(spinabc) != pa) {
+        sesymself(spinabc);
+      }
+      // Get new subface vbc above the updated subface avc (= spinabc).
+      senext(spinabc, oldbc);
+      spivot(oldbc, vbc);
+      if (sorg(vbc) == newpoint) {
+        sesymself(vbc);
+      }
+      senextself(vbc);
+      // Bond the new subface and the new subsegment.
+      ssbond(vbc, vb);
+      // Go to the next.
+      spivotself(spinabc);
 #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);
+      assert(spinabc.sh != dummysh);
 #endif
-  
-  // Save the old configuration at the convex hull.
-  enextfnext(abce, oldbce);
-  enext2fnext(abce, oldcae);
-  enextfnext(bade, oldade);
-  enext2fnext(bade, olddbe);
-  sym(oldbce, bcecasing);
-  sym(oldcae, caecasing);
-  sym(oldade, adecasing);
-  sym(olddbe, dbecasing);
-  if (checksubfaces) {
-    tspivot(oldbce, bcesh);
-    tspivot(oldcae, caesh);
-    tspivot(oldade, adesh);
-    tspivot(olddbe, dbesh);
-    tspivot(abce, abc);
-    tspivot(bade, bad);
-  }
-  if (mirrorflag) {
-    enextfnext(bacf, oldacf);
-    enext2fnext(bacf, oldcbf);
-    enextfnext(abdf, oldbdf);
-    enext2fnext(abdf, olddaf);
-    sym(oldacf, acfcasing);
-    sym(oldcbf, cbfcasing);
-    sym(oldbdf, bdfcasing);
-    sym(olddaf, dafcasing);
-    if (checksubfaces) {
-      tspivot(oldacf, acfsh);
-      tspivot(oldcbf, cbfsh);
-      tspivot(oldbdf, bdfsh);
-      tspivot(olddaf, dafsh);
-    }
+    } while (spinabc.sh != startabc.sh);
   }
 
-  // Rotate abce, bade one-quarter turn counterclockwise.
-  bond(oldbce, caecasing);
-  bond(oldcae, adecasing);
-  bond(oldade, dbecasing);
-  bond(olddbe, bcecasing);
-  if (checksubfaces) {
-    // Check for subfaces and rebond them to the rotated tets.
-    if (caesh.sh == dummysh) {
-      tsdissolve(oldbce);
-    } else {
-      tsbond(oldbce, caesh);
+  // Bond the new subfaces to new tetrahedra if they exist.  New tetrahedra
+  //   should have been created before calling this routine.
+  spinabc = startabc;
+  do {
+    // Adjust spinabc be edge av.
+    if (sorg(spinabc) != pa) {
+      sesymself(spinabc);
     }
-    if (adesh.sh == dummysh) {
-      tsdissolve(oldcae);
-    } else {
-      tsbond(oldcae, adesh);
+    // Get new subface vbc above the updated subface avc (= spinabc).
+    senext(spinabc, oldbc);
+    spivot(oldbc, vbc);
+    if (sorg(vbc) == newpoint) {
+      sesymself(vbc);
     }
-    if (dbesh.sh == dummysh) {
-      tsdissolve(oldade);
+    senextself(vbc);
+    // Get the adjacent tetrahedra at 'spinabc'.
+    stpivot(spinabc, abcd);
+    if (abcd.tet != dummytet) {
+      findedge(&abcd, sorg(spinabc), sdest(spinabc));
+      enextfnext(abcd, vbcd);
+      fnextself(vbcd);
+#ifdef SELF_CHECK
+      assert(vbcd.tet != dummytet);
+#endif
+      tsbond(vbcd, vbc);
+      sym(vbcd, bvce);
+      sesymself(vbc);
+      tsbond(bvce, vbc);
     } else {
-      tsbond(oldade, dbesh);
+      // One side is empty, check the other side.
+      sesymself(spinabc);
+      stpivot(spinabc, bace);
+      if (bace.tet != dummytet) {
+        findedge(&bace, sorg(spinabc), sdest(spinabc));
+        enext2fnext(bace, bvce);
+        fnextself(bvce);
+#ifdef SELF_CHECK
+        assert(bvce.tet != dummytet);
+#endif
+        sesymself(vbc); 
+        tsbond(bvce, vbc);
+      }
     }
-    if (bcesh.sh == dummysh) {
-      tsdissolve(olddbe);
-    } else {
-      tsbond(olddbe, bcesh);
+    // Go to the next.
+    spivotself(spinabc);
+    if (spinabc.sh == dummysh) {
+      break; // 'ab' is a hull edge.
     }
-  }
-  if (mirrorflag) {
-    // Rotate bacf, abdf one-quarter turn counterclockwise.
-    bond(oldcbf, acfcasing);
-    bond(oldacf, dafcasing);
-    bond(olddaf, bdfcasing);
-    bond(oldbdf, cbfcasing);
-    if (checksubfaces) {
-      // Check for subfaces and rebond them to the rotated tets.
-      if (acfsh.sh == dummysh) {
-        tsdissolve(oldcbf);
-      } else {
-        tsbond(oldcbf, acfsh);
-      }
-      if (dafsh.sh == dummysh) {
-        tsdissolve(oldacf);
-      } else {
-        tsbond(oldacf, dafsh);
+  } while (spinabc.sh != startabc.sh);
+  
+  if (b->verbose > 3) {
+    spinabc = startabc;
+    do {
+      // Adjust spinabc be edge av.
+      if (sorg(spinabc) != pa) {
+        sesymself(spinabc);
       }
-      if (bdfsh.sh == dummysh) {
-        tsdissolve(olddaf);
-      } else {
-        tsbond(olddaf, bdfsh);
+      printf("    Updating abc:\n");
+      printsh(&spinabc);
+      // Get new subface vbc above the updated subface avc (= spinabc).
+      senext(spinabc, oldbc);
+      spivot(oldbc, vbc);
+      if (sorg(vbc) == newpoint) {
+        sesymself(vbc);
       }
-      if (cbfsh.sh == dummysh) {
-        tsdissolve(oldbdf);
-      } else {
-        tsbond(oldbdf, cbfsh);
+      senextself(vbc);
+      printf("    Creating vbc:\n");
+      printsh(&vbc);
+      // Go to the next.
+      spivotself(spinabc);
+      if (spinabc.sh == dummysh) {
+        break; // 'ab' is a hull edge.
       }
-    }
-  }
-
-  // New vertex assignments for the rotated tetrahedra.
-  setorg(abce, pd); // Update abce to dcae
-  setdest(abce, pc);
-  setapex(abce, pa);
-  setorg(bade, pc); // Update bade to cdbe
-  setdest(bade, pd);
-  setapex(bade, pb);
-  if (mirrorflag) {
-    setorg(bacf, pc); // Update bacf to cdaf
-    setdest(bacf, pd);
-    setapex(bacf, pa);
-    setorg(abdf, pd); // Update abdf to dcbf
-    setdest(abdf, pc);
-    setapex(abdf, pb);
-  }
-
-  // Are there subfaces need to be flipped?
-  if (checksubfaces && abc.sh != dummysh) {
-    assert(bad.sh != dummysh);
-    // Adjust the edge be ab, so the rotation of subfaces is according with
-    //   the rotation of tetrahedra.
-    findedge(&abc, pa, pb);
-    // Flip an edge of two subfaces, ignore non-Delaunay edges.
-    flip22sub(&abc, NULL);
-  }
-
-  if (b->verbose > 3) {
-    printf("    Updating abce ");
-    printtet(&abce);
-    printf("    Updating bade ");
-    printtet(&bade);
-    if (mirrorflag) {
-      printf("    Updating bacf ");
-      printtet(&bacf);
-      printf("    Updating abdf ");
-      printtet(&abdf);
-    }
+    } while (spinabc.sh != startabc.sh);
   }
 
-  if (flipqueue != (queue *) NULL) { 
-    enextfnext(abce, bcecasing);
-    enqueueflipface(bcecasing, flipqueue);
-    enext2fnext(abce, caecasing);
-    enqueueflipface(caecasing, flipqueue);
-    enextfnext(bade, adecasing);
-    enqueueflipface(adecasing, flipqueue);
-    enext2fnext(bade, dbecasing);
-    enqueueflipface(dbecasing, flipqueue);
-    if (mirrorflag) {
-      enextfnext(bacf, acfcasing);
-      enqueueflipface(acfcasing, flipqueue);
-      enext2fnext(bacf, cbfcasing);
-      enqueueflipface(cbfcasing, flipqueue);
-      enextfnext(abdf, bdfcasing);
-      enqueueflipface(bdfcasing, flipqueue);
-      enext2fnext(abdf, dafcasing);
-      enqueueflipface(dafcasing, flipqueue);
-    }
-    // The two new faces dcae (abce), cdbe (bade) may still not be locally
-    //   Delaunay, and may need be flipped (flip23).  On the other hand, in
-    //   conforming Delaunay algorithm, two new subfaces dca (abc), and cdb
-    //   (bad) may be non-conforming Delaunay, they need be queued if they
-    //   are locally Delaunay but non-conforming Delaunay.
-    enqueueflipface(abce, flipqueue);
-    enqueueflipface(bade, flipqueue);
+  if (flipqueue != (queue *) NULL) {
+    spinabc = startabc;
+    do {
+      // Adjust spinabc be edge av.
+      if (sorg(spinabc) != pa) {
+        sesymself(spinabc);
+      }
+      senext2(spinabc, oldbc); // Re-use oldbc.
+      enqueueflipedge(oldbc, flipqueue);
+      // Get new subface vbc above the updated subface avc (= spinabc).
+      senext(spinabc, oldbc);
+      spivot(oldbc, vbc);
+      if (sorg(vbc) == newpoint) {
+        sesymself(vbc);
+      }
+      senextself(vbc);
+      senext(vbc, oldbc); // Re-use oldbc.
+      enqueueflipedge(oldbc, flipqueue);
+      // Go to the next.
+      spivotself(spinabc);
+      if (spinabc.sh == dummysh) {
+        break; // 'ab' is a hull edge.
+      }
+    } while (spinabc.sh != startabc.sh);
   }
-
-  // Save a live handle in 'recenttet'.
-  recenttet = abce;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// flip22sub()    Perform a 2-to-2 flip on a subface edge.                   //
-//                                                                           //
-// The flip edge is given by subface 'flipedge'.  Let it is abc, where ab is //
-// the flipping edge.  The other subface is bad,  where a, b, c, d form a    //
-// convex quadrilateral.  ab is not a subsegment.                            //
-//                                                                           //
-// A 2-to-2 subface flip is to change two subfaces abc and bad to another    //
-// two subfaces dca and cdb.  Hence, edge ab has been removed and dc becomes //
-// an edge. If a point e is above abc, this flip is equal to rotate abc and  //
-// bad counterclockwise using right-hand rule with thumb points to e. It is  //
-// important to know that the edge rings of the flipped subfaces dca and cdb //
-// are keeping the same orientation as their original subfaces. So they have //
-// the same orientation with respect to the lift point of this facet.        //
+// unsplitsubedge()    Reverse the operation of splitting an edge of subface,//
+//                     so as to remove a point from the edge.                //
 //                                                                           //
-// During rotating, the face rings of the four edges bc, ca, ad, and de need //
-// be re-connected. If the edge is not a subsegment, then its face ring has  //
-// only two faces, a sbond() will bond them together. If it is a subsegment, //
-// one should use sbond1() twice to bond two different handles to the rotat- //
-// ing subface, one is predecssor (-casin), another is successor (-casout).  //
+// Assume the original edge is ab, the subface containing it is abc. It was  //
+// split by a point v into avc, and vbc.  'splitsh' represents avc, further- //
+// more, if av is a subsegment, av should be the zero version of the split   //
+// subsegment (i.e., av.shver = 0), so we are sure that the destination (v)  //
+// of both avc and av is the deleting point.                                 //
 //                                                                           //
-// If 'flipqueue' is not NULL, it returns four edges bc, ca, ad, de, which   //
-// may be non-Delaunay.                                                      //
+// To remove point v is to expand avc to abc, delete vbc, do the same for    //
+// other subfaces containing av and vb. If av and vb are subsegments, expand //
+// av to ab, delete vb.  On completion, point v is not deleted.              //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::flip22sub(face* flipedge, queue* flipqueue)
+void tetgenmesh::unsplitsubedge(face* splitsh)
 {
-  face abc, bad;
-  face oldbc, oldca, oldad, olddb;
-  face bccasin, bccasout, cacasin, cacasout;
-  face adcasin, adcasout, dbcasin, dbcasout;
-  face bc, ca, ad, db;
-  face spinsh;
-  point pa, pb, pc, pd;
-
-  abc = *flipedge;
-  spivot(abc, bad);
-  if (sorg(bad) != sdest(abc)) {
-    sesymself(bad);
-  }
-  pa = sorg(abc);
-  pb = sdest(abc);
-  pc = sapex(abc);
-  pd = sapex(bad);
-
-  if (b->verbose > 2) {
-    printf("    Flip sub edge (%d, %d).\n", pointmark(pa), pointmark(pb));
-  }
+  face startavc, spinavc, spinbcv;
+  face oldvc, bccasin, bccasout, spinsh;
+  face av, vb, bc;
+  point pa, pv, pb;
 
-  // Save the old configuration outside the quadrilateral.  
-  senext(abc, oldbc);
-  senext2(abc, oldca);
-  senext(bad, oldad);
-  senext2(bad, olddb);
-  // Get the outside connection. Becareful if there is a subsegment on the
-  //   quadrilateral, two casings (casin and casout) are needed to save for
-  //   keeping the face link.
-  spivot(oldbc, bccasout);
-  sspivot(oldbc, bc);
-  if (bc.sh != dummysh) {
-    // 'bc' is a subsegment.
-    assert(bccasout.sh != dummysh);
-    if (oldbc.sh != bccasout.sh) {
-      // 'oldbc' is not self-bonded.
-      spinsh = bccasout;
-      do {
-        bccasin = spinsh;
-        spivotself(spinsh);
-      } while (spinsh.sh != oldbc.sh);
-    } else {
-      bccasout.sh = dummysh;
-    }
-    ssdissolve(oldbc);
-  }
-  spivot(oldca, cacasout);
-  sspivot(oldca, ca);
-  if (ca.sh != dummysh) {
-    // 'ca' is a subsegment. 
-    assert(cacasout.sh != dummysh);
-    if (oldca.sh != cacasout.sh) {
-      // 'oldca' is not self-bonded.
-      spinsh = cacasout;
-      do {
-        cacasin = spinsh;
-        spivotself(spinsh);
-      } while (spinsh.sh != oldca.sh);
-    } else {
-      cacasout.sh = dummysh;
+  startavc = *splitsh;
+  sspivot(startavc, av);
+  if (av.sh != dummysh) {
+    // Orient the direction of subsegment to conform the subface. 
+    if (sorg(av) != sorg(startavc)) {
+      sesymself(av);
     }
-    ssdissolve(oldca);
+#ifdef SELF_CHECK
+    assert(av.shver == 0);
+#endif
   }
-  spivot(oldad, adcasout);
-  sspivot(oldad, ad);
-  if (ad.sh != dummysh) {
-    // 'ad' is a subsegment. 
-    assert(adcasout.sh != dummysh);
-    if (oldad.sh != adcasout.sh) {
-      // 'adcasout' is not self-bonded.
-      spinsh = adcasout;
-      do {
-        adcasin = spinsh;
-        spivotself(spinsh);
-      } while (spinsh.sh != oldad.sh);
-    } else {
-      adcasout.sh = dummysh;
-    }
-    ssdissolve(oldad);
+  senext(startavc, oldvc);
+  spivot(oldvc, vb);  // vb is subface vbc
+  if (sorg(vb) != sdest(oldvc)) {
+    sesymself(vb);
   }
-  spivot(olddb, dbcasout);
-  sspivot(olddb, db);
-  if (db.sh != dummysh) {
-    // 'db' is a subsegment.
-    assert(dbcasout.sh != dummysh);
-    if (olddb.sh != dbcasout.sh) {
-      // 'dbcasout' is not self-bonded.
-      spinsh = dbcasout;
-      do {
-        dbcasin = spinsh;
-        spivotself(spinsh);
-      } while (spinsh.sh != olddb.sh);
-    } else {
-      dbcasout.sh = dummysh;
-    }
-    ssdissolve(olddb);
+  senextself(vb);
+  pa = sorg(startavc);
+  pv = sdest(startavc);
+  pb = sdest(vb);
+
+  if (b->verbose > 1) {
+    printf("  Removing point %d from subedge (%d, %d).\n",
+           pointmark(pv), pointmark(pa), pointmark(pb));
   }
 
-  // Rotate abc and bad one-quarter turn counterclockwise.
-  if (ca.sh != dummysh) {
-    if (cacasout.sh != dummysh) {
-      sbond1(cacasin, oldbc);
-      sbond1(oldbc, cacasout);
-    } else {
-      // Bond 'oldbc' to itself.
-      sbond(oldbc, oldbc);
-      // Make sure that dummysh always correctly bonded.
-      dummysh[0] = sencode(oldbc);
+  // Spin arround av, unsplit every subface containing av.
+  spinavc = startavc;
+  do {
+    // Adjust spinavc be edge av.
+    if (sorg(spinavc) != pa) {
+      sesymself(spinavc);
     }
-    ssbond(oldbc, ca);
-  } else {
-    sbond(oldbc, cacasout);
-  }
-  if (ad.sh != dummysh) {
-    if (adcasout.sh != dummysh) {
-      sbond1(adcasin, oldca);
-      sbond1(oldca, adcasout);
-    } else {
-      // Bond 'oldca' to itself.
-      sbond(oldca, oldca);
-      // Make sure that dummysh always correctly bonded.
-      dummysh[0] = sencode(oldca);
+    // Save old configuration at edge bc, if bc has a subsegment, save the
+    //   face link of it.
+    senext(spinavc, oldvc);
+    spivot(oldvc, spinbcv);
+    if (sorg(spinbcv) != sdest(oldvc)) {
+      sesymself(spinbcv);
     }
-    ssbond(oldca, ad);
-  } else {
-    sbond(oldca, adcasout);
-  }
-  if (db.sh != dummysh) {
-    if (dbcasout.sh != dummysh) {
-      sbond1(dbcasin, oldad);
-      sbond1(oldad, dbcasout);
-    } else {
-      // Bond 'oldad' to itself.
-      sbond(oldad, oldad);
-      // Make sure that dummysh always correctly bonded.
-      dummysh[0] = sencode(oldad);
+    senext2self(spinbcv);
+    spivot(spinbcv, bccasout);
+    sspivot(spinbcv, bc);
+    if (bc.sh != dummysh) {
+      if (spinbcv.sh != bccasout.sh) {
+        // 'spinbcv' is not self-bonded.
+        spinsh = bccasout;
+        do {
+          bccasin = spinsh;
+          spivotself(spinsh);
+        } while (spinsh.sh != spinbcv.sh);
+      } else {
+        bccasout.sh = dummysh;
+      }
     }
-    ssbond(oldad, db);
-  } else {
-    sbond(oldad, dbcasout);
-  }
-  if (bc.sh != dummysh) {
-    if (bccasout.sh != dummysh) {
-      sbond1(bccasin, olddb);
-      sbond1(olddb, bccasout);
+    // Expand avc to abc.
+    setsdest(spinavc, pb);
+    if (bc.sh != dummysh) {
+      if (bccasout.sh != dummysh) {
+        sbond1(bccasin, oldvc);
+        sbond1(oldvc, bccasout);
+      } else {
+        // Bond 'oldbc' to itself.
+        sbond(oldvc, oldvc);
+      }
+      ssbond(oldvc, bc);
     } else {
-      // Bond 'olddb' to itself.
-      sbond(olddb, olddb);
-      // Make sure that dummysh always correctly bonded.
-      dummysh[0] = sencode(olddb);
+      sbond(oldvc, bccasout);
     }
-    ssbond(olddb, bc);
-  } else {
-    sbond(olddb, bccasout);
-  }
-
-  // New vertex assignments for the rotated subfaces.
-  setsorg(abc, pd);  // Update abc to dca.
-  setsdest(abc, pc);
-  setsapex(abc, pa);
-  setsorg(bad, pc);  // Update bad to cdb.
-  setsdest(bad, pd);
-  setsapex(bad, pb);
+    // Delete bcv.
+    shellfacedealloc(subfaces, spinbcv.sh);
+    // Go to next subface at edge av.
+    spivotself(spinavc);
+    if (spinavc.sh == dummysh) {
+      break; // 'av' is a hull edge.
+    }
+  } while (spinavc.sh != startavc.sh);
 
-  if (flipqueue != (queue *) NULL) {
-    enqueueflipedge(bccasout, flipqueue);
-    enqueueflipedge(cacasout, flipqueue);
-    enqueueflipedge(adcasout, flipqueue);
-    enqueueflipedge(dbcasout, flipqueue);
+  // Is there a subsegment need to be unsplit?
+  if (av.sh != dummysh) {
+    senext(av, oldvc);  // Re-use oldvc.
+    spivot(oldvc, vb);
+    vb.shver = 0;
+#ifdef SELF_CHECK
+    assert(sdest(av) == sorg(vb));
+#endif
+    senext(vb, spinbcv); // Re-use spinbcv.
+    spivot(spinbcv, bccasout);
+    // Expand av to ab.
+    setsdest(av, pb);
+    sbond(oldvc, bccasout);
+    // Delete vb.
+    shellfacedealloc(subsegs, vb.sh);
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// flip()    Flips non-locally Delaunay faces in flipqueue until it is empty.//
-//                                                                           //
-// Assumpation:  Current tetrahedralization is non-Delaunay after inserting  //
-// a point or performing a flip operation, all possibly non-Delaunay faces   //
-// are in 'flipqueue'.                                                       //
-//                                                                           //
-// If 'plastflip' is not NULL,  it is used to return a stack of recently     //
-// flipped faces.  This stack will be used to reverse the flips done in this //
-// routine later for removing a newly inserted point because it encroaches   //
-// any subfaces or subsegments.                                              //
+// insertsite()    Insert a point into the mesh.                             //
 //                                                                           //
-// Flags 'chkencsegs', 'chkencsubs', and 'chkbadqual' are used for Delaunay  //
-// refinement. If a face is determined to be locally Delaunay or unflipable, //
-// 'chkencsegs' indicates to detect and queue encroach segment. 'chkencsubs' //
-// demands to test and queue the bad quality or encroached subface. The tets //
-// will be queued for quality check if 'chkbadqual' is TRUE.                 //
+// The 'newpoint' is located.  If 'searchtet->tet' is not NULL, the search   //
+// for the containing tetrahedron begins from 'searchtet', otherwise, a full //
+// point location procedure is called.  If 'newpoint' is found inside a      //
+// tetrahedron, the tetrahedron is split into four (by splittetrahedron());  //
+// if 'newpoint' lies on a face, the face is split into three, thereby       //
+// splitting the two adjacent tetrahedra into six (by splittetface()); if    //
+// 'newpoint' lies on an edge, the edge is split into two, thereby, every    //
+// tetrahedron containing this edge is split into two. If 'newpoint' lies on //
+// an existing vertex, no action is taken, and the value DUPLICATEPOINT  is  //
+// returned and 'searchtet' is set to a handle whose origin is the vertex.   //
 //                                                                           //
-// The return value is the total number of flips done during this invocation.//
+// If 'flipqueue' is not NULL, after 'newpoint' is inserted, it returns all  //
+// faces which may become non-Delaunay due to the newly inserted point. Flip //
+// operations can be performed as necessary on them to maintain the Delaunay //
+// property.                                                                 //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-long tetgenmesh::
-flip(queue* flipqueue, badface **plastflip, bool chkencsegs, bool chkencsubs,
-     bool chkbadqual)
+enum tetgenmesh::insertsiteresult tetgenmesh::
+insertsite(point newpoint, triface* searchtet, bool approx, queue* flipqueue)
 {
-  badface *qface;
-  badface *newflip;
-  triface flipface, symface;
-  face checkseg, checksh;
-  enum fliptype fc;
-  bool flipped;
-  REAL sign, bakepsilon;
-  long flipcount, maxfaces;
-  int epscount, fcount;
-  int i;
+  enum locateresult intersect, exactloc;
+  point checkpt;
+  REAL epspp, checklen;
+  int count;
 
   if (b->verbose > 1) {
-    printf("    Do flipface queue: %ld faces.\n", flipqueue->len());
-  }
-
-  flipcount = flip23s + flip32s + flip22s + flip44s;
-  if (checksubfaces) {
-    maxfaces = (4l * tetrahedrons->items + hullsize) / 2l;
-    fcount = 0;
+    printf("  Insert point to mesh: (%.12g, %.12g, %.12g) %d.\n",
+           newpoint[0], newpoint[1], newpoint[2], pointmark(newpoint));
   }
 
-  if (plastflip != (badface **) NULL) {
-    // Initialize the stack of the flip sequence.
-    flipstackers->restart();
-    *plastflip = (badface *) NULL;
+  if (searchtet->tet == (tetrahedron *) NULL) {
+    // Search for a tetrahedron containing 'newpoint'.
+    searchtet->tet = dummytet;
+    exactloc = locate(newpoint, searchtet);
+  } else {
+    // Start searching from the tetrahedron provided by the caller. 
+    exactloc = preciselocate(newpoint, searchtet, tetrahedrons->items);
   }
-
-  // Loop until the queue is empty.
-  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;
-    flipped = false;
-    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) {
-      // For positive orientation that insphere() test requires.
-      adjustedgering(flipface, CW); 
-      sign = insphere(org(flipface), dest(flipface), apex(flipface),
-                      oppo(flipface), oppo(symface));
-    } else {
-      sign = -1.0; // A hull face is locally Delaunay.
-    }
-    if (sign > 0.0) {
-      // 'flipface' is non-locally Delaunay, try to flip it.     
-      if (checksubfaces) {
-        fcount++;
-        assert(fcount < maxfaces);
-        bakepsilon = b->epsilon;
-        epscount = 0;
-        while (epscount < 32) {
-          fc = categorizeface(flipface);
-          if (fc == NONCONVEX) {
-            b->epsilon *= 1e-1;
-            epscount++;
-            continue;
-          }
-          break;
-        }
-        b->epsilon = bakepsilon;
-        if (epscount >= 32) {
-          if (b->verbose) {
-            printf("Warning:  Can't flip a degenerate tetrahedron.\n");
-          }
-          fc = NONCONVEX;
-        }
-      } else {
-        fc = categorizeface(flipface);
-        assert(fc != NONCONVEX);
-      }
-      switch (fc) {
-      // The following face types are flipable.
-      case T44:
-      case T22:
-        flip22(&flipface, flipqueue); 
-        flipped = true;
-        break;
-      case T23:
-        flip23(&flipface, flipqueue); 
-        flipped = true;
-        break;
-      case T32:
-        flip32(&flipface, flipqueue); 
-        flipped = true;
-        break;
-      // The following face types are unflipable.
-      case UNFLIPABLE:
-        break;
-      case FORBIDDENFACE:
-        // Meet an encroaching subface, unflipable.
-        break;
-      case FORBIDDENEDGE:
-        // Meet an encroaching subsegment, unflipable.
-        break;
-      // This case is only possible when the domain is nonconvex.
-      case NONCONVEX:
-        // assert(nonconvex);
-        break;
-      }
-      if (plastflip != (badface **) NULL && flipped) { 
-        // Push the flipped face into stack.
-        newflip = (badface *) flipstackers->alloc();
-        newflip->tt = flipface;
-        newflip->key = (REAL) fc;
-        newflip->forg = org(flipface);
-        newflip->fdest = dest(flipface);
-        newflip->fapex = apex(flipface);
-        newflip->previtem = *plastflip;
-        *plastflip = newflip;  
-      }
-    }
-    if (!flipped) {
-      if (chkencsegs) {
-        assert(badsubsegs != (memorypool *) NULL);
-        // Check for encroaching subsegments, add them into list.
-        for (i = 0; i < 3; i++) {
-          tsspivot(&flipface, &checkseg);
-          if (checkseg.sh != dummysh) {
-            if (!shell2badface(checkseg)) {
-              if (varconstraint && (areabound(checkseg) > 0.0)) {
-                checkseg4badqual(&checkseg, true);
-              }
-            }
-            if (!shell2badface(checkseg)) {
-              checkseg4encroach(&checkseg, NULL, NULL, true);
-            }
-          }
-          enextself(flipface);
-        }
-      }
-      if (chkencsubs) {
-        assert(badsubfaces != (memorypool *) NULL);
-        // Check for encroaching subface, add it into list.
-        tspivot(flipface, checksh);
-        if (checksh.sh != dummysh) {
-          if (!shell2badface(checksh)) {
-            checksub4badqual(&checksh, true);
-          }
-          if (!shell2badface(checksh)) {
-            checksub4encroach(&checksh, NULL, true);
-          }
-        }
-      }
-      if (chkbadqual) {
-        // Put the tetrahedra at both sides into list for quality check.
-        qualchecktetlist->append(&flipface);
-        if (symface.tet != dummytet) {
-          qualchecktetlist->append(&symface);
+  intersect = exactloc;
+  if (approx && (exactloc != ONVERTEX)) {
+    // Adjust the exact location to an approx. location wrt. epsilon.
+    epspp = b->epsilon;
+    count = 0;
+    while (count < 16) {
+      intersect = adjustlocate(newpoint, searchtet, exactloc, epspp);
+      if (intersect == ONVERTEX) {
+        checkpt = org(*searchtet);
+        checklen = distance(checkpt, newpoint);
+        if (checklen / longest > b->epsilon) {
+          epspp *= 1e-2;
+          count++;
+          continue;
         }
       }
+      break;
     }
   }
+  // Keep current search state for next searching.
+  recenttet = *searchtet; 
 
-  flipcount = flip23s + flip32s + flip22s + flip44s - flipcount;
-  if (b->verbose > 1) {
-    printf("    %ld flips.\n", flipcount);
-  }
+  // Insert the point using the right routine
+  switch (intersect) {
+  case ONVERTEX:
+    // There's already a vertex there. Return in 'searchtet' a tetrahedron
+    //   whose origin is the existing vertex.
+    if (b->verbose > 1) {
+      printf("  Not insert for duplicating point.\n");
+    }
+    return DUPLICATEPOINT;
 
-  return flipcount;
+  case OUTSIDE:
+    if (b->verbose > 1) {
+      printf("  Not insert for locating outside the mesh.\n");
+    }
+    return OUTSIDEPOINT;
+
+  case ONEDGE:
+    // 'newpoint' falls on an edge.
+    splittetedge(newpoint, searchtet, flipqueue);
+    return SUCCESSONEDGE;
+
+  case ONFACE:
+    // 'newpoint' falls on a face.
+    splittetface(newpoint, searchtet, flipqueue);
+    return SUCCESSONFACE;
+
+  case INTETRAHEDRON:
+    // 'newpoint' falls inside a tetrahedron.
+    splittetrahedron(newpoint, searchtet, flipqueue);
+    return SUCCESSINTET;
+  
+  default:
+    // Impossible case.
+    return OUTSIDEPOINT;
+  }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// undoflip()    Undo the most recent flip sequence induced by flip().       //
+// undosite()    Undo the most recently point insertion.                     //
 //                                                                           //
-// 'lastflip' is the stack of recently flipped faces. Walks through the list //
-// of flips, in the reverse of the order in which they were done, and undoes //
-// them.                                                                     //
+// 'insresult' indicates in where the newpoint has been inserted, i.e., in a //
+// tetrahedron, on a face, or on an edge.  A correspoding routine will be    //
+// called to undo the point insertion.  'splittet' is a handle represent one //
+// of the resulting tetrahedra, but it may be changed after transformation,  //
+// even may be dead.  Four points 'torg', ... 'toppo' are the corners which  //
+// 'splittet' should have. On finish, 'newpoint' is not removed.             //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::undoflip(badface *lastflip)
+void tetgenmesh::
+undosite(enum insertsiteresult insresult, triface* splittet, point torg,
+         point tdest, point tapex, point toppo)
 {
-  enum fliptype fc;
-
-  while (lastflip != (badface *) NULL) {
-    // Get the right flipped face.
-    findface(&lastflip->tt, lastflip->forg, lastflip->fdest, lastflip->fapex);
-    fc = (enum fliptype) (int) lastflip->key;
-    switch (fc) {
-    case T23:
-      // The reverse operation of T23 is T32.
-      flip32(&lastflip->tt, NULL);
-      break;
-    case T32:
-      // The reverse operation of T32 is T23.
-      flip23(&lastflip->tt, NULL);
-      break;
-    case T22:
-    case T44:
-      // The reverse operation of T22 or T44 is again T22 or T44.
-      flip22(&lastflip->tt, NULL);
-      break;
-    }
-    // Go on and process the next transformation.
-    lastflip = lastflip->previtem;
+  // 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;
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// splittetrahedron()    Insert a point into a tetrahedron, split it into    //
-//                       four tetrahedra.                                    //
+// Terminology: BC(p) and CBC(p), B(p) and C(p).                             //
 //                                                                           //
-// The tetrahedron is given by 'splittet'.  Let it is abcd.  The inserting   //
-// point 'newpoint' v should lie strictly inside abcd.                       //
+// Given an arbitrary point p,  the Bowyer-Watson cavity BC(p) is formed by  //
+// tets whose circumspheres containing p.  The outer faces of BC(p) form a   //
+// polyhedron B(p).                                                          //
 //                                                                           //
-// Splitting a tetrahedron is to shrink abcd to abcv,  and create three new  //
-// tetrahedra badv, cbdv, and acdv.                                          //
+// If p is on a facet F, the constrained Bowyer-Watson cavity CBC(p) on F is //
+// formed by subfaces of F whose circumspheres containing p. The outer edges //
+// of CBC(p) form a polygon C(p).  B(p) is separated into two parts by C(p), //
+// denoted as B_1(p) and B_2(p), one of them may be empty (F is on the hull).//
 //                                                                           //
-// On completion, 'splittet' returns abcv.  If 'flipqueue' is not NULL, it   //
-// contains all possibly non-locally Delaunay faces.                         //
+// If p is on a segment S which is shared by n facets.  There exist n C(p)s, //
+// each one is a non-closed polygon (without S). B(p) is split into n parts, //
+// each of them is denoted as B_i(p), some B_i(p) may be empty.              //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-splittetrahedron(point newpoint, triface* splittet, queue* flipqueue)
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// formbowatcavitysub()    Form CBC(p) and C(p) on a facet F.                //
+//                                                                           //
+// Parameters: bp = p, bpseg = S, sublist = CBC(p), subceillist = C(p).      //
+//                                                                           //
+// CBC(p) contains at least one subface on input; S may be NULL which means  //
+// that p is inside a facet. On output, all subfaces of CBC(p) are infected, //
+// and the edge rings are oriented to the same halfspace.                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::formbowatcavitysub(point bp, face* bpseg, list* sublist,
+  list* subceillist)
 {
-  triface oldabd, oldbcd, oldcad;                      // Old configuration.
-  triface abdcasing, bcdcasing, cadcasing;
-  face abdsh, bcdsh, cadsh;
-  triface abcv, badv, cbdv, acdv;                      // New configuration.
+  triface adjtet;
+  face startsh, neighsh;
+  face checkseg;
   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);
-  sym(oldbcd, bcdcasing);
-  sym(oldcad, cadcasing);
-  maketetrahedron(&badv);
-  maketetrahedron(&cbdv);
-  maketetrahedron(&acdv);
-
-  // Set 'badv' vertices.
-  setorg (badv, pb);
-  setdest(badv, pa);
-  setapex(badv, pd);
-  setoppo(badv, newpoint);
-  // Set 'cbdv' vertices.
-  setorg (cbdv, pc);
-  setdest(cbdv, pb);
-  setapex(cbdv, pd);
-  setoppo(cbdv, newpoint);
-  // Set 'acdv' vertices.
-  setorg (acdv, pa);
-  setdest(acdv, pc);
-  setapex(acdv, pd);
-  setoppo(acdv, newpoint);
-  // Set 'abcv' vertices
-  setoppo(abcv, newpoint);
-
-  // Set the element attributes of the new tetrahedra.
-  for (i = 0; i < in->numberoftetrahedronattributes; i++) {
-    attrib = elemattribute(abcv.tet, i);
-    setelemattribute(badv.tet, i, attrib);
-    setelemattribute(cbdv.tet, i, attrib);
-    setelemattribute(acdv.tet, i, attrib);
-  }
-  // Set the volume constraint of the new tetrahedra.
-  if (b->varvolume) {
-    volume = volumebound(abcv.tet);
-    setvolumebound(badv.tet, volume);
-    setvolumebound(cbdv.tet, volume);
-    setvolumebound(acdv.tet, volume);
-  }
+  REAL sign;
+  int i, j;  
 
-  // Bond the new triangles to the surrounding tetrahedron.
-  bond(badv, abdcasing);
-  bond(cbdv, bcdcasing);
-  bond(acdv, cadcasing);
-  // There may exist subfaces need to be bonded to the new tetrahedra.
-  if (checksubfaces) {
-    tspivot(oldabd, abdsh);
-    if (abdsh.sh != dummysh) {
-      tsdissolve(oldabd);
-      tsbond(badv, abdsh);
-    }
-    tspivot(oldbcd, bcdsh);
-    if (bcdsh.sh != dummysh) {
-      tsdissolve(oldbcd);
-      tsbond(cbdv, bcdsh);
-    }
-    tspivot(oldcad, cadsh);
-    if (cadsh.sh != dummysh) {
-      tsdissolve(oldcad);
-      tsbond(acdv, cadsh);
+  // Form CBC(p) and C(p) by a broadth-first searching.
+  for (i = 0; i < sublist->len(); i++) {
+    startsh = * (face *)(* sublist)[i]; // startsh = f.
+    // Look for three neighbors of f.
+    for (j = 0; j < 3; j++) {
+      sspivot(startsh, checkseg);
+      if (checkseg.sh == dummysh) {
+        // Get its neighbor n.
+        spivot(startsh, neighsh);
+        // Is n already in CBC(p)?
+        if (!sinfected(neighsh)) {
+          stpivot(neighsh, adjtet);
+          if (adjtet.tet == dummytet) {
+            sesymself(neighsh);
+            stpivot(neighsh, adjtet);
+          }
+          // For positive orientation that insphere() test requires.
+          adjustedgering(adjtet, CW);
+          pa = org(adjtet);
+          pb = dest(adjtet);
+          pc = apex(adjtet);
+          pd = oppo(adjtet);
+          sign = insphere(pa, pb, pc, pd, bp);
+          if (sign >= 0.0) {
+            // Orient edge ring of n according to that of f.
+            if (sorg(neighsh) != sdest(startsh)) sesymself(neighsh);
+            // Collect it into CBC(p).
+            sinfect(neighsh);
+            sublist->append(&neighsh);
+          } else {
+            subceillist->append(&startsh); // Found an edge of C(p).
+          }
+        }
+      } else {
+        // Do not cross a segment.
+        if (bpseg != (face *) NULL) {
+          if (checkseg.sh != bpseg->sh) {
+            subceillist->append(&startsh); // Found an edge of C(p).
+          }
+        } else {
+          subceillist->append(&startsh); // Found an edge of C(p).
+        }
+      }
+      senextself(startsh);
     }
   }
-  badv.loc = 3; 
-  cbdv.loc = 2;
-  bond(badv, cbdv);
-  cbdv.loc = 3; 
-  acdv.loc = 2;
-  bond(cbdv, acdv);
-  acdv.loc = 3; 
-  badv.loc = 2;
-  bond(acdv, badv);
-  badv.loc = 1; 
-  bond(badv, oldabd);
-  cbdv.loc = 1; 
-  bond(cbdv, oldbcd);
-  acdv.loc = 1; 
-  bond(acdv, oldcad);
-  
-  badv.loc = 0;
-  cbdv.loc = 0;
-  acdv.loc = 0;
-  if (b->verbose > 3) {
-    printf("    Updating abcv ");
-    printtet(&abcv);
-    printf("    Creating badv ");
-    printtet(&badv);
-    printf("    Creating cbdv ");
-    printtet(&cbdv);
-    printf("    Creating acdv ");
-    printtet(&acdv);
-  }
 
-  if (flipqueue != (queue *) NULL) {
-    enqueueflipface(abcv, flipqueue);
-    enqueueflipface(badv, flipqueue);
-    enqueueflipface(cbdv, flipqueue);
-    enqueueflipface(acdv, flipqueue);
+  if (b->verbose > 2) {
+    printf("    Collect CBC(%d): %d subfaces, %d edges.\n", pointmark(bp),
+           sublist->len(), subceillist->len());
   }
-
-  // Save a handle for quick point location.
-  recenttet = abcv;
-  // Set the return handle be abcv.
-  *splittet = abcv;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// unsplittetrahedron()    Reverse the operation of inserting a point into a //
-//                         tetrahedron, so as to remove the newly inserted   //
-//                         point from the mesh.                              //
+// formbowatcavityquad()    Form BC_i(p) and B_i(p) in a quadrant.           //
 //                                                                           //
-// Assume the origional tetrahedron is abcd, it was split by v into four     //
-// tetrahedra abcv, badv, cbdv, and acdv. 'splittet' represents face abc of  //
-// abcv (i.e., its opposite is v).                                           //
+// Parameters: bp = p, tetlist = BC_i(p), ceillist = B_i(p).                 //
 //                                                                           //
-// Point v is removed by expanding abcv to abcd, deleting three tetrahedra   //
-// badv, cbdv and acdv.  On return, point v is not deleted in this routine.  //
+// BC_i(p) contains at least one tet on input. On finish, all tets collected //
+// in BC_i(p) are infected. B_i(p) may not closed when p is on segment or in //
+// facet. C(p) must be formed before this routine.  Check the infect flag of //
+// a subface to identify the unclosed side of B_i(p).  These sides will be   //
+// closed by new subfaces of C(p)s.                                          //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::unsplittetrahedron(triface* splittet)
+void tetgenmesh::formbowatcavityquad(point bp, list* tetlist, list* ceillist)
 {
-  triface abcv, badv, cbdv, acdv;
-  triface oldabv, oldbcv, oldcav;
-  triface badcasing, cbdcasing, acdcasing;
-  face badsh, cbdsh, acdsh;
-
-  abcv = *splittet;
-  adjustedgering(abcv, CCW);  // for sure.
-  fnext(abcv, oldabv);
-  fnext(oldabv, badv);
-  esymself(badv);
-  enextfnext(abcv, oldbcv);
-  fnext(oldbcv, cbdv);
-  esymself(cbdv);
-  enext2fnext(abcv, oldcav);
-  fnext(oldcav, acdv);
-  esymself(acdv);
+  triface starttet, neightet;
+  face checksh;
+  point pa, pb, pc, pd;
+  REAL sign;
+  int i;
 
-  if (b->verbose > 1) {
-    printf("  Removing point %d in tetrahedron (%d, %d, %d, %d).\n",
-           pointmark(oppo(abcv)), pointmark(org(abcv)), pointmark(dest(abcv)),
-           pointmark(apex(abcv)), pointmark(apex(badv)));
+  // Form BC_i(p) and B_i(p) by a broadth-first searching.
+  for (i = 0; i < tetlist->len(); i++) {
+    starttet = * (triface *)(* tetlist)[i];
+    for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
+      // Try to collect the neighbor of the face (f).
+      tspivot(starttet, checksh);
+      if (checksh.sh == dummysh) {
+        // Get its neighbor n.
+        sym(starttet, neightet);
+        // Is n already in BC_i(p)?
+        if (!infected(neightet)) {
+          // For positive orientation that insphere() test requires.
+          adjustedgering(neightet, CW);
+          pa = org(neightet);
+          pb = dest(neightet);
+          pc = apex(neightet);
+          pd = oppo(neightet);
+          sign = insphere(pa, pb, pc, pd, bp);
+          if (sign >= 0.0) {
+            // Collect it into BC_i(p).
+            infect(neightet);
+            tetlist->append(&neightet);
+          } else {
+            ceillist->append(&starttet); // Found a face of B_i(p).
+          }
+        }
+      } else {
+        // Do not cross a boundary face.
+        if (!sinfected(checksh)) {
+          ceillist->append(&starttet); // Found a face of B_i(p).
+        }
+      }
+    }
   }
 
-  sym(badv, badcasing);
-  tspivot(badv, badsh);
-  sym(cbdv, cbdcasing);
-  tspivot(cbdv, cbdsh);
-  sym(acdv, acdcasing);
-  tspivot(acdv, acdsh);
-
-  // Expanding abcv to abcd.
-  setoppo(abcv, apex(badv));
-  bond(oldabv, badcasing);
-  if (badsh.sh != dummysh) {
-    tsbond(oldabv, badsh);
-  }
-  bond(oldbcv, cbdcasing);
-  if (cbdsh.sh != dummysh) {
-    tsbond(oldbcv, cbdsh);
-  }
-  bond(oldcav, acdcasing);
-  if (acdsh.sh != dummysh) {
-    tsbond(oldcav, acdsh);
+  if (b->verbose > 2) {
+    printf("    Collect BC_i(%d): %d tets, %d faces.\n", pointmark(bp),
+           tetlist->len(), ceillist->len());
   }
-
-  // Delete the three split-out tetrahedra.
-  tetrahedrondealloc(badv.tet);
-  tetrahedrondealloc(cbdv.tet);
-  tetrahedrondealloc(acdv.tet);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// splittetface()    Insert a point on a face of a mesh.                     //
-//                                                                           //
-// 'splittet' is the splitting face.  Let it is abcd, where abc is the face  //
-// will be split. If abc is not a hull face, abce is the tetrahedron at the  //
-// opposite of d.                                                            //
+// formbowatcavitysegquad()    Form BC_i(p) and B_i(p) in a segment quadrant.//
 //                                                                           //
-// To split face abc by a point v is to shrink the tetrahedra abcd to abvd,  //
-// create two new tetrahedra bcvd, cavd.  If abc is not a hull face, shrink  //
-// the tetrahedra bace to bave, create two new tetrahedra cbve, acve.        //
+// Parameters: bp = p, tetlist = BC_i(p), ceillist = B_i(p).                 //
 //                                                                           //
-// If abc is a subface, it is split into three subfaces simultaneously by    //
-// calling routine splitsubface(), hence, abv, bcv, cav.  The edge rings of  //
-// the split subfaces have the same orientation as abc's.                    //
+// BC_i(p) contains at least one tet on input. On finish, all tets collected //
+// in BC_i(p) are infected. B_i(p) is not closed. C(p) must be formed before //
+// this routine. Check the infect flag of a subface to identify the unclosed //
+// sides of B_i(p).  These sides will be closed by new subfaces of C(p)s.    //
 //                                                                           //
-// On completion, 'splittet' returns abvd.  If 'flipqueue' is not NULL, it   //
-// contains all possibly non-locally Delaunay faces.                         //
+// During the repair of encroaching subsegments, there may exist locally non-//
+// Delaunay faces. These faces are collected in BC_i(p) either.  B_i(p) has  //
+// to be formed later than BC_i(p).                                          //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-splittetface(point newpoint, triface* splittet, queue* flipqueue)
+void tetgenmesh::formbowatcavitysegquad(point bp, list* tetlist,list* ceillist)
 {
-  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 starttet, neightet, cavtet;
+  face checksh;
   point pa, pb, pc, pd, pe;
-  REAL attrib, volume;
-  bool mirrorflag;
+  REAL sign;
   int i;
 
-  abcd = *splittet;
-  // abcd.ver = 0; // Adjust to be CCW edge ring.
-  adjustedgering(abcd, CCW);
-  pa = org(abcd);
-  pb = dest(abcd);
-  pc = apex(abcd);
-  pd = oppo(abcd);
-  // Is there a second tetrahderon?
-  mirrorflag = issymexist(&abcd);
-  if (mirrorflag) {
-    // This is an interior face.
-    sym(abcd, bace);
-    findedge(&bace, dest(abcd), org(abcd));
-    pe = oppo(bace);
-  }
-  if (checksubfaces) {
-    // Is there a subface need to be split together?
-    tspivot(abcd, abcsh);
-    if (abcsh.sh != dummysh) {
-      // Exists! Keep the edge ab of both handles be the same.
-      findedge(&abcsh, org(abcd), dest(abcd));
+  // Form BC_i(p) by a broadth-first searching.
+  for (i = 0; i < tetlist->len(); i++) {
+    starttet = * (triface *)(* tetlist)[i];
+    for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
+      // Try to collect the neighbor of the face f.
+      tspivot(starttet, checksh);
+      if (checksh.sh == dummysh) {
+        // Get its neighbor n.
+        sym(starttet, neightet);
+        // Is n already in BC_i(p)?
+        if (!infected(neightet)) {
+          // For positive orientation that insphere() test requires.
+          adjustedgering(neightet, CW);
+          pa = org(neightet);
+          pb = dest(neightet);
+          pc = apex(neightet);
+          pd = oppo(neightet);
+          sign = insphere(pa, pb, pc, pd, bp);
+          if (sign >= 0.0) {
+            // Collect it into BC_i(p).
+            infect(neightet);
+            tetlist->append(&neightet);
+          } else {
+            // Check if the face is locally non-Delaunay.
+            pe = oppo(starttet);
+            sign = insphere(pa, pb, pc, pd, pe);
+            if (sign >= 0.0) {
+              // Collect it into BC_i(p).
+              infect(neightet);
+              tetlist->append(&neightet);
+            }
+          }
+        }
+      }
     }
   }
 
-  if (b->verbose > 1) {
-    printf("  Inserting point %d on face (%d, %d, %d).\n", pointmark(newpoint),
-           pointmark(pa), pointmark(pb), pointmark(pc));
+  // Generate B_i(p).
+  for (i = 0; i < tetlist->len(); i++) {
+    cavtet = * (triface *)(* tetlist)[i];
+    for (cavtet.loc = 0; cavtet.loc < 4; cavtet.loc++) {
+      tspivot(cavtet, checksh);
+      if (checksh.sh == dummysh) {
+        sym(cavtet, neightet);
+        if (!infected(neightet)) {
+          ceillist->append(&cavtet); // Found a face of B(p).
+        }
+      } else {
+        // Do not cross a boundary face.
+        if (!sinfected(checksh)) {
+          ceillist->append(&cavtet); // Found a face of B(p).
+        }
+      }
+    }
   }
 
-#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);
-  sym(oldbcd, bcdcasing);
-  sym(oldcad, cadcasing);
-  // Create two new tetrahedra.
-  maketetrahedron(&bcvd);
-  maketetrahedron(&cavd);
-  if (mirrorflag) {
-    // Save the old configuration at faces bce and cae.
-    enextfnext(bace, oldace);
-    enext2fnext(bace, oldcbe);
-    sym(oldace, acecasing);
-    sym(oldcbe, cbecasing);
-    // Create two new tetrahedra.
-    maketetrahedron(&acve);
-    maketetrahedron(&cbve);
-  } else {
-    // Splitting a boundary face increases the number of boundary faces.
-    hullsize += 2;
+  if (b->verbose > 2) {
+    printf("    Collect BC_i(%d): %d tets, %d faces.\n", pointmark(bp),
+           tetlist->len(), ceillist->len());
   }
+}
 
-  // Set vertices to the changed tetrahedron and new tetrahedra.
-  abvd = abcd;  // Update 'abcd' to 'abvd'.
-  setapex(abvd, newpoint);
-  setorg (bcvd, pb);  // Set 'bcvd'.
-  setdest(bcvd, pc);
-  setapex(bcvd, newpoint);
-  setoppo(bcvd, pd);
-  setorg (cavd, pc);  // Set 'cavd'.
-  setdest(cavd, pa);
-  setapex(cavd, newpoint);
-  setoppo(cavd, pd);
-  // Set the element attributes of the new tetrahedra.
-  for (i = 0; i < in->numberoftetrahedronattributes; i++) {
-    attrib = elemattribute(abvd.tet, i);
-    setelemattribute(bcvd.tet, i, attrib);
-    setelemattribute(cavd.tet, i, attrib);
-  }
-  if (b->varvolume) {
-    // Set the area constraint of the new tetrahedra.
-    volume = volumebound(abvd.tet);
-    setvolumebound(bcvd.tet, volume);
-    setvolumebound(cavd.tet, volume);
-  }
-  if (mirrorflag) {
-    bave = bace;  // Update 'bace' to 'bave'.
-    setapex(bave, newpoint);
-    setorg (acve, pa);  // Set 'acve'.
-    setdest(acve, pc);
-    setapex(acve, newpoint);
-    setoppo(acve, pe);
-    setorg (cbve, pc);  // Set 'cbve'.
-    setdest(cbve, pb);
-    setapex(cbve, newpoint);
-    setoppo(cbve, pe);
-    // Set the element attributes of the new tetrahedra.
-    for (i = 0; i < in->numberoftetrahedronattributes; i++) {
-      attrib = elemattribute(bave.tet, i);
-      setelemattribute(acve.tet, i, attrib);
-      setelemattribute(cbve.tet, i, attrib);
-    }
-    if (b->varvolume) {
-      // Set the area constraint of the new tetrahedra.
-      volume = volumebound(bave.tet);
-      setvolumebound(acve.tet, volume);
-      setvolumebound(cbve.tet, volume);
-    }
-  }
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// formbowatcavity()    Form BC(p), B(p), CBC(p)s, and C(p)s.                //
+//                                                                           //
+// If 'bpseg'(S) != NULL, p is on segment S, else, p is on facet containing  //
+// 'bpsh' (F).  'n' returns the number of quadrants in BC(p). 'nmax' is the  //
+// maximum pre-allocated array length for the lists.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
-  // Bond the new tetrahedra to the surrounding tetrahedra.
-  bcvd.loc = 1;
-  bond(bcvd, bcdcasing); 
-  cavd.loc = 1;
-  bond(cavd, cadcasing); 
-  bcvd.loc = 3;
-  bond(bcvd, oldbcd);
-  cavd.loc = 2;
-  bond(cavd, oldcad);
-  bcvd.loc = 2;
-  cavd.loc = 3;
-  bond(bcvd, cavd);  
-  if (mirrorflag) {
-    acve.loc = 1;
-    bond(acve, acecasing);
-    cbve.loc = 1;
-    bond(cbve, cbecasing);
-    acve.loc = 3;
-    bond(acve, oldace);
-    cbve.loc = 2;
-    bond(cbve, oldcbe);
-    acve.loc = 2;
-    cbve.loc = 3;
-    bond(acve, cbve);
-    // Bond two new coplanar facets.
-    bcvd.loc = 0;
-    cbve.loc = 0;
-    bond(bcvd, cbve);
-    cavd.loc = 0;
-    acve.loc = 0;
-    bond(cavd, acve);
-  }
+void tetgenmesh::formbowatcavity(point bp, face* bpseg, face* bpsh, int* n,
+  int* nmax, list** sublists, list** subceillists, list** tetlists,
+  list** ceillists)
+{
+  list *sublist;
+  triface adjtet;
+  face startsh, spinsh;
+  point pa, pb;
+  int i, j;
 
-  // There may exist subface needed to be bonded to the new tetrahedra.
-  if (checksubfaces) {
-    tspivot(oldbcd, bcdsh);
-    if (bcdsh.sh != dummysh) {
-      tsdissolve(oldbcd);
-      bcvd.loc = 1;
-      tsbond(bcvd, bcdsh);
-    }
-    tspivot(oldcad, cadsh);
-    if (cadsh.sh != dummysh) {
-      tsdissolve(oldcad);
-      cavd.loc = 1;
-      tsbond(cavd, cadsh);
+  *n = 0;
+  if (bpseg != (face *) NULL) {
+    // p is on segment S.
+    bpseg->shver = 0;
+    pa = sorg(*bpseg);
+    pb = sdest(*bpseg);
+    // Count the number of facets sharing at S.
+    spivot(*bpseg, startsh);
+    spinsh = startsh;
+    do {
+      (*n)++; // spinshlist->append(&spinsh);
+      spivotself(spinsh);
+    } while (spinsh.sh != startsh.sh);
+    // *n is the number of quadrants around S.
+    if (*n > *nmax) {
+      // Reallocate arrays. Should not happen very often.
+      delete [] tetlists;
+      delete [] ceillists;
+      delete [] sublists;
+      delete [] subceillists;
+      tetlists = new list*[*n];
+      ceillists = new list*[*n];
+      sublists = new list*[*n];
+      subceillists = new list*[*n];
+      *nmax = *n;
+    }
+    // Form CBC(p)s and C(p)s.
+    spinsh = startsh;
+    for (i = 0; i < *n; i++) {
+      sublists[i] = new list(sizeof(face), NULL, 256);
+      subceillists[i] = new list(sizeof(face), NULL, 256);
+      // Set a subface f to start search.
+      startsh = spinsh;
+      // Let f face to the quadrant of interest (used in forming BC(p)).
+      findedge(&startsh, pa, pb);
+      sinfect(startsh);
+      sublists[i]->append(&startsh);
+      formbowatcavitysub(bp, bpseg, sublists[i], subceillists[i]);
+      // Go to the next facet.
+      spivotself(spinsh);
     }
-    if (mirrorflag) {
-      tspivot(oldace, acesh);
-      if (acesh.sh != dummysh) {
-        tsdissolve(oldace);
-        acve.loc = 1;
-        tsbond(acve, acesh);
+  } else if (sublists != (list **) NULL) {
+    // p is on a facet.
+    *n = 2;
+    // Form CBC(p) and C(p).
+    sublists[0] = new list(sizeof(face), NULL, 256);
+    subceillists[0] = new list(sizeof(face), NULL, 256);
+    sinfect(*bpsh);
+    sublists[0]->append(bpsh);
+    formbowatcavitysub(bp, NULL, sublists[0], subceillists[0]);
+  } else {
+    // p is inside a tet.
+    *n = 1;
+  }
+
+  // Form BC_i(p) and B_i(p).
+  for (i = 0; i < *n; i++) {
+    tetlists[i] = new list(sizeof(triface), NULL, 256);
+    ceillists[i] = new list(sizeof(triface), NULL, 256);
+    if (sublists != (list **) NULL) {
+      // There are C(p)s.
+      sublist = ((bpseg == (face *) NULL) ? sublists[0] : sublists[i]);
+      // Add all adjacent tets of C_i(p) into BC_i(p).
+      for (j = 0; j < sublist->len(); j++) {    
+        startsh = * (face *)(* sublist)[j];
+        // Adjust the side facing to the right quadrant for C(p).
+        if ((bpseg == (face *) NULL) && (i == 1)) sesymself(startsh);
+        stpivot(startsh, adjtet);
+        if (adjtet.tet != dummytet) {
+          if (!infected(adjtet)) {
+            infect(adjtet);
+            tetlists[i]->append(&adjtet);
+          }
+        }
       }
-      tspivot(oldcbe, cbesh);
-      if (cbesh.sh != dummysh) {
-        tsdissolve(oldcbe);
-        cbve.loc = 1;
-        tsbond(cbve, cbesh);
+      if (bpseg != (face *) NULL) {
+        // The quadrant is bounded by another facet.
+        sublist = ((i < *n - 1) ? sublists[i + 1] : sublists[0]);
+        for (j = 0; j < sublist->len(); j++) {    
+          startsh = * (face *)(* sublist)[j];
+          // Adjust the side facing to the right quadrant for C(p).
+          sesymself(startsh);
+          stpivot(startsh, adjtet);
+          if (adjtet.tet != dummytet) {
+            if (!infected(adjtet)) {
+              infect(adjtet);
+              tetlists[i]->append(&adjtet);
+            }
+          }
+        }
       }
     }
-    // Is there a subface needs to be split together?
-    if (abcsh.sh != dummysh) {
-      // Split this subface 'abc' into three i.e, abv, bcv, cav.
-      splitsubface(newpoint, &abcsh, (queue *) NULL);
-    }  
+    // It is possible that BC_i(p) is empty.
+    if (tetlists[i]->len() == 0) continue;
+    // Collect the rest of tets of BC_i(p) and form B_i(p).
+    // if (b->conformdel) {
+      // formbowatcavitysegquad(bp, tetlists[i], ceillists[i]);
+    // } else {
+      formbowatcavityquad(bp, tetlists[i], ceillists[i]);
+    // }
   }
+}
 
-  // Save a handle for quick point location.
-  recenttet = abvd;
-  // Set the return handle be abvd.
-  *splittet = abvd;
-
-  bcvd.loc = 0;
-  cavd.loc = 0;
-  if (mirrorflag) {
-    cbve.loc = 0;
-    acve.loc = 0;
-  }
-  if (b->verbose > 3) {
-    printf("    Updating abvd ");
-    printtet(&abvd);
-    printf("    Creating bcvd ");
-    printtet(&bcvd);
-    printf("    Creating cavd ");
-    printtet(&cavd);
-    if (mirrorflag) {
-      printf("    Updating bave ");
-      printtet(&bave);
-      printf("    Creating cbve ");
-      printtet(&cbve);
-      printf("    Creating acve ");
-      printtet(&acve);
-    }
-  }
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// releasebowatcavity()    Undo and free the memory allocated in routine     //
+//                         formbowatcavity().                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
-  if (flipqueue != (queue *) NULL) {
-    fnextself(abvd);
-    enqueueflipface(abvd, flipqueue);
-    fnextself(bcvd);
-    enqueueflipface(bcvd, flipqueue);
-    fnextself(cavd);
-    enqueueflipface(cavd, flipqueue);
-    if (mirrorflag) {
-      fnextself(bave);
-      enqueueflipface(bave, flipqueue);
-      fnextself(cbve);
-      enqueueflipface(cbve, flipqueue);
-      fnextself(acve);
-      enqueueflipface(acve, flipqueue);
+void tetgenmesh::releasebowatcavity(face* bpseg, int n, list** sublists,
+  list** subceillist, list** tetlists, list** ceillists)
+{
+  triface oldtet;
+  face oldsh;
+  int i, j;
+
+  if (sublists != (list **) NULL) {
+    // Release CBC(p)s.
+    for (i = 0; i < n; i++) {
+      // Uninfect subfaces of CBC(p).
+      for (j = 0; j < sublists[i]->len(); j++) {
+        oldsh = * (face *)(* (sublists[i]))[j];
+#ifdef SELF_CHECK
+        assert(sinfected(oldsh));
+#endif
+        suninfect(oldsh);
+      }
+      delete sublists[i];
+      delete subceillist[i];
+      sublists[i] = (list *) NULL;
+      subceillist[i] = (list *) NULL;
+      if (bpseg == (face *) NULL) break;
+    }
+  }
+  // Release BC(p).
+  for (i = 0; i < n; i++) {
+    // Uninfect tets of BC_i(p).
+    for (j = 0; j < tetlists[i]->len(); j++) {
+      oldtet = * (triface *)(* (tetlists[i]))[j];
+#ifdef SELF_CHECK
+      assert(infected(oldtet));
+#endif
+      uninfect(oldtet);
     }
+    delete tetlists[i];
+    delete ceillists[i];
+    tetlists[i] = (list *) NULL;
+    ceillists[i] = (list *) NULL;
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// unsplittetface()    Reverse the operation of inserting a point on a face, //
-//                     so as to remove the newly inserted point.             //
+// validatebowatcavityquad()    Valid B_i(p).                                //
 //                                                                           //
-// Assume the original face is abc, the tetrahedron containing abc is abcd.  //
-// If abc is not a hull face, bace is the tetrahedron at the opposite of d.  //
-// After face abc was split by a point v, tetrahedron abcd had been split    //
-// into three tetrahedra, abvd, bcvd, cavd, and bace (if it exists) had been //
-// split into bave, cbve, acve. 'splittet' represents abvd (its apex is v).  //
+// B_i(p) is valid if all faces of B_i(p) are visible by p, else B_i(p) is   //
+// invalid.  Each tet of BC_i(p) which has such a face is marked (uninfect). //
+// They will be removed in updatebowatcavityquad().                          //
 //                                                                           //
-// Point v is removed by expanding abvd to abcd, deleting two tetrahedra     //
-// bcvd, cavd. Expanding bave(if it exists) to bace, deleting two tetrahedra //
-// cbve, acve.  If abv is a subface, routine unsplitsubface() will be called //
-// to reverse the operation of splitting a subface. On completion, point v   //
-// is not deleted in this routine.                                           //
+// Return TRUE if B(p) is valid, else, return FALSE.                         //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::unsplittetface(triface* splittet)
+bool tetgenmesh::validatebowatcavityquad(point bp,list* ceillist,REAL maxcosd)
 {
-  triface abvd, bcvd, cavd, bave, cbve, acve;
-  triface oldbvd, oldvad, oldvbe, oldave;
-  triface bcdcasing, cadcasing, cbecasing, acecasing;
-  face bcdsh, cadsh, cbesh, acesh;
-  face abvsh;
-  bool mirrorflag;
+  triface ceiltet;
+  point pa, pb, pc;
+  REAL ori, cosd;
+  int remcount, i;
 
-  abvd = *splittet;
-  adjustedgering(abvd, CCW); // for sure.
-  enextfnext(abvd, oldbvd);
-  fnext(oldbvd, bcvd);
-  esymself(bcvd);
-  enextself(bcvd);
-  enext2fnext(abvd, oldvad);
-  fnext(oldvad, cavd);
-  esymself(cavd);
-  enext2self(cavd);
-  // Is there a second tetrahedron?
-  sym(abvd, bave);
-  mirrorflag = bave.tet != dummytet;
-  if (mirrorflag) {
-    findedge(&bave, dest(abvd), org(abvd));
-    enextfnext(bave, oldave);  
-    fnext(oldave, acve);
-    esymself(acve);
-    enextself(acve);
-    enext2fnext(bave, oldvbe);  
-    fnext(oldvbe, cbve);
-    esymself(cbve);
-    enext2self(cbve);
-  } else {
-    // Unsplit a hull face decrease the number of boundary faces.
-    hullsize -= 2;
-  }
-  // Is there a subface at abv.
-  tspivot(abvd, abvsh);
-  if (abvsh.sh != dummysh) {
-    // Exists! Keep the edge ab of both handles be the same.
-    findedge(&abvsh, org(abvd), dest(abvd));
+  // Check the validate of B(p), cut tets having invisible faces.
+  remcount = 0;
+  for (i = 0; i < ceillist->len(); i++) {
+    ceiltet = * (triface *)(* ceillist)[i];
+    if (infected(ceiltet)) {
+      adjustedgering(ceiltet, CCW);
+      pa = org(ceiltet);
+      pb = dest(ceiltet);
+      pc = apex(ceiltet);
+      ori = orient3d(pa, pb, pc, bp);
+      if (ori >= 0.0) {
+        // Found an invisible face.
+        uninfect(ceiltet);
+        remcount++;
+        continue;
+      }
+      // If a non-trival 'maxcosd' is given.
+      if (maxcosd > -1.0) {
+        // Get the maximal dihedral angle of tet abcp.
+        tetalldihedral(pa, pb, pc, bp, NULL, &cosd, NULL);
+        // Do not form the tet if the maximal dihedral angle is not reduced.
+        if (cosd < maxcosd) {
+          uninfect(ceiltet);
+          remcount++;
+        }
+      }
+    }
   }
+  return remcount == 0;
+}
 
-  if (b->verbose > 1) {
-    printf("  Removing point %d on face (%d, %d, %d).\n",
-           pointmark(apex(abvd)), pointmark(org(abvd)), pointmark(dest(abvd)),
-           pointmark(dest(bcvd)));
-  }
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// updatebowatcavityquad()    Update BC_i(p) and reform B_i(p).              //
+//                                                                           //
+// B_i(p) is invalid and some tets in BC_i(p) have been marked to be removed //
+// in validatebowatcavityquad().  This routine actually remove the cut tets  //
+// of BC_i(p) and re-form the B_i(p).                                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
-  fnextself(bcvd); // bcvd has changed to bcdv.
-  sym(bcvd, bcdcasing);
-  tspivot(bcvd, bcdsh);
-  fnextself(cavd); // cavd has changed to cadv.
-  sym(cavd, cadcasing);
-  tspivot(cavd, cadsh);
-  if (mirrorflag) {
-    fnextself(acve); // acve has changed to acev.
-    sym(acve, acecasing);
-    tspivot(acve, acesh);
-    fnextself(cbve); // cbve has changed to cbev.
-    sym(cbve, cbecasing);
-    tspivot(cbve, cbesh);
+void tetgenmesh::updatebowatcavityquad(list* tetlist, list* ceillist)
+{
+  triface cavtet, neightet;
+  face checksh;
+  int remcount, i;
+
+  remcount = 0;
+  for (i = 0; i < tetlist->len(); i++) {
+    cavtet = * (triface *)(* tetlist)[i];
+    if (!infected(cavtet)) {
+      tetlist->del(i, 1);
+      remcount++;
+      i--;
+    }
   }
 
-  // Expand abvd to abcd.
-  setapex(abvd, dest(bcvd));
-  bond(oldbvd, bcdcasing);
-  if (bcdsh.sh != dummysh) {
-    tsbond(oldbvd, bcdsh);
-  }
-  bond(oldvad, cadcasing);
-  if (cadsh.sh != dummysh) {
-    tsbond(oldvad, cadsh);
-  }
-  if (mirrorflag) {
-    // Expanding bave to bace.
-    setapex(bave, dest(acve));
-    bond(oldave, acecasing);
-    if (acesh.sh != dummysh) {
-      tsbond(oldave, acesh);
+  // Are there tets have been cut in BC_i(p)?
+  if (remcount > 0) {
+    // Re-form B_i(p).
+    ceillist->clear();
+    for (i = 0; i < tetlist->len(); i++) {
+      cavtet = * (triface *)(* tetlist)[i];
+      for (cavtet.loc = 0; cavtet.loc < 4; cavtet.loc++) {
+        tspivot(cavtet, checksh);
+        if (checksh.sh == dummysh) {
+          sym(cavtet, neightet);
+          if (!infected(neightet)) {
+            ceillist->append(&cavtet); // Found a face of B_i(p).
+          }
+        } else {
+          // Do not cross a boundary face.
+          if (!sinfected(checksh)) {
+            ceillist->append(&cavtet); // Found a face of B_i(p).
+          }
+        }
+      }
     }
-    bond(oldvbe, cbecasing);
-    if (cbesh.sh != dummysh) {
-      tsbond(oldvbe, cbesh);
+    if (b->verbose > 2) {
+      printf("    Update BC_i(p): %d tets, %d faces.\n", tetlist->len(),
+             ceillist->len());
     }
   }
-
-  // Unsplit a subface if there exists.
-  if (abvsh.sh != dummysh) {
-    unsplitsubface(&abvsh);
-  }
-
-  // Delete the split-out tetrahedra.
-  tetrahedrondealloc(bcvd.tet);
-  tetrahedrondealloc(cavd.tet);
-  if (mirrorflag) {
-    tetrahedrondealloc(acve.tet);
-    tetrahedrondealloc(cbve.tet);
-  }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// splitsubface()    Insert a point on a subface, split it into three.       //
+// updatebowatcavitysub()    Check and update CBC(p) and C(p).               //
 //                                                                           //
-// The subface is 'splitface'.  Let it is abc. The inserting point 'newpoint'//
-// v should lie inside abc.  If the neighbor tetrahedra of abc exist, i.e.,  //
-// abcd and bace, they should have been split by routine splittetface()      //
-// before calling this routine, so the connection between the new tetrahedra //
-// and new subfaces can be correctly set.                                    //
+// A CBC(p) is valid if all its subfaces are inside or on the hull of BC(p). //
+// A subface s of CBC(p) is invalid if it is in one of the two cases:        //
+//   (1) s is completely outside BC(p);                                      //
+//   (2) s has two adjacent tets but only one of them is in BC(p);           //
+// s is removed from CBC(p) if it is invalid. If there is an adjacent tet of //
+// s which is in BC(p), it gets removed from BC(p) too. If CBC(p) is updated,//
+// C(p) is re-formed.                                                        //
 //                                                                           //
-// To split subface abc by point v is to shrink abc to abv, create two new   //
-// subfaces bcv and cav.  Set the connection between updated and new created //
-// subfaces. If there is a subsegment at edge bc or ca, connection of new    //
-// subface (bcv or cav) to its casing subfaces is a face link, 'casingin' is //
-// the predecessor and 'casingout' is the successor. It is important to keep //
-// the orientations of the edge rings of the updated and created subfaces be //
-// the same as abc's. So they have the same orientation as other subfaces of //
-// this facet with respect to the lift point of this facet.                  //
+// A C(p) is valid if all its edges are on the hull of BC(p).  An edge e of  //
+// C(p) may be inside BC(p) if e is a segment and belongs to only one facet. //
+// To correct C(p), a tet of BC(p) which shields e gets removed.             //
 //                                                                           //
-// On completion, 'splitface' returns abv.  If 'flipqueue' is not NULL, it   //
-// returns all possibly non-Delaunay edges.                                  //
+// If BC(p) is formed with locally non-Delaunay check (b->conformdel > 0).   //
+// A boundary-consistent check is needed for non-segment edges of C(p). Let  //
+// e be such an edge, the subface f contains e and outside C(p) may belong   //
+// to B(p) due to the non-coplanarity of the facet definition.  The tet of   //
+// BC(p) containing f gets removed to avoid creating a degenerate new tet.   //
+//                                                                           //
+// 'cutcount' accumulates the total number of cuttets(not only by this call).//
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-splitsubface(point newpoint, face* splitface, queue* flipqueue)
+void tetgenmesh::updatebowatcavitysub(list* sublist, list* subceillist,
+  int* cutcount)
 {
-  triface abvd, bcvd, cavd, bave, cbve, acve;
-  face abc, oldbc, oldca, bc, ca, spinsh;
-  face bccasin, bccasout, cacasin, cacasout;
-  face abv, bcv, cav;
+  triface adjtet, rotface;
+  face checksh, neighsh;
+  face checkseg;
   point pa, pb, pc;
-  
-  abc = *splitface;
-  // The newly created subfaces will have the same edge ring as abc.
-  adjustedgering(abc, CCW);
-  pa = sorg(abc);
-  pb = sdest(abc);
-  pc = sapex(abc);
+  REAL ori1, ori2;
+  int remcount;
+  int i, j;
 
-  if (b->verbose > 1) {
-    printf("  Inserting point %d on subface (%d, %d, %d).\n",
-           pointmark(newpoint), pointmark(pa), pointmark(pb), pointmark(pc));
+  remcount = 0;
+  // Check the validity of CBC(p).
+  for (i = 0; i < sublist->len(); i++) {
+    checksh = * (face *)(* sublist)[i];
+    // Check two adjacent tets of s.
+    for (j = 0; j < 2; j++) {
+      stpivot(checksh, adjtet);
+      if (adjtet.tet != dummytet) {
+        if (!infected(adjtet)) {
+          // Could be either case (1) or (2).
+          suninfect(checksh); // s survives.
+          // If the sym. adjtet exists, it should remove from BC(p) too.
+          sesymself(checksh);
+          stpivot(checksh, adjtet);
+          if (adjtet.tet != dummytet) {
+            if (infected(adjtet)) {
+              // Found an adj. tet in BC(p), remove it.
+              uninfect(adjtet);
+              (*cutcount)++;
+            }
+          }
+          // Remove s from C(p).
+          sublist->del(i, 1);
+          i--;
+          remcount++;
+          break;
+        }
+      }
+      sesymself(checksh);
+    }
   }
-
-  // Save the old configuration at edge bc and ca.  Subsegments may appear
-  //   at both sides, save the face links and dissolve them.
-  senext(abc, oldbc);
-  senext2(abc, oldca);
-  spivot(oldbc, bccasout);
-  sspivot(oldbc, bc);
-  if (bc.sh != dummysh) {
-    if (oldbc.sh != bccasout.sh) {
-      // 'oldbc' is not self-bonded.
-      spinsh = bccasout;
-      do {
-        bccasin = spinsh;
-        spivotself(spinsh);
-      } while (spinsh.sh != oldbc.sh);
-    } else {
-      bccasout.sh = dummysh;
+  if (remcount > 0) {
+    if (b->verbose > 2) {
+      printf("    Removed %d subfaces from CBC(p).\n", remcount);
     }
-    ssdissolve(oldbc);
-  } 
-  spivot(oldca, cacasout);
-  sspivot(oldca, ca);
-  if (ca.sh != dummysh) {
-    if (oldca.sh != cacasout.sh) {
-      // 'oldca' is not self-bonded.
-      spinsh = cacasout;
-      do {
-        cacasin = spinsh;
-        spivotself(spinsh);
-      } while (spinsh.sh != oldca.sh);
-    } else {
-      cacasout.sh = dummysh;
+    // Re-generate C(p).
+    subceillist->clear();
+    for (i = 0; i < sublist->len(); i++) {
+      checksh = * (face *)(* sublist)[i];
+      for (j = 0; j < 3; j++) {
+        spivot(checksh, neighsh);
+        if (!sinfected(neighsh)) {
+          subceillist->append(&checksh);
+        }
+        senextself(checksh);
+      }
     }
-    ssdissolve(oldca);
-  }
-  // Create two new subfaces.
-  makeshellface(subfaces, &bcv);
-  makeshellface(subfaces, &cav);
-
-  // Set the vertices of changed and new subfaces.
-  abv = abc;  // Update 'abc' to 'abv'.
-  setsapex(abv, newpoint);
-  setsorg(bcv, pb);  // Set 'bcv'.
-  setsdest(bcv, pc);
-  setsapex(bcv, newpoint);
-  setsorg(cav, pc);  // Set 'cav'.
-  setsdest(cav, pa);
-  setsapex(cav, newpoint);
-  if (b->quality && varconstraint) {
-    // Copy yhr area bound into the new subfaces.
-    setareabound(bcv, areabound(abv));
-    setareabound(cav, areabound(abv));
-  }
-  // Copy the boundary mark into the new subfaces.
-  setshellmark(bcv, shellmark(abv));
-  setshellmark(cav, shellmark(abv));  
-  // Copy the subface type into the new subfaces.
-  setshelltype(bcv, shelltype(abv));
-  setshelltype(cav, shelltype(abv));
-  if (checkpbcs) {
-    // Copy the pbcgroup into the new subfaces.
-    setshellpbcgroup(bcv, shellpbcgroup(abv));
-    setshellpbcgroup(cav, shellpbcgroup(abv));
-  }
-  // Bond the new subfaces to the surrounding subfaces.
-  if (bc.sh != dummysh) {
-    if (bccasout.sh != dummysh) {
-      sbond1(bccasin, bcv);
-      sbond1(bcv, bccasout);
-    } else {
-      // Bond 'bcv' to itsself.
-      sbond(bcv, bcv);
+    if (b->verbose > 2) {
+      printf("    Update CBC(p): %d subs, %d edges.\n", sublist->len(),
+             subceillist->len());
     }
-    ssbond(bcv, bc);
-  } else {
-    sbond(bcv, bccasout);
   }
-  if (ca.sh != dummysh) {
-    if (cacasout.sh != dummysh) {
-      sbond1(cacasin, cav);
-      sbond1(cav, cacasout);
+
+  // Check the validity of C(p).
+  for (i = 0; i < subceillist->len(); i++) {
+    checksh = * (face *)(* subceillist)[i];
+    sspivot(checksh, checkseg);
+    if (checkseg.sh != dummysh) {
+      // A segment. Check if it is inside BC(p).
+      stpivot(checksh, adjtet);
+      if (adjtet.tet == dummytet) {
+        sesym(checksh, neighsh);
+        stpivot(neighsh, adjtet);
+      }
+      findedge(&adjtet, sorg(checkseg), sdest(checkseg));
+      adjustedgering(adjtet, CCW);
+      fnext(adjtet, rotface); // It's the same tet.
+      // Rotate rotface (f), stop on either of the following cases:
+      //   (a) meet a subface, or
+      //   (b) enter an uninfected tet, or
+      //   (c) rewind back to adjtet.
+      do {
+        if (!infected(rotface)) break; // case (b)
+        tspivot(rotface, neighsh);
+        if (neighsh.sh != dummysh) break; // case (a)
+        // Go to the next tet of the facing ring.
+        fnextself(rotface);
+      } while (apex(rotface) != apex(adjtet));
+      // Is it case (c)?
+      if (apex(rotface) == apex(adjtet)) {
+        // The segment is enclosed by BC(p), invalid cavity.
+        pa = org(adjtet);
+        pb = dest(adjtet);
+        pc = apex(adjtet);
+        // Find the shield tet and cut it. Notice that the shield tet may
+        //   not be unique when there are four coplanar points, ie.,
+        //   ori1 * ori2 == 0.0. In such case, choose either of them.
+        fnext(adjtet, rotface);
+        do {
+          fnextself(rotface);
+          assert(infected(rotface));
+          ori1 = orient3d(pa, pb, pc, apex(rotface));
+          ori2 = orient3d(pa, pb, pc, oppo(rotface));
+        } while (ori1 * ori2 > 0.0);
+        // Cut this tet from BC(p).
+        uninfect(rotface);
+        (*cutcount)++;
+      }
     } else {
-      // Bond 'cav' to itself.
-      sbond(cav, cav);
+      /*// An edge. Check if boundary-consistency should be enforced.
+      if (b->conformdel > 0) {
+        // Get the adj-sub n at e, it must be outside C(p).
+        spivot(checksh, neighsh);
+        assert(!sinfected(neighsh));
+        // Check if n is on B(p).
+        for (j = 0; j < 2; j++) {
+          stpivot(neighsh, adjtet);
+          if (adjtet.tet != dummytet) {
+            if (infected(adjtet)) {
+              uninfect(adjtet);
+              (*cutcount)++;
+            }
+          }
+          sesymself(neighsh);
+        }
+      } */
     }
-    ssbond(cav, ca);
-  } else {
-    sbond(cav, cacasout);
   }
-  senext2self(bcv);
-  sbond(bcv, oldbc);
-  senextself(cav);
-  sbond(cav, oldca);
-  senext2self(bcv);
-  senextself(cav);
-  sbond(bcv, cav);
+}
 
-  // Bond the new subfaces to the new tetrahedra if they exist.
-  stpivot(abv, abvd);
-  if (abvd.tet != dummytet) {
-    // Get two new tetrahedra and their syms.
-    findedge(&abvd, sorg(abv), sdest(abv));
-    enextfnext(abvd, bcvd);
-    assert(bcvd.tet != dummytet);
-    fnextself(bcvd);
-    enext2fnext(abvd, cavd);
-    assert(cavd.tet != dummytet);
-    fnextself(cavd);
-    // Bond two new subfaces to the two new tetrahedra.
-    tsbond(bcvd, bcv);
-    tsbond(cavd, cav);
-  }
-  // Set the connection at the other sides if the tetrahedra exist.
-  sesymself(abv);  // bav
-  stpivot(abv, bave);
-  if (bave.tet != dummytet) {
-    sesymself(bcv);  // cbv
-    sesymself(cav);  // acv
-    // Get two new tetrahedra and their syms.
-    findedge(&bave, sorg(abv), sdest(abv));
-    enextfnext(bave, acve);
-    assert(acve.tet != dummytet);
-    fnextself(acve);
-    enext2fnext(bave, cbve);
-    assert(cbve.tet != dummytet);
-    fnextself(cbve);
-    // Bond two new subfaces to the two new tetrahedra.
-    tsbond(acve, cav);
-    tsbond(cbve, bcv);
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// trimbowatcavity()    Validate B(p), CBC(p)s and C(p)s, update BC(p).      //
+//                                                                           //
+// A B(p) is valid if all its faces are visible by p. If a face f of B(p) is //
+// found invisible by p, the tet of BC(p) containing f gets removed and B(p) //
+// is refromed. The new B(p) may still contain invisible faces by p. Iterat- //
+// ively do the above procedure until B(p) is satisfied.                     //
+//                                                                           //
+// A CBC(p) is valid if each subface of CBC(p) is either on the hull of BC(p)//
+// or completely inside BC(p). If a subface s of CBC(p) is not valid, it is  //
+// removed from CBC(p) and C(p) is reformed. If there exists a tet t of BC(p)//
+// containg s, t is removed from BC(p). The process for validating BC(p) and //
+// B(p) is re-excuted.                                                       //
+//                                                                           //
+// A C(p) is valid if each edge of C(p) is on the hull of BC(p). If an edge  //
+// e of C(p) is invalid (e should be a subsegment which only belong to one   //
+// facet), a tet of BC(p) which contains e and has two other faces shielding //
+// e is removed. The process for validating BC(p) and B(p) is re-excuted.    //
+//                                                                           //
+// If either BC(p) or CBC(p) becomes empty. No valid BC(p) is found, return  //
+// FALSE. else, return TRUE.                                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::trimbowatcavity(point bp, face* bpseg, int n, list** sublists,
+  list** subceillists, list** tetlists, list** ceillists, REAL maxcosd)
+{
+  bool valflag;
+  int oldnum, cutnum, cutcount;
+  int i;
+
+  cutnum = 0; // Count the total number of cut-off tets of BC(p).
+  valflag = true;
+
+  do {
+    // Validate BC(p), B(p).
+    for (i = 0; i < n && valflag; i++) {
+      oldnum = tetlists[i]->len();
+      // Iteratively validate BC_i(p) and B_i(p).
+      while (!validatebowatcavityquad(bp, ceillists[i], maxcosd)) {
+        // Update BC_i(p) and B_i(p).
+        updatebowatcavityquad(tetlists[i], ceillists[i]);
+        valflag = tetlists[i]->len() > 0;
+      }
+      cutnum += (oldnum - tetlists[i]->len());
+    }
+    if (valflag && (sublists != (list **) NULL)) {
+      // Validate CBC(p), C(p).
+      cutcount = 0;
+      for (i = 0; i < n; i++) {
+        updatebowatcavitysub(sublists[i], subceillists[i], &cutcount);
+        // Only do once if p is on a facet.
+        if (bpseg == (face *) NULL) break; 
+      }
+      // Are there cut tets?
+      if (cutcount > 0) {
+        // Squeeze all cut tets in BC(p), keep valflag once it gets FLASE.
+        for (i = 0; i < n; i++) {
+          if (tetlists[i]->len() > 0) {
+            updatebowatcavityquad(tetlists[i], ceillists[i]);
+            if (valflag) {
+              valflag = tetlists[i]->len() > 0;
+            }
+          }
+        }
+        cutnum += cutcount;
+        // Go back to valid the updated BC(p).
+        continue;
+      }
+    }
+    break; // Leave the while-loop.
+  } while (true);
+
+  // Check if any CBC(p) becomes non-empty.
+  if (valflag && (sublists != (list **) NULL)) {
+    for (i = 0; i < n && valflag; i++) {
+      valflag = (sublists[i]->len() > 0);
+      if (bpseg == (face *) NULL) break; 
+    }
   }
 
-  bcv.shver = 0;
-  cav.shver = 0;
-  if (b->verbose > 3) {
-    printf("    Updating abv ");
-    printsh(&abv);
-    printf("    Creating bcv ");
-    printsh(&bcv);
-    printf("    Creating cav ");
-    printsh(&cav);
+  if (valflag && (cutnum > 0)) {
+    // Accumulate counters.
+    if (bpseg != (face *) NULL) {
+      updsegcount++;
+    } else if (sublists != (list **) NULL) {
+      updsubcount++;
+    } else {
+      updvolcount++;
+    }
   }
 
-  if (flipqueue != (queue *) NULL) {
-    enqueueflipedge(abv, flipqueue);
-    enqueueflipedge(bcv, flipqueue);
-    enqueueflipedge(cav, flipqueue);
+  if (!valflag) {
+    // Accumulate counters.
+    if (bpseg != (face *) NULL) {
+      failsegcount++;
+    } else if (sublists != (list **) NULL) {
+      failsubcount++;
+    } else {
+      failvolcount++;
+    }
   }
 
-  // Set the return handle be abv.
-  *splitface = abv;
+  return valflag;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// unsplitsubface()    Reverse the operation of inserting a point on a       //
-//                     subface, so as to remove the newly inserted point.    //
+// bowatinsertsite()    Insert a point using the Bowyer-Watson method.       //
 //                                                                           //
-// Assume the original subface is abc, it was split by a point v into three  //
-// subfaces abv, bcv and cav.  'splitsh' represents abv.                     //
+// Parameters: 'bp' = p, 'splitseg' = S, 'n' = the number of quadrants,      //
+// 'sublists', an array of CBC_i(p)s, 'subceillists', an array of C_i(p)s,   //
+// 'tetlists', an array of BC_i(p)s, 'ceillists', an array of B_i(p)s.       //
 //                                                                           //
-// To remove point v is to expand abv to abc, delete bcv and cav. If edge bc //
-// or ca is a subsegment,  the connection at a subsegment is a subface link, //
-// '-casin' and '-casout' are used to save the predecessor and successor of  //
-// bcv or cav.  On completion, point v is not deleted in this routine.       //
+// If p is inside the mesh domain, then S = NULL, n = 1, CBC(p) and C(p) are //
+//   NULLs. 'tetlists[0]' = BC(p), 'ceillists[0]' = B(p).                    //
+// If p is on a facet F, then S = NULL, n = 2, and 'subceillists[0]' = C(p), //
+//  'subceillists[1]' is not needed (set it to NULL). B_1(p) and B_2(p) are  //
+//  in 'ceillists[0]' and 'ceillists[1]'.                                    //
+// If p is on a segment S, then F(S) is a list of subfaces around S, and n = //
+//   len(F(S)), there are n C_i(p)s and B_i(p)s supplied in 'subceillists[i]'//
+//   and 'ceillists[i]'.                                                     //
+//                                                                           //
+// If 'verlist' != NULL, it returns a list of vertices which connect to p.   //
+//   This vertices are used for interpolating size of p.                     //
+//                                                                           //
+// If 'flipque' != NULL, it returns a list of internal faces of new tets in  //
+//   BC(p), faces on C(p)s are excluded. These faces may be locally non-     //
+//   Delaunay and will be flipped if they are flippable. Such non-Delaunay   //
+//   faces may exist when p is inserted to split an encroaching segment.     //
+//                                                                           //
+// 'chkencseg', 'chkencsub', and 'chkbadtet' are flags that indicate whether //
+// or not there should be checks for the creation of encroached subsegments, //
+// subfaces, or bad quality tets. If 'chkencseg' = TRUE, the encroached sub- //
+// segments are added to the list of subsegments to be split.                //
+//                                                                           //
+// On return, 'ceillists' returns Star(p).                                   //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::unsplitsubface(face* splitsh)
+void tetgenmesh::bowatinsertsite(point bp,face* splitseg,int n,list** sublists,
+  list** subceillists, list** tetlists, list** ceillists, list* verlist,
+  queue* flipque, bool chkencseg, bool chkencsub, bool chkbadtet)
 {
-  face abv, bcv, cav;
-  face oldbv, oldva, bc, ca, spinsh;
-  face bccasin, bccasout, cacasin, cacasout;
+  list *ceillist, *subceillist; 
+  triface oldtet, newtet, newface, rotface, neightet; 
+  face oldsh, newsh, newedge, checksh;
+  face spinsh, casingin, casingout;
+  face *apsegshs, *pbsegshs;
+  face apseg, pbseg, checkseg;
+  point pa, pb, pc;
+  REAL attrib, volume;
+  int idx, i, j, k;
 
-  abv = *splitsh;
-  senext(abv, oldbv);
-  spivot(oldbv, bcv);
-  if (sorg(bcv) != sdest(oldbv)) {
-    sesymself(bcv);
+  if (b->verbose > 1) {
+    printf("    Insert point %d (%.12g, %.12g, %.12g)", pointmark(bp), bp[0],
+           bp[1], bp[2]);
   }
-  senextself(bcv);
-  senext2(abv, oldva);
-  spivot(oldva, cav);
-  if (sorg(cav) != sdest(oldva)) {
-    sesymself(cav);
+  if (splitseg != (face *) NULL) {
+    if (b->verbose > 1) {
+      printf(" on segment.\n");
+    }
+    bowatsegcount++;
+  } else {
+    if (subceillists != (list **) NULL) {
+      if (b->verbose > 1) {
+        printf(" on facet.\n");
+      }
+      bowatsubcount++;
+    } else {
+      if (b->verbose > 1) {
+        printf(" in volume.\n");
+      }
+      bowatvolcount++;
+    }
   }
-  senext2self(cav);
 
-  if (b->verbose > 1) {
-    printf("  Removing point %d on subface (%d, %d, %d).\n",
-           pointmark(sapex(abv)), pointmark(sorg(abv)), pointmark(sdest(abv)),
-           pointmark(sdest(bcv)));
+  // Create new tets to fill B(p).
+  for (k = 0; k < n; k++) {
+    // Create new tets from each B_i(p).
+    ceillist = ceillists[k];
+    for (i = 0; i < ceillist->len(); i++) {
+      oldtet = * (triface *)(* ceillist)[i];
+      adjustedgering(oldtet, CCW);
+      pa = org(oldtet);
+      pb = dest(oldtet);
+      pc = apex(oldtet);
+      maketetrahedron(&newtet);
+      setorg(newtet, pa);
+      setdest(newtet, pb);
+      setapex(newtet, pc);
+      setoppo(newtet, bp);
+      for (j = 0; j < in->numberoftetrahedronattributes; j++) {
+        attrib = elemattribute(oldtet.tet, j);
+        setelemattribute(newtet.tet, j, attrib);
+      }
+      if (b->varvolume) {
+        volume = volumebound(oldtet.tet);
+        if (volume > 0.0) {
+          if (!b->fixedvolume && b->refine) {
+            // '-r -a' switches and a .vol file case. Enlarge the maximum
+            //   volume constraint for the new tets. Hence the new points
+            //   only spread near the original constrained tet.
+            volume *= 1.2;
+          }
+        }
+        setvolumebound(newtet.tet, volume);
+      }
+      sym(oldtet, neightet);
+      tspivot(oldtet, checksh);
+      if (neightet.tet != dummytet) {
+        bond(newtet, neightet);
+      }
+      if (checksh.sh != dummysh) {
+        tsbond(newtet, checksh);
+      }
+      if (verlist != (list *) NULL) {
+        // Collect vertices connecting to p.
+        idx = pointmark(pa);
+        if (idx >= 0) {
+          setpointmark(pa, -idx - 1);
+          verlist->append(&pa);
+        }
+        idx = pointmark(pb);
+        if (idx >= 0) {
+          setpointmark(pb, -idx - 1);
+          verlist->append(&pb);
+        }
+        idx = pointmark(pc);
+        if (idx >= 0) {
+          setpointmark(pc, -idx - 1);
+          verlist->append(&pc);
+        }
+      }
+      // Replace the tet by the newtet for checking the quality.
+      * (triface *)(* ceillist)[i] = newtet;
+    }
   }
-
-  spivot(bcv, bccasout);
-  sspivot(bcv, bc);
-  if (bc.sh != dummysh) {
-    if (bcv.sh != bccasout.sh) {
-      // 'bcv' is not self-bonded.
-      spinsh = bccasout;
-      do {
-        bccasin = spinsh;
-        spivotself(spinsh);
-      } while (spinsh.sh != bcv.sh);
-    } else {
-      bccasout.sh = dummysh;
+  if (verlist != (list *) NULL) {
+    // Uninfect collected vertices.
+    for (i = 0; i < verlist->len(); i++) {
+      pa = * (point *)(* verlist)[i];
+      idx = pointmark(pa);
+      setpointmark(pa, -(idx + 1));
     }
   }
-  spivot(cav, cacasout);
-  sspivot(cav, ca);
-  if (ca.sh != dummysh) {
-    if (cav.sh != cacasout.sh) {
-      // 'cav' is not self-bonded.
-      spinsh = cacasout;
-      do {
-       cacasin = spinsh;
-       spivotself(spinsh);
-      } while (spinsh.sh != cav.sh);
-    } else {
-      cacasout.sh = dummysh;
+
+  // Connect new tets of B(p). Not all faces of new tets can be connected,
+  //   e.g., if there are empty B_i(p)s.
+  for (k = 0; k < n; k++) {
+    ceillist = ceillists[k];
+    for (i = 0; i < ceillist->len(); i++) {
+      newtet = * (triface *)(* ceillist)[i];
+      newtet.ver = 0;
+      for (j = 0; j < 3; j++) {
+        fnext(newtet, newface);
+        sym(newface, neightet);
+        if (neightet.tet == dummytet) {
+          // Find the neighbor face by rotating the faces at edge ab.
+          esym(newtet, rotface);
+          pa = org(rotface);
+          pb = dest(rotface);
+          while (fnextself(rotface));
+          // Do we meet a boundary face?
+          tspivot(rotface, checksh);
+          if (checksh.sh != dummysh) {
+            // Walk through the boundary and continue to rotate faces.
+            do {
+              findedge(&checksh, pa, pb);
+              sfnextself(checksh);
+              assert((sorg(checksh) == pa) && (sdest(checksh) == pb));
+              stpivot(checksh, rotface);
+              if (infected(rotface)) {
+                // Meet an old tet of B_i(p). This side is on the hull and
+                //   will be connected to a new subface created in C(p).
+                break;
+              }
+              findedge(&rotface, pa, pb);
+              while (fnextself(rotface));
+              tspivot(rotface, checksh);
+            } while (checksh.sh != dummysh);
+          }
+          // The rotface has edge ab, but it may not have newpt.
+          if (apex(rotface) == apex(newface)) { 
+            // Bond the two tets together.
+            bond(newface, rotface);
+            // Queue (uniquely) this face if 'flipque' is given.
+            if (flipque != (queue *) NULL) {
+              enqueueflipface(newface, flipque);
+            }
+          }
+        }
+        enextself(newtet);
+      }
     }
   }
 
-  // Expand abv to abc.
-  setsapex(abv, sdest(bcv));
-  if (bc.sh != dummysh) {
-    if (bccasout.sh != dummysh) {
-      sbond1(bccasin, oldbv);
-      sbond1(oldbv, bccasout);
-    } else {
-      // Bond 'oldbv' to itself.
-      sbond(oldbv, oldbv);
+  if (subceillists != (list **) NULL) {
+    // There are C(p)s.
+    if (splitseg != (face *) NULL) {
+      // S (ab) is split by p.
+      splitseg->shver = 0;
+      pa = sorg(*splitseg);
+      pb = sdest(*splitseg);
+      // Allcate two arrays for saving the subface rings of the two new
+      //   segments a->p and p->b.
+      apsegshs = new face[n];
+      pbsegshs = new face[n];
     }
-    ssbond(oldbv, bc);
-  } else {
-    sbond(oldbv, bccasout);
-  } 
-  if (ca.sh != dummysh) {
-    if (cacasout.sh != dummysh) {
-      sbond1(cacasin, oldva);
-      sbond1(oldva, cacasout);
-    } else {
-      // Bond 'oldva' to itself.
-      sbond(oldva, oldva);
+
+    // For each C_k(p), do the following:
+    //   (1) Create new subfaces to fill C_k(p), insert them into B(p);
+    //   (2) Connect new subfaces to each other;
+    for (k = 0; k < n; k++) {      
+      subceillist = subceillists[k];
+
+      // Check if 'hullsize' should be updated.
+      oldsh = * (face *)(* subceillist)[0];
+      stpivot(oldsh, neightet);
+      if (neightet.tet != dummytet) {
+        sesymself(oldsh);
+        stpivot(oldsh, neightet);
+      }
+      if (neightet.tet == dummytet) {
+        // The hull size changes.
+        hullsize += (subceillist->len() - sublists[k]->len());
+      }
+
+      // (1) Create new subfaces to fill C_k(p), insert them into B(p).
+      for (i = 0; i < subceillist->len(); i++) {
+        oldsh = * (face *)(* subceillist)[i];
+        makeshellface(subfaces, &newsh);
+        setsorg(newsh, sorg(oldsh));
+        setsdest(newsh, sdest(oldsh));
+        setsapex(newsh, bp);
+        if (b->quality && varconstraint) {
+          setareabound(newsh, areabound(oldsh));
+        }
+        setshellmark(newsh, shellmark(oldsh));
+        setshelltype(newsh, shelltype(oldsh));
+        if (checkpbcs) {
+          setshellpbcgroup(newsh, shellpbcgroup(oldsh));
+        }
+        // Replace oldsh by newsh at the edge.
+        spivot(oldsh, casingout);
+        sspivot(oldsh, checkseg);
+        if (checkseg.sh != dummysh) {
+          // A segment. Insert s into the face ring, ie, s_in -> s -> s_out.
+          if (oldsh.sh != casingout.sh) {
+            // s is not bonded to itself.
+            spinsh = casingout;
+            do {
+              casingin = spinsh;
+              spivotself(spinsh);
+            } while (sapex(spinsh) != sapex(oldsh));
+            assert(casingin.sh != oldsh.sh); 
+            // Bond s_in -> s -> s_out (and dissolve s_in -> s_old -> s_out).
+            sbond1(casingin, newsh);
+            sbond1(newsh, casingout);
+          } else {
+            // Bond newsh -> newsh.
+            sbond(newsh, newsh);
+          }
+          // Bond the segment.
+          ssbond(newsh, checkseg);
+        } else {
+          // Bond s <-> s_out (and dissolve s_out -> s_old).
+          sbond(newsh, casingout);
+        }
+
+        // Insert newsh into B(p). Use the coonections of oldsh.
+        stpivot(oldsh, neightet);
+        if (neightet.tet == dummytet) {
+          sesymself(oldsh);
+          sesymself(newsh); // Keep the same orientation as oldsh.
+          stpivot(oldsh, neightet);
+        }
+        assert(infected(neightet));
+        // Set on the rotating edge.
+        findedge(&neightet, sorg(oldsh), sdest(oldsh));
+        // Choose the rotating direction (to the inside of B(p)).
+        adjustedgering(neightet, CCW);
+        rotface = neightet;
+        // Rotate face. Stop at a non-infected tet t (not in B(p)) or a
+        //   hull face f (on B(p)). Get the neighbor n of t or f.  n is
+        //   a new tet that has just been created to fill B(p).
+        do {
+          fnextself(rotface);
+          sym(rotface, neightet);
+          if (neightet.tet == dummytet) {
+            tspivot(rotface, checksh);
+            assert(checksh.sh != dummysh);
+            stpivot(checksh, newtet);
+            break;
+          } else if (!infected(neightet)) {
+            sym(neightet, newtet);
+            break;
+          }
+        } while (true);
+        assert(newtet.tet != rotface.tet);
+        // Set the rotating edge of n.
+        findedge(&newtet, sorg(oldsh), sdest(oldsh));
+        // Choose the rotating direction (to the inside of B(p)).
+        adjustedgering(newtet, CCW);
+        fnext(newtet, newface);
+        assert(apex(newface) == bp);
+        // newsh has already been oriented toward n.
+        tsbond(newface, newsh);
+        sym(newface, neightet); // 'neightet' maybe outside.
+        sesymself(newsh);
+        tsbond(neightet, newsh); // Bond them anyway.
+
+        // Replace oldsh by newsh in list.
+        * (face *)(* subceillist)[i] = newsh;
+      }
+
+      // (2) Connect new subfaces to each other.
+      for (i = 0; i < subceillist->len(); i++) {
+        // Get a face cdp.
+        newsh = * (face *)(* subceillist)[i];
+        // Get a new tet containing cdp.
+        stpivot(newsh, newtet);
+        if (newtet.tet == dummytet) {
+          sesymself(newsh);
+          stpivot(newsh, newtet);
+        }
+        for (j = 0; j < 2; j++) {
+          if (j == 0) {
+            senext(newsh, newedge); // edge dp.
+          } else {
+            senext2(newsh, newedge); // edge pc.
+            sesymself(newedge); // edge cp.
+          }
+          if (splitseg != (face *) NULL) {
+            // Don not operate on newedge if it is ap or pb.
+            if (sorg(newedge) == pa) {
+              apsegshs[k] = newedge;
+              continue;
+            } else if (sorg(newedge) == pb) {
+              pbsegshs[k] = newedge;
+              continue;
+            }
+          }
+          // There should no segment inside the cavity. Check it.
+          sspivot(newedge, checkseg);
+          assert(checkseg.sh == dummysh);
+          spivot(newedge, casingout);
+          if (casingout.sh == dummysh) {
+            rotface = newtet;
+            findedge(&rotface, sorg(newedge), sdest(newedge));
+            // Rotate newtet until meeting a new subface which contains
+            //   newedge. It must exist since newedge is not a seg.
+            adjustedgering(rotface, CCW);
+            do {
+              fnextself(rotface);
+              tspivot(rotface, checksh);
+              if (checksh.sh != dummysh) break;
+            } while (true);
+            findedge(&checksh, sorg(newedge), sdest(newedge));
+            sbond(newedge, checksh);
+          }
+        }
+      }
+      // Only do once if p is on a facet.
+      if (splitseg == (face *) NULL) break;
+    } // for (k = 0; k < n; k++)
+
+    if (splitseg != (face *) NULL) {
+      // Update a->b to be a->p.
+      apseg = *splitseg;
+      setsdest(apseg, bp);
+      // Create a new subsegment p->b.
+      makeshellface(subsegs, &pbseg);
+      setsorg(pbseg, bp);
+      setsdest(pbseg, pb);
+      // p->b gets the same mark and segment type as a->p.
+      setshellmark(pbseg, shellmark(apseg));
+      setshelltype(pbseg, shelltype(apseg));
+      if (b->quality && varconstraint) {
+        // Copy the area bound into the new subsegment.
+        setareabound(pbseg, areabound(apseg));
+      }
+      senext(apseg, checkseg);
+      // Get the old connection at b of a->b.
+      spivot(checkseg, casingout);
+      // Bond a->p and p->b together.
+      senext2(pbseg, casingin);
+      sbond(casingin, checkseg);
+      if (casingout.sh != dummysh) {
+        // There is a subsegment connect at b of p->b.
+        casingout.shver = 0;
+#ifdef SELF_CHECK
+        assert(sorg(casingout) == pb); 
+#endif
+        senext2self(casingout);
+        senext(pbseg, casingin);
+        sbond(casingin, casingout);
+      }
+
+      // Bond all new subfaces to a->p and p->b.
+      for (i = 0; i < n; i++) {
+        spinsh = apsegshs[i];
+        findedge(&spinsh, pa, bp);
+        ssbond(spinsh, apseg);
+        spinsh = pbsegshs[i];
+        findedge(&spinsh, bp, pb);
+        ssbond(spinsh, pbseg);
+      }
+      // Bond all subfaces share at a->p together.
+      for (i = 0; i < n; i++) {
+        spinsh = apsegshs[i];
+        if (i < (n - 1)) {
+          casingout = apsegshs[i + 1];
+        } else {
+          casingout = apsegshs[0];
+        }
+        sbond1(spinsh, casingout);
+      }
+      // Bond all subfaces share at p->b together.
+      for (i = 0; i < n; i++) {
+        spinsh = pbsegshs[i];
+        if (i < (n - 1)) {
+          casingout = pbsegshs[i + 1];
+        } else {
+          casingout = pbsegshs[0];
+        }
+        sbond1(spinsh, casingout);
+      }
+      delete [] apsegshs;
+      delete [] pbsegshs;
+
+      // Check for newly encroached subsegments if the flag is set.
+      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);
+      }
+    } // if (splitseg != (face *) NULL) 
+
+    // Delete subfaces of old CBC_i(p)s.
+    for (k = 0; k < n; k++) {
+      for (i = 0; i < sublists[k]->len(); i++) {
+        oldsh = * (face *)(* (sublists[k]))[i];
+        shellfacedealloc(subfaces, oldsh.sh);
+      }
+      // Clear the list so that the subs will not get unmarked later in
+      //   routine releasebowatcavity() which only frees the memory.
+      sublists[k]->clear();
+      // Only do once if p is on a facet.
+      if (splitseg == (face *) NULL) break; 
+    }
+
+    // Check for newly encroached subfaces if the flag is set.
+    if (chkencsub) {
+      // Check if new subfaces of C_i(p) are encroached by other vertices.
+      for (k = 0; k < n; k++) {
+        subceillist = subceillists[k];
+        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; 
+      }
+      // Check if the adjacent subfaces are encroached by p.
+      tallencsubs(bp, n, ceillists);
     }
-    ssbond(oldva, ca);
-  } else {
-    sbond(oldva, cacasout);
+  } // if (subceillists != (list **) NULL)
+
+  // Delete tets of old BC_i(p)s.
+  for (k = 0; k < n; k++) {
+    for (i = 0; i < tetlists[k]->len(); i++) {
+      oldtet = * (triface *)(* (tetlists[k]))[i];
+      tetrahedrondealloc(oldtet.tet);
+    }
+    // Clear the list so that the tets will not get unmarked later in
+    //   routine releasebowatcavity() which only frees the memory.
+    tetlists[k]->clear();
   }
 
-  // Delete two split-out subfaces.
-  shellfacedealloc(subfaces, bcv.sh);
-  shellfacedealloc(subfaces, cav.sh);
+  // check for bad quality tets if the flags is set.
+  if (chkbadtet) {
+    for (k = 0; k < n; k++) {
+      ceillist = ceillists[k];
+      for (i = 0; i < ceillist->len(); i++) {
+        newtet = * (triface *)(* ceillist)[i];
+        checktet4badqual(&newtet, true);
+      }
+    }
+  }
+
+  if (flipque != (queue *) NULL) {
+    // Newly created internal faces of BC(p) (excluding faces on C(p)s) are
+    //   in 'flipque'.  Some of these faces may be locally non-Delaunay due,
+    //   to the existence of non-constrained tets. check and fix them.
+    repairflipcount += flip(flipque, NULL);
+  }
 }
 
+//
+// End of mesh transformation routines
+//
+
+//
+// Begin Delaunay tetrahedralization routines
+//
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// splittetedge()    Insert a point on an edge of the mesh.                  //
-//                                                                           //
-// The edge is given by 'splittet'. Assume its four corners are a, b, n1 and //
-// n2, where ab is the edge will be split. Around ab may exist any number of //
-// tetrahedra. For convenience, they're ordered in a sequence following the  //
-// right-hand rule with your thumb points from a to b. Let the vertex set of //
-// these tetrahedra be {a, b, n1, n2, ..., n(i)}. NOTE the tetrahedra around //
-// ab may not connect to each other (can only happen when ab is a subsegment,//
-// hence some faces abn(i) are subfaces).  If ab is a subsegment, abn1 must  //
-// be a subface.                                                             //
+// formstarpolyhedron()    Get the star ployhedron of a point 'pt'.          //
 //                                                                           //
-// To split edge ab by a point v is to split all tetrahedra containing ab by //
-// v.  More specifically, for each such tetrahedron, an1n2b, it is shrunk to //
-// an1n2v, and a new tetrahedra bn2n1v is created. If ab is a subsegment, or //
-// some faces of the splitting tetrahedra are subfaces, they must be split   //
-// either by calling routine 'splitsubedge()'.                               //
+// The polyhedron P is formed by faces of tets having 'pt' as a vertex.  If  //
+// 'complete' is TRUE, P is the complete star of 'pt'. Otherwise, P is boun- //
+// ded by subfaces, i.e. P is only part of the star of 'pt'.                 //
 //                                                                           //
-// On completion, 'splittet' returns avn1n2.  If 'flipqueue' is not NULL, it //
-// returns all faces which may become non-Delaunay after this operation.     //
+// 'tetlist' T returns the tets, it has one of such tets on input. Moreover, //
+// if t is in T, then oppo(t) = p.  Topologically, T is the star of p;  and  //
+// the faces of T is the link of p. 'verlist' V returns the vertices of T.   //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-splittetedge(point newpoint, triface* splittet, queue* flipqueue)
+void tetgenmesh::formstarpolyhedron(point pt, list* tetlist, list* verlist,
+  bool complete)
 {
-  triface *bots, *newtops;
-  triface oldtop, topcasing;
-  triface spintet, tmpbond0, tmpbond1;
-  face abseg, splitsh, topsh, spinsh;
-  point pa, pb, n1, n2;
-  REAL attrib, volume;
-  int wrapcount, hitbdry;
-  int i, j;
-
-  if (checksubfaces) {
-    // Is there a subsegment need to be split together?
-    tsspivot(splittet, &abseg);
-    if (abseg.sh != dummysh) {
-      abseg.shver = 0;
-      // Orient the edge direction of 'splittet' be abseg.
-      if (org(*splittet) != sorg(abseg)) {
-        esymself(*splittet);
-      }
-    }
-  } 
-  spintet = *splittet;
-  pa = org(spintet);
-  pb = dest(spintet);
+  triface starttet, neightet;
+  face checksh;
+  point ver[3];
+  int idx, i, j;
 
-  if (b->verbose > 1) {
-    printf("  Inserting point %d on edge (%d, %d).\n", 
-           pointmark(newpoint), pointmark(pa), pointmark(pb));
+  // Get a tet t containing p.
+  starttet = * (triface *)(* tetlist)[0];
+  // Let oppo(t) = p.
+  for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
+    if (oppo(starttet) == pt) break;
+  }
+  assert(starttet.loc < 4);
+  // 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]));
   }
 
-  // Collect the tetrahedra containing the splitting edge (ab).
-  n1 = apex(spintet);
-  hitbdry = 0;
-  wrapcount = 1;
-  if (checksubfaces && abseg.sh != dummysh) {
-    // It may happen that some tetrahedra containing ab (a subsegment) are
-    //   completely disconnected with others. If it happens, use the face
-    //   link of ab to cross the boundary. 
-    while (true) {
-      if (!fnextself(spintet)) {
-        // Meet a boundary, walk through it.
-        hitbdry ++;
-        tspivot(spintet, spinsh);
-        assert(spinsh.sh != dummysh);
-        findedge(&spinsh, pa, pb);
-        sfnextself(spinsh);
-        stpivot(spinsh, spintet);
-        assert(spintet.tet != dummytet);
-        findedge(&spintet, pa, pb);
-        // Remember this position (hull face) in 'splittet'.
-        *splittet = spintet;
-        // Split two hull faces increase the hull size;
-        hullsize += 2;
-      }
-      if (apex(spintet) == n1) break;
-      wrapcount ++;
-    }
-    if (hitbdry > 0) {
-      wrapcount -= hitbdry;
-    }
-  } else {
-    // All the tetrahedra containing ab are connected together. If there
-    //   are subfaces, 'splitsh' keeps one of them.
-    splitsh.sh = dummysh;
-    while (hitbdry < 2) {
-      if (checksubfaces && splitsh.sh == dummysh) {
-        tspivot(spintet, splitsh);
-      }
-      if (fnextself(spintet)) {
-        if (apex(spintet) == n1) break;
-        wrapcount++;
-      } else {
-        hitbdry ++;
-        if (hitbdry < 2) {
-          esym(*splittet, spintet);
+  // Find other tets by a broadth-first search.
+  for (i = 0; i < tetlist->len(); i++) {
+    starttet = * (triface *)(* tetlist)[i];
+    starttet.ver = 0;
+    for (j = 0; j < 3; j++) {
+      fnext(starttet, neightet);
+      tspivot(neightet, checksh);
+      // Should we cross a subface.
+      if ((checksh.sh == dummysh) || complete) {
+        // Get the neighbor n.
+        symself(neightet);
+        if ((neightet.tet != dummytet) && !infected(neightet)) {
+          // Let oppo(n) = p.
+          for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) {
+            if (oppo(neightet) == pt) break;
+          }
+          assert(neightet.loc < 4);
+          // 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 (hitbdry > 0) {
-      // ab is on the hull.
-      wrapcount -= 1;
-      // 'spintet' now is a hull face, inverse its edge direction.
-      esym(spintet, *splittet);
-      // Split two hull faces increases the number of hull faces.
-      hullsize += 2;
+      enextself(starttet);
     }
   }
-  
-  // Make arrays of updating (bot, oldtop) and new (newtop) tetrahedra.
-  bots = new triface[wrapcount];
-  newtops = new triface[wrapcount];
-  // Spin around ab, gather tetrahedra and set up new tetrahedra. 
-  spintet = *splittet;
-  for (i = 0; i < wrapcount; i++) {
-    // Get 'bots[i] = an1n2b'.
-    enext2fnext(spintet, bots[i]);
-    esymself(bots[i]);
-    // Create 'newtops[i]'.
-    maketetrahedron(&(newtops[i]));
-    // Go to the next.
-    fnextself(spintet);
-    if (checksubfaces && abseg.sh != dummysh) {
-      if (!issymexist(&spintet)) {
-        // We meet a hull face, walk through it.
-        tspivot(spintet, spinsh);
-        assert(spinsh.sh != dummysh);
-        findedge(&spinsh, pa, pb);
-        sfnextself(spinsh);
-        stpivot(spinsh, spintet);
-        assert(spintet.tet != dummytet);
-        findedge(&spintet, pa, pb);
-      }
-    }
+
+  // Uninfect tets.
+  for (i = 0; i < tetlist->len(); i++) {
+    starttet = * (triface *)(* tetlist)[i];
+    uninfect(starttet);
   }
-  
-  // Set the vertices of updated and new tetrahedra.
-  for (i = 0; i < wrapcount; i++) {
-    // Update 'bots[i] = an1n2v'.
-    setoppo(bots[i], newpoint);
-    // Set 'newtops[i] = bn2n1v'.
-    n1 = dest(bots[i]);
-    n2 = apex(bots[i]);
-    // Set 'newtops[i]'.
-    setorg(newtops[i], pb);
-    setdest(newtops[i], n2);
-    setapex(newtops[i], n1);
-    setoppo(newtops[i], newpoint);
-    // Set the element attributes of a new tetrahedron.
-    for (j = 0; j < in->numberoftetrahedronattributes; j++) {
-      attrib = elemattribute(bots[i].tet, j);
-      setelemattribute(newtops[i].tet, j, attrib);
-    }
-    if (b->varvolume) {
-      // Set the area constraint of a new tetrahedron.
-      volume = volumebound(bots[i].tet);
-      setvolumebound(newtops[i].tet, volume);
-    }
-#ifdef SELF_CHECK
-    // Make sure no inversed tetrahedron has been created.
-    assert(orient3d(pa, n1, n2, newpoint) <= 0.0);
-    assert(orient3d(pb, n2, n1, newpoint) <= 0.0);
-#endif
+  // Uninfect vertices.
+  for (i = 0; i < verlist->len(); i++) {
+    ver[0] = * (point *)(* verlist)[i];
+    idx = pointmark(ver[0]);
+    setpointmark(ver[0], -(idx + 1));
   }
+}
 
-  // Bond newtops to topcasings and bots.
-  for (i = 0; i < wrapcount; i++) {
-    // Get 'oldtop = n1n2va' from 'bots[i]'.
-    enextfnext(bots[i], oldtop);
-    sym(oldtop, topcasing);
-    bond(newtops[i], topcasing);
-    if (checksubfaces) {
-      tspivot(oldtop, topsh);
-      if (topsh.sh != dummysh) {
-        tsdissolve(oldtop);
-        tsbond(newtops[i], topsh);
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// unifypoint()    Unify two distinct points if they're very close.          //
+//                                                                           //
+// This function is used for dealing with inputs from CAD tools.  Two points //
+// p and q are unified if: dist(p, q) / longest < eps.  Where dist() is the  //
+// Euclidean distance between p and q, longest is the maximum edge size of   //
+// the input point set, eps is the tolerrence specified by user, default is  //
+// 1e-6, it can be adjusted by '-T' switch.                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::unifypoint(point testpt, triface *starttet, enum locateresult
+  loc, REAL eps)
+{
+  triface symtet, spintet;
+  point checkpt, tapex;
+  REAL tol;
+  bool merged;
+  int hitbdry;
+  int i;
+
+  merged = false;
+  tol = longest * eps;
+  if ((loc == OUTSIDE) || (loc == INTETRAHEDRON) || (loc == ONFACE)) {
+    // Check p is close to the four corners of the tet.
+    for (i = 0; i < 4; i++) {
+      checkpt = (point) starttet->tet[4 + i];
+      if (distance(testpt, checkpt) < tol) {
+        merged = true; // Found a merge point p'.
+        break;
       }
     }
-    enextfnext(newtops[i], tmpbond0);
-    bond(oldtop, tmpbond0);
-  }
-  // Bond between newtops.
-  fnext(newtops[0], tmpbond0);
-  enext2fnext(bots[0], spintet); 
-  for (i = 1; i < wrapcount; i ++) {
-    if (issymexist(&spintet)) {
-      enext2fnext(newtops[i], tmpbond1);
-      bond(tmpbond0, tmpbond1);
+    if (!merged && (loc == ONFACE)) {
+      // Check the opposite point of the neighbor tet if it exists.
+      sym(*starttet, symtet);
+      if (symtet.tet != dummytet) {
+        checkpt = oppo(symtet);
+        if (distance(testpt, checkpt) < tol) {
+          merged = true; // Found a merge point p'.
+        }
+      }
     }
-    fnext(newtops[i], tmpbond0);
-    enext2fnext(bots[i], spintet); 
-  }
-  // Bond the last to the first if no boundary.
-  if (issymexist(&spintet)) {
-    enext2fnext(newtops[0], tmpbond1);
-    bond(tmpbond0, tmpbond1);
-  }
-
-  // Is there exist subfaces and subsegment need to be split?
-  if (checksubfaces) {
-    if (abseg.sh != dummysh) {
-      // A subsegment needs be split.
-      spivot(abseg, splitsh);
-      assert(splitsh.sh != dummysh);
+  } else if (loc == ONEDGE) {
+    // Check two endpoints of the edge.
+    checkpt = org(*starttet);
+    if (distance(testpt, checkpt) < tol) {
+      merged = true; // Found a merge point p'.
     }
-    if (splitsh.sh != dummysh) {
-      // Split subfaces (and subsegment).
-      findedge(&splitsh, pa, pb);
-      splitsubedge(newpoint, &splitsh, (queue *) NULL);
+    if (!merged) {
+      checkpt = dest(*starttet);
+      if (distance(testpt, checkpt) < tol) {
+        merged = true; // Found a merge point p'.
+      }
+    }
+    if (!merged) {
+      // Check apexes of the faces having the edge.
+      spintet = *starttet;
+      tapex = apex(*starttet);
+      hitbdry = 0;
+      do {
+        checkpt = apex(spintet);
+        if (distance(testpt, checkpt) < tol) {
+          merged = true; // Found a merge point p'.
+          break;
+        }
+        if (!fnextself(spintet)) {
+          hitbdry++;
+          if (hitbdry < 2) {
+            esym(*starttet, spintet);
+            if (!fnextself(spintet)) {
+              hitbdry++;
+            }
+          }
+        }
+      } while ((apex(spintet) != tapex) && (hitbdry < 2));
     }
   }
-
-  if (b->verbose > 3) {
-    for (i = 0; i < wrapcount; i++) {
-      printf("    Updating bots[%i] ", i);
-      printtet(&(bots[i]));
-      printf("    Creating newtops[%i] ", i);
-      printtet(&(newtops[i]));
+  if (merged) {
+    if (b->object != tetgenbehavior::STL) {
+      if (!b->quiet) {
+        printf("Warning:  Point %d is unified to point %d.\n",
+               pointmark(testpt), pointmark(checkpt));
+      }
+      // Count the number of duplicated points.
+      dupverts++;
     }
+    // Remember it is a duplicated point.
+    setpointtype(testpt, DUPLICATEDVERTEX);
+    // Set a pointer to the point it duplicates.
+    setpoint2ppt(testpt, checkpt);
   }
+  return merged;
+}
 
-  if (flipqueue != (queue *) NULL) {
-    for (i = 0; i < wrapcount; i++) {
-      enqueueflipface(bots[i], flipqueue);
-      enqueueflipface(newtops[i], flipqueue);
-    }
-  }
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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.                                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
-  // Set the return handle be avn1n2.  It is got by transforming from
-  //   'bots[0]' (which is an1n2v).
-  fnext(bots[0], spintet); // spintet is an1vn2.
-  esymself(spintet); // spintet is n1avn2.
-  enextself(spintet); // spintet is avn1n2.
-  *splittet = spintet;
+void tetgenmesh::closeopenface(triface* openface, queue* flipque)
+{
+  triface newtet, oldhull;
+  triface newopenface, closeface;
+  point inspoint, pa, pb, pc;
+  REAL attrib, volume;
+  int i;
 
-  delete [] bots;
-  delete [] newtops;
+  // 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);
+  }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// unsplittetedge()    Reverse the operation of splitting an edge, so as to  //
-//                     remove the newly inserted point.                      //
+// inserthullsite()    Insert a point which lies outside the convex hull.    //
 //                                                                           //
-// Assume the original edge is ab, the tetrahedron containing ab is abn1n2.  //
-// After ab was split by a point v, every tetrahedron containing ab (e.g.,   //
-// abn1n2) has been split into two (e.g., an1n2v and bn2n1v). 'splittet'     //
-// represents avn1n2 (i.e., its destination is v).                           //
+// 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 remove point v is to expand each split tetrahedron containing ab (e.g.,//
-// (avn1n2 to abn1n2), then delete the redundant one(e.g., vbn1n2). If there //
-// exists any subface around ab, routine unsplitsubedge() will be called to  //
-// reverse the operation of splitting a edge (or a subsegment) of subfaces.  //
-// On completion, point v is not deleted in this routine.                    //
+// 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::unsplittetedge(triface* splittet)
+void tetgenmesh::inserthullsite(point inspoint, triface* horiz, queue* flipque)
 {
-  triface *bots, *newtops;
-  triface oldtop, topcasing;
-  triface spintet;
-  face avseg, splitsh, topsh, spinsh;
-  point pa, pv, n1;
-  int wrapcount, hitbdry;
+  triface firstnewtet;
+  triface openface, closeface;
+  REAL attrib, volume;
   int i;
 
-  spintet = *splittet;
-  pa = org(spintet);
-  pv = dest(spintet);
-  if (checksubfaces) {
-    // Is there a subsegment need to be unsplit together?
-    tsspivot(splittet, &avseg);
-    if (avseg.sh != dummysh) {
-      // The subsegment's direction should conform to 'splittet'.
-      if (sorg(avseg) != pa) {
-        sesymself(avseg);
-      }
-    }
-  } 
+  // 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--;
 
-  n1 = apex(spintet);
-  hitbdry = 0;
-  wrapcount = 1;
-  if (checksubfaces && avseg.sh != dummysh) {
-    // It may happen that some tetrahedra containing ab (a subsegment) are
-    //   completely disconnected with others. If it happens, use the face
-    //   link of ab to cross the boundary. 
-    while (true) {    
-      if (!fnextself(spintet)) {
-        // Meet a boundary, walk through it.
-        hitbdry ++;
-        tspivot(spintet, spinsh);
-        assert(spinsh.sh != dummysh);
-        findedge(&spinsh, pa, pv);
-        sfnextself(spinsh);
-        stpivot(spinsh, spintet);
-        assert(spintet.tet != dummytet);
-        findedge(&spintet, pa, pv);
-        // Remember this position (hull face) in 'splittet'.
-        *splittet = spintet;
-        // Split two hull faces increase the hull size;
-        hullsize += 2;
-      }
-      if (apex(spintet) == n1) break;
-      wrapcount ++;
-    }
-    if (hitbdry > 0) {
-      wrapcount -= hitbdry;
+  // 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  //
+//                      3D points by the incremental flip algorithm.         //
+//                                                                           //
+// The incremental flip algorithm (by Edelsbrunner and Shah) can be describ- //
+// ed as follows:                                                            //
+//                                                                           //
+//   S be a set of points in 3D, Let 4 <= i <= n and assume that the         //
+//   Delaunay tetrahedralization of the first i-1 points in S is already     //
+//   constructed; call it D(i-1). Add the i-th point p_i (belong to S) to    //
+//   D(i-1), and restore Delaunayhood by flipping; this result in D(i).      //
+//   Repeat this procedure until i = n.                                      //
+//                                                                           //
+// This strategy always leads to the Delaunay triangulation of a point set.  //
+// The return value is the number of convex hull faces of D.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::incrflipdelaunay(triface* oldtet, point* insertarray, 
+  long arraysize, bool jump, bool merge, REAL eps, queue* flipque)
+{
+  triface newtet, searchtet;
+  point swappt, lastpt;
+  enum locateresult loc;
+  REAL det, n[3];
+  REAL attrib, volume;
+  int i, j;
+
+  if (b->verbose > 0) {
+    printf("  Creating initial tetrahedralization.\n");
+  }
+
+  // The initial tetrahedralization T only has one tet formed by 4 affinely
+  //   linear independent vertices of the point set V = 'insertarray'. The
+  //   first point a = insertarray[0].
+ 
+  // Get the second point b, that is not identical or very close to a.
+  for (i = 1; i < arraysize; i++) {
+    det = distance(insertarray[0], insertarray[i]);
+    if (det > (longest * eps)) break;
+  }
+  if (i == arraysize) {
+    printf("\nAll points seem to be identical.\n");
+    return;
   } else {
-    // All the tetrahedra containing ab are connected together. If there
-    //   are subfaces, 'splitsh' keeps one of them.
-    splitsh.sh = dummysh;
-    while (hitbdry < 2) {
-      if (checksubfaces && splitsh.sh == dummysh) {
-        tspivot(spintet, splitsh);
-      }
-      if (fnextself(spintet)) {
-        if (apex(spintet) == n1) break;
-        wrapcount++;
-      } else {
-        hitbdry ++;
-        if (hitbdry < 2) {
-          esym(*splittet, spintet);
-        }
-      }
-    }
-    if (hitbdry > 0) {
-      // ab is on the hull.
-      wrapcount -= 1;
-      // 'spintet' now is a hull face, inverse its edge direction.
-      esym(spintet, *splittet);
-      // Split two hull faces increases the number of hull faces.
-      hullsize += 2;
+    // Swap to move b from index i to index 1.
+    swappt = insertarray[i];
+    insertarray[i] = insertarray[1];
+    insertarray[1] = swappt;  
+  }
+  // Get the third point c, that is not collinear with a and b.
+  for (i++; i < arraysize; i++) {
+    if (!iscollinear(insertarray[0], insertarray[1], insertarray[i], eps)) 
+      break;
+  }
+  if (i == arraysize) {
+    printf("\nAll points seem to be collinear.\n");
+    return;
+  } else {
+    // Swap to move c from index i to index 2.
+    swappt = insertarray[i];
+    insertarray[i] = insertarray[2];
+    insertarray[2] = swappt;
+  }
+  // Get the fourth point d, that is not coplanar with a, b, and c.
+  for (i++; i < arraysize; i++) {
+    det = orient3d(insertarray[0], insertarray[1], insertarray[2],
+                   insertarray[i]);
+    if (det == 0.0) continue;
+    if (!iscoplanar(insertarray[0], insertarray[1], insertarray[2],
+                    insertarray[i], det, eps)) break;
+  }
+  if (i == arraysize) {
+    // It's a 2D problem.
+    in->mesh_dim = 2;
+    // All points are coplanar.
+    if (b->plc) {
+      // Create an abovepoint. Maybe a surface triangulation can be formed.
+      facenormal(insertarray[0], insertarray[1], insertarray[2], n, &det);
+      if (det != 0.0) for (j = 0; j < 3; j++) n[j] /= det;
+      // Take the average edge length of the bounding box.
+      det = (0.5*(xmax - xmin) + 0.5*(ymax - ymin) + 0.5*(zmax - zmin)) / 3.0;
+      // Temporarily create a point. It will be removed by jettison();
+      makepoint(&lastpt);
+      for (j = 0; j < 3; j++) lastpt[j] = insertarray[0][j] + det * n[j];
+      abovepoint = lastpt;
+      det = orient3d(insertarray[0], insertarray[1], insertarray[2], lastpt);
+      // The index of the next inserting point is 3.
+      i = 3;
+    } else {
+      printf("\nAll points seem to be coplanar.\n");
+      return;
     }
+  } else {
+    // Swap to move d from index i to index 3.
+    swappt = insertarray[i];
+    insertarray[i] = insertarray[3];
+    insertarray[3] = swappt;
+    lastpt = insertarray[3];
+    // The index of the next inserting point is 4.
+    i = 4;
   }
   
-  // Make arrays of updating (bot, oldtop) and new (newtop) tetrahedra.
-  bots = new triface[wrapcount];
-  newtops = new triface[wrapcount];
-  // Spin around av, gather tetrahedra and set up new tetrahedra. 
-  spintet = *splittet;
-  for (i = 0; i < wrapcount; i++) {
-    // Get 'bots[i] = an1n2v'.
-    enext2fnext(spintet, bots[i]);
-    esymself(bots[i]);
-    // Get 'oldtop = n1n2va'.
-    enextfnext(bots[i], oldtop);
-    // Get 'newtops[i] = 'bn1n2v'
-    fnext(oldtop, newtops[i]); // newtop = n1n2bv
-    esymself(newtops[i]); // newtop = n2n1bv
-    enext2self(newtops[i]); // newtop = bn2n1v
-    // Go to the next.
-    fnextself(spintet);
-    if (checksubfaces && avseg.sh != dummysh) {
-      if (!issymexist(&spintet)) {
-        // We meet a hull face, walk through it.
-        tspivot(spintet, spinsh);
-        assert(spinsh.sh != dummysh);
-        findedge(&spinsh, pa, pv);
-        sfnextself(spinsh);
-        stpivot(spinsh, spintet);
-        assert(spintet.tet != dummytet);
-        findedge(&spintet, pa, pv);
-      }
+  // Create the initial tet.
+  maketetrahedron(&newtet);
+  if (det > 0.0) {
+    // For keeping the positive orientation.
+    swappt = insertarray[0];
+    insertarray[0] = insertarray[1];
+    insertarray[1] = swappt;
+  }
+  setorg(newtet, insertarray[0]);
+  setdest(newtet, insertarray[1]);
+  setapex(newtet, insertarray[2]);
+  setoppo(newtet, lastpt);
+  if (oldtet != (triface *) NULL) {
+    for (j = 0; j < in->numberoftetrahedronattributes; j++) {
+      attrib = elemattribute(oldtet->tet, j);
+      setelemattribute(newtet.tet, j, attrib);
+    }
+    if (b->varvolume) {
+      volume = volumebound(oldtet->tet);
+      setvolumebound(newtet.tet, volume);
     }
   }
+  // Set vertex type be VOLVERTEX if it has no type yet.
+  if (pointtype(insertarray[0]) == UNUSEDVERTEX) {
+    setpointtype(insertarray[0], VOLVERTEX);
+  }
+  if (pointtype(insertarray[1]) == UNUSEDVERTEX) {
+    setpointtype(insertarray[1], VOLVERTEX);
+  }
+  if (pointtype(insertarray[2]) == UNUSEDVERTEX) {
+    setpointtype(insertarray[2], VOLVERTEX);
+  }
+  if (pointtype(lastpt) == UNUSEDVERTEX) {
+    setpointtype(lastpt, VOLVERTEX);
+  }
+  // Bond to 'dummytet' for point location.
+  dummytet[0] = encode(newtet);
+  if (b->verbose > 3) {
+    printf("    Creating tetra ");
+    printtet(&newtet);
+  }
+  // At init, all faces of this tet are hull faces.
+  hullsize = 4;
 
-  if (b->verbose > 1) {
-    printf("  Removing point %d from edge (%d, %d).\n", 
-           pointmark(oppo(bots[0])), pointmark(org(bots[0])),
-           pointmark(org(newtops[0])));
+  if (b->verbose > 0) {
+    printf("  Incrementally inserting points.\n");
   }
 
-  for (i = 0; i < wrapcount; i++) {
-    // Expand an1n2v to an1n2b.
-    setoppo(bots[i], org(newtops[i]));
-    // Get 'oldtop = n1n2va' from 'bot[i]'.
-    enextfnext(bots[i], oldtop);
-    // Get 'topcasing' from 'newtop[i]'
-    sym(newtops[i], topcasing);
-    // Bond them.
-    bond(oldtop, topcasing);
-    if (checksubfaces) {
-      tspivot(newtops[i], topsh);
-      if (topsh.sh != dummysh) {
-        tsbond(oldtop, topsh);
+  flip23s = flip32s = flip22s = flip44s = 0;
+  searchtet.tet = (tetrahedron *) NULL;
+
+  // Insert the rest of points, one by one.
+  for (; i < arraysize; i++) {
+    // Locate p_i in T.
+    if (jump) {
+      loc = locate(insertarray[i], &searchtet);
+    } else {
+      loc = preciselocate(insertarray[i], &searchtet, tetrahedrons->items);
+    }
+    // Keep current search state for next searching.
+    recenttet = searchtet;
+    if (loc == ONVERTEX) {
+      if (b->object != tetgenbehavior::STL) {
+        if (!b->quiet) {
+          printf("Warning:  Point %d is identical with point %d.\n",
+                 pointmark(insertarray[i]), pointmark(org(searchtet)));
+        }
+      }
+      // Count the number of duplicated points.
+      dupverts++;
+      // Remember it is a duplicated point.
+      setpointtype(insertarray[i], DUPLICATEDVERTEX);
+      if (b->plc || b->refine) {
+        // Set a pointer to the point it duplicates.
+        setpoint2ppt(insertarray[i], org(searchtet));
       }
+      continue; // p_i is not inserted.
     }
-    // Delete the tetrahedron above an1n2v.
-    tetrahedrondealloc(newtops[i].tet);
-  }
-
-  // If there exists any subface, unsplit them.
-  if (checksubfaces) {
-    if (avseg.sh != dummysh) {
-      spivot(avseg, splitsh);
-      assert(splitsh.sh != dummysh);
+    if (merge) {
+      // Unify p_i if it is too close to a point of T.
+      if (unifypoint(insertarray[i], &searchtet, loc, eps)) {
+        continue; // p_i is not inserted.
+      }
+    }
+    // Insert p_i in T.
+    if (loc != OUTSIDE) {
+      if (b->verbose > 1) {
+        printf("  Insert point %d in tetrahedralization.\n",
+               pointmark(insertarray[i]));
+      }
+      if (loc == INTETRAHEDRON) {
+        splittetrahedron(insertarray[i], &searchtet, flipque);
+      } else if (loc == ONFACE) {
+        splittetface(insertarray[i], &searchtet, flipque);
+      } else if (loc == ONEDGE) {
+        splittetedge(insertarray[i], &searchtet, flipque);
+      }
+    } else {
+      if (b->verbose > 1) {
+        printf("  Insert point %d on convex hull.\n",
+               pointmark(insertarray[i]));
+      }
+      inserthullsite(insertarray[i], &searchtet, flipque);
     }
-    if (splitsh.sh != dummysh) {
-      findedge(&splitsh, pa, pv);
-      unsplitsubedge(&splitsh);
+    if (pointtype(insertarray[i]) == UNUSEDVERTEX) {
+      // p_i becomes a (volume) vertex of T.
+      setpointtype(insertarray[i], VOLVERTEX);
+    }
+    if (!b->noflip) {
+      // Recover Delaunayness of T by flipping.
+      flip(flipque, NULL); 
+    } else {
+      // T remains regular.
+      flipque->clear();
     }
   }
 
-  delete [] bots;
-  delete [] newtops;
+  if (!b->noflip && b->verbose > 0) {
+    printf("  %ld Flips (T23 %ld, T32 %ld, T22 %ld, T44 %ld)\n",
+      flip23s+flip32s+flip22s+flip44s, flip23s, flip32s, flip22s, flip44s);
+  }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// splitsubedge()    Insert a point on an edge of the surface mesh.          //
-//                                                                           //
-// The splitting edge is given by 'splitsh'. Assume its three corners are a, //
-// b, c, where ab is the edge will be split. ab may be a subsegment.         //
-//                                                                           //
-// To split edge ab is to split all subfaces conatining ab. If ab is not a   //
-// subsegment, there are only two subfaces need be split, otherwise, there   //
-// may have any number of subfaces need be split. Each splitting subface abc //
-// is shrunk to avc, a new subface vbc is created.  It is important to keep  //
-// the orientations of edge rings of avc and vbc be the same as abc's. If ab //
-// is a subsegment, it is shrunk to av and a new subsegment vb is created.   //
-//                                                                           //
-// If there are tetrahedra adjoining to the splitting subfaces, they should  //
-// be split before calling this routine, so the connection between the new   //
-// tetrahedra and the new subfaces can be correctly set.                     //
+// delaunizevertices()    Form a Delaunay tetrahedralization.                //
 //                                                                           //
-// On completion, 'splitsh' returns avc.  If 'flipqueue' is not NULL, it     //
-// returns all edges which may be non-Delaunay.                              //
+// Given a point set V (saved in 'points').  The Delaunay tetrahedralization //
+// D of V is created by incrementally inserting vertices. Returns the number //
+// of triangular faces bounding the convex hull of D.                        //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::splitsubedge(point newpoint, face* splitsh, queue* flipqueue)
+long tetgenmesh::delaunizevertices()
 {
-  triface abcd, bace, vbcd, bvce;
-  face startabc, spinabc, spinsh;
-  face oldbc, bccasin, bccasout;
-  face ab, bc;
-  face avc, vbc, vbc1;
-  face av, vb;
-  point pa, pb;
+  queue *flipque;
+  point *insertarray;
+  long arraysize;
+  int i, j;
 
-  startabc = *splitsh;
-  // Is there a subsegment?
-  sspivot(startabc, ab);
-  if (ab.sh != dummysh) {
-    ab.shver = 0; 
-    if (sorg(startabc) != sorg(ab)) {
-      sesymself(startabc);
+  if (!b->quiet) {
+    if (!b->noflip) {
+      printf("Constructing Delaunay tetrahedralization.\n");
+    } else {
+      printf("Constructing regular tetrahedralization.\n");
     }
   }
-  pa = sorg(startabc);
-  pb = sdest(startabc);
-  
-  if (b->verbose > 1) {
-    printf("  Inserting point %d on subedge (%d, %d) %s.\n",
-           pointmark(newpoint), pointmark(pa), pointmark(pb),
-           (ab.sh != dummysh ? "(seg)" : " "));
+
+  // Prepare the array of points for inserting.
+  arraysize = points->items;
+  insertarray = new point[arraysize];
+  // Randomize the point order.
+  // randomseed = b->srandseed;
+  points->traversalinit();
+  for (i = 0; i < arraysize; i++) {
+    j = (int) randomnation(i + 1); // 0 <= j <= i;
+    insertarray[i] = insertarray[j];
+    insertarray[j] = pointtraverse();
   }
-  
-  // Spin arround ab, split every subface containing ab.
-  spinabc = startabc;
-  do {
-    // Adjust spinabc be edge ab.
-    if (sorg(spinabc) != pa) {
-      sesymself(spinabc);
-    }
-    // Save old configuration at edge bc, if bc has a subsegment, save the
-    //   face link of it and dissolve it from bc.
-    senext(spinabc, oldbc);
-    spivot(oldbc, bccasout);    
-    sspivot(oldbc, bc);
-    if (bc.sh != dummysh) {
-      if (spinabc.sh != bccasout.sh) {
-        // 'spinabc' is not self-bonded.
-        spinsh = bccasout;
-        do {
-          bccasin = spinsh;
-          spivotself(spinsh);
-        } while (spinsh.sh != oldbc.sh);
-      } else {
-        bccasout.sh = dummysh;
-      }
-      ssdissolve(oldbc);
-    }
-    // Create a new subface.
-    makeshellface(subfaces, &vbc);
-    // Split abc.
-    avc = spinabc;  // Update 'abc' to 'avc'.
-    setsdest(avc, newpoint);
-    // Make 'vbc' be in the same edge ring as 'avc'. 
-    vbc.shver = avc.shver; 
-    setsorg(vbc, newpoint); // Set 'vbc'.
-    setsdest(vbc, pb);
-    setsapex(vbc, sapex(avc));
-    if (b->quality && varconstraint) {
-      // Copy the area bound into the new subface.
-      setareabound(vbc, areabound(avc));
-    }
-    // Copy the shell marker and shell type into the new subface.
-    setshellmark(vbc, shellmark(avc));
-    setshelltype(vbc, shelltype(avc));
-    if (checkpbcs) {
-      // Copy the pbcgroup into the new subface.
-      setshellpbcgroup(vbc, shellpbcgroup(avc));
-    }
-    // Set the connection between updated and new subfaces.
-    senext2self(vbc);
-    sbond(vbc, oldbc);
-    // Set the connection between new subface and casings.
-    senext2self(vbc);
-    if (bc.sh != dummysh) {
-      if (bccasout.sh != dummysh) {
-        // Insert 'vbc' into face link.
-        sbond1(bccasin, vbc);
-        sbond1(vbc, bccasout);
-      } else {
-        // Bond 'vbc' to itself.
-        sbond(vbc, vbc);
-      }
-      ssbond(vbc, bc);
-    } else {
-      sbond(vbc, bccasout);
-    }
-    // Go to next subface at edge ab.
-    spivotself(spinabc);
-    if (spinabc.sh == dummysh) {
-      break; // 'ab' is a hull edge.
-    }
-  } while (spinabc.sh != startabc.sh);
+  flipque = new queue(sizeof(badface));
 
-  // Get the new subface vbc above the updated subface avc (= startabc).
-  senext(startabc, oldbc);
-  spivot(oldbc, vbc);
-  if (sorg(vbc) == newpoint) {
-    sesymself(vbc);
+  // Form the DT by incremental flip Delaunay algorithm.
+  incrflipdelaunay(NULL, insertarray, arraysize, true, b->plc, b->epsilon,
+                   flipque);
+
+  delete [] insertarray;
+  delete flipque;
+  return hullsize;
+}
+
+//
+// End Delaunay tetrahedralization routines
+//
+
+//
+// Begin of surface triangulation routines
+//
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// formstarpolygon()    Form the star polygon of a point in facet.           //
+//                                                                           //
+// The polygon P is formed by all coplanar subfaces having 'pt' as a vertex. //
+// P is bounded by segments, e.g, if no segments, P is the full star of pt.  //
+//                                                                           //
+// 'trilist' T returns the subfaces, it has one of such subfaces on input.   //
+// In addition, if f is in T, then sapex(f) = p. 'vertlist' V are verts of P.//
+// Topologically, T is the star of p; V and the edges of T are the link of p.//
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::formstarpolygon(point pt, list* trilist, list* vertlist)
+{
+  face steinsh, lnextsh, rnextsh;
+  face checkseg;
+  point pa, pb, pc, pd;
+  int i;
+
+  // Get a subface f containing p.
+  steinsh = * (face *)(* trilist)[0];
+  steinsh.shver = 0; // CCW
+  // Let sapex(f) be p.
+  for (i = 0; i < 3; i++) {
+    if (sapex(steinsh) == pt) break;
+    senextself(steinsh);
   }
-  assert(sorg(vbc) == sdest(oldbc) && sdest(vbc) == sorg(oldbc));
-  senextself(vbc);
-  // Set the face link for the new created subfaces around edge vb.
-  spinabc = startabc;
+  assert(i < 3);
+  * (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);
+
+  // Rotate edge pa to the left (CW) until meet pb or a segment.
+  lnextsh = steinsh;
+  pc = pa;
   do {
-    // Go to the next subface at edge av.
-    spivotself(spinabc);
-    if (spinabc.sh == dummysh) {
-      break; // 'ab' is a hull edge.
-    }
-    if (sorg(spinabc) != pa) {
-      sesymself(spinabc);
-    }
-    // Get the new subface vbc1 above the updated subface avc (= spinabc).
-    senext(spinabc, oldbc);
-    spivot(oldbc, vbc1);
-    if (sorg(vbc1) == newpoint) {
-      sesymself(vbc1);
-    }
-    assert(sorg(vbc1) == sdest(oldbc) && sdest(vbc1) == sorg(oldbc));
-    senextself(vbc1);
-    // Set the connection: vbc->vbc1.
-    sbond1(vbc, vbc1);
-    // For the next connection.
-    vbc = vbc1;
-  } while (spinabc.sh != startabc.sh);
+    senext2self(lnextsh);
+    assert(sorg(lnextsh) == pt);
+    sspivot(lnextsh, checkseg);
+    if (checkseg.sh != dummysh) break; // Do not cross a segment.
+    // Get neighbor subface n (must exist).
+    spivotself(lnextsh);
+    if (lnextsh.sh == dummysh) break; // It's a hull edge.
+    // Go to the edge ca opposite to p.
+    if (sdest(lnextsh) != pt) sesymself(lnextsh);
+    assert(sdest(lnextsh) == pt);
+    senext2self(lnextsh);
+    // Add n (at edge ca) to T.
+    trilist->append(&lnextsh);
+    // Add edge ca to E.
+    pc = sorg(lnextsh);
+    if (pc == pb) break; // Rotate back.
+    // Add vert c to V.
+    vertlist->append(&pc);
+  } while (true);
 
-  // Split ab if it is a subsegment.
-  if (ab.sh != dummysh) {
-    // Update subsegment ab to av.
-    av = ab;
-    setsdest(av, newpoint);
-    // Create a new subsegment vb.
-    makeshellface(subsegs, &vb);
-    setsorg(vb, newpoint);
-    setsdest(vb, pb);
-    // vb gets the same mark and segment type as av.
-    setshellmark(vb, shellmark(av));
-    setshelltype(vb, shelltype(av));
-    if (b->quality && varconstraint) {
-      // Copy the area bound into the new subsegment.
-      setareabound(vb, areabound(av));
-    }
-    // Save the old connection at ab (re-use the handles oldbc, bccasout).
-    senext(av, oldbc);
-    spivot(oldbc, bccasout);
-    // Bond av and vb (bonded at their "fake" edges).
-    senext2(vb, bccasin);
-    sbond(bccasin, oldbc);
-    if (bccasout.sh != dummysh) {
-      // There is a subsegment connecting with ab at b. It will connect
-      //   to vb at b after splitting.
-      bccasout.shver = 0;
-      assert(sorg(bccasout) == pb); 
-      senext2self(bccasout);
-      senext(vb, bccasin);
-      sbond(bccasin, bccasout);
-    }
-    // Bond all new subfaces (vbc) to vb. 
-    spinabc = startabc;
+  if (pc != pb) {
+    // Rotate edge bp to the right (CCW) until meet a segment.
+    rnextsh = steinsh;
     do {
-      // Adjust spinabc be edge av.
-      if (sorg(spinabc) != pa) {
-        sesymself(spinabc);
-      }
-      // Get new subface vbc above the updated subface avc (= spinabc).
-      senext(spinabc, oldbc);
-      spivot(oldbc, vbc);
-      if (sorg(vbc) == newpoint) {
-        sesymself(vbc);
+      senextself(rnextsh);
+      assert(sdest(rnextsh) == pt);
+      sspivot(rnextsh, checkseg);
+      if (checkseg.sh != dummysh) break; // Do not cross a segment.
+      // Get neighbor subface n (must exist).
+      spivotself(rnextsh);
+      if (rnextsh.sh == dummysh) break; // It's a hull edge.
+      // Go to the edge bd opposite to p.
+      if (sorg(rnextsh) != pt) sesymself(rnextsh);
+      assert(sorg(rnextsh) == pt);
+      senextself(rnextsh);
+      // Add n (at edge bd) to T.
+      trilist->append(&rnextsh);
+      // Add edge bd to E.
+      pd = sdest(rnextsh);
+      if (pd == pa) break; // Rotate back.
+      // Add vert d to V.
+      vertlist->append(&pd);
+    } while (true);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// About the 'abovepoint'                                                    //
+//                                                                           //
+// The 'abovepoint' of a facet is a point which is exactly non-coplanar with //
+// the plane containing that facet.  With such an point, the 3D predicates:  //
+// orient3d(), and insphere() can be used to substitute the corresponding 2D //
+// siblings, e.g. orient2d(), and incircle().  Its location is not critical, //
+// but floating-point accuracy is improved if it is nicely placed over the   //
+// facet, not too close or too far away.                                     //
+//                                                                           //
+// We take the convention that the abovepoint of a facet always lies above   //
+// the facet. By this convention, given three points a, b, and c in a facet, //
+// we say c has the counterclockwise order with ab is corresponding to say   //
+// that c is below the plane abp, where p is the lift point.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// getfacetabovepoint()    Get a point above a plane pass through a facet.   //
+//                                                                           //
+// The calulcated point is saved in 'facetabovepointarray'. The 'abovepoint' //
+// is set on return.                                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::getfacetabovepoint(face* facetsh)
+{
+  list *verlist, *trilist, *tetlist;
+  tetrahedron tetptr;
+  triface adjtet;
+  face symsh;
+  point p1, p2, p3, pa;
+  enum locateresult loc;
+  REAL smallcos, cosa;
+  REAL largevol, volume;
+  REAL v1[3], v2[3], len;
+  int smallidx, largeidx;
+  int shmark;
+  int i, j;
+
+  abovecount++;
+  // Initialize working lists.
+  verlist = new list(sizeof(point *), NULL);
+  trilist = new list(sizeof(face), NULL);
+  tetlist = new list(sizeof(triface), NULL);
+
+  // Get three pivotal points p1, p2, and p3 in the facet as a base triangle
+  //   which is non-trivil and has good base angle (close to 90 degree).
+
+  // p1 is chosen as the one which has the smallest index in pa, pb, pc.
+  p1 = sorg(*facetsh);
+  pa = sdest(*facetsh);
+  if (pointmark(pa) < pointmark(p1)) p1 = pa;
+  pa = sapex(*facetsh);
+  if (pointmark(pa) < pointmark(p1)) p1 = pa;
+  // Form the star polygon of p1.
+  trilist->append(facetsh);
+  formstarpolygon(p1, trilist, verlist);
+
+  // Get the second pivotal point p2.
+  p2 = * (point *)(* verlist)[0];
+  // Get vector v1 = p1->p2.
+  for (i = 0; i < 3; i++) v1[i] = p2[i] - p1[i];
+  len = sqrt(dot(v1, v1));
+  assert(len > 0.0);  // p2 != p1.
+  for (i = 0; i < 3; i++) v1[i] /= len;
+
+  // Get the third pivotal point p3. p3 is chosen as the one in 'verlist'
+  //   which forms an angle with v1 closer to 90 degree than others do.
+  smallcos = 1.0; // The cosine value of 0 degree.
+  smallidx = 1;   // Default value.
+  for (i = 1; i < verlist->len(); i++) {
+    p3 = * (point *)(* verlist)[i];
+    for (j = 0; j < 3; j++) v2[j] = p3[j] - p1[j];
+    len = sqrt(dot(v2, v2));
+    if (len > 0.0) { // v2 is not too small.
+      cosa = fabs(dot(v1, v2)) / len;
+      if (cosa < smallcos) {
+        smallidx = i;
+        smallcos = cosa;
+      }
+    }
+  }
+  assert(smallcos < 1.0); // p1->p3 != p1->p2.
+  p3 = * (point *)(* verlist)[smallidx];
+  verlist->clear();
+
+  if (tetrahedrons->items > 0l) {
+    // Get a tet having p1 as a vertex.
+    stpivot(*facetsh, adjtet);
+    if (adjtet.tet == dummytet) {
+      sesym(*facetsh, symsh);
+      stpivot(symsh, adjtet);
+    }
+    if (adjtet.tet == dummytet) {
+      tetptr = point2tet(p1);
+      if (tetptr != (tetrahedron) NULL) {
+        decode(tetptr, adjtet);
+        if (isdead(&adjtet)) {
+          adjtet.tet = dummytet;
+        }
       }
-      senextself(vbc);
-      // Bond the new subface and the new subsegment.
-      ssbond(vbc, vb);
-      // Go to the next.
-      spivotself(spinabc);
-      assert(spinabc.sh != dummysh);
-    } while (spinabc.sh != startabc.sh);
+    }
+    if (adjtet.tet == dummytet) {
+      loc = locate(p1, &adjtet);
+      if (loc != ONVERTEX) adjtet.tet = dummytet;
+    }
+    if (adjtet.tet != dummytet) {
+      // Get the star polyhedron of p1.
+      tetlist->append(&adjtet);
+      formstarpolyhedron(p1, tetlist, verlist, false);
+    }
   }
 
-  // Bond the new subfaces to new tetrahedra if they exist.  New tetrahedra
-  //   should have been created before calling this routine.
-  spinabc = startabc;
-  do {
-    // Adjust spinabc be edge av.
-    if (sorg(spinabc) != pa) {
-      sesymself(spinabc);
+  // Get the abovepoint in 'verlist'. It is the one form the largest valid
+  //   volumw with the base triangle over other points in 'verlist.
+  largevol = 0.0;
+  largeidx = 0;
+  for (i = 0; i < verlist->len(); i++) {
+    pa = * (point *)(* verlist)[i];
+    volume = orient3d(p1, p2, p3, pa);
+    if (!iscoplanar(p1, p2, p3, pa, volume, b->epsilon * 1e+2)) {
+      if (fabs(volume) > largevol) {
+        largevol = fabs(volume);
+        largeidx = i;
+      }
     }
-    // Get new subface vbc above the updated subface avc (= spinabc).
-    senext(spinabc, oldbc);
-    spivot(oldbc, vbc);
-    if (sorg(vbc) == newpoint) {
-      sesymself(vbc);
+  }
+
+  // Do we have the abovepoint?
+  if (largevol > 0.0) {
+    abovepoint = * (point *)(* verlist)[largeidx];
+    if (b->verbose > 1) {
+      printf("    Chosen abovepoint %d for facet %d.\n", pointmark(abovepoint),
+             shellmark(*facetsh));
     }
-    senextself(vbc);
-    // Get the adjacent tetrahedra at 'spinabc'.
-    stpivot(spinabc, abcd);
-    if (abcd.tet != dummytet) {
-      findedge(&abcd, sorg(spinabc), sdest(spinabc));
-      enextfnext(abcd, vbcd);
-      fnextself(vbcd);
-      assert(vbcd.tet != dummytet);
-      tsbond(vbcd, vbc);
-      sym(vbcd, bvce);
-      sesymself(vbc);
-      tsbond(bvce, vbc);
-    } else {
-      // One side is empty, check the other side.
-      sesymself(spinabc);
-      stpivot(spinabc, bace);
-      if (bace.tet != dummytet) {
-        findedge(&bace, sorg(spinabc), sdest(spinabc));
-        enext2fnext(bace, bvce);
-        fnextself(bvce);
-        assert(bvce.tet != dummytet);
-        sesymself(vbc); 
-        tsbond(bvce, vbc);
-      }
+  } else {
+    // Calculate an abovepoint for this facet.
+    facenormal(p1, p2, p3, v1, &len);
+    if (len != 0.0) for (i = 0; i < 3; i++) v1[i] /= len;
+    // Take the average edge length of the bounding box.
+    len = (0.5*(xmax - xmin) + 0.5*(ymax - ymin) + 0.5*(zmax - zmin)) / 3.0;
+    // Temporarily create a point. It will be removed by jettison();
+    makepoint(&abovepoint);
+    setpointtype(abovepoint, UNUSEDVERTEX);
+    unuverts++;
+    for (i = 0; i < 3; i++) abovepoint[i] = p1[i] + len * v1[i];
+    if (b->verbose > 1) {
+      printf("    Calculated abovepoint %d for facet %d.\n",
+             pointmark(abovepoint), shellmark(*facetsh));
     }
-    // Go to the next.
-    spivotself(spinabc);
-    if (spinabc.sh == dummysh) {
-      break; // 'ab' is a hull edge.
+  }
+  // Save the abovepoint in 'facetabovepointarray'.
+  shmark = shellmark(*facetsh);
+  facetabovepointarray[shmark] = abovepoint;
+  
+  delete trilist;
+  delete tetlist;
+  delete verlist;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// collectcavsubs()    Collect non-locally Delaunay subfaces wrt a point.    //
+//                                                                           //
+// 'cavsublist' returns the list of subfaces. On input, it conatins at least //
+// one subface.                                                              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::collectcavsubs(point newpoint, list* cavsublist)
+{
+  face startsub, neighsub;
+  face checkseg;
+  point pa, pb, pc;
+  REAL sign, ori;
+  int i, j;
+
+  // First infect subfaces in 'cavsublist'.
+  for (i = 0; i < cavsublist->len(); i++) {
+    startsub = * (face *)(* cavsublist)[i];
+    sinfect(startsub);
+  }
+  // Find the other subfaces by a broadth-first searching.
+  for (i = 0; i < cavsublist->len(); i++) {
+    startsub = * (face *)(* cavsublist)[i];
+    for (j = 0; j < 3; j++) {
+      sspivot(startsub, checkseg);
+      // Is there a segment?
+      if (checkseg.sh == dummysh) {
+        // No segment. Get the neighbor.
+        spivot(startsub, neighsub);
+        if (!sinfected(neighsub)) {
+          pa = sorg(neighsub);
+          pb = sdest(neighsub);
+          pc = sapex(neighsub);
+          sign = insphere(pa, pb, pc, abovepoint, newpoint);
+          ori = orient3d(pa, pb, pc, abovepoint);
+          if (sign != 0.0) {
+            // Correct the sign.
+            sign = ori > 0.0 ? sign : -sign;
+          }
+          if (sign > 0.0) {
+            // neighsub is encroached by newpoint.
+            sinfect(neighsub);
+            cavsublist->append(&neighsub);
+          }
+        }
+      }
+      senextself(startsub);
     }
-  } while (spinabc.sh != startabc.sh);
+  }
+  // Having found all subfaces, uninfect them before return.
+  for (i = 0; i < cavsublist->len(); i++) {
+    startsub = * (face *)(* cavsublist)[i];
+    suninfect(startsub);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// collectvisiblesubs()    Collect convex hull edges which are visible from  //
+//                         the inserting point. Construct new subfaces from  //
+//                         these edges and the point.                        //
+//                                                                           //
+// Let T be the current Delaunay triangulation (of vertices of a facet F).   //
+// 'shmark', the index of F in 'in->facetlist' (starts from 1);  'inspoint'  //
+// lies outside of T; 'horiz' is a hull edge of T which is visible by it.    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::collectvisiblesubs(int shmark, point inspoint, face* horiz,
+  queue* flipqueue)
+{
+  face newsh, hullsh;
+  face rightsh, leftsh, spinedge;
+  point horg, hdest;
+  bool aboveflag;
+  REAL ori, sign;
+
+  // Get the sign of abovepoint (so we can assume it is above the plane).  
+  adjustedgering(*horiz, CCW);
+  horg = sorg(*horiz);
+  hdest = sdest(*horiz);
+  ori = orient3d(horg, hdest, sapex(*horiz), abovepoint);
+  sign = ori > 0.0 ? -1 : 1;
+
+  // Create a new subface above 'horiz'.
+  makeshellface(subfaces, &newsh);
+  setsorg(newsh, hdest);
+  setsdest(newsh, horg);
+  setsapex(newsh, inspoint);
+  setshellmark(newsh, shmark);
+  if (b->quality && varconstraint) {
+    setareabound(newsh, areabound(*horiz));
+  }
+  if (checkpbcs) {
+    setshellpbcgroup(newsh, shellpbcgroup(*horiz));
+  }
+  // Make the connection.
+  sbond(newsh, *horiz);
+  // 'horiz' becomes interior edge.
+  enqueueflipedge(*horiz, flipqueue);
   
-  if (b->verbose > 3) {
-    spinabc = startabc;
+  // Finish the hull edges at the right side of the newsh.
+  hullsh = *horiz;
+  while (1) {
+    senext(newsh, rightsh);
+    // Get the right hull edge of 'horiz' by spinning inside edges around
+    //   'horg' until reaching the 'dummysh'.
+    spinedge = hullsh;
     do {
-      // Adjust spinabc be edge av.
-      if (sorg(spinabc) != pa) {
-        sesymself(spinabc);
-      }
-      printf("    Updating abc:\n");
-      printsh(&spinabc);
-      // Get new subface vbc above the updated subface avc (= spinabc).
-      senext(spinabc, oldbc);
-      spivot(oldbc, vbc);
-      if (sorg(vbc) == newpoint) {
-        sesymself(vbc);
+      hullsh = spinedge;
+      senext2self(hullsh);
+      spivot(hullsh, spinedge);
+      if (spinedge.sh == dummysh) break;
+      if (sorg(spinedge) != horg) sesymself(spinedge);
+      assert(sorg(spinedge) == horg);
+    } while (true);
+    horg = sorg(hullsh);
+    // Test whether 'inspoint' is visible by 'hullsh'.
+    ori = orient3d(horg, sdest(hullsh), abovepoint, inspoint);
+    ori *= sign;
+    aboveflag = ori < 0.0;
+    if (aboveflag) {
+      // It's visible.
+      makeshellface(subfaces, &newsh);
+      setsorg(newsh, sdest(hullsh));
+      setsdest(newsh, horg);
+      setsapex(newsh, inspoint);
+      setshellmark(newsh, shmark);
+      if (b->quality && varconstraint) {
+        setareabound(newsh, areabound(hullsh));
       }
-      senextself(vbc);
-      printf("    Creating vbc:\n");
-      printsh(&vbc);
-      // Go to the next.
-      spivotself(spinabc);
-      if (spinabc.sh == dummysh) {
-        break; // 'ab' is a hull edge.
+      if (checkpbcs) {
+        setshellpbcgroup(newsh, shellpbcgroup(hullsh));
       }
-    } while (spinabc.sh != startabc.sh);
+      // Make the connection.
+      sbond(newsh, hullsh);
+      senext2(newsh, leftsh);
+      sbond(leftsh, rightsh);
+      // 'hullsh' becomes interior edge.
+      enqueueflipedge(hullsh, flipqueue); 
+    } else {
+      // 'rightsh' is a new hull edge.
+      dummysh[0] = sencode(rightsh);
+      break;
+    }
   }
 
-  if (flipqueue != (queue *) NULL) {
-    spinabc = startabc;
+  // Finish the hull edges at the left side of the newsh.
+  hullsh = *horiz;
+  spivot(*horiz, newsh);
+  while (1) {
+    senext2(newsh, leftsh);
+    // Get the left hull edge of 'horiz' by spinning edges around 'hdest'.
+    spinedge = hullsh;
     do {
-      // Adjust spinabc be edge av.
-      if (sorg(spinabc) != pa) {
-        sesymself(spinabc);
-      }
-      senext2(spinabc, oldbc); // Re-use oldbc.
-      enqueueflipedge(oldbc, flipqueue);
-      // Get new subface vbc above the updated subface avc (= spinabc).
-      senext(spinabc, oldbc);
-      spivot(oldbc, vbc);
-      if (sorg(vbc) == newpoint) {
-        sesymself(vbc);
+      hullsh = spinedge;
+      senextself(hullsh);
+      spivot(hullsh, spinedge);
+      if (spinedge.sh == dummysh) break;
+      if (sdest(spinedge) != hdest) sesymself(spinedge);
+      assert(sdest(spinedge) == hdest);
+    } while (true);
+    // Update 'hdest'.
+    hdest = sdest(hullsh);
+    // Test whether 'inspoint' is visible from 'hullsh'.
+    ori = orient3d(sorg(hullsh), hdest, abovepoint, inspoint);
+    ori *= sign;
+    aboveflag = ori < 0.0;
+    if (aboveflag) {
+      // It's a visible hull edge.
+      makeshellface(subfaces, &newsh);
+      setsorg(newsh, hdest);
+      setsdest(newsh, sorg(hullsh));
+      setsapex(newsh, inspoint);
+      setshellmark(newsh, shmark);
+      if (b->quality && varconstraint) {
+        setareabound(newsh, areabound(hullsh));
       }
-      senextself(vbc);
-      senext(vbc, oldbc); // Re-use oldbc.
-      enqueueflipedge(oldbc, flipqueue);
-      // Go to the next.
-      spivotself(spinabc);
-      if (spinabc.sh == dummysh) {
-        break; // 'ab' is a hull edge.
+      if (checkpbcs) {
+        setshellpbcgroup(newsh, shellpbcgroup(hullsh));
       }
-    } while (spinabc.sh != startabc.sh);
+      // Make the connection.
+      sbond(newsh, hullsh);
+      senext(newsh, rightsh);
+      sbond(rightsh, leftsh);
+      // 'horiz' becomes interior edge.
+      enqueueflipedge(hullsh, flipqueue); 
+    } else {
+      // 'leftsh' is a new hull edge.
+      dummysh[0] = sencode(leftsh);
+      break;
+    }
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// unsplitsubedge()    Reverse the operation of splitting an edge of subface,//
-//                     so as to remove a point from the edge.                //
-//                                                                           //
-// Assume the original edge is ab, the subface containing it is abc. It was  //
-// split by a point v into avc, and vbc.  'splitsh' represents avc, further- //
-// more, if av is a subsegment, av should be the zero version of the split   //
-// subsegment (i.e., av.shver = 0), so we are sure that the destination (v)  //
-// of both avc and av is the deleting point.                                 //
+// incrflipdelaunaysub()    Create a DT from a 3D coplanar point set using   //
+//                          the incremental flip algorithm.                  //
 //                                                                           //
-// To remove point v is to expand avc to abc, delete vbc, do the same for    //
-// other subfaces containing av and vb. If av and vb are subsegments, expand //
-// av to ab, delete vb.  On completion, point v is not deleted.              //
+// Let T be the current Delaunay triangulation (of vertices of a facet F).   //
+// 'shmark', the index of F in 'in->facetlist' (starts from 1).              //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::unsplitsubedge(face* splitsh)
+void tetgenmesh::incrflipdelaunaysub(int shmark, REAL eps, list* ptlist,
+  int holes, REAL* holelist, queue* flipque)
 {
-  face startavc, spinavc, spinbcv;
-  face oldvc, bccasin, bccasout, spinsh;
-  face av, vb, bc;
-  point pa, pv, pb;
-
-  startavc = *splitsh;
-  sspivot(startavc, av);
-  if (av.sh != dummysh) {
-    // Orient the direction of subsegment to conform the subface. 
-    if (sorg(av) != sorg(startavc)) {
-      sesymself(av);
+  face newsh, startsh;
+  point *insertarray;
+  point swappt;
+  pbcdata *pd;
+  enum locateresult loc;
+  REAL det, area;
+  bool aboveflag;
+  int arraysize;
+  int fmarker;
+  int idx, i, j, k;  
+
+  // Get the point array (saved in 'ptlist').
+  insertarray = (point *) ptlist->base;
+  arraysize = ptlist->len();
+  if (arraysize < 3) return;
+
+  // Do calculation of 'abovepoint' if number of points > 3.
+  aboveflag = (arraysize > 3);
+
+  // The initial triangulation T only has one triangle formed by 3 not
+  //   cillinear points of the set V = 'insertarray'. The first point:
+  //   a = insertarray[0].
+
+  for (i = 1; i < arraysize; i++) {
+    det = distance(insertarray[0], insertarray[i]);
+    if (det > (longest * eps)) break;
+  }
+  if (i < arraysize) {
+    // Swap to move b from index i to index 1.
+    swappt = insertarray[i];
+    insertarray[i] = insertarray[1];
+    insertarray[1] = swappt;  
+  }
+  // Get the third point c, that is not collinear with a and b.
+  for (i++; i < arraysize; i++) {
+    if (!iscollinear(insertarray[0], insertarray[1], insertarray[i], eps))
+      break;
+  }
+  if (i < arraysize) {
+    // Swap to move c from index i to index 2.
+    swappt = insertarray[i];
+    insertarray[i] = insertarray[2];
+    insertarray[2] = swappt;
+    i = 3; // The next inserting point.
+  } else {
+    // 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");
+      }
     }
-    assert(av.shver == 0);
-  }
-  senext(startavc, oldvc);
-  spivot(oldvc, vb);  // vb is subface vbc
-  if (sorg(vb) != sdest(oldvc)) {
-    sesymself(vb);
+    // Only use the first three points.
+    i = arraysize;
+    // Don't do calculation of abovepoint.
+    aboveflag = false;
   }
-  senextself(vb);
-  pa = sorg(startavc);
-  pv = sdest(startavc);
-  pb = sdest(vb);
 
-  if (b->verbose > 1) {
-    printf("  Removing point %d from subedge (%d, %d).\n",
-           pointmark(pv), pointmark(pa), pointmark(pb));
+  // Create the initial triangle.
+  makeshellface(subfaces, &newsh);
+  setsorg(newsh, insertarray[0]);
+  setsdest(newsh, insertarray[1]);
+  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);
   }
+  if (pointtype(insertarray[1]) == VOLVERTEX) {
+    setpointtype(insertarray[1], FACETVERTEX);
+  }
+  if (pointtype(insertarray[2]) == VOLVERTEX) {
+    setpointtype(insertarray[2], FACETVERTEX);
+  }
+  // Let 'dummysh' point to it (for point location).
+  dummysh[0] = sencode(newsh);
 
-  // Spin arround av, unsplit every subface containing av.
-  spinavc = startavc;
-  do {
-    // Adjust spinavc be edge av.
-    if (sorg(spinavc) != pa) {
-      sesymself(spinavc);
-    }
-    // Save old configuration at edge bc, if bc has a subsegment, save the
-    //   face link of it.
-    senext(spinavc, oldvc);
-    spivot(oldvc, spinbcv);
-    if (sorg(spinbcv) != sdest(oldvc)) {
-      sesymself(spinbcv);
-    }
-    senext2self(spinbcv);
-    spivot(spinbcv, bccasout);
-    sspivot(spinbcv, bc);
-    if (bc.sh != dummysh) {
-      if (spinbcv.sh != bccasout.sh) {
-        // 'spinbcv' is not self-bonded.
-        spinsh = bccasout;
-        do {
-          bccasin = spinsh;
-          spivotself(spinsh);
-        } while (spinsh.sh != spinbcv.sh);
-      } else {
-        bccasout.sh = dummysh;
+  // Are there area constraints?
+  if (b->quality && (in->facetconstraintlist != (REAL *) NULL)) {
+    idx = in->facetmarkerlist[shmark - 1]; // The actual facet marker.
+    for (k = 0; k < in->numberoffacetconstraints; k++) {
+      fmarker = (int) in->facetconstraintlist[k * 2];
+      if (fmarker == idx) {
+        area = in->facetconstraintlist[k * 2 + 1];
+        setareabound(newsh, area);
+        break;
       }
     }
-    // Expand avc to abc.
-    setsdest(spinavc, pb);
-    if (bc.sh != dummysh) {
-      if (bccasout.sh != dummysh) {
-        sbond1(bccasin, oldvc);
-        sbond1(oldvc, bccasout);
-      } else {
-        // Bond 'oldbc' to itself.
-        sbond(oldvc, oldvc);
+  }
+
+  // Are there pbc conditions?
+  if (checkpbcs) {
+    idx = in->facetmarkerlist[shmark - 1]; // The actual facet marker.
+    for (k = 0; k < in->numberofpbcgroups; k++) {
+      pd = &subpbcgrouptable[k];
+      for (j = 0; j < 2; j++) {
+        if (pd->fmark[j] == idx) {
+          setshellpbcgroup(newsh, k);
+          pd->ss[j] = newsh;
+        }
       }
-      ssbond(oldvc, bc);
-    } else {
-      sbond(oldvc, bccasout);
     }
-    // Delete bcv.
-    shellfacedealloc(subfaces, spinbcv.sh);
-    // Go to next subface at edge av.
-    spivotself(spinavc);
-    if (spinavc.sh == dummysh) {
-      break; // 'av' is a hull edge.
+  }
+
+  if (aboveflag) {
+    // Compute the 'abovepoint' for orient3d().
+    abovepoint = facetabovepointarray[shmark];
+    if (abovepoint == (point) NULL) {
+      getfacetabovepoint(&newsh);
     }
-  } while (spinavc.sh != startavc.sh);
+  }
 
-  // Is there a subsegment need to be unsplit?
-  if (av.sh != dummysh) {
-    senext(av, oldvc);  // Re-use oldvc.
-    spivot(oldvc, vb);
-    vb.shver = 0;
-    assert(sdest(av) == sorg(vb));
-    senext(vb, spinbcv); // Re-use spinbcv.
-    spivot(spinbcv, bccasout);
-    // Expand av to ab.
-    setsdest(av, pb);
-    sbond(oldvc, bccasout);
-    // Delete vb.
-    shellfacedealloc(subsegs, vb.sh);
+  if (holes > 0) {
+    // Project hole points onto the plane containing the facet.
+    REAL prj[3];
+    for (k = 0; k < holes; k++) {
+      projpt2face(&(holelist[k * 3]), insertarray[0], insertarray[1],
+                  insertarray[2], prj);
+      for (j = 0; j < 3; j++) holelist[k * 3 + j] = prj[j];
+    }
+  }
+
+  // Incrementally insert the rest of points into T.
+  for (; i < arraysize; i++) {
+    // Insert p_i.
+    startsh.sh = dummysh;
+    loc = locatesub(insertarray[i], &startsh, 0, 0.0);
+    if (loc == ONFACE) {
+      splitsubface(insertarray[i], &startsh, flipque);
+    } else if (loc == ONEDGE) {
+      splitsubedge(insertarray[i], &startsh, flipque);
+    } else if (loc == OUTSIDE) {
+      collectvisiblesubs(shmark, insertarray[i], &startsh, flipque);
+    } 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);
+    }
+    flipsub(flipque);
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// insertsite()    Insert a point into the mesh.                             //
+// finddirectionsub()    Find the first subface in a facet on the path from  //
+//                       one point to another.                               //
 //                                                                           //
-// The 'newpoint' is located.  If 'searchtet->tet' is not NULL, the search   //
-// for the containing tetrahedron begins from 'searchtet', otherwise, a full //
-// point location procedure is called.  If 'newpoint' is found inside a      //
-// tetrahedron, the tetrahedron is split into four (by splittetrahedron());  //
-// if 'newpoint' lies on a face, the face is split into three, thereby       //
-// splitting the two adjacent tetrahedra into six (by splittetface()); if    //
-// 'newpoint' lies on an edge, the edge is split into two, thereby, every    //
-// tetrahedron containing this edge is split into two. If 'newpoint' lies on //
-// an existing vertex, no action is taken, and the value DUPLICATEPOINT  is  //
-// returned and 'searchtet' is set to a handle whose origin is the vertex.   //
+// Finds the subface in the facet that intersects a line segment drawn from  //
+// the origin of `searchsh' to the point `tend', and returns the result in   //
+// `searchsh'.  The origin of `searchsh' does not change,  even though the   //
+// subface returned may differ from the one passed in.                       //
 //                                                                           //
-// If 'flipqueue' is not NULL, after 'newpoint' is inserted, it returns all  //
-// faces which may become non-Delaunay due to the newly inserted point. Flip //
-// operations can be performed as necessary on them to maintain the Delaunay //
-// property.                                                                 //
+// The return value notes whether the destination or apex of the found face  //
+// is collinear with the two points in question.                             //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::insertsiteresult tetgenmesh::
-insertsite(point newpoint, triface* searchtet, bool approx, queue* flipqueue)
+enum tetgenmesh::finddirectionresult tetgenmesh::finddirectionsub(
+  face* searchsh, point tend)
 {
-  enum locateresult intersect, exactloc;
-  point checkpt;
-  REAL epspp, checklen;
-  int count;
+  face checksh;
+  point startpoint, leftpoint, rightpoint;
+  REAL leftccw, rightccw;
+  REAL ori, sign;
+  int leftflag, rightflag;
 
-  if (b->verbose > 1) {
-    printf("  Insert point to mesh: (%.12g, %.12g, %.12g) %d.\n",
-           newpoint[0], newpoint[1], newpoint[2], pointmark(newpoint));
-  }
+  startpoint = sorg(*searchsh);
+  // Find the sign to simulate that abovepoint is 'above' the facet.
+  adjustedgering(*searchsh, CCW);
+  // Make sure 'startpoint' is the origin.
+  if (sorg(*searchsh) != startpoint) senextself(*searchsh);
+  rightpoint = sdest(*searchsh);
+  leftpoint = sapex(*searchsh);
+  ori = orient3d(startpoint, rightpoint, leftpoint, abovepoint);
+  sign = ori > 0.0 ? -1 : 1;
 
-  if (searchtet->tet == (tetrahedron *) NULL) {
-    // Search for a tetrahedron containing 'newpoint'.
-    searchtet->tet = dummytet;
-    exactloc = locate(newpoint, searchtet);
-  } else {
-    // Start searching from the tetrahedron provided by the caller. 
-    exactloc = preciselocate(newpoint, searchtet);
-  }
-  intersect = exactloc;
-  if (approx && (exactloc != ONVERTEX)) {
-    // Adjust the exact location to an approx. location wrt. epsilon.
-    epspp = b->epsilon;
-    count = 0;
-    while (count < 16) {
-      intersect = adjustlocate(newpoint, searchtet, exactloc, epspp);
-      if (intersect == ONVERTEX) {
-        checkpt = org(*searchtet);
-        checklen = distance(checkpt, newpoint);
-        if (checklen / longest > b->epsilon) {
-          epspp *= 1e-2;
-          count++;
-          continue;
-        }
-      }
-      break;
+  // Is `tend' to the left?
+  ori = orient3d(tend, startpoint, abovepoint, leftpoint);
+  leftccw = ori * sign;
+  leftflag = leftccw > 0.0;
+  // Is `tend' to the right?
+  ori = orient3d(startpoint, tend, abovepoint, rightpoint);
+  rightccw = ori * sign;
+  rightflag = rightccw > 0.0;
+  if (leftflag && rightflag) {
+    // `searchsh' faces directly away from `tend'.  We could go left or
+    //   right.  Ask whether it's a triangle or a boundary on the left.
+    senext2(*searchsh, checksh);
+    spivotself(checksh);
+    if (checksh.sh == dummysh) {
+      leftflag = 0;
+    } else {
+      rightflag = 0;
     }
   }
-  // Keep current search state for next searching.
-  recenttet = *searchtet; 
-
-  // Insert the point using the right routine
-  switch (intersect) {
-  case ONVERTEX:
-    // There's already a vertex there. Return in 'searchtet' a tetrahedron
-    //   whose origin is the existing vertex.
-    if (b->verbose > 1) {
-      printf("  Not insert for duplicating point.\n");
+  while (leftflag) {
+    // Turn left until satisfied.
+    senext2self(*searchsh);
+    spivotself(*searchsh);
+    if (searchsh->sh == dummysh) {
+      printf("Internal error in finddirectionsub():  Unable to find a\n");
+      printf("  subface leading from %d to %d.\n", pointmark(startpoint),
+             pointmark(tend));
+      internalerror();
     }
-    return DUPLICATEPOINT;
-
-  case OUTSIDE:
-    if (b->verbose > 1) {
-      printf("  Not insert for locating outside the mesh.\n");
+    if (sorg(*searchsh) != startpoint) sesymself(*searchsh);
+    assert(sorg(*searchsh) == startpoint);
+    leftpoint = sapex(*searchsh);
+    rightccw = leftccw;
+    ori = orient3d(tend, startpoint, abovepoint, leftpoint);
+    leftccw = ori * sign;
+    leftflag = leftccw > 0.0;
+  }
+  while (rightflag) {
+    // Turn right until satisfied.
+    spivotself(*searchsh);
+    if (searchsh->sh == dummysh) {
+      printf("Internal error in finddirectionsub():  Unable to find a\n");
+      printf("  subface leading from %d to %d.\n", pointmark(startpoint),
+             pointmark(tend));
+      internalerror();
     }
-    return OUTSIDEPOINT;
+    if (sdest(*searchsh) != startpoint) sesymself(*searchsh);
+    assert(sdest(*searchsh) == startpoint);
+    senextself(*searchsh);
+    rightpoint = sdest(*searchsh);
+    leftccw = rightccw;
+    ori = orient3d(startpoint, tend, abovepoint, rightpoint);
+    rightccw = ori * sign;
+    rightflag = rightccw > 0.0;
+  }
+  if (leftccw == 0.0) {
+    return LEFTCOLLINEAR;
+  } else if (rightccw == 0.0) {
+    return RIGHTCOLLINEAR;
+  } else {
+    return ACROSSEDGE;
+  }
+}
 
-  case ONEDGE:
-    // 'newpoint' falls on an edge.
-    splittetedge(newpoint, searchtet, flipqueue);
-    return SUCCESSONEDGE;
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertsubseg()    Create a subsegment and insert it between two subfaces. //
+//                                                                           //
+// The new subsegment ab is inserted at the edge of subface 'tri'.  If ab is //
+// not a hull edge, it is inserted between two subfaces.  If 'tri' is a hull //
+// face, the initial face ring of ab will be set only one face which is self-//
+// bonded.  The final face ring will be constructed in 'unifysegments()'.    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
-  case ONFACE:
-    // 'newpoint' falls on a face.
-    splittetface(newpoint, searchtet, flipqueue);
-    return SUCCESSONFACE;
+void tetgenmesh::insertsubseg(face* tri)
+{
+  face oppotri;
+  face newsubseg;
+  point pa, pb;
+  REAL len;
+  int e1, e2;
+  int i;
 
-  case INTETRAHEDRON:
-    // 'newpoint' falls inside a tetrahedron.
-    splittetrahedron(newpoint, searchtet, flipqueue);
-    return SUCCESSINTET;
+  // Check if there's already a subsegment here.
+  sspivot(*tri, newsubseg);
+  if (newsubseg.sh == dummysh) {
+    // Make new subsegment and initialize its vertices.
+    makeshellface(subsegs, &newsubseg);
+    pa = sorg(*tri);
+    pb = sdest(*tri);
+    setsorg(newsubseg, pa);
+    setsdest(newsubseg, pb);
+    // Are there length constraints?
+    if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
+      for (i = 0; i < in->numberofsegmentconstraints; i++) {
+        e1 = (int) in->segmentconstraintlist[i * 3];
+        e2 = (int) in->segmentconstraintlist[i * 3 + 1];
+        if (((pointmark(pa) == e1) && (pointmark(pb) == e2)) ||
+            ((pointmark(pa) == e2) && (pointmark(pb) == e1))) {
+          len = in->segmentconstraintlist[i * 3 + 2];
+          setareabound(newsubseg, len);
+          break;
+        }
+      }
+    }
+    // Bond new subsegment to the two subfaces it is sandwiched between.
+    ssbond(*tri, newsubseg);
+    spivot(*tri, oppotri);
+    // 'oppotri' might be "out space".
+    if (oppotri.sh != dummysh) {
+      ssbond(oppotri, newsubseg);
+    } /* else {
+      // Outside! Bond '*tri' to itself.
+      sbond(*tri, *tri);
+    } */
   }
-
-  // Impossible case.
-  assert(0);
-  return OUTSIDEPOINT;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// undosite()    Undo the most recently point insertion.                     //
+// scoutsegmentsub()    Scout the first triangle on the path from one point  //
+//                      to another, and check for completion (reaching the   //
+//                      second point), a collinear point,or the intersection //
+//                      of two segments.                                     //
 //                                                                           //
-// 'insresult' indicates in where the newpoint has been inserted, i.e., in a //
-// tetrahedron, on a face, or on an edge.  A correspoding routine will be    //
-// called to undo the point insertion.  'splittet' is a handle represent one //
-// of the resulting tetrahedra, but it may be changed after transformation,  //
-// even may be dead.  Four points 'torg', ... 'toppo' are the corners which  //
-// 'splittet' should have. On finish, 'newpoint' is not removed.             //
+// Returns true if the entire segment is successfully inserted, and false if //
+// the job must be finished by constrainededge().                            //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-undosite(enum insertsiteresult insresult, triface* splittet, point torg,
-         point tdest, point tapex, point toppo)
+bool tetgenmesh::scoutsegmentsub(face* searchsh, point tend)
 {
-  // Set the four corners of 'splittet' exactly be 'torg', ... 'toppo'.
-  findface(splittet, torg, tdest, tapex);
-  if (oppo(*splittet) != toppo) {
-    symself(*splittet);
-    assert(oppo(*splittet) == toppo);
-    // 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;
+  face newsubseg;
+  face crosssub, crosssubseg;
+  point leftpoint, rightpoint;
+  enum finddirectionresult collinear;
+
+  collinear = finddirectionsub(searchsh, tend);
+  rightpoint = sdest(*searchsh);
+  leftpoint = sapex(*searchsh);
+  if (rightpoint == tend || leftpoint == tend) {
+    // The segment is already an edge.
+    if (leftpoint == tend) {
+      senext2self(*searchsh);
+    }
+    // Insert a subsegment.
+    insertsubseg(searchsh);
+    return true;
+  } else if (collinear == LEFTCOLLINEAR) {
+    // We've collided with a vertex between the segment's endpoints.
+    // Make the collinear vertex be the triangle's origin.
+    senextself(*searchsh); // lprevself(*searchtri);
+    // Insert a subsegment.
+    insertsubseg(searchsh);
+    // Insert the remainder of the segment.
+    return scoutsegmentsub(searchsh, tend);
+  } else if (collinear == RIGHTCOLLINEAR) {
+    // We've collided with a vertex between the segment's endpoints.
+    // Insert a subsegment.
+    insertsubseg(searchsh);
+    // Make the collinear vertex be the triangle's origin.
+    senextself(*searchsh); // lnextself(*searchtri);
+    // Insert the remainder of the segment.
+    return scoutsegmentsub(searchsh, tend);
+  } else {
+    senext(*searchsh, crosssub); // lnext(*searchtri, crosstri);
+    // Check for a crossing segment.
+    sspivot(crosssub, crosssubseg);
+#ifdef SELF_CHECK
+    assert(crosssubseg.sh == dummysh);
+#endif
+    return false;
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// inserthullsite()    Insert a point which is outside the convex hull.      //
+// flipedgerecursive()    Flip an edge.                                      //
 //                                                                           //
-// The inserting point 'inspoint' lies outside the tetrahedralization.'horiz'//
-// is one of the convex hull faces which are visible from it. (You can image //
-// that is is parallel to the horizon). To insert a point outside the convex //
-// hull we have to enlarge current convex hull of the tetrahedralization for //
-// including this point.  This routine collects convex hull faces which are  //
-// visible from the inserting point, constructs new tetrahedra from these    //
-// faces and the inserting point. On return, 'inspoint' has become a vertex  //
-// of the augmented tetrahedralization.  The convex hull has been updated.   //
-// 'flipcheckqueue' returns the old convex hull faces which may become non-  //
-// Delaunay and need be flipped.                                             //
+// This is a support routine for inserting segments into a CDT.              //
 //                                                                           //
-// The caller can optionally provide two variables. 'hulllink' is a link for //
-// saving newly created hull faces (containing 'inspoint') which may not     //
-// convex. Non-convex hull faces will be detected and finished by mounting   //
-// new tetrahedra with other hull vertex near them.  'worklist' is an array, //
-// used for face matching.                                                   //
+// Let 'flipedge' be ab, and two triangles abc, abd share at it.  ab may not //
+// flipable if the four vertices a, b, c, and d are non-convex. If it is the //
+// case, recursively flip ad or bd. Return when ab is flipped.               //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-inserthullsite(point inspoint, triface* horiz, queue* flipqueue,
-               link* hulllink, int* worklist)
+void tetgenmesh::flipedgerecursive(face* flipedge, queue* flipqueue)
 {
-  link *myhulllink;
-  triface newtet, hullface;
-  triface oldhull, newhull;
-  point workpt[3];
-  bool finished;
-  int *myworklist;
-  int idx, share;
-  int i, j, k;
-
-  if (b->verbose > 1) {
-    printf("  Collect visible convex hull faces.\n");
-  }
+  face fixupsh;
+  point pa, pb, pc, pd;
+  REAL oria, orib;
+  bool doflip;
 
-  // Check if the 'hulllink' is provided by the caller.
-  if (hulllink != (link *) NULL) {
-    myhulllink = (link *) NULL;
-  } else {
-    myhulllink = new link(sizeof(triface), NULL, 256);
-    hulllink = myhulllink;
-  }
+  pa = sorg(*flipedge);
+  pb = sdest(*flipedge);
+  pc = sapex(*flipedge);
+  do {
+    spivot(*flipedge, fixupsh);    
+    pd = sapex(fixupsh);
+    oria = orient3d(pc, pd, abovepoint, pa);
+    orib = orient3d(pc, pd, abovepoint, pb);
+    doflip = (oria * orib < 0.0);
+    if (doflip) {
+      // Flip the edge (a, b) away.      
+      flip22sub(flipedge, flipqueue);
+      // Fix flipedge on edge e (c, d).
+      findedge(flipedge, pc, pd);
+    } else {
+      // ab is unflipable. Get the next edge (bd, or da) to flip.
+      if (sorg(fixupsh) != pb) sesymself(fixupsh);
+      assert(sdest(fixupsh) == pa);
+      if (fabs(oria) > fabs(orib)) {
+        // acd has larger area. Choose da.
+        senextself(fixupsh);
+      } else {
+        // bcd has larger area. Choose bd.
+        senext2self(fixupsh);
+      }
+      // Flip the edge.
+      flipedgerecursive(&fixupsh, flipqueue);
+    }
+  } while (!doflip);
+}
 
-  // Check if the 'worklist' is provided by the caller.
-  if (worklist != (int *) NULL) {
-    myworklist = (int *) NULL;
-  } else {
-    myworklist = new int[points->items];
-    for (i = 0; i < points->items; i++) myworklist[i] = 0;
-    worklist = myworklist;
-  }
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// constrainededge()    Force a segment into a CDT.                          //
+//                                                                           //
+// The segment s is recovered by flipping away the edges it intersects, and  //
+// triangulating the polygons that form on each side of it.                  //
+//                                                                           //
+// Generates a single subsegment connecting `tstart' to `tend'. The triangle //
+// `startsh' has `tstart' as its origin.                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
-  adjustedgering(*horiz, CW);
-  // Create a new tetrahedron from 'horiz' and 'inspoint'.
-  maketetrahedron(&newtet);
-  setorg (newtet, org(*horiz));
-  setdest(newtet, dest(*horiz));
-  setapex(newtet, apex(*horiz));
-  setoppo(newtet, inspoint);
-  // Make the connection of two tets.
-  bond(newtet, *horiz);
-  // 'horiz' becomes interior face.
-  enqueueflipface(*horiz, flipqueue);
-  // Add the three sides of 'newtet' to 'hulllink'.
-  fnext(newtet, hullface);
-  hulllink->add(&hullface);
-  enextfnext(newtet, hullface);
-  hulllink->add(&hullface);
-  enext2fnext(newtet, hullface);
-  hulllink->add(&hullface);
-  if (b->verbose > 3) {
-    printf("    Creating newtet ");
-    printtet(&newtet);
-  }
-  // Hull face number decreased caused by face bond() operation.
-  hullsize--;
+void tetgenmesh::constrainededge(face* startsh, point tend, queue* flipqueue)
+{
+  point tstart, tright, tleft;
+  REAL rori, lori;
+  bool collision;
 
-  // Loop untill 'hulllink' is empty.  Find other visible convex hull faces,
-  //   create tetrahedra from them and 'inspoint'. Update 'hulllink'.
-  while (hulllink->len() > 0) {
-    // Remove the top hull face from the link, its apex is 'inspoint'.
-    hullface = * (triface *) hulllink->del(1);
-    // Get the neighbor convex hull face at the edge of 'hullface'.  This is
-    //   done by rotating faces around the edge from the inside until reach
-    //   outer space (The rotation of faces should always terminate).
-    esym(hullface, oldhull);
-    while (fnextself(oldhull)) ;
-    // Is 'inspoint' visible from 'oldhull'?
-    if (orient3d(org(oldhull), dest(oldhull), apex(oldhull), inspoint) < 0.0) {
-      // 'oldhull' is visible from 'inspoint'. Create a new tetrahedron
-      //   from them.
-      maketetrahedron(&newtet);
-      setorg(newtet, org(oldhull));
-      setdest(newtet, dest(oldhull));
-      setapex(newtet, apex(oldhull));
-      setoppo(newtet, inspoint);
-      // Bond 'newtet' to 'oldhull'.
-      bond(newtet, oldhull);
-      // Hull face number decrease caused by bond().
-      hullsize--;
-      // Bond 'newtet' to 'hullface'.
-      fnext(newtet, newhull);
-      bond(newhull, hullface);
-      // 'oldhull' becomes interior face.
-      enqueueflipface(oldhull, flipqueue);
-      // Check other two sides of 'newtet'.  If one exists in 'hulllink'.
-      //   remove the one in 'hulllink' (it is finished), otherwise, it
-      //   becomes a new hull face, add it into 'hulllink'.
-      for (i = 0; i < 2; i++) {
-        // Get 'newhull' and set flags for its vertices.
-        if (i == 0) {
-          enextfnext(newtet, newhull);
-        } else {
-          enext2fnext(newtet, newhull);
-        }
-        workpt[0] = org(newhull);
-        workpt[1] = dest(newhull);
-        workpt[2] = apex(newhull);
-        for (k = 0; k < 3; k++) {
-          idx = pointmark(workpt[k]) - in->firstnumber;
-          worklist[idx] = 1;
-        }
-        // Search 'newhull' in 'hulllink'.
-        finished = false;        
-        for (j = 0; j < hulllink->len() && !finished; j++) {
-          hullface = * (triface *) hulllink->getnitem(j + 1);
-          workpt[0] = org(hullface);
-          workpt[1] = dest(hullface);
-          workpt[2] = apex(hullface);
-          share = 0;
-          for (k = 0; k < 3; k++) {
-            idx = pointmark(workpt[k]) - in->firstnumber;
-            if (worklist[idx] == 1) {
-              share++;
-            }
-          }
-          if (share == 3) {
-            // Two faces are identical. Bond them togther.
-            bond(newhull, hullface);
-            // Remove 'hullface' from the link.
-            hulllink->del(j + 1);
-            finished = true;
-          }
-        }
-        if (!finished) {
-          // 'newhull' becomes a hull face, add it into 'hulllink'.
-          hulllink->add(&newhull); 
-        }
-        // Clear used flags.
-        workpt[0] = org(newhull);
-        workpt[1] = dest(newhull);
-        workpt[2] = apex(newhull);
-        for (k = 0; k < 3; k++) {
-          idx = pointmark(workpt[k]) - in->firstnumber;
-          worklist[idx] = 0;
-        }
+  tstart = sorg(*startsh);
+  do {
+    // Loop edges oppo to tstart until find one crosses the segment.
+    do {
+      tright = sdest(*startsh);
+      tleft = sapex(*startsh);
+      // Is edge (tright, tleft) corss the segment.
+      rori = orient3d(tstart, tright, abovepoint, tend);
+      collision = (rori == 0.0);
+      if (collision) break; // tright is on the segment.
+      lori = orient3d(tstart, tleft, abovepoint, tend);
+      collision = (lori == 0.0);
+      if (collision) { //  tleft is on the segment.
+        senext2self(*startsh);
+        break;
       }
-    } else {
-      // 'hullface' becomes a convex hull face. 
-      hullsize++;
-      // Let 'dummytet[0]' points to it for next point location.
-      dummytet[0] = encode(hullface);
-    }
-  }
+      if (rori * lori < 0.0) break; // Find the crossing edge.
+      // Both points are at one side of the segment. 
+      finddirectionsub(startsh, tend);
+    } while (true);
+    if (collision) break;
+    // Get the neighbor face at edge e (tright, tleft).
+    senextself(*startsh);
+    // Flip the crossing edge.
+    flipedgerecursive(startsh, flipqueue);
+    // After flip, sorg(*startsh) == tstart.
+    assert(sorg(*startsh) == tstart);
+  } while (sdest(*startsh) != tend);
 
-  if (myhulllink != (link *) NULL) {
-    delete myhulllink;
-  }
-  if (myworklist != (int *) NULL) {
-    delete [] myworklist;
+  // Insert a subsegment to make the segment permanent.
+  insertsubseg(startsh);
+  // If there was a collision with an interceding vertex, install another
+  //   segment connecting that vertex with endpoint2.
+  if (collision) {
+    // Insert the remainder of the segment.
+    if (!scoutsegmentsub(startsh, tend)) {
+      constrainededge(startsh, tend, flipqueue);
+    }
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// collectcavtets()    Collect all tets whose circumsphere contain newpoint. //
-//                                                                           //
-// 'cavtetlist' returns the list of tetrahedra. On input, it contains one    //
-// tetrahedron which contains 'newpoint'.                                    //
+// recoversegment()    Recover a segment in the surface triangulation.       //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::collectcavtets(point newpoint, list* cavtetlist)
+void tetgenmesh::recoversegment(point tstart, point tend, queue* flipqueue)
 {
-  triface starttet, neightet;
-  REAL sign;
-  int i;
+  face searchsh;
 
-  // Now starttet contains newpoint.
-  starttet = * (triface *)(* cavtetlist)[0];
-  infect(starttet);
+  if (b->verbose > 2) {
+    printf("    Insert seg (%d, %d).\n", pointmark(tstart), pointmark(tend));
+  }
 
-  // Find the other tetrahedra by looping in list.
-  for (i = 0; i < cavtetlist->len(); i++) {
-    starttet = * (triface *)(* cavtetlist)[i];
-    // Check the four neighbors of starttet.
-    for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
-      sym(starttet, neightet);
-      if ((neightet.tet != dummytet) && !infected(neightet)) {
-        // For positive orientation that insphere() test requires.
-        adjustedgering(neightet, CW);
-        sign = insphere(org(neightet), dest(neightet), apex(neightet),
-                        oppo(neightet), newpoint);
-        if (sign >= 0.0) {
-          // Add neightet into list.
-          infect(neightet);
-          cavtetlist->append(&neightet);
-        }
+  // Find a triangle whose origin is the segment's first endpoint.
+  searchsh.sh = dummysh;
+  // Search for the segment's first endpoint by point location.
+  if (locatesub(tstart, &searchsh, 0, 0.0) != ONVERTEX) {
+    // Possibly caused by a degenerate subface. Do a brute-force search.
+    list *newshlist;
+    int i, j;
+    newshlist = new list(sizeof(face), NULL, 256);
+    // Get new subfaces, do not remove protected segments.
+    retrievenewsubs(newshlist, false);
+    // Search for a sub contain tstart.
+    for (i = 0; i < newshlist->len(); i++) {
+      searchsh = * (face *)(* newshlist)[i];
+      for (j = 0; j < 3; j++) {
+        if (sorg(searchsh) == tstart) break;
+        senextself(searchsh);
       }
+      if (j < 3) break;
+    }
+    delete newshlist;
+    if (sorg(searchsh) != tstart) {
+      printf("Internal error in recoversegment():  Vertex location failed.\n");
+      internalerror();
     }
   }
-
-  // Having find all tetrahedra, uninfect them before return.
-  for (i = 0; i < cavtetlist->len(); i++) {
-    starttet = * (triface *)(* cavtetlist)[i];
-    assert(infected(starttet));
-    uninfect(starttet);
-  }
+  // Scout the segment and insert it if it is found.
+  if (scoutsegmentsub(&searchsh, tend)) {
+    // The segment was easily inserted.
+    return;
+  }  
+  // Insert the segment into the triangulation by flips.
+  constrainededge(&searchsh, tend, flipqueue);
+  // Some edges may need flipping.
+  flipsub(flipqueue);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// collectcavsubs()    Collect subfaces whose circumsphere contain newpoint. //
-//                                                                           //
-// 'cavsublist' returns the list of subfaces. It is not empty on input, it   //
-// contains at least one such subface.                                       //
+// infecthullsub()    Virally infect all of the triangles of the convex hull //
+//                    that are not protected by subsegments.                 //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::collectcavsubs(point newpoint, list* cavsublist)
+void tetgenmesh::infecthullsub(memorypool* viri)
 {
-  face startsub, neighsub;
-  face checkseg;
-  point pa, pb, pc, liftpt;
-  REAL sign, ori;
-  int i, j;
-
-  // First infect subfaces in 'cavsublist'.
-  for (i = 0; i < cavsublist->len(); i++) {
-    startsub = * (face *)(* cavsublist)[i];
-    if (i == 0) {
-      liftpt = getliftpoint(shellmark(startsub));
-    }
-    sinfect(startsub);
-  }
+  face hulltri, nexttri, starttri;
+  face hullsubseg;
+  shellface **deadshellface;
 
-  // Find the other subfaces by looping in list.
-  for (i = 0; i < cavsublist->len(); i++) {
-    startsub = * (face *)(* cavsublist)[i];
-    for (j = 0; j < 3; j++) {
-      sspivot(startsub, checkseg);
-      if (checkseg.sh == dummysh) {
-        spivot(startsub, neighsub);
-        if (!sinfected(neighsub)) {
-          pa = sorg(neighsub);
-          pb = sdest(neighsub);
-          pc = sapex(neighsub);
-          sign = insphere(pa, pb, pc, liftpt, newpoint);
-          ori = orient3d(pa, pb, pc, liftpt);
-          if (sign != 0.0) {
-            // Correct the sign. 
-            assert(ori != 0.0);
-            sign = ori > 0.0 ? sign : -sign;
-          }
-          if (sign > 0.0) {
-            // neighsub is encroached by newpoint.
-            sinfect(neighsub);
-            cavsublist->append(&neighsub);
-          }
+  // Find a triangle handle on the hull.
+  hulltri.sh = dummysh;
+  hulltri.shver = 0;
+  spivotself(hulltri);
+  adjustedgering(hulltri, CCW);
+  // Remember where we started so we know when to stop.
+  starttri = hulltri;
+  // Go once counterclockwise around the convex hull.
+  do {
+    // Ignore triangles that are already infected.
+    if (!sinfected(hulltri)) {
+      // Is the triangle protected by a subsegment?
+      sspivot(hulltri, hullsubseg);
+      if (hullsubseg.sh == dummysh) {
+        // The triangle is not protected; infect it.
+        if (!sinfected(hulltri)) {
+          sinfect(hulltri);
+          deadshellface = (shellface **) viri->alloc();
+          *deadshellface = hulltri.sh;
         }
+      } 
+    }
+    // To find the next hull edge, go clockwise around the next vertex.
+    senextself(hulltri); // lnextself(hulltri);
+    spivot(hulltri, nexttri); // oprev(hulltri, nexttri);
+    if (nexttri.sh == hulltri.sh) {
+      nexttri.sh = dummysh;  // 'hulltri' is self-bonded.
+    } else {
+      adjustedgering(nexttri, CCW);
+      senextself(nexttri);
+    }
+    while (nexttri.sh != dummysh) {
+      hulltri = nexttri;
+      spivot(hulltri, nexttri); // oprev(hulltri, nexttri);
+      if (nexttri.sh == hulltri.sh) {
+        nexttri.sh = dummysh;  // 'hulltri' is self-bonded.
+      } else {
+        adjustedgering(nexttri, CCW);
+        senextself(nexttri);
       }
-      senextself(startsub);
     }
-  }
-
-  // Having find all subfaces, uninfect them before return.
-  for (i = 0; i < cavsublist->len(); i++) {
-    startsub = * (face *)(* cavsublist)[i];
-    suninfect(startsub);
-  }
+  } while (hulltri != starttri);
 }
 
-//
-// End of mesh transformation routines
-//
-
-//
-// Begin of incremental flip Delaunay triangulation routines
-//
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// incrflipinit()    Create an initial tetrahedralization.                   //
-//                                                                           //
-// The initial tetrahedralization only contains one tetrahedron formed from  //
-// four affinely linear independent vertices from the input point set.       //
+// plaguesub()    Spread the virus from all infected triangles to any        //
+//                neighbors not protected by subsegments.  Delete all        //
+//                infected triangles.                                        //
 //                                                                           //
-// 'insertqueue' returns the rest of vertices of the input point set.  These //
-// vertices will be inserted one by one in the later step.                   //
+// This is the procedure that actually creates holes and concavities.        //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::incrflipinit(queue* insertqueue)
+void tetgenmesh::plaguesub(memorypool* viri)
 {
-  triface newtet;
-  point *plist, pointloop;
-  point pa, pb, pc, pd;
-  REAL det;
-  int count;
-  int i, j;
-
-  if (b->verbose > 1) {
-    printf("  Constructing an initial tetrahedron.\n");
-  }
-
-  // Create a point list and initialize it.
-  plist = new point[in->numberofpoints];
-  i = 0;
-  points->traversalinit();
-  pointloop = pointtraverse();
-  while (pointloop != (point) NULL) {
-    plist[i++] = pointloop;
-    pointloop = pointtraverse();
-  }
-  assert(i == in->numberofpoints);
-
-  if (b->dopermute) {
-    // Do permutation.  Initialize the random seed.
-    randomseed = b->srandseed;
-    for (i = 0; i < in->numberofpoints; i++) {
-      // Get a index j (from 0 to in->numberofpoints - i - 1).
-      j = (int) randomnation(in->numberofpoints - i);
-      // Exchange the i-th point and (j + i)-th point.
-      pointloop = plist[j + i];
-      plist[j + i] = plist[i];
-      plist[i] = pointloop;
-    }
-  }
-
-  // Set the plist into insertqueue.
-  if (!insertqueue->empty()) {
-    insertqueue->clear(); 
-  }
-  for (i = 0; i < in->numberofpoints; i++) {
-    pointloop = plist[i];
-    insertqueue->push(&pointloop);
-  }
-  delete [] plist;
-
-  // Get the first two point 'pa'.
-  pa = * (point *) insertqueue->pop();
-
-  // Get the second point 'pb', which is not identical with 'pa'.
-  count = 0;
-  pb = * (point *) insertqueue->pop();
-  while ((pb != (point) NULL) && (count < in->numberofpoints)) {
-    if ((pb[0] == pa[0]) && (pb[1] == pa[1]) && (pb[2] == pa[2])) {
-      // 'pb' is identical to 'pa', skip it.
-      insertqueue->push(&pb);
-    } else {
-      break;
-    }
-    pb = * (point *) insertqueue->pop();
-    count++;
-  }
-  if (pb == (point) NULL) {
-    printf("\nAll points are identical, no triangulation be constructed.\n");
-    exit(1);
-  }
+  face testtri, neighbor, ghostsh;
+  face neighborsubseg;
+  shellface **virusloop;
+  shellface **deadshellface;
+  int i;
 
-  // Get the third point 'pc', which is not collinear with 'pa' and 'pb'.
-  count = 0;
-  pc = * (point *) insertqueue->pop();
-  while ((pc != (point) NULL) && (count < in->numberofpoints)) {
-    if (iscollinear(pa, pb, pc, (b->epsilon * 1e-2))) {
-      // They are collinear or identical, put it back to queue.
-      insertqueue->push(&pc);
-    } else {
-      break;
+  // Loop through all the infected triangles, spreading the virus to
+  //   their neighbors, then to their neighbors' neighbors.
+  viri->traversalinit();
+  virusloop = (shellface **) viri->traverse();
+  while (virusloop != (shellface **) NULL) {
+    testtri.sh = *virusloop;
+    // Check each of the triangle's three neighbors.
+    for (i = 0; i < 3; i++) {
+      // Find the neighbor.
+      spivot(testtri, neighbor);
+      // Check for a subsegment between the triangle and its neighbor.
+      sspivot(testtri, neighborsubseg);
+      // Check if the neighbor is nonexistent or already infected.
+      if ((neighbor.sh == dummysh) || sinfected(neighbor)) {
+        if (neighborsubseg.sh != dummysh) {
+          // There is a subsegment separating the triangle from its
+          //   neighbor, but both triangles are dying, so the subsegment
+          //   dies too.
+          shellfacedealloc(subsegs, neighborsubseg.sh);
+          if (neighbor.sh != dummysh) {
+            // Make sure the subsegment doesn't get deallocated again
+            //   later when the infected neighbor is visited.
+            ssdissolve(neighbor);
+          }
+        }
+      } else {                   // The neighbor exists and is not infected.
+        if (neighborsubseg.sh == dummysh) {
+          // There is no subsegment protecting the neighbor, so the
+          //   neighbor becomes infected.
+          sinfect(neighbor);
+          // Ensure that the neighbor's neighbors will be infected.
+          deadshellface = (shellface **) viri->alloc();
+          *deadshellface = neighbor.sh;
+        } else {               // The neighbor is protected by a subsegment.
+          // Remove this triangle from the subsegment.
+          ssbond(neighbor, neighborsubseg);
+        }
+      }
+      senextself(testtri);
     }
-    pc = * (point *) insertqueue->pop();
-    count++;
-  }
-  if (pc == (point) NULL) {
-    printf("\nAll points are collinear, no triangulation be constructed.\n");
-    exit(1);
+    virusloop = (shellface **) viri->traverse();
   }
 
-  // Get the fourth point which is not coplanar with pa, pb, and pc.
-  count = 0;
-  pd = * (point *) insertqueue->pop();
-  while ((pd != (point) NULL) && (count < in->numberofpoints)) {
-    det = orient3d(pa, pb, pc, pd);
-    if (det == 0.0) {
-      // They are coplanar or identical, put it back to queue.
-      insertqueue->push(&pd);
-    } else {
-      break;
+  ghostsh.sh = dummysh; // A handle of outer space.
+  viri->traversalinit();
+  virusloop = (shellface **) viri->traverse();
+  while (virusloop != (shellface **) NULL) {
+    testtri.sh = *virusloop;
+    // Record changes in the number of boundary edges, and disconnect
+    //   dead triangles from their neighbors. 
+    for (i = 0; i < 3; i++) {
+      spivot(testtri, neighbor);
+      if (neighbor.sh != dummysh) {
+        // Disconnect the triangle from its neighbor.
+        // sdissolve(neighbor);
+        sbond(neighbor, ghostsh); 
+      }
+      senextself(testtri);
     }
-    pd = * (point *) insertqueue->pop();
-    count++;
-  }
-  if (pd == (point) NULL) {
-    printf("\nAll points are coplanar, no triangulation be constructed.\n");
-    exit(1);
-  }
-  if (det > 0.0) {
-    pointloop = pa; pa = pb; pb = pointloop;
-  }
-
-  // Create the tetrahedron with corners pa, pb, pc and pd.
-  maketetrahedron(&newtet);
-  setorg(newtet, pa);
-  setdest(newtet, pb);
-  setapex(newtet, pc);
-  setoppo(newtet, pd);
-  // Set the vertices be FREEVOLVERTEX to indicate they belong to the mesh.
-  setpointtype(pa, FREEVOLVERTEX);
-  setpointtype(pb, FREEVOLVERTEX);
-  setpointtype(pc, FREEVOLVERTEX);
-  setpointtype(pd, FREEVOLVERTEX);
-  // Bond to 'dummytet' for point location.
-  dummytet[0] = encode(newtet);
-  if (b->verbose > 3) {
-    printf("    Creating tetra ");
-    printtet(&newtet);
+    // Return the dead triangle to the pool of triangles.
+    shellfacedealloc(subfaces, testtri.sh);
+    virusloop = (shellface **) viri->traverse();
   }
-  // At init, all faces of this tet are hull faces.
-  hullsize = 4;
+  // Empty the virus pool.
+  viri->restart();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// mergepoints()    Merge two very close points to be one point.             //
+// carveholessub()    Find the holes and infect them.  Find the area         //
+//                    constraints and infect them.  Infect the convex hull.  //
+//                    Spread the infection and kill triangles.  Spread the   //
+//                    area constraints.                                      //
 //                                                                           //
-// This function is used for dealing with inputs from CAD tools. It uses the //
-// (relative) epsilon to determine whether two points are merged or not. The //
-// default epsilon is (b->epsilon * 1e+2 = 1e-6). You can set the value thr- //
-// ough the -T switch, e.g. -T1e-5.                                          //
+// This routine mainly calls other routines to carry out all these functions.//
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-mergepoints(point testpt, triface* starttet, link* hulllink, int* worklist)
+void tetgenmesh::carveholessub(int holes, REAL* holelist, memorypool *viri)
 {
-  triface hullface, neihull, checkhull;
-  point workpt[4], checkpt;
-  enum locateresult loc;
-  REAL ori, dist, epspp;
-  bool merged;
-  int share;
-  int i, j, k;
+  face searchtri, triangleloop;
+  shellface **holetri;
+  enum locateresult intersect;
+  int i;
 
-  // First locate the point in DT.
-  loc = locate(testpt, starttet);
-  if (loc == ONVERTEX) return; // They are merged.
-  
-  // Now testpt is either outside or insde.
-  merged = false;
-  if (loc == OUTSIDE) {
-    // Outside, collect hullfaces which are visible by testpt.
-    hulllink->add(starttet);
-    for (i = 0; i < hulllink->len(); i++) {
-      hullface = * (triface *) hulllink->getnitem(i + 1);
-      // Check if hullface has a point close to testpt.
-      workpt[0] = org(hullface);
-      workpt[1] = dest(hullface);
-      workpt[2] = apex(hullface);
-      workpt[3] = oppo(hullface);
-      for (j = 0; j < 4; j++) {
-        dist = distance(testpt, workpt[j]);
-        epspp = dist / longest;
-        if (epspp <= (b->epsilon * 1e+2)) {
-          // Merge the point to the existing point.
-          for (k = 0; k < 3; k++) testpt[k] = workpt[j][k];
-          merged = true;
-          break;
-        }
-      }
-      if (merged) break;
-      // Check the neighbor visible hullfaces by testpt.
-      adjustedgering(hullface, CCW);
-      for (j = 0; j < 3; j++) {
-        neihull = hullface;
-        while (fnextself(neihull)) ;
-        workpt[0] = org(neihull);
-        workpt[1] = dest(neihull);
-        workpt[2] = apex(neihull);
-        ori = orient3d(workpt[0], workpt[1], workpt[2], testpt);
-        if (ori < 0.0) {
-          // Visible. Add neihull to link if it doesn't exist in it.
-          for (k = 0; k < 3; k++) worklist[pointmark(workpt[k])] = 1;
-          // Do a brute-force search.
-          for (k = 0; k < hulllink->len(); k++) {
-            if (k == i) continue;
-            checkhull = * (triface *) hulllink->getnitem(k + 1);
-            checkpt = org(checkhull);
-            share = worklist[pointmark(checkpt)];
-            checkpt = dest(checkhull);
-            share += worklist[pointmark(checkpt)];
-            checkpt = apex(checkhull);
-            share += worklist[pointmark(checkpt)];
-            if (share == 3) break;
-          }
-          if (k >= hulllink->len()) {
-            hulllink->add(&neihull);
-          }
-          for (k = 0; k < 3; k++) worklist[pointmark(workpt[k])] = 0;
-        } else {
-          // Check the apex anyway.
-          dist = distance(testpt, workpt[2]);
-          epspp = dist / longest;
-          if (epspp <= (b->epsilon * 1e+2)) {
-            // Merge the point to the existing point.
-            for (k = 0; k < 3; k++) testpt[k] = workpt[2][k];
-            merged = true;
-            break;
-          }
-          // Check the opposite anyway.
-          workpt[3] = oppo(neihull);
-          dist = distance(testpt, workpt[3]);
-          epspp = dist / longest;
-          if (epspp <= (b->epsilon * 1e+2)) {
-            // Merge the point to the existing point.
-            for (k = 0; k < 3; k++) testpt[k] = workpt[3][k];
-            merged = true;
-            break;
-          }
+  // Mark as infected any unprotected triangles on the boundary.
+  //   This is one way by which concavities are created.
+  infecthullsub(viri);
+
+  if (holes > 0) {
+    // Infect each triangle in which a hole lies.
+    for (i = 0; i < 3 * holes; i += 3) {
+      // Ignore holes that aren't within the bounds of the mesh.
+      if ((holelist[i] >= xmin) && (holelist[i] <= xmax)
+          && (holelist[i + 1] >= ymin) && (holelist[i + 1] <= ymax)
+          && (holelist[i + 2] >= zmin) && (holelist[i + 2] <= zmax)) {
+        // Start searching from some triangle on the outer boundary.
+        searchtri.sh = dummysh;
+        // Find a triangle that contains the hole.
+        intersect = locatesub(&holelist[i], &searchtri, 0, 0.0);
+        if ((intersect != OUTSIDE) && (!sinfected(searchtri))) {
+          // Infect the triangle.  This is done by marking the triangle
+          //   as infected and including the triangle in the virus pool.
+          sinfect(searchtri);
+          holetri = (shellface **) viri->alloc();
+          *holetri = searchtri.sh;
         }
-        enextself(hullface);
-      }
-      if (merged) break;
-    }
-  } else {
-    hullface = *starttet;
-    // Check if there is a close point?
-    for (j = 0; j < 4 && !merged; j++) {
-      checkpt = (point) hullface.tet[4 + j];
-      dist = distance(testpt, checkpt);
-      epspp = dist / longest;
-      if (epspp <= (b->epsilon * 1e+2)) {
-        // Merge the point to the existing point.
-        for (k = 0; k < 3; k++) testpt[k] = checkpt[k];
-        merged = true;
       }
     }
   }
-  // Clear hulllink for the next use.
-  hulllink->clear();
+
+  if (viri->items > 0) {
+    // Carve the holes and concavities.
+    plaguesub(viri);
+  }
+  // The virus pool should be empty now.
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// incrflipdelaunay()   Construct a delaunay tetrahedrization from a set of  //
-//                      3D points using the incremental flip algorithm.      //
+// triangulate()    Triangulate a PSLG into a CDT.                           //
 //                                                                           //
-// The incremental flip algorithm is described in the paper of Edelsbrunner  //
-// and Shah, "Incremental Topological Flipping Works for Regular Triangulat- //
-// ions",  Algorithmica 15: 223-241, 1996.  It can be described as follows:  //
+// A Planar Straight Line Graph (PSLG) P is actually a 2D polygonal region,  //
+// possibly contains holes, segments and vertices in its interior. P is tri- //
+// angulated into a set of _subfaces_ forming a CDT of P.                    //
 //                                                                           //
-//   S be a set of points in 3D, Let 4 <= i <= n and assume that the         //
-//   Delaunay triangulation of the first i-1 points in S is already          //
-//   constructed; call it D(i-1). Add the i-th point p_i (belong to S) to    //
-//   the triangulation,and restore Delaunayhood by flipping; this result     //
-//   in D(i). Repeat this procedure until i = n.                             //
+// The vertices and segments of P are found in 'ptlist' and 'conlist', resp- //
+// ectively. 'holelist' contains a list of hole points. 'shmark' will be set //
+// to all subfaces of P.                                                     //
 //                                                                           //
-// This strategy always leads to the Ddelaunay triangulation of a point set. //
-// The return value is the number of convex hull faces of this point set.    //
+// The CDT is created directly in the pools 'subfaces' and 'subsegs'. It can //
+// be retrived by a broadth-first searching starting from 'dummysh[0]'(debug //
+// function 'outsurfmesh()' does it).                                        //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-long tetgenmesh::incrflipdelaunay()
+void tetgenmesh::triangulate(int shmark, REAL eps, list* ptlist, list* conlist,
+  int holes, REAL* holelist, memorypool* viri, queue* flipqueue)
 {
-  triface starttet;
-  point pointloop;
-  queue *flipqueue;
-  queue *insertqueue;
-  link *hulllink;
-  enum insertsiteresult insres;
-  int *worklist, i;
+  face newsh;
+  point *cons;
+  int i;
 
-  if (!b->quiet) {
-    if (!b->noflip) {
-      printf("Constructing Delaunay tetrahedrization.\n");
-    } else {
-      printf("Constructing tetrahedrization.\n");
+  if (b->verbose > 1) {
+    printf("    %d vertices, %d segments", ptlist->len(), conlist->len());
+    if (holes > 0) {
+      printf(", %d holes", holes);
     }
+    printf(", shmark: %d.\n", shmark);
   }
 
-  // Initialize subsidary queues, link, list, ...
-  flipqueue = new queue(sizeof(badface));
-  insertqueue = new queue(sizeof(point*), in->numberofpoints);
-  hulllink = new link(sizeof(triface), NULL, 256);
-  worklist = new int[in->numberofpoints + 1];
-  for (i = 0; i < in->numberofpoints + 1; i++) worklist[i] = 0;
-  flip23s = flip32s = flip22s = flip44s = 0;
-
-  // Algorithm starts from here.
-  
-  // Construct an initial tetrahedralization and fill 'insertqueue'.
-  incrflipinit(insertqueue);
-
-  // Loop untill all points are inserted.
-  while (!insertqueue->empty()) {
-    pointloop = * (point *) insertqueue->pop();
-    // It will become a mesh point unless it duplicates an existing point.
-    setpointtype(pointloop, FREEVOLVERTEX);
-    // Try to insert the point first.
-    starttet.tet = (tetrahedron *) NULL;
-
-    // For STL, PLY, and OFF inputs. Merge very close points.
-    if (b->detectinter || (b->object == tetgenbehavior::STL) ||
-        (b->object == tetgenbehavior::PLY) ||
-        (b->object == tetgenbehavior::OFF) ||
-        (b->object == tetgenbehavior::MEDIT)) {
-      mergepoints(pointloop, &starttet, hulllink, worklist);
-    }
-
-    insres = insertsite(pointloop, &starttet, false, flipqueue);
-    if (insres == OUTSIDEPOINT) {
-      // Point locates outside the convex hull.
-      inserthullsite(pointloop, &starttet, flipqueue, hulllink, worklist);
-    } else if (insres == DUPLICATEPOINT) {
-      if (b->object != tetgenbehavior::STL) {
-        if (!b->quiet) {
-          printf("Warning:  Point %d is identical with point %d.\n",
-                 pointmark(pointloop), pointmark(org(starttet)));
-        }
-        // Count the number of duplicated points.
-        dupverts++;
-      }
-      // Remember it is a duplicated point.
-      setpointtype(pointloop, DUPLICATEDVERTEX);
-      if (b->plc || b->refine) {
-        // Set a pointer to the point it duplicates.
-        setpoint2pt(pointloop, org(starttet));
-      }
-    }
-    if (!b->noflip) {
-      // Call flip algorithm to recover Delaunayness.
-      flip(flipqueue, NULL, false, false, false); 
-    } else {
-      // Not perform flip.
-      flipqueue->clear();
+  // Create the DT of V by the 2D incremental flip algorithm.
+  incrflipdelaunaysub(shmark, eps, ptlist, holes, holelist, flipqueue);
+  // Recover boundary edges.
+  if (ptlist->len() > 3) {
+    // Insert segments into the DT.
+    for (i = 0; i < conlist->len(); i++) {
+      cons = (point *)(* conlist)[i];
+      recoversegment(cons[0], cons[1], flipqueue);        
+    }
+    // Carve holes and concavities.
+    carveholessub(holes, holelist, viri);
+  } else if (ptlist->len() == 3) {
+    // Insert 3 segments directly.
+    newsh.sh = dummysh;
+    newsh.shver = 0;
+    spivotself(newsh);
+    for (i = 0; i < 3; i++) {
+      insertsubseg(&newsh);
+      senextself(newsh);
     }
   }
-
-  if (!b->noflip && b->verbose) {
-    printf("  Total flips: %ld, where T23 %ld, T32 %ld, T22 %ld, T44 %ld\n",
-           flip23s + flip32s + flip22s + flip44s,
-           flip23s, flip32s, flip22s, flip44s);
-  }
-
-  delete flipqueue;
-  delete insertqueue;
-  delete hulllink;
-  delete [] worklist;
-
-  return hullsize;
 }
 
-//
-// End of incremental flip Delaunay triangulation routines
-//
-
-//
-// Begin of surface triangulation routines
-//
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// The lift points                                                           //
-//                                                                           //
-// A 'lifting point' of a facet is a point which lies exactly non-coplanar   //
-// with the plane containing that facet.  With such an additional point, the //
-// three-dimensional geometric predicates (orient3d, insphere) can be used   //
-// to substitute the lower dimensional predicates (orient2d, incircle). The  //
-// advantage is there is no need to project 3D points back into 2D, so the   //
-// rounding error can be avoid.                                              //
-//                                                                           //
-// These points are calculated during the initialization of triangulating    //
-// the facets. It is important to orient subfaces of the same facet to have  //
-// the same orientation with respect to its lift point. This way guarantees  //
-// the test results are consistent. We take the convention that the lift     //
-// point of a facet always lies above the CCW edge rings of subfaces of the  //
-// same facet. By this convention, given three points a, b, and c in a facet,//
-// we say c has the counterclockwise order with ab is corresponding to say   //
-// that c is below the plane abp, where p is the lift point.                 //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// locatesub()    Find a point in the surface mesh.                          //
-//                                                                           //
-// Searching begins from the input 'searchsh', it should be a handle on the  //
-// convex hull of the facet triangulation.                                   //
-//                                                                           //
-// If 'stopatseg' is nonzero, the search will stop if it tries to walk       //
-// through a subsegment, and will return OUTSIDE.                            //
+// retrievenewsubs()    Retrieve newly created subfaces.                     //
 //                                                                           //
-// On completion, 'searchsh' is a subface that contains 'searchpt'.          //
-//   - Returns ONVERTEX if the point lies on an existing vertex. 'searchsh'  //
-//     is a handle whose origin is the existing vertex.                      //
-//   - Returns ONEDGE if the point lies on a mesh edge.  'searchsh' is a     //
-//     handle whose primary edge is the edge on which the point lies.        //
-//   - Returns ONFACE if the point lies strictly within a subface.           //
-//     'searchsh' is a handle on which the point lies.                       //
-//   - Returns OUTSIDE if the point lies outside the triangulation.          //
+// The new subfaces created by triangulate() can be found by a broadth-first //
+// searching starting from 'dummysh[0]'.                                     //
 //                                                                           //
-// WARNING: This routine is designed for convex triangulations, and will not //
-// not generally work after the holes and concavities have been carved.      //
+// 'newshlist' (empty on input) returns the retrieved subfaces. Each edge on //
+// the hull is bound to 'dummysh' and protected by a segment. If 'removeseg' //
+// is TRUE, the segment is removed.                                          //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::locateresult tetgenmesh::
-locatesub(point searchpt, face* searchsh, int stopatseg)
+void tetgenmesh::retrievenewsubs(list* newshlist, bool removeseg)
 {
-  face backtracksh, spinsh, checkedge;
-  point forg, fdest, fapex, liftpoint;
-  REAL abovept[3], norm[3], nlen;
-  REAL orgori, destori, ori;
-  int moveleft, i;
-
-  if (searchsh->sh == dummysh) {
-    searchsh->shver = 0;
-    spivotself(*searchsh);
-    assert(searchsh->sh != dummysh);
-  }
-
-  // Set the liftpoint.
-  adjustedgering(*searchsh, CCW);
-  forg = sorg(*searchsh);
-  fdest = sdest(*searchsh);
-  fapex = sapex(*searchsh);
-  if (liftpointarray != (REAL *) NULL) {
-    // The liftpoint already exits. 
-    liftpoint = getliftpoint(shellmark(*searchsh));
-  } else {
-    // Calculate the liftpoint from the normal direction of searchsh.
-    facenormal(forg, fdest, fapex, norm, &nlen);
-    assert(nlen > 0.0);
-    for (i = 0; i < 3; i++) norm[i] /= nlen;
-    nlen = distance(forg, fdest);
-    for (i = 0; i < 3; i++) abovept[i] = forg[i] + nlen * norm[i];
-    liftpoint = abovept;
-  }
-  // Adjust the liftpoint be above the face.
-  orgori = orient3d(forg, fdest, fapex, liftpoint);
-  assert(orgori != 0.0);
-  if (orgori > 0.0) {
-    sesymself(*searchsh);
-  }
+  face startsh, neighsh;
+  face deadseg;
+  int i, j;
 
-  // Orient 'searchsh' so that 'searchpt' is below it (i.e., searchpt has
-  //   CCW orientation with respect to searchsh in plane).  Such edge
-  //   should always exist. Save it as (forg, fdest).
-  for (i = 0; i < 3; i++) {
-    forg = sorg(*searchsh);
-    fdest = sdest(*searchsh);
-    if (orient3d(forg, fdest, liftpoint, searchpt) > 0.0) break;
-    senextself(*searchsh);
-  }
-  assert(i < 3);
-  
-  while (1) {
-    fapex = sapex(*searchsh);
-    // Check whether the apex is the point we seek.
-    if (fapex[0] == searchpt[0] && fapex[1] == searchpt[1] &&
-        fapex[2] == searchpt[2]) {
-      senext2self(*searchsh);
-      return ONVERTEX;
-    }
-    // Does the point lie on the other side of the line defined by the
-    //   triangle edge opposite the triangle's destination?
-    destori = orient3d(forg, fapex, liftpoint, searchpt);
-    // Does the point lie on the other side of the line defined by the
-    //   triangle edge opposite the triangle's origin? 
-    orgori = orient3d(fapex, fdest, liftpoint, searchpt);
-    if (destori > 0.0) {
-      moveleft = 1;
-    } else {
-      if (orgori > 0.0) {
-        moveleft = 0;
+  // The first new subface is found at dummysh[0].
+  startsh.sh = dummysh;
+  startsh.shver = 0;
+  spivotself(startsh);
+  assert(startsh.sh != dummysh);
+  sinfect(startsh);
+  newshlist->append(&startsh);
+
+  // Find the rest of new subfaces by a broadth-first searching.
+  for (i = 0; i < newshlist->len(); i++) {
+    // Get a new subface s.
+    startsh = * (face *)(* newshlist)[i];
+    for (j = 0; j < 3; j++) {
+      spivot(startsh, neighsh);
+      if (neighsh.sh != dummysh) {
+        if (!sinfected(neighsh)) {
+          // Discovered a new subface.
+          sinfect(neighsh);
+          newshlist->append(&neighsh);
+        }
       } else {
-        // The point must be on the boundary of or inside this triangle.
-        if (destori == 0.0) {
-          senext2self(*searchsh);
-          return ONEDGE;
-        } 
-        if (orgori == 0.0) {
-          senextself(*searchsh);
-          return ONEDGE;
+        // Found a boundary edge. 
+        if (removeseg) {
+          // This side of s may be protected by a segment.
+          sspivot(startsh, deadseg);
+          if (deadseg.sh != dummysh) {
+            // Detach it from s.
+            ssdissolve(startsh);
+            // Delete the segment.
+            shellfacedealloc(subsegs, deadseg.sh);
+          }
         }
-        return ONFACE;
-      }
-    }
-    // Move to another triangle.  Leave a trace `backtracksh' in case
-    //   walking off a boundary of the triangulation.
-    if (moveleft) {
-      senext2(*searchsh, backtracksh);
-      fdest = fapex;
-    } else {
-      senext(*searchsh, backtracksh);
-      forg = fapex;
-    }
-    // Check if we meet a segment.
-    sspivot(backtracksh, checkedge);
-    if (checkedge.sh != dummysh) {
-      if (stopatseg) {
-        // The flag indicates we should not cross a segment. Stop.
-        *searchsh = backtracksh;
-        return OUTSIDE;
       }
-      // Try to walk through a segment. We need to find a coplanar subface
-      //   sharing this segment to get into.
-      spinsh = backtracksh;
-      do {
-        spivotself(spinsh);
-        if (spinsh.sh == backtracksh.sh) {
-          // Turn back, no coplanar subface is found.
-          break;
-        }
-        // Are they belong to the same facet.
-        if (shellmark(spinsh) == shellmark(backtracksh)) {
-          // Find a coplanar subface. Walk into it.
-          *searchsh = spinsh;
-          break;
-        }
-        // Are they (nearly) coplanar?
-        ori = orient3d(forg, fdest, sapex(backtracksh), sapex(spinsh));
-        if (iscoplanar(forg, fdest, sapex(backtracksh), sapex(spinsh), ori,
-                       b->epsilon)) {
-          // Find a coplanar subface. Walk into it.
-          *searchsh = spinsh;
-          break;
-        }
-      } while (spinsh.sh != backtracksh.sh);
-    } else {
-      spivot(backtracksh, *searchsh);
-    }
-    // Check for walking right out of the triangulation.
-    if ((searchsh->sh == dummysh) || (searchsh->sh == backtracksh.sh)) {
-      // Go back to the last triangle.
-      *searchsh = backtracksh;
-      return OUTSIDE;
-    }
-    // To keep the same orientation wrt. liftpoint.
-    // adjustedgering(*searchsh, CCW);
-    if (sorg(*searchsh) != forg) {
-      sesymself(*searchsh);
+      senextself(startsh);
     }
-    assert((sorg(*searchsh) == forg) && (sdest(*searchsh) == fdest));
+  }
+  for (i = 0; i < newshlist->len(); i++) {
+    startsh = * (face *)(* newshlist)[i];
+    suninfect(startsh);
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// adjustlocatesub()    Adjust the precise location of a vertex.             //
-//                                                                           //
-// 'precise' is the precise location (returned from locatesub()) of 'searcht'//
-// with respect to 'searchsh'. 'epspp' is the given relative tolerance.      //
-//                                                                           //
-// This routine re-evaluates the orientations of 'searchpt' with respect to  //
-// the three edges of 'searchsh'. Detects the collinearities by additinal    //
-// tests based on the given tolerance. If 'precise' is ONEDGE, one can save  //
-// one orientation test for the current edge of 'searchsh'.                  //
+// unifysegments()    Unify identical segments and build facet connections.  //
 //                                                                           //
-// On completion, 'searchsh' is a subface contains 'searchpt'. The returned  //
-// value indicates one of the following cases:                               //
-//   - Returns ONVERTEX if the point lies on an existing vertex. 'searchsh'  //
-//     is a handle whose origin is the existing vertex.                      //
-//   - Returns ONEDGE if the point lies on a mesh edge.  'searchsh' is a     //
-//     handle whose primary edge is the edge on which the point lies.        //
-//   - Returns ONFACE if the point lies strictly within a subface.           //
-//     'searchsh' is a handle on which the point lies.                       //
-//   - Returns OUTSIDE if the point lies outside 'searchsh'.                 //
+// After creating the surface mesh. Each facet has its own segments.  There  //
+// are duplicated segments between adjacent facets.  This routine has three  //
+// purposes:                                                                 //
+//   (1) identify the set of segments which have the same endpoints and      //
+//       unify them into one segment, remove redundant ones;                 //
+//   (2) create the face rings of the unified segments, hence setup the      //
+//       connections between facets; and                                     //
+//   (3) set a unique marker (1-based) for each segment.                     //
+// On finish, each segment is unique and the face ring around it (right-hand //
+// rule) is constructed. The connections between facets-facets are setup.    //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::locateresult tetgenmesh::
-adjustlocatesub(point searchpt, face* searchsh, enum locateresult precise,
-                REAL epspp)
+void tetgenmesh::unifysegments()
 {
-  point pa, pb, pc;
-  bool s1, s2, s3;
-
-  pa = sorg(*searchsh);
-  pb = sdest(*searchsh);
-  pc = sapex(*searchsh);
+  list *sfacelist;
+  shellface **facesperverlist;
+  face subsegloop, testseg;
+  face sface, sface1, sface2;
+  point torg, tdest;
+  REAL da1, da2;
+  int *idx2facelist;
+  int segmarker;
+  int idx, k, m;
 
-  if (precise == ONEDGE) {
-    s1 = true;
-  } else {
-    s1 = iscollinear(pa, pb, searchpt, epspp);
+  if (b->verbose > 0) {
+    printf("  Unifying segments.\n");
   }
-  s2 = iscollinear(pb, pc, searchpt, epspp);
-  s3 = iscollinear(pc, pa, searchpt, epspp);
-  if (s1) {
-    if (s2) {
-      // on vertex pb.
-      assert(!s3);
-      senextself(*searchsh);
-      return ONVERTEX;
-    } else if (s3) {
-      // on vertex pa.
-      return ONVERTEX;
-    } else {
-      // on edge pa->pb.
-      return ONEDGE;
+
+  // Compute a mapping from indices of vertices to subfaces.
+  makesubfacemap(idx2facelist, facesperverlist);
+  // Initialize 'sfacelist' for constructing the face link of each segment.
+  sfacelist = new list(sizeof(face), NULL); 
+  
+  segmarker = 1;
+  subsegs->traversalinit();
+  subsegloop.sh = shellfacetraverse(subsegs);
+  while (subsegloop.sh != (shellface *) NULL) {
+    subsegloop.shver = 0; // For sure.
+    torg = sorg(subsegloop);
+    tdest = sdest(subsegloop);
+    idx = pointmark(torg) - in->firstnumber;
+    // Loop through the set of subfaces containing 'torg'.  Get all the
+    //   subfaces containing the edge (torg, tdest). Save and order them
+    //   in 'sfacelist', the ordering is defined by the right-hand rule
+    //   with thumb points from torg to tdest.
+    for (k = idx2facelist[idx]; k < idx2facelist[idx + 1]; k++) {
+      sface.sh = facesperverlist[k];
+      sface.shver = 0;
+      // sface may be died due to the removing of duplicated subfaces.
+      if (!isdead(&sface) && isfacehasedge(&sface, torg, tdest)) {
+        // 'sface' contains this segment.
+        findedge(&sface, torg, tdest);
+        // Save it in 'sfacelist'.
+        if (sfacelist->len() < 2) {
+          sfacelist->append(&sface);
+        } else {
+          for (m = 0; m < sfacelist->len() - 1; m++) {
+            sface1 = * (face *)(* sfacelist)[m];
+            sface2 = * (face *)(* sfacelist)[m + 1];
+            da1 = facedihedral(torg, tdest, sapex(sface1), sapex(sface));
+            da2 = facedihedral(torg, tdest, sapex(sface1), sapex(sface2));
+            if (da1 < da2) {
+              break;  // Insert it after m.
+            }
+          }
+          sfacelist->insert(m + 1, &sface);
+        }
+      }
     }
-  } else if (s2) {
-    if (s3) {
-      // on vertex pc.
-      senext2self(*searchsh);
-      return ONVERTEX;
-    } else {
-      // on edge pb->pc.
-      senextself(*searchsh);
-      return ONEDGE;
+    if (b->verbose > 1) {
+      printf("    Identifying %d segments of (%d  %d).\n", sfacelist->len(),
+             pointmark(torg), pointmark(tdest));
+    }
+    // Set the connection between this segment and faces containing it,
+    //   at the same time, remove redundant segments.
+    for (k = 0; k < sfacelist->len(); k++) {
+      sface = *(face *)(* sfacelist)[k];
+      sspivot(sface, testseg);
+      // If 'testseg' is not 'subsegloop', it is a redundant segment that
+      //   needs be removed. BE CAREFUL it may already be removed. Do not
+      //   remove it twice, i.e., do test 'isdead()' together.
+      if ((testseg.sh != subsegloop.sh) && !isdead(&testseg)) {
+        shellfacedealloc(subsegs, testseg.sh);
+      }
+      // 'ssbond' bonds the subface and the segment together, and dissloves
+      //   the old bond as well.
+      ssbond(sface, subsegloop);
     }
-  } else if (s3) {
-    // on edge pc->pa.
-    senext2self(*searchsh);
-    return ONEDGE;
-  } else {
-    return precise;
+    // Set connection between these faces.
+    sface = *(face *)(* sfacelist)[0];
+    for (k = 1; k <= sfacelist->len(); k++) {
+      if (k < sfacelist->len()) {
+        sface1 = *(face *)(* sfacelist)[k];
+      } else {
+        sface1 = *(face *)(* sfacelist)[0];    // Form a face loop.
+      }
+      /*
+      // Check if these two subfaces are the same. It is possible when user
+      //   defines one facet (or polygon) two or more times. If they are,
+      //   they should not be bonded together, instead of that, one of them
+      //   should be delete from the surface mesh.
+      if ((sfacelist->len() > 1) && sapex(sface) == sapex(sface1)) {
+        // They are duplicated faces.
+        if (b->verbose > 0) {
+          printf("  A duplicated subface (%d, %d, %d) is removed.\n",
+                 pointmark(torg), pointmark(tdest), pointmark(sapex(sface)));
+        }
+        if (k == sfacelist->len()) {
+          // 'sface' is the last face, however, it is same as the first one.
+          //   In order to form the ring, we have to let the second last
+          //   face bond to the first one 'sface1'.
+          shellfacedealloc(subfaces, sface.sh);
+          assert(sfacelist->len() >= 2);
+          assert(k == sfacelist->len());
+          sface = *(face *)(* sfacelist)[k - 2];
+        } else {
+          // 'sface1' is in the middle and may be the last one. 
+          shellfacedealloc(subfaces, sface1.sh);
+          // Skip this face and go to the next one.
+          continue;
+        }
+      }
+      */ 
+      if (b->verbose > 2) {
+        printf("    Bond subfaces (%d, %d, %d) and (%d, %d, %d).\n",
+               pointmark(torg), pointmark(tdest), pointmark(sapex(sface)),
+               pointmark(torg), pointmark(tdest), pointmark(sapex(sface1)));
+      }
+      sbond1(sface, sface1);
+      sface = sface1;
+    }
+    // Set the unique segment marker into the unified segment.
+    setshellmark(subsegloop, segmarker);
+    // Increase the marker.
+    segmarker++;
+    // Clear the working list.
+    sfacelist->clear(); 
+    subsegloop.sh = shellfacetraverse(subsegs);
   }
+
+  delete [] idx2facelist;
+  delete [] facesperverlist;
+  delete sfacelist;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// flipsub()    Flip all non-Delaunay edges in a given queue of subfaces.    //
+// mergefacets()    Merge adjacent facets to be one facet if they are        //
+//                  coplanar and have the same boundary marker.              //
 //                                                                           //
-// Assumpation:  Current triangulation is non-Delaunay after inserting a     //
-// point or performing a flip operation, all possibly non-Delaunay edges are //
-// in 'facequeue'. The return value is the total number of flips done during //
-// this invocation.                                                          //
+// 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.                                    //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-long tetgenmesh::flipsub(queue* flipqueue)
+void tetgenmesh::mergefacets(queue* flipqueue)
 {
-  badface *qedge;
-  face flipedge, symedge, bdedge;
-  point pa, pb, pc, pd;
-  REAL liftpt[3], n[3], nlen;
-  REAL sign, ll, d1, d2;
-  int edgeflips, i;
+  face parentsh, neighsh, neineighsh;
+  face segloop;
+  point eorg, edest;
+  REAL ori;
+  bool mergeflag, pbcflag;
+  int* segspernodelist;
+  int fidx1, fidx2;
+  int i, j;
 
-  if (b->verbose > 1) {
-    printf("  Start do edge queue: %ld edges.\n", flipqueue->len());
+  if (b->verbose > 0) {
+    printf("  Merging coplanar facets.\n");
   }
+  // Create and initialize 'segspernodelist'.
+  segspernodelist = new int[points->items + 1];
+  for (i = 0; i < points->items + 1; i++) segspernodelist[i] = 0;
 
-  edgeflips = 0;
-
-  while ((qedge = (badface *) flipqueue->pop()) != NULL) {
-    flipedge = qedge->ss;
-    if (flipedge.sh == dummysh) continue;
-    if ((sorg(flipedge) != qedge->forg) || 
-        (sdest(flipedge) != qedge->fdest)) continue; 
-    sspivot(flipedge, bdedge);
-    if (bdedge.sh != dummysh) continue;  // Can't flip a subsegment.
-    spivot(flipedge, symedge);
-    if (symedge.sh == dummysh) continue; // Can't flip a hull edge.
-    pa = sorg(flipedge);
-    pb = sdest(flipedge);
-    pc = sapex(flipedge);
-    pd = sapex(symedge);
-    // liftpoint = getliftpoint(shellmark(flipedge));
-    // If abc is nearly collinear, orient3d() test may return wrong value.
-    //   Choose abc or abd when it has the bigger area than the other.
-    d1 = shortdistance(pc, pa, pb);
-    d2 = shortdistance(pd, pa, pb);
-    ll = distance(pa, pb);
-    if (d1 > d2) {
-      // Use abc as the base.
-      facenormal(pa, pb, pc, n, &nlen);
-      for (i = 0; i < 3; i++) n[i] /= nlen;
-      for (i = 0; i < 3; i++) liftpt[i] = pa[i] + ll * n[i];
-      // liftpt is above abc;
-      sign = insphere(pb, pa, pc, liftpt, pd);
-    } else {
-      // Use abd as the base.
-      facenormal(pa, pb, pd, n, &nlen);
-      for (i = 0; i < 3; i++) n[i] /= nlen;
-      for (i = 0; i < 3; i++) liftpt[i] = pa[i] + ll * n[i];
-      // liftpt is above abd;
-      sign = insphere(pb, pa, pd, liftpt, pc);
+  // Loop the segments, counter the number of segments sharing each vertex.
+  subsegs->traversalinit();
+  segloop.sh = shellfacetraverse(subsegs);
+  while (segloop.sh != (shellface *) NULL) {
+    // Increment the number of sharing segments for each endpoint.
+    for (i = 0; i < 2; i++) {
+      j = pointmark((point) segloop.sh[3 + i]);
+      segspernodelist[j]++;
     }
-    if (sign > 0.0) {
-      // Flip the non-Delaunay edge.
-      flip22sub(&flipedge, flipqueue);
-      edgeflips++;
+    segloop.sh = shellfacetraverse(subsegs);
+  }
+
+  // Loop the segments, find out dead segments.
+  subsegs->traversalinit();
+  segloop.sh = shellfacetraverse(subsegs);
+  while (segloop.sh != (shellface *) NULL) {
+    eorg = sorg(segloop);
+    edest = sdest(segloop);
+    spivot(segloop, parentsh);
+    spivot(parentsh, neighsh);
+    spivot(neighsh, neineighsh);
+    if (parentsh.sh != neighsh.sh && parentsh.sh == neineighsh.sh) {
+      // Exactly two subfaces at this segment.
+      fidx1 = shellmark(parentsh) - 1;
+      fidx2 = shellmark(neighsh) - 1;
+      pbcflag = false;
+      if (checkpbcs) {
+        pbcflag = (shellpbcgroup(parentsh) >= 0)
+          || (shellpbcgroup(neighsh) >= 0);
+      }
+      // Possibly merge them if they are not in the same facet.
+      if ((fidx1 != fidx2) && !pbcflag) {
+        // Test if they are coplanar.
+        ori = orient3d(eorg, edest, sapex(parentsh), sapex(neighsh));
+        if (ori != 0.0) {
+          if (iscoplanar(eorg, edest, sapex(parentsh), sapex(neighsh), ori,
+                         b->epsilon)) {
+            ori = 0.0; // They are assumed as coplanar.
+          }
+        }
+        if (ori == 0.0) {
+          mergeflag = (in->facetmarkerlist == (int *) NULL || 
+          in->facetmarkerlist[fidx1] == in->facetmarkerlist[fidx2]);
+          if (mergeflag) {
+            // This segment becomes dead.
+            if (b->verbose > 1) {
+              printf("  Removing segment (%d, %d).\n", pointmark(eorg),
+                     pointmark(edest));
+            }
+            ssdissolve(parentsh);
+            ssdissolve(neighsh);
+            shellfacedealloc(subsegs, segloop.sh);
+            j = pointmark(eorg);
+            segspernodelist[j]--;
+            if (segspernodelist[j] == 0) {
+              setpointtype(eorg, FACETVERTEX);
+            }
+            j = pointmark(edest);
+            segspernodelist[j]--;
+            if (segspernodelist[j] == 0) {
+              setpointtype(edest, FACETVERTEX);
+            }
+            // Add 'parentsh' to queue checking for flip.
+            enqueueflipedge(parentsh, flipqueue);
+          }
+        }
+      }
     }
+    segloop.sh = shellfacetraverse(subsegs);
   }
 
-  if (b->verbose > 1) {
-    printf("  Total %d flips.\n", edgeflips);
+  if (!flipqueue->empty()) {
+    // Restore the Delaunay property in the facet triangulation.
+    flipsub(flipqueue);
   }
 
-  return edgeflips;
+  delete [] segspernodelist;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// incrflipinitsub()    Create a initial triangulation.                      //
+// meshsurface()    Create the surface mesh of a PLC.                        //
+//                                                                           //
+// Let X be the PLC, the surface mesh S of X consists of triangulated facets.//
+// S is created mainly in the following steps:                               //
 //                                                                           //
-// The initial triangulation only consists of one triangle formed by three   //
-// non-collinear points. 'facetidx' is the index of the facet in 'facetlist' //
-// (starts from 1) of the tetgenio structure;  'ptlist' is a list of indices //
-// of the facet vertices; 'idx2verlist' is a map from indices to vertices.   //
+// (1) Form the CDT of each facet of X separately (by routine triangulate()).//
+// After it is done, the subfaces of each facet are connected to each other, //
+// however there is no connection between facets yet.  Notice each facet has //
+// its own segments, some of them are duplicated.                            //
 //                                                                           //
-// The 'lift point' of this facet is calculated.  If not all vertices of the //
-// facet are collinear,  such point is found by lifting the centroid of the  //
-// set of vertices for a certain distance along the normal of this facet.    //
+// (2) Remove the redundant segments created in step (1) (by routine unify-  //
+// segment()). The subface ring of each segment is created,  the connection  //
+// between facets are established as well.                                   //
+//                                                                           //
+// The return value indicates the number of segments of X.                   //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::
-incrflipinitsub(int facetidx, list* ptlist, point* idx2verlist)
+long tetgenmesh::meshsurface()
 {
-  face newsh;
-  point pt1, pt2, pt3;
-  point liftpoint, ptloop;
-  pbcdata *pd;
-  REAL cent[3], norm[3];
-  REAL v1[3], v2[3];
-  REAL smallcos, cosa;
-  REAL liftdist, len, vol;
-  int idx, smallidx;
-  int i, j;
+  list *ptlist, *conlist;
+  queue *flipqueue;
+  tetgenio::facet *f;
+  tetgenio::polygon *p;
+  memorypool *viri;
+  point *idx2verlist;
+  point tstart, tend, *cons;
+  int *worklist;
+  int end1, end2;
+  int shmark, i, j;
+
+  if (!b->quiet) {
+    printf("Creating surface mesh.\n");
+  }
+
+  // Compute a mapping from indices to points.
+  makeindex2pointmap(idx2verlist);
+  // Compute a mapping from points to tets for computing abovepoints.
+  makepoint2tetmap();
+  // Initialize 'facetabovepointarray'.
+  facetabovepointarray = new point[in->numberoffacets + 1];
+  for (i = 0; i < in->numberoffacets + 1; i++) {
+    facetabovepointarray[i] = (point) NULL;
+  }
+  if (checkpbcs) {
+    // Initialize the global array 'subpbcgrouptable'.
+    createsubpbcgrouptable();
+  }
+
+  // Initialize working lists.
+  viri = new memorypool(sizeof(shellface *), 1024, POINTER, 0);
+  flipqueue = new queue(sizeof(badface));
+  ptlist = new list(sizeof(point *), NULL, 256);
+  conlist = new list(sizeof(point *) * 2, NULL, 256);
+  worklist = new int[points->items + 1];
+  for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
   
-  if (ptlist->len() > 3) {
-    // Find a (non-degenerate) vector from the vertex set.
-    idx =  * (int *) (* ptlist)[0];
-    pt1 = idx2verlist[idx - in->firstnumber];
-    len = 0.0;
-    // Loop the set of vertices until a not too small edge be found.
-    for (i = 1; i < ptlist->len(); i++) {
-      idx =  * (int *) (* ptlist)[i];
-      pt2 = idx2verlist[idx - in->firstnumber];
-      v1[0] = pt2[0] - pt1[0];
-      v1[1] = pt2[1] - pt1[1];
-      v1[2] = pt2[2] - pt1[2];
-      len = sqrt(dot(v1, v1));
-      if ((len / longest) > (b->epsilon * 1e+2)) break;
-    } 
-    // Remember this size as lift distance.
-    liftdist = len;
-    // 'v1' is a reasonable vector, normalize it.
-    for (i = 0; i < 3; i++) v1[i] /= len;
-    // Continue to find another (non-degenerate) vector, which forms an
-    //   angle with v1 most close to 90 degree.
-    smallcos = 1.0; // The cosine value of 0 degree.
-    for (i = 1; i < ptlist->len(); i++) {
-      idx =  * (int *) (* ptlist)[i];
-      pt3 = idx2verlist[idx - in->firstnumber];
-      if (pt3 == pt2) continue; // Skip the same point.
-      v2[0] = pt3[0] - pt1[0];
-      v2[1] = pt3[1] - pt1[1];
-      v2[2] = pt3[2] - pt1[2];
-      len = sqrt(dot(v2, v2));
-      if (len > 0.0) { // v2 is not too small.
-        cosa = fabs(dot(v1, v2)) / len;
-        if (cosa < smallcos) {
-          smallidx = idx;
-          smallcos = cosa;
-        }
-      } else {  // len == 0.0, two identical points defined in a facet.
-        printf("Warning:  Facet %d has two identical vertices: %d, %d.\n",
-               facetidx, pointmark(pt1), pointmark(pt3));
-        return false; // Invalid polygon, do not procced.
-      }
-    }
-    if (smallcos == 1.0) {
-      // The input set of vertices is not a good set (or nearly degenerate).
-      printf("Warning:  Facet %d with vertices: ", facetidx);
-      for (i = 0; i < 3; i++) {
-        idx =  * (int *) (* ptlist)[i];
-        ptloop = idx2verlist[idx - in->firstnumber];
-        printf("%d ", pointmark(ptloop));
-      }
-      printf("... is degenerate.\n");
-      return false; // Invalid polygon, do not procced.
-    }
-    // Get the right point to form v2.
-    pt3 = idx2verlist[smallidx - in->firstnumber];
-    assert(pt3 != pt2);
-    v2[0] = pt3[0] - pt1[0];
-    v2[1] = pt3[1] - pt1[1];
-    v2[2] = pt3[2] - pt1[2];
-    len = sqrt(dot(v2, v2));
-    assert(len > 0.0);
-    // Remember this size as lift distance.
-    liftdist = (liftdist > len ? liftdist : len);
-    // 'v2' is a reasonable vector, normalize it.
-    for (i = 0; i < 3; i++) v2[i] /= len;
-  } else { 
-    // There are only three vertices of this facet (a triangle).
-    idx =  * (int *) (* ptlist)[0];
-    pt1 = idx2verlist[idx - in->firstnumber];
-    idx =  * (int *) (* ptlist)[1];
-    pt2 = idx2verlist[idx - in->firstnumber];
-    idx =  * (int *) (* ptlist)[2];
-    pt3 = idx2verlist[idx - in->firstnumber];
-    v1[0] = pt2[0] - pt1[0];
-    v1[1] = pt2[1] - pt1[1];
-    v1[2] = pt2[2] - pt1[2];
-    len = sqrt(dot(v1, v1));
-    if (len == 0.0) {
-      printf("Warning:  Facet %d has two identical vertices: %d, %d.\n",
-             facetidx, pointmark(pt1), pointmark(pt2));
-      return false; // Invalid polygon, do not procced.
-    }
-    // Remember this size as lift distance.
-    liftdist = len;
-    // 'v1' is a reasonable vector, normalize it.
-    for (i = 0; i < 3; i++) v1[i] /= len;
-    v2[0] = pt3[0] - pt1[0];
-    v2[1] = pt3[1] - pt1[1];
-    v2[2] = pt3[2] - pt1[2];
-    len = sqrt(dot(v2, v2));
-    if (len == 0.0) {
-      printf("Warning:  Facet %d has two identical vertices: %d, %d.\n",
-             facetidx, pointmark(pt1), pointmark(pt3));
-      return false; // Invalid polygon, do not procced.
-    }
-    // Remember this size as lift distance.
-    liftdist = (liftdist > len ? liftdist : len);
-    // 'v2' is a reasonable vector, normalize it.
-    for (i = 0; i < 3; i++) v2[i] /= len;
-  }
-  // Calculate the unit normal of this facet.
-  cross(v1, v2, norm);
-
-  // Calculate the centroid point of the vertex set. At the same time, check
-  //   whether vertices of this facet are roughly coplanar or not.
-  cent[0] = cent[1] = cent[2] = 0.0;
-  for (i = 0; i < ptlist->len(); i++) {
-    idx =  * (int *) (* ptlist)[i];
-    ptloop = idx2verlist[idx - in->firstnumber];
-    if (ptlist->len() > 3) {
-      vol = orient3d(pt1, pt2, pt3, ptloop);
-      if (vol != 0.0) {
-        if (!iscoplanar(pt1, pt2, pt3, ptloop, vol, b->epsilon * 1e+3)) {
-          printf("Warning:  Facet %d has a non-coplanar vertex %d.\n",
-                 facetidx, pointmark(ptloop));
-          // This is not a fatal problem, we still can procced.
-        }
-      }
-    }
-    cent[0] += ptloop[0];
-    cent[1] += ptloop[1];
-    cent[2] += ptloop[2];
-  }
-  for (i = 0; i < 3; i++) cent[i] /= ptlist->len();
-  // Calculate the lifting point of the facet. It is lifted from 'cent'
-  //   along the normal direction with a certain ditance.
-  liftpoint = getliftpoint(facetidx); 
-  for (i = 0; i < 3; i++) {
-    liftpoint[i] = cent[i] + liftdist * norm[i];
+  // Loop the facet list, triangulate each facet. On finish, all subfaces
+  //   are in 'subfaces', all segments are in 'subsegs'. Notice: there're
+  //   redundant segments.  Remember: All facet indices count from 1.
+  for (shmark = 1; shmark <= in->numberoffacets; shmark++) {    
+    // Get a facet F.
+    f = &in->facetlist[shmark - 1];
+
+    // Process the duplicated points first, they are marked with type
+    //   DUPLICATEDVERTEX by incrflipdelaunay().  Let p and q are dup.
+    //   and the index of p is larger than q's, p is substituted by q.
+    //   In a STL mesh, duplicated points are implicitly included.
+    if ((b->object == tetgenbehavior::STL) || dupverts) {
+      // Loop all polygons of this facet.
+      for (i = 0; i < f->numberofpolygons; i++) {
+        p = &(f->polygonlist[i]);
+        // Loop other vertices of this polygon.
+        for (j = 0; j < p->numberofvertices; j++) {
+          end1 = p->vertexlist[j];
+          tstart = idx2verlist[end1 - in->firstnumber];
+          if (pointtype(tstart) == DUPLICATEDVERTEX) {
+            // Reset the index of vertex-j.
+            tend = point2ppt(tstart);
+            end2 = pointmark(tend);
+            p->vertexlist[j] = end2;
+          }
+        }
+      }
+    }
+
+    // Loop polygons of F, get the set V of vertices and S of segments.
+    for (i = 0; i < f->numberofpolygons; i++) {
+      // Get a polygon.
+      p = &(f->polygonlist[i]);
+      // Get the first vertex.
+      end1 = p->vertexlist[0];
+      if ((end1 < in->firstnumber) || 
+          (end1 >= in->firstnumber + in->numberofpoints)) {
+        if (!b->quiet) {
+          printf("Warning:  Invalid the 1st vertex %d of polygon", end1);
+          printf(" %d in facet %d.\n", i + 1, shmark);
+        }
+        continue; // Skip this polygon.
+      }
+      tstart = idx2verlist[end1 - in->firstnumber];
+      // Add tstart to V if it haven't been added yet.
+      if (worklist[end1] == 0) {
+        ptlist->append(&tstart);
+        worklist[end1] = 1;
+      }
+      // Loop other vertices of this polygon.
+      for (j = 1; j <= p->numberofvertices; j++) {
+        // get a vertex.
+        if (j < p->numberofvertices) {
+          end2 = p->vertexlist[j];
+        } else {
+          end2 = p->vertexlist[0];  // Form a loop from last to first.
+        }
+        if ((end2 < in->firstnumber) ||
+            (end2 >= in->firstnumber + in->numberofpoints)) {
+          if (!b->quiet) {
+            printf("Warning:  Invalid vertex %d in polygon %d", end2, i + 1);
+            printf(" in facet %d.\n", shmark);
+          }
+        } else {
+          if (end1 != end2) {
+            // 'end1' and 'end2' form a segment.
+            tend = idx2verlist[end2 - in->firstnumber];
+            // Add tstart to V if it haven't been added yet.
+            if (worklist[end2] == 0) {
+              ptlist->append(&tend);
+              worklist[end2] = 1;
+            }
+            // Save the segment in S (conlist).
+            cons = (point *) conlist->append(NULL);
+            cons[0] = tstart;
+            cons[1] = tend;
+            // Set the start for next continuous segment.
+            end1 = end2;
+            tstart = tend;
+          } else {
+            // Two identical vertices represent an isolated vertex of F.
+            if (p->numberofvertices > 2) {
+              // This may be an error in the input, anyway, we can continue
+              //   by simply skipping this segment.
+              if (!b->quiet) {
+                printf("Warning:  Polygon %d has two identical verts", i + 1);
+                printf(" in facet %d.\n", shmark);
+              }
+            } 
+            // Ignore this vertex.
+          } 
+        }
+        // Is the polygon degenerate (a segment or a vertex)?
+        if (p->numberofvertices == 2) break;
+      } 
+    }
+    // Unmark vertices.
+    for (i = 0; i < ptlist->len(); i++) {
+      tstart = * (point *)(* ptlist)[i];
+      end1 = pointmark(tstart);
+      assert(worklist[end1] == 1);
+      worklist[end1] = 0;
+    }
+
+    // Create a CDT of F.
+    triangulate(shmark, b->epsilon * 1e+2, ptlist, conlist, f->numberofholes,
+                f->holelist, viri, flipqueue);
+    // Clear working lists.
+    ptlist->clear();
+    conlist->clear();
+    viri->restart();
+  }
+
+  // Unify segments in 'subsegs', remove redundant segments.  Face links
+  //   of segments are also built.
+  unifysegments();
+
+  if (checkpbcs) {
+    // Create the global array 'segpbcgrouptable'.
+    createsegpbcgrouptable();
+  }
+
+  if (b->object == tetgenbehavior::STL) {
+    // Remove redundant vertices (for .stl input mesh).
+    jettisonnodes();
   }
 
-  // Create the initial triangle. The liftpoint is above (pt1, pt2, pt3).
-  makeshellface(subfaces, &newsh);
-  setsorg(newsh, pt1);
-  setsdest(newsh, pt2);
-  setsapex(newsh, pt3);
-  // Remeber the facet it belongs to.
-  setshellmark(newsh, facetidx);
-  // Set vertices be type FACETVERTEX to indicate they belong to a facet.
-  setpointtype(pt1, FACETVERTEX);
-  setpointtype(pt2, FACETVERTEX);
-  setpointtype(pt3, FACETVERTEX);
-  // Bond this subface to 'dummysh' for point location routine.
-  dummysh[0] = sencode(newsh);
-
-  // Is there pbc conditions?
-  if (checkpbcs) {
-    // Get the facet marker (saved in 'in->facetmarkerlist').
-    idx = in->facetmarkerlist[facetidx - 1];
-    for (i = 0; i < in->numberofpbcgroups; i++) {
-      pd = &subpbcgrouptable[i];
-      for (j = 0; j < 2; j++) {
-        if (pd->fmark[j] == idx) {
-          setshellpbcgroup(newsh, i);
-          pd->ss[j] = newsh;
-        }
-      }
-    }
+  if (!b->nomerge && !checkpbcs) {
+    // No '-M' switch - merge adjacent facets if they are coplanar.
+    mergefacets(flipqueue);
   }
 
-  return true;
+  delete [] idx2verlist;
+  delete [] worklist;
+  delete ptlist;
+  delete conlist;
+  delete flipqueue;
+  delete viri;
+
+  return subsegs->items;
 }
 
+//
+// End of surface triangulation routines
+//
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// collectvisiblesubs()    Collect convex hull edges which are visible from  //
-//                         the inserting point. Construct new subfaces from  //
-//                         these edges and the point.                        //
+// interecursive()    Recursively do intersection test on a set of triangles.//
 //                                                                           //
-// 'facetidx' is the index of the facet in 'in->facetlist' (starts from 1),  //
-// 'inspoint' is located outside current triangulation, 'horiz' is the hull  //
-// edge it is visible. 'flipqueue' returns the visible hull edges which have //
-// become interior edges on completion of this routine.                      //
+// Recursively split the set 'subfacearray' of subfaces into two sets using  //
+// a cut plane parallel to x-, or, y-, or z-axies.  The split criteria are   //
+// follows. Assume the cut plane is H, and H+ denotes the left halfspace of  //
+// H, and H- denotes the right halfspace of H; and s be a subface:           //
+//                                                                           //
+//    (1) If all points of s lie at H+, put it into left array;              //
+//    (2) If all points of s lie at H-, put it into right array;             //
+//    (3) If some points of s lie at H+ and some of lie at H-, or some       //
+//        points lie on H, put it into both arraies.                         //
+//                                                                           //
+// Partitions by x-axis if axis == '0'; by y-axis if axis == '1'; by z-axis  //
+// if axis == '2'. If current cut plane is parallel to the x-axis, the next  //
+// one will be parallel to y-axis, and the next one after the next is z-axis,//
+// and then alternately return back to x-axis.                               //
+//                                                                           //
+// Stop splitting when the number of triangles of the input array is not     //
+// decreased anymore. Do tests on the current set.                           //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 void tetgenmesh::
-collectvisiblesubs(int facetidx, point inspoint, face* horiz, queue* flipqueue)
+interecursive(shellface** subfacearray, int arraysize, int axis, REAL bxmin,
+              REAL bxmax, REAL bymin, REAL bymax, REAL bzmin, REAL bzmax,
+              int* internum)
 {
-  face newsh, hullsh;
-  face rightsh, leftsh, spinedge;
-  point horg, hdest, liftpoint;
-  bool aboveflag;
+  shellface **leftarray, **rightarray;
+  face sface1, sface2;
+  point p1, p2, p3;
+  point p4, p5, p6;
+  enum interresult intersect;
+  REAL split;
+  bool toleft, toright;
+  int leftsize, rightsize;
+  int i, j;
 
-  liftpoint = getliftpoint(facetidx); 
+  if (b->verbose > 1) {
+    printf("  Recur %d faces. Bbox (%g, %g, %g),(%g, %g, %g). %s-axis\n",
+           arraysize, bxmin, bymin, bzmin, bxmax, bymax, bzmax,
+           axis == 0 ? "x" : (axis == 1 ? "y" : "z"));
+  }
+    
+  leftarray = new shellface*[arraysize];
+  if (leftarray == NULL) {
+    printf("Error in interecursive():  Insufficient memory.\n");
+    terminatetetgen(1);
+  }
+  rightarray = new shellface*[arraysize];
+  if (rightarray == NULL) {
+    printf("Error in interecursive():  Insufficient memory.\n");
+    terminatetetgen(1);
+  }
+  leftsize = rightsize = 0;
 
-  // Create a new subface above 'horiz'.
-  adjustedgering(*horiz, CCW);
-  makeshellface(subfaces, &newsh);
-  setsorg(newsh, sdest(*horiz));
-  setsdest(newsh, sorg(*horiz));
-  setsapex(newsh, inspoint);
-  setshellmark(newsh, facetidx);
-  if (checkpbcs) {
-    setshellpbcgroup(newsh, shellpbcgroup(*horiz));
+  if (axis == 0) {
+    // Split along x-axis.
+    split = 0.5 * (bxmin + bxmax);
+  } else if (axis == 1) {
+    // Split along y-axis.
+    split = 0.5 * (bymin + bymax);
+  } else {
+    // Split along z-axis.
+    split = 0.5 * (bzmin + bzmax);
   }
-  // Make the connection.
-  sbond(newsh, *horiz);
-  // 'horiz' becomes interior edge.
-  enqueueflipedge(*horiz, flipqueue);
-  
-  // Finish the hull edges at the right side of the newsh.
-  hullsh = *horiz;
-  while (1) {
-    senext(newsh, rightsh);
-    // Get the right hull edge of 'horiz' by spinning inside edges around
-    //   the origin of 'horiz' until reaching the 'dummysh'.
-    spinedge = hullsh;
-    do {
-      hullsh = spinedge;
-      senext2self(hullsh);
-      spivot(hullsh, spinedge);
-      adjustedgering(spinedge, CCW);
-    } while (spinedge.sh != dummysh);
-    // Test whether 'inspoint' is visible from 'hullsh'.
-    horg = sorg(hullsh);
-    hdest = sdest(hullsh);
-    aboveflag = orient3d(horg, hdest, liftpoint, inspoint) < 0.0;
-    if (aboveflag) {
-      // It's a visible hull edge.
-      makeshellface(subfaces, &newsh);
-      setsorg(newsh, sdest(hullsh));
-      setsdest(newsh, sorg(hullsh));
-      setsapex(newsh, inspoint);
-      setshellmark(newsh, facetidx);
-      if (checkpbcs) {
-        setshellpbcgroup(newsh, shellpbcgroup(hullsh));
-      }
-      // Make the connection.
-      sbond(newsh, hullsh);
-      senext2(newsh, leftsh);
-      sbond(leftsh, rightsh);
-      // 'horiz' becomes interior edge.
-      enqueueflipedge(hullsh, flipqueue); 
+
+  for (i = 0; i < arraysize; i++) {
+    sface1.sh = subfacearray[i];
+    p1 = (point) sface1.sh[3];
+    p2 = (point) sface1.sh[4];
+    p3 = (point) sface1.sh[5];
+    toleft = toright = false;
+    if (p1[axis] < split) {
+      toleft = true;
+      if (p2[axis] >= split || p3[axis] >= split) {
+        toright = true;
+      } 
+    } else if (p1[axis] > split) {
+      toright = true;
+      if (p2[axis] <= split || p3[axis] <= split) {
+        toleft = true;
+      } 
     } else {
-      // 'rightsh' is a new hull edge.
-      dummysh[0] = sencode(rightsh);
-      break;
+      // p1[axis] == split;
+      toleft = true;
+      toright = true;
+    }
+    // At least one is true;
+#ifdef SELF_CHECK
+    assert(!(toleft == false && toright == false));
+#endif
+    if (toleft) {
+      leftarray[leftsize] = sface1.sh;
+      leftsize++;
+    }
+    if (toright) {
+      rightarray[rightsize] = sface1.sh;
+      rightsize++;
     }
   }
 
-  // Finish the hull edges at the left side of the newsh.
-  hullsh = *horiz;
-  spivot(*horiz, newsh);
-  while (1) {
-    senext2(newsh, leftsh);
-    // Get the left hull edge of 'horiz' by spinning edges around the
-    //   destination of 'horiz'.
-    spinedge = hullsh;
-    do {
-      hullsh = spinedge;
-      senextself(hullsh);
-      spivot(hullsh, spinedge);
-      adjustedgering(spinedge, CCW);
-    } while (spinedge.sh != dummysh);
-    // Test whether 'inspoint' is visible from 'hullsh'.
-    horg = sorg(hullsh);
-    hdest = sdest(hullsh);
-    aboveflag = orient3d(horg, hdest, liftpoint, inspoint) < 0.0;
-    if (aboveflag) {
-      // It's a visible hull edge.
-      makeshellface(subfaces, &newsh);
-      setsorg(newsh, sdest(hullsh));
-      setsdest(newsh, sorg(hullsh));
-      setsapex(newsh, inspoint);
-      setshellmark(newsh, facetidx);
-      if (checkpbcs) {
-        setshellpbcgroup(newsh, shellpbcgroup(hullsh));
-      }
-      // Make the connection.
-      sbond(newsh, hullsh);
-      senext(newsh, rightsh);
-      sbond(rightsh, leftsh);
-      // 'horiz' becomes interior edge.
-      enqueueflipedge(hullsh, flipqueue); 
+  if (leftsize < arraysize && rightsize < arraysize) {
+    // Continue to partition the input set. Now 'subfacearray' has been
+    //   split into two sets, it's memory can be freed. 'leftarray' and
+    //   'rightarray' will be freed in the next recursive (after they're
+    //   partitioned again or performing tests).
+    delete [] subfacearray;
+    // Continue to split these two sets.
+    if (axis == 0) {
+      interecursive(leftarray, leftsize, 1, bxmin, split, bymin, bymax,
+                    bzmin, bzmax, internum);
+      interecursive(rightarray, rightsize, 1, split, bxmax, bymin, bymax,
+                    bzmin, bzmax, internum);
+    } else if (axis == 1) {
+      interecursive(leftarray, leftsize, 2, bxmin, bxmax, bymin, split,
+                    bzmin, bzmax, internum);
+      interecursive(rightarray, rightsize, 2, bxmin, bxmax, split, bymax,
+                    bzmin, bzmax, internum);
     } else {
-      // 'leftsh' is a new hull edge.
-      dummysh[0] = sencode(leftsh);
-      break;
+      interecursive(leftarray, leftsize, 0, bxmin, bxmax, bymin, bymax,
+                    bzmin, split, internum);
+      interecursive(rightarray, rightsize, 0, bxmin, bxmax, bymin, bymax,
+                    split, bzmax, internum);
+    }
+  } else {
+    if (b->verbose > 1) {
+      printf("  Checking intersecting faces.\n");
+    }
+    // Perform a brute-force compare on the set.
+    for (i = 0; i < arraysize; i++) {
+      sface1.sh = subfacearray[i];
+      p1 = (point) sface1.sh[3];
+      p2 = (point) sface1.sh[4];
+      p3 = (point) sface1.sh[5];
+      for (j = i + 1; j < arraysize; j++) {
+        sface2.sh = subfacearray[j];
+        p4 = (point) sface2.sh[3];
+        p5 = (point) sface2.sh[4];
+        p6 = (point) sface2.sh[5];
+        intersect = tri_tri_inter(p1, p2, p3, p4, p5, p6);
+        if (intersect == INTERSECT || intersect == SHAREFACE) {
+          if (!b->quiet) {
+            if (intersect == INTERSECT) {
+              printf("  Facet #%d intersects facet #%d at triangles:\n",
+                     shellmark(sface1), shellmark(sface2));
+              printf("    (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
+                     pointmark(p1), pointmark(p2), pointmark(p3),
+                     pointmark(p4), pointmark(p5), pointmark(p6));
+            } else {
+              printf("  Facet #%d duplicates facet #%d at triangle:\n",
+                     shellmark(sface1), shellmark(sface2));
+              printf("    (%4d, %4d, %4d)\n", pointmark(p1), pointmark(p2),
+                     pointmark(p3));
+            }
+          }
+          // Increase the number of intersecting pairs.
+          (*internum)++; 
+          // Infect these two faces (although they may already be infected).
+          sinfect(sface1);
+          sinfect(sface2);
+        }
+      }
     }
+    // Don't forget to free all three arrays. No further partition.
+    delete [] leftarray;
+    delete [] rightarray;  
+    delete [] subfacearray;
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// incrflipdelaunaysub()    Create a Delaunay triangulation from a 3D point  //
-//                          set using the incremental flip algorithm.        //
+// detectinterfaces()    Detect intersecting triangles.                      //
+//                                                                           //
+// Given a set of triangles,  find the pairs of intersecting triangles from  //
+// them.  Here the set of triangles is in 'subfaces' which is a surface mesh //
+// of a PLC (.poly or .smesh).                                               //
+//                                                                           //
+// To detect whether two triangles are intersecting is done by the routine   //
+// 'tri_tri_inter()'.  The algorithm for the test is very simple and stable. //
+// It is based on geometric orientation test which uses exact arithmetics.   //
+//                                                                           //
+// Use divide-and-conquer algorithm for reducing the number of intersection  //
+// tests.  Start from the bounding box of the input point set, recursively   //
+// partition the box into smaller boxes, until the number of triangles in a  //
+// box is not decreased anymore. Then perform triangle-triangle tests on the //
+// remaining set of triangles.  The memory allocated in the input set is     //
+// freed immediately after it has been partitioned into two arrays.  So it   //
+// can be re-used for the consequent partitions.                             //
 //                                                                           //
-// 'facetidx' is the index of the facet in 'in->facetlist' (starts from 1),  //
-// 'ptlist' is the index list of the vertices of the facet, 'idx2verlist' is //
-// a map from indices to vertices.                                           //
+// On return, the pool 'subfaces' will be cleared, and only the intersecting //
+// triangles remain for output (to a .face file).                            //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-incrflipdelaunaysub(int facetidx, list* ptlist, point* idx2verlist,
-                    queue* flipqueue)
+void tetgenmesh::detectinterfaces()
 {
-  face startsh;
-  point pointloop;
-  enum locateresult loc;
-  int idx, i;  
+  shellface **subfacearray;
+  face shloop;
+  int internum;
+  int i;
 
-  for (i = 1; i < ptlist->len(); i++) {
-    idx =  * (int *) (* ptlist)[i];
-    pointloop = idx2verlist[idx - in->firstnumber];
-    // Set vertices be type FACETVERTEX to indicate they belong to a facet.
-    setpointtype(pointloop, FACETVERTEX);
-    startsh.sh = dummysh;
-    loc = locatesub(pointloop, &startsh, 0);
-    if (loc == ONVERTEX) continue;
-    if (loc == ONFACE) {
-      splitsubface(pointloop, &startsh, flipqueue);
-    } else if (loc == ONEDGE) {
-      splitsubedge(pointloop, &startsh, flipqueue);
-    } else if (loc == OUTSIDE) {
-      collectvisiblesubs(facetidx, pointloop, &startsh, flipqueue);
-    }
-    flipsub(flipqueue);
+  if (!b->quiet) {
+    printf("Detecting intersecting facets.\n");
   }
-}
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// finddirectionsub()    Find the first subface in a facet on the path from  //
-//                       one point to another.                               //
-//                                                                           //
-// Finds the subface in the facet that intersects a line segment drawn from  //
-// the origin of `searchsh' to the point `tend', and returns the result in   //
-// `searchsh'.  The origin of `searchsh' does not change,  even though the   //
-// subface returned may differ from the one passed in.                       //
-//                                                                           //
-// The return value notes whether the destination or apex of the found face  //
-// is collinear with the two points in question.                             //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
+  // Construct a map from indices to subfaces;
+  subfacearray = new shellface*[subfaces->items];
+  subfaces->traversalinit();
+  shloop.sh = shellfacetraverse(subfaces);
+  i = 0;
+  while (shloop.sh != (shellface *) NULL) {
+    subfacearray[i] = shloop.sh;
+    shloop.sh = shellfacetraverse(subfaces);
+    i++;
+  }
 
-enum tetgenmesh::finddirectionresult tetgenmesh::
-finddirectionsub(face* searchsh, point tend)
-{
-  face checksh;
-  point startpoint, liftpoint;
-  point leftpoint, rightpoint;
-  REAL leftccw, rightccw;
-  int leftflag, rightflag;
+  internum = 0;
+  // Recursively split the set of triangles into two sets using a cut plane
+  //   parallel to x-, or, y-, or z-axies.  Stop splitting when the number
+  //   of subfaces is not decreasing anymore. Do tests on the current set.
+  interecursive(subfacearray, subfaces->items, 0, xmin, xmax, ymin, ymax,
+                zmin, zmax, &internum);
 
-  adjustedgering(*searchsh, CCW);
-  liftpoint = getliftpoint(shellmark(*searchsh)); 
-  startpoint = sorg(*searchsh);
-  rightpoint = sdest(*searchsh);
-  leftpoint = sapex(*searchsh);
-  // Is `tend' to the left?
-  leftccw = orient3d(tend, startpoint, liftpoint, leftpoint);
-  leftflag = leftccw > 0.0;
-  // Is `tend' to the right?
-  rightccw = orient3d(startpoint, tend, liftpoint, rightpoint);
-  rightflag = rightccw > 0.0;
-  if (leftflag && rightflag) {
-    // `searchsh' faces directly away from `tend'.  We could go left or
-    //   right.  Ask whether it's a triangle or a boundary on the left.
-    senext2(*searchsh, checksh);
-    spivotself(checksh);
-    if (checksh.sh == dummysh) {
-      leftflag = 0;
+  if (!b->quiet) {
+    if (internum > 0) {
+      printf("\n!! Found %d pairs of faces are intersecting.\n\n", internum);
     } else {
-      rightflag = 0;
-    }
-  }
-  while (leftflag) {
-    // Turn left until satisfied.
-    senext2self(*searchsh);
-    spivotself(*searchsh);
-    if (searchsh->sh == dummysh) {
-      printf("Internal error in finddirectionsub():  Unable to find a\n");
-      printf("  triangle leading from %d to %d.\n", pointmark(startpoint),
-             pointmark(tend));
-      internalerror();
+      printf("\nNo faces are intersecting.\n\n");
     }
-    adjustedgering(*searchsh, CCW);
-    leftpoint = sapex(*searchsh);
-    rightccw = leftccw;
-    leftccw = orient3d(tend, startpoint, liftpoint, leftpoint);
-    leftflag = leftccw > 0.0;
   }
-  while (rightflag) {
-    // Turn right until satisfied.
-    spivotself(*searchsh);
-    if (searchsh->sh == dummysh) {
-      printf("Internal error in finddirectionsub():  Unable to find a\n");
-      printf("  triangle leading from %d to %d.\n", pointmark(startpoint),
-             pointmark(tend));
-      internalerror();
+
+  if (internum > 0) {
+    // Traverse all subfaces, deallocate those have not been infected (they
+    //   are not intersecting faces). Uninfect those have been infected.
+    //   After this loop, only intersecting faces remain.
+    subfaces->traversalinit();
+    shloop.sh = shellfacetraverse(subfaces);
+    while (shloop.sh != (shellface *) NULL) {
+      if (sinfected(shloop)) {
+        suninfect(shloop);
+      } else {
+        shellfacedealloc(subfaces, shloop.sh);
+      }
+      shloop.sh = shellfacetraverse(subfaces);
     }
-    adjustedgering(*searchsh, CCW);
-    senextself(*searchsh);
-    rightpoint = sdest(*searchsh);
-    leftccw = rightccw;
-    rightccw = orient3d(startpoint, tend, liftpoint, rightpoint);
-    rightflag = rightccw > 0.0;
-  }
-  if (leftccw == 0.0) {
-    return LEFTCOLLINEAR;
-  } else if (rightccw == 0.0) {
-    return RIGHTCOLLINEAR;
   } else {
-    return ACROSSEDGE;
+    // Deallocate all subfaces.
+    subfaces->restart();
   }
 }
 
+//
+// Begin of periodic boundary condition routines
+//
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// insertsubseg()    Create a subsegment and insert it between two subfaces. //
+// createsubpbcgrouptable()    Create the 'subpbcgrouptable'.                //
 //                                                                           //
-// The new subsegment is inserted at the edge described by the handle 'tri'. //
-// If 'tri' is not on the hull, the segment is inserted between two faces.   //
-// If 'tri' is a hull face, the initial face ring of this segment will be    //
-// set only one face which is self-bonded.  The official face ring will be   //
-// constructed later in routine unifysegments().                             //
+// Allocate the memory for 'subpbcgrouptable'.  Each entry i (a pbcdata) of  //
+// the table represents a pbcgroup.  Most of the fields of a group-i are set //
+// in this routine. 'fmark[0]', 'fmark[1]', and 'transmat[0]' are directly   //
+// copied from the corresponding data of 'in->numberofpbcgroups'. 'transmat  //
+// [1]' is calculated as the inverse matrix of 'transmat[0]'.  'ss[0]' and   //
+// 'ss[1]' are initilized be 'dummysh'. They are set in 'trangulatefacet()'  //
+// (when -p is in use) or 'reconstructmesh()' (when -r is in use).           //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::insertsubseg(face* tri)
+void tetgenmesh::createsubpbcgrouptable()
 {
-  face oppotri;
-  face newsubseg;
+  tetgenio::pbcgroup *pg;
+  pbcdata *pd;
+  REAL A[4][4], rhs[4], D;
+  int indx[4];
+  int i, j, k;
 
-  // Check if there's already a subsegment here.
-  sspivot(*tri, newsubseg);
-  if (newsubseg.sh == dummysh) {
-    // Make new subsegment and initialize its vertices.
-    makeshellface(subsegs, &newsubseg);
-    setsorg(newsubseg, sorg(*tri));
-    setsdest(newsubseg, sdest(*tri));
-    // Bond new subsegment to the two triangles it is sandwiched between.
-    ssbond(*tri, newsubseg);
-    spivot(*tri, oppotri);
-    // 'oppotri' might be "out space".
-    if (oppotri.sh != dummysh) {
-      ssbond(oppotri, newsubseg);
-    } else {
-      // Outside! Bond '*tri' to itself.
-      sbond(*tri, *tri);
+  subpbcgrouptable = new pbcdata[in->numberofpbcgroups];
+  for (i = 0; i < in->numberofpbcgroups; i++) {
+    pg = &(in->pbcgrouplist[i]);
+    pd = &(subpbcgrouptable[i]);
+    // Copy data from pg to pd.
+    pd->fmark[0] = pg->fmark1;
+    pd->fmark[1] = pg->fmark2;
+    // Initialize array 'pd->ss'.
+    pd->ss[0].sh = dummysh;
+    pd->ss[1].sh = dummysh;
+    // Copy the transform matrix from pg to pd->transmat[0].
+    for (j = 0; j < 4; j++) {
+      for (k = 0; k < 4; k++) {
+        pd->transmat[0][j][k] = pg->transmat[j][k];
+        // Prepare for inverting the matrix.
+        A[j][k] = pg->transmat[j][k];
+      }
+    }
+    // Calculate the inverse matrix (pd->transmat[1]) of pd->transmat[0].
+    lu_decmp(A, 4, indx, &D, 0);
+    for (j = 0; j < 4; j++) {
+      for (k = 0; k < 4; k++) rhs[k] = 0.0;
+      rhs[j] = 1.0;
+      lu_solve(A, 4, indx, rhs, 0);
+      for (k = 0; k < 4; k++) pd->transmat[1][k][j] = rhs[k];
     }
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// scoutsegmentsub()    Scout the first triangle on the path from one point  //
-//                      to another, and check for completion (reaching the   //
-//                      second point), a collinear point,or the intersection //
-//                      of two segments.                                     //
+// getsubpbcgroup()    Get the pbcgroup of a subface.                        //
 //                                                                           //
-// Returns true if the entire segment is successfully inserted, and false if //
-// the job must be finished by constrainededge().                            //
+// 'pbcsub' has pbc defined. Its pbcgroup is returned in 'pd'. In addition,  //
+// 'f1' (0 or 1) indicates the position of 'pbcsub' in 'pd'; 'f2' (= 1 - f1) //
+// is the position where the symmetric subface of 'pbcsub' is found.         //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::scoutsegmentsub(face* searchsh, point tend)
+void tetgenmesh::getsubpbcgroup(face* pbcsub, pbcdata** pd, int *f1, int *f2)
 {
-  face newsubseg;
-  face crosssub, crosssubseg;
-  point leftpoint, rightpoint;
-  enum finddirectionresult collinear;
+  int groupid, fmark, idx;
 
-  collinear = finddirectionsub(searchsh, tend);
-  rightpoint = sdest(*searchsh);
-  leftpoint = sapex(*searchsh);
-  if (rightpoint == tend || leftpoint == tend) {
-    // The segment is already an edge.
-    if (leftpoint == tend) {
-      senext2self(*searchsh);
-    }
-    // Insert a subsegment.
-    insertsubseg(searchsh);
-    return true;
-  } else if (collinear == LEFTCOLLINEAR) {
-    // We've collided with a vertex between the segment's endpoints.
-    // Make the collinear vertex be the triangle's origin.
-    senextself(*searchsh); // lprevself(*searchtri);
-    // Insert a subsegment.
-    insertsubseg(searchsh);
-    // Insert the remainder of the segment.
-    return scoutsegmentsub(searchsh, tend);
-  } else if (collinear == RIGHTCOLLINEAR) {
-    // We've collided with a vertex between the segment's endpoints.
-    // Insert a subsegment.
-    insertsubseg(searchsh);
-    // Make the collinear vertex be the triangle's origin.
-    senextself(*searchsh); // lnextself(*searchtri);
-    // Insert the remainder of the segment.
-    return scoutsegmentsub(searchsh, tend);
-  } else {
-    senext(*searchsh, crosssub); // lnext(*searchtri, crosstri);
-    // Check for a crossing segment.
-    sspivot(crosssub, crosssubseg);
-    assert(crosssubseg.sh == dummysh);
-    return false;
+  groupid = shellpbcgroup(*pbcsub);
+  *pd = &subpbcgrouptable[groupid];
+  
+  // Get the facet index (1 - based).
+  idx = shellmark(*pbcsub);
+  // Get the facet marker from array (0 - based).
+  fmark = in->facetmarkerlist[idx - 1];
+  if ((*pd)->fmark[0] == fmark) {
+    *f1 = 0;
+  } else {
+#ifdef SELF_CHECK
+    assert((*pd)->fmark[1] == fmark);
+#endif
+    *f1 = 1;
   }
+  *f2 = 1 - (*f1);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// delaunayfixup()    Enforce the Delaunay condition at an edge, fanning out //
-//                    recursively from an existing point. Pay special        //
-//                    attention to stacking inverted triangles.              //
-//                                                                           //
-// This is a support routine for inserting segments into a constrained       //
-// Delaunay triangulation.                                                   //
-//                                                                           //
-// The origin of 'fixupsh' is treated as if it has just been inserted, and   //
-// the local Delaunay condition needs to be enforced. It is only enforced in //
-// one sector, however, that being the angular range defined by 'fixupsh'.   //
+// getsubpbcsympoint()    Compute the symmetric point for a subface point.   //
 //                                                                           //
-// `leftside' indicates whether or not fixupsh is to the left of the segment //
-// being inserted.  (Imagine that the segment is pointing up from endpoint1  //
-// to endpoint2.)                                                            //
+// 'newpoint' lies on 'splitsub'. This routine calculates a 'sympoint' which //
+// locates on 'symsplitsub' and symmtric to 'newpoint'.  Return the location //
+// of sympoint wrt. symsplitsub.                                             //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::delaunayfixup(face* fixupsh, int leftside)
+enum tetgenmesh::locateresult tetgenmesh:: getsubpbcsympoint(point newpoint,
+  face* splitsub, point sympoint, face* symsplitsub)
 {
-  face nearsh, farsh, faredge;
-  point nearpoint, leftpoint, rightpoint, farpoint;
-  point liftpoint;
-  REAL sign;
+  pbcdata *pd;
+  face subloop;
+  point pa, pb, pc;
+  enum locateresult symloc;
+  REAL ori;
+  int f1, f2, i;
 
-  // It is up to the caller, that 'fixupsh' must be in CCW edge ring.
-  // adjustedgering(*fixupsh, CCW);
-  assert((fixupsh->shver % 2) == 0);
-  senext(*fixupsh, nearsh);
-  spivot(nearsh, farsh);
-  if (nearsh.sh == farsh.sh) {
-    farsh.sh = dummysh;
-  }
-  // Check if the edge opposite the origin of fixupsh can be flipped.
-  if (farsh.sh == dummysh) {
-    return;
-  }
-  adjustedgering(farsh, CCW);
-  sspivot(nearsh, faredge);
-  if (faredge.sh != dummysh) {
-    return;
+  // Get the pbcgroup of 'splitsub'.
+  getsubpbcgroup(splitsub, &pd, &f1, &f2);
+      
+  // Transform newpoint from f1 -> f2.
+  for (i = 0; i < 3; i++) {
+    sympoint[i] = pd->transmat[f1][i][0] * newpoint[0]
+                + pd->transmat[f1][i][1] * newpoint[1]
+                + pd->transmat[f1][i][2] * newpoint[2]
+                + pd->transmat[f1][i][3] * 1.0;
   }
-  // Find all the relevant vertices.
-  liftpoint = getliftpoint(shellmark(*fixupsh));
-  nearpoint = sapex(nearsh);
-  leftpoint = sorg(nearsh);
-  rightpoint = sdest(nearsh);
-  farpoint = sapex(farsh);
-  // Check whether the previous polygon point is a reflex point.
-  if (leftside) {
-    if (orient3d(nearpoint, leftpoint, liftpoint, farpoint) <= 0.0) {
-      // leftpoint is a reflex point too.  Nothing can
-      //   be done until a convex section is found. 
-      return;
-    }
-  } else {
-    if (orient3d(farpoint, rightpoint, liftpoint, nearpoint) <= 0.0) {
-      // rightpoint is a reflex point too.  Nothing can
-      //   be done until a convex section is found.
-      return;
+  // Locate sympoint in f2.
+  symloc = OUTSIDE;
+  *symsplitsub = pd->ss[f2];
+  // Is the stored subface valid? Hole removal may delete the subface.  
+  if ((symsplitsub->sh != dummysh) && !isdead(symsplitsub)) {
+    // 'symsplitsub' should lie on the symmetric facet. Check it.
+    i = shellmark(*symsplitsub);
+    if (in->facetmarkerlist[i - 1] == pd->fmark[f2]) {
+      // 'symsplitsub' has the symmetric boundary marker.
+      pa = sorg(*symsplitsub);
+      pb = sdest(*symsplitsub);
+      pc = sapex(*symsplitsub);
+      // Test if they are (nearly) coplanar. Some facets may have the
+      //   same boundary marker but not coplanar with this point.
+      ori = orient3d(pa, pb, pc, sympoint);
+      if (iscoplanar(pa, pb, pc, sympoint, ori, b->epsilon * 1e+2)) {
+        // Locate sympoint in facet. Don't stop at subsegment.
+        abovepoint = facetabovepointarray[shellmark(*symsplitsub)];
+        if (abovepoint == (point) NULL) {
+          getfacetabovepoint(symsplitsub);
+        }
+        symloc = locatesub(sympoint, symsplitsub, 0, b->epsilon * 1e+2);
+      }
     }
   }
-  if (orient3d(rightpoint, leftpoint, liftpoint, farpoint) > 0.0) {
-    // farsh is not an inverted triangle, and farpoint is not a reflex
-    //   point.  As there are no reflex vertices, fixupsh isn't an
-    //   inverted triangle, either.  Hence, test the edge between the
-    //   triangles to ensure it is locally Delaunay.
-    sign = insphere(leftpoint, farpoint, rightpoint, liftpoint, nearpoint)
-         * orient3d(leftpoint, farpoint, rightpoint, liftpoint);
-    if (sign <= 0.0) {
-      return;
-    }
-    // Not locally Delaunay; go on to an edge flip.
-  }         // else farsh is inverted; remove it from the stack by flipping.
-  flip22sub(&nearsh, NULL);
-  senext2self(*fixupsh);    // Restore the origin of fixupsh after the flip.
-  // Recursively process the two triangles that result from the flip.
-  delaunayfixup(fixupsh, leftside);
-  delaunayfixup(&farsh, leftside);
+  if (symloc == OUTSIDE) {
+    // Do a brute-force searching for the symmetric subface.
+    REAL epspp = b->epsilon * 1e+2;
+    int lcount = 0;
+    do {
+      // Locate sympoint in the pool of subfaces (with fmark pd->fmark[f2]).
+      subfaces->traversalinit();
+      subloop.sh = shellfacetraverse(subfaces);
+      while (subloop.sh != (shellface *) NULL) {
+        i = shellmark(subloop);
+        if (in->facetmarkerlist[i - 1] == pd->fmark[f2]) {
+          // Found a facet have the symmetric boundary marker.
+          pa = sorg(subloop);
+          pb = sdest(subloop);
+          pc = sapex(subloop);
+          // Test if they are (nearly) coplanar. Some facets may have the
+          //   same boundary marker but not coplanar with this point.
+          ori = orient3d(pa, pb, pc, sympoint);
+          if (iscoplanar(pa, pb, pc, sympoint, ori, epspp)) {
+            // Test if sympoint is (nearly) inside this facet. 
+            // Get the abovepoint of the facet.
+            abovepoint = facetabovepointarray[shellmark(subloop)];
+            // Do we need to calculate the abovepoint?
+            if (abovepoint == (point) NULL) {
+              getfacetabovepoint(&subloop);
+            }
+            // subloop is on the facet, search sympoint.
+            symloc = locatesub(sympoint, &subloop, 0, epspp);
+            if (symloc != OUTSIDE) break;
+          }
+        }
+        subloop.sh = shellfacetraverse(subfaces);
+      }
+      lcount++;
+      epspp *= 10.0;
+    } while ((symloc == OUTSIDE) && (lcount < 3));
+#ifdef SELF_CHECK
+    // sympoint should be inside the facet.
+    assert(symloc != OUTSIDE);
+#endif
+    // Set the returning subface.
+    *symsplitsub = subloop;
+    // Update the stored subface for next searching.
+    pd->ss[f2] = *symsplitsub;
+  }
+
+  return adjustlocatesub(sympoint, symsplitsub, symloc, b->epsilon);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// constrainededge()    Force a segment into a constrained Delaunay          //
-//                      triangulation by deleting the triangles it           //
-//                      intersects, and triangulating the polygons that      //
-//                      form on each side of it.                             //
+// createsegpbcgrouptable()    Create the 'segpbcgrouptable'.                //
 //                                                                           //
-// Generates a single subsegment connecting `tstart' to `tend'. The triangle //
-// `startsh' has `tstart' as its origin.                                     //
+// Each segment may belong to more than one pbcgroups.  For example, segment //
+// ab may need to be symmteric to both segments cd, and ef, then  ab and cd, //
+// cd and ef, ef and ab form three pbcgroups.                                //
+//                                                                           //
+// 'segpbcgrouptable' is  implemented as a list of pbcdatas. Each item i is  //
+// a pbcgroup.                                                               //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::constrainededge(face* startsh, point tend)
+void tetgenmesh::createsegpbcgrouptable()
 {
-  face fixupsh, fixupsh2;
-  face crosssubseg, newsubseg;
-  point tstart, farpoint;
-  point liftpoint;
-  REAL area;
-  int collision;
-  int done;
+  pbcdata *pd, *pd1, *pd2;
+  face segloop, symseg;
+  face startsh, spinsh, symsh;
+  point pa, pb;
+  enum locateresult symloc;
+  REAL testpt[3], sympt[3];
+  bool inflag;
+  int segid1, segid2;
+  int f1, f2;
+  int i, j, k, l;
 
-  liftpoint = getliftpoint(shellmark(*startsh));
-  tstart = sorg(*startsh);
-  // Always works in the CCW edge ring.
-  adjustedgering(*startsh, CCW);
-  // Make sure the 'tstart' remians be the origin.
-  if (sorg(*startsh) != tstart) {
-    senextself(*startsh);
-    assert(sorg(*startsh) == tstart);
+  // Allocate memory for 'subpbcgrouptable'.
+  segpbcgrouptable = new list(sizeof(pbcdata), NULL, 256);
+
+  // Loop through the segment list.
+  subsegs->traversalinit();
+  segloop.sh = shellfacetraverse(subsegs);
+  while (segloop.sh != (shellface *) NULL) {
+    // Loop the subface ring of segloop ab.
+    pa = sorg(segloop);
+    pb = sdest(segloop);
+    segid1 = shellmark(segloop);
+    spivot(segloop, startsh);
+    spinsh = startsh;
+    do {
+      // Adjust spinsh be edge ab.
+      if (sorg(spinsh) != pa) {
+        sesymself(spinsh);
+      }
+      // 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);
+#ifdef SELF_CHECK
+        assert(symloc == ONEDGE);
+#endif
+        sspivot(symsh, symseg);
+#ifdef SELF_CHECK
+        assert(symseg.sh != dummysh);
+#endif
+        // Check whether this group has already been created in list.
+        segid2 = shellmark(symseg);
+        inflag = false;
+        for (i = 0; i < segpbcgrouptable->len() && !inflag; i++) {
+          pd = (pbcdata *)(* segpbcgrouptable)[i];
+          if (pd->segid[0] == segid1) {
+            if (pd->segid[1] == segid2) inflag = true;
+          } else if (pd->segid[0] == segid2) {
+            if (pd->segid[1] == segid1) inflag = true;
+          }
+        }
+        if (!inflag) {
+          // Create a segment pbcgroup in list for ab and cd.
+          pd = (pbcdata *) segpbcgrouptable->append(NULL);
+          // Save the markers of ab and cd.
+          pd->segid[0] = segid1;
+          pd->segid[1] = segid2;
+          // Save the handles of ab and cd.
+          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];
+          // 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];
+            }
+          }
+          // 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];
+            }
+          }
+        }
+      }
+      // Go to the next subface in the ring of ab.
+      spivotself(spinsh);
+    } while (spinsh.sh != startsh.sh);
+    segloop.sh = shellfacetraverse(subsegs);
   }
-  senext(*startsh, fixupsh);
-  flip22sub(&fixupsh, NULL);
-  // `collision' indicates whether we have found a vertex directly
-  //   between endpoint1 and endpoint2.
-  collision = 0;
-  done = 0;
-  do {
-    farpoint = sorg(fixupsh);
-    // `farpoint' is the extreme point of the polygon we are "digging"
-    //   to get from tstart to tend.
-    if (farpoint == tend) {
-      spivot(fixupsh, fixupsh2);  // oprev(fixupsh, fixupsh2);
-      adjustedgering(fixupsh2, CCW);
-      senextself(fixupsh2);
-      // Enforce the Delaunay condition around tend.
-      delaunayfixup(&fixupsh, 0);
-      delaunayfixup(&fixupsh2, 1);
-      done = 1;
-    } else {
-      // Check whether farpoint is to the left or right of the segment
-      //   being inserted, to decide which edge of fixupsh to dig 
-      //   through next.
-      area = orient3d(tstart, tend, liftpoint, farpoint);
-      if (area == 0.0) {
-        // We've collided with a vertex between tstart and tend.
-        collision = 1;
-        spivot(fixupsh, fixupsh2);  // oprev(fixupsh, fixupsh2);
-        adjustedgering(fixupsh2, CCW);
-        senextself(fixupsh2);
-        // Enforce the Delaunay condition around farpoint.
-        delaunayfixup(&fixupsh, 0);
-        delaunayfixup(&fixupsh2, 1);
-        done = 1;
-      } else {
-        if (area > 0.0) {        // farpoint is to the left of the segment.
-          spivot(fixupsh, fixupsh2);  // oprev(fixupsh, fixupsh2);
-          adjustedgering(fixupsh2, CCW);
-          senextself(fixupsh2); 
-          // Enforce the Delaunay condition around farpoint, on the
-          //   left side of the segment only.
-          delaunayfixup(&fixupsh2, 1);
-          // Flip the edge that crosses the segment.  After the edge is
-          //   flipped, one of its endpoints is the fan vertex, and the
-          //   destination of fixupsh is the fan vertex.
-          senext2self(fixupsh); // lprevself(fixupsh);
-        } else {                // farpoint is to the right of the segment.
-          delaunayfixup(&fixupsh, 0);
-          // Flip the edge that crosses the segment.  After the edge is
-          //   flipped, one of its endpoints is the fan vertex, and the
-          //   destination of fixupsh is the fan vertex.
-          spivotself(fixupsh);  // oprevself(fixupsh);
-          adjustedgering(fixupsh, CCW);
-          senextself(fixupsh); 
-        }
-        // Check for two intersecting segments.
-        sspivot(fixupsh, crosssubseg);
-        if (crosssubseg.sh == dummysh) {
-          flip22sub(&fixupsh, NULL);// May create inverted triangle at left.
-        } else {
-          // We've collided with a segment between tstart and tend.
-          /* collision = 1;
-          // Insert a vertex at the intersection.
-          segmentintersection(m, b, &fixupsh, &crosssubseg, tend);
-          done = 1;
-          */
-          assert(0);
+
+  // Create the indirect segment pbcgroups.
+  for (i = 0; i < segpbcgrouptable->len(); i++) {
+    pd1 = (pbcdata *)(* segpbcgrouptable)[i];
+    for (f1 = 0; f1 < 2; 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];
+        f2 = -1;
+        if (pd1->segid[f1] == pd2->segid[0]) {
+          f2 = 0;
+        } else if (pd1->segid[f1] == pd2->segid[1]) {
+          f2 = 1;
+        }
+        if (f2 != -1) {
+#ifdef SELF_CHECK
+          assert(pd1->segid[f1] == pd2->segid[f2]);
+#endif
+          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++) {
+            pd = (pbcdata *)(* segpbcgrouptable)[k];
+            if (pd->segid[0] == segid1) {
+              if (pd->segid[1] == segid2) inflag = true;
+            } else if (pd->segid[0] == segid2) {
+              if (pd->segid[1] == segid1) inflag = true;
+            }
+          }
+          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];
+            // 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].
+            for (k = 0; k < 4; k++) {
+              for (l = 0; l < 4; l++) { 
+                pd->transmat[0][k][l] = pd2->transmat[f2][k][l];
+              }
+            }
+            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].
+            for (k = 0; k < 4; k++) {
+              for (l = 0; l < 4; l++) { 
+                pd->transmat[1][k][l] = pd1->transmat[f1][k][l];
+              }
+            }
+            m4xm4(pd->transmat[1], pd2->transmat[1 - f2]);
+          }
         }
       }
     }
-  } while (!done);
-  // Insert a subsegment to make the segment permanent.
-  insertsubseg(&fixupsh);
-  // If there was a collision with an interceding vertex, install another
-  //   segment connecting that vertex with endpoint2.
-  if (collision) {
-    // Insert the remainder of the segment.
-    if (!scoutsegmentsub(&fixupsh, tend)) {
-      constrainededge(&fixupsh, tend);
+  }
+
+  // Form a map from segment index to pbcgroup list of this segment.
+  idx2segpglist = new int[subsegs->items + 1];
+  for (i = 0; i < subsegs->items + 1; i++) idx2segpglist[i] = 0;
+  // Loop through 'segpbcgrouptable', counter the number of pbcgroups of
+  //   each segment.
+  for (i = 0; i < segpbcgrouptable->len(); i++) {
+    pd = (pbcdata *)(* segpbcgrouptable)[i];
+    for (j = 0; j < 2; j++) {
+      k = pd->segid[j] - 1;
+      idx2segpglist[k]++;
+    }
+  }
+  // Calculate the total length of array 'segpglist'.
+  j = idx2segpglist[0];
+  idx2segpglist[0] = 0;  // Array starts from 0 element.
+  for (i = 0; i < subsegs->items; i++) {
+    k = idx2segpglist[i + 1];
+    idx2segpglist[i + 1] = idx2segpglist[i] + j;
+    j = k;
+  }
+  // The total length is in the last unit of idx2segpglist.
+  segpglist = new int[idx2segpglist[i]];
+  // Loop the set of pbcgroups again, set the data into segpglist.
+  for (i = 0; i < segpbcgrouptable->len(); i++) {
+    pd = (pbcdata *)(* segpbcgrouptable)[i];
+    for (j = 0; j < 2; j++) {
+      k = pd->segid[j] - 1;
+      segpglist[idx2segpglist[k]] = i;
+      idx2segpglist[k]++;
     }
   }
+  // Contents in 'idx2segpglist' are shifted, now shift them back.
+  for (i = subsegs->items - 1; i >= 0; i--) {
+    idx2segpglist[i + 1] = idx2segpglist[i];
+  }
+  idx2segpglist[0] = 0;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// insertsegmentsub()    Insert a PSLG segment into a triangulation.         //
+// getsegpbcsympoint()    Compute the symmetric point for a segment point.   //
+//                                                                           //
+// 'newpoint' lies on 'splitseg'. This routine calculates a 'sympoint' which //
+// locates on 'symsplitseg' and symmtric to 'newpoint'.  Return the location //
+// of sympoint wrt. symsplitseg.                                             //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::insertsegmentsub(point tstart, point tend)
+enum tetgenmesh::locateresult tetgenmesh::
+getsegpbcsympoint(point newpoint, face* splitseg, point sympoint,
+                  face* symsplitseg, int groupid)
 {
-  face searchsh1, searchsh2;
+  pbcdata *pd;
+  enum locateresult symloc;
+  int segid, f1, f2, i;
 
-  if (b->verbose > 2) {
-    printf("    Insert subsegment (%d, %d).\n", pointmark(tstart),
-           pointmark(tend));
+  pd = (pbcdata *)(* segpbcgrouptable)[groupid];
+  segid = shellmark(*splitseg);
+  if (pd->segid[0] == segid) {
+    f1 = 0;
+  } else {
+#ifdef SELF_CHECK
+    assert(pd->segid[1] == segid);
+#endif
+    f1 = 1;
   }
+  f2 = 1 - f1;
 
-  // Find a triangle whose origin is the segment's first endpoint.
-  searchsh1.sh = dummysh;
-  // Search for the segment's first endpoint by point location.
-  if (locatesub(tstart, &searchsh1, 0) != ONVERTEX) {
-    printf("Internal error in insertsegmentsub():");
-    printf("  Unable to locate PSLG vertex %d.\n", pointmark(tstart));
-    internalerror();
-  }
-  // Scout the beginnings of a path from the first endpoint
-  //   toward the second. 
-  if (scoutsegmentsub(&searchsh1, tend)) {
-    // The segment was easily inserted.
-    return;
-  }
-  // The first endpoint may have changed if a collision with an intervening
-  //   vertex on the segment occurred.
-  tstart = sorg(searchsh1);
-  
-  // Find a boundary triangle to search from.
-  searchsh2.sh = dummysh;
-  // Search for the segment's second endpoint by point location.
-  if (locatesub(tend, &searchsh2, 0) != ONVERTEX) {
-    printf("Internal error in insertsegmentsub():");
-    printf("  Unable to locate PSLG vertex %d.\n", pointmark(tend));
-    internalerror();
-  }
-  // Scout the beginnings of a path from the second endpoint
-  //   toward the first.
-  if (scoutsegmentsub(&searchsh2, tstart)) {
-    // The segment was easily inserted.
-    return;
+  // Transform newpoint from f1 -> f2.
+  for (i = 0; i < 3; i++) {
+    sympoint[i] = pd->transmat[f1][i][0] * newpoint[0]
+                + pd->transmat[f1][i][1] * newpoint[1]
+                + pd->transmat[f1][i][2] * newpoint[2]
+                + pd->transmat[f1][i][3] * 1.0;
   }
-  // The second endpoint may have changed if a collision with an intervening
-  //   vertex on the segment occurred. 
-  tend = sorg(searchsh2);
-  
-  // Insert the segment directly into the triangulation.
-  constrainededge(&searchsh1, tend);
+  // Locate sympoint in f2.
+  *symsplitseg = pd->ss[f2];
+#ifdef SELF_CHECK
+  assert(symsplitseg->sh != dummysh);
+#endif
+  // Locate sympoint in facet. Stop at subsegment.
+  symloc = locateseg(sympoint, symsplitseg);
+  symloc = adjustlocateseg(sympoint, symsplitseg, symloc, b->epsilon * 1e+2);
+  return symloc;
 }
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// infecthullsub()    Virally infect all of the triangles of the convex hull //
-//                    that are not protected by subsegments.                 //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-void tetgenmesh::infecthullsub(memorypool* viri)
-{
-  face hulltri, nexttri, starttri;
-  face hullsubseg;
-  shellface **deadshellface;
+//
+// End of periodic boundary condition routines
+//
 
-  // Find a triangle handle on the hull.
-  hulltri.sh = dummysh;
-  hulltri.shver = 0;
-  spivotself(hulltri);
-  adjustedgering(hulltri, CCW);
-  // Remember where we started so we know when to stop.
-  starttri = hulltri;
-  // Go once counterclockwise around the convex hull.
-  do {
-    // Ignore triangles that are already infected.
-    if (!sinfected(hulltri)) {
-      // Is the triangle protected by a subsegment?
-      sspivot(hulltri, hullsubseg);
-      if (hullsubseg.sh == dummysh) {
-        // The triangle is not protected; infect it.
-        if (!sinfected(hulltri)) {
-          sinfect(hulltri);
-          deadshellface = (shellface **) viri->alloc();
-          *deadshellface = hulltri.sh;
-        }
-      } 
-    }
-    // To find the next hull edge, go clockwise around the next vertex.
-    senextself(hulltri); // lnextself(hulltri);
-    spivot(hulltri, nexttri); // oprev(hulltri, nexttri);
-    if (nexttri.sh == hulltri.sh) {
-      nexttri.sh = dummysh;  // 'hulltri' is self-bonded.
-    } else {
-      adjustedgering(nexttri, CCW);
-      senextself(nexttri);
-    }
-    while (nexttri.sh != dummysh) {
-      hulltri = nexttri;
-      spivot(hulltri, nexttri); // oprev(hulltri, nexttri);
-      if (nexttri.sh == hulltri.sh) {
-        nexttri.sh = dummysh;  // 'hulltri' is self-bonded.
-      } else {
-        adjustedgering(nexttri, CCW);
-        senextself(nexttri);
-      }
-    }
-  } while (hulltri != starttri);
-}
+//
+// Begin of vertex perturbation routines
+//
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// plaguesub()    Spread the virus from all infected triangles to any        //
-//                neighbors not protected by subsegments.  Delete all        //
-//                infected triangles.                                        //
-//                                                                           //
-// This is the procedure that actually creates holes and concavities.        //
+// randgenerator()    Generate a random REAL number between (0, |range|).    //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::plaguesub(memorypool* viri)
+REAL tetgenmesh::randgenerator(REAL range)
 {
-  face testtri, neighbor, ghostsh;
-  face neighborsubseg;
-  shellface **virusloop;
-  shellface **deadshellface;
-  int i;
+  REAL worknumber, result;
+  int expo;
 
-  // Loop through all the infected triangles, spreading the virus to
-  //   their neighbors, then to their neighbors' neighbors.
-  viri->traversalinit();
-  virusloop = (shellface **) viri->traverse();
-  while (virusloop != (shellface **) NULL) {
-    testtri.sh = *virusloop;
-    // Check each of the triangle's three neighbors.
-    for (i = 0; i < 3; i++) {
-      // Find the neighbor.
-      spivot(testtri, neighbor);
-      // Check for a subsegment between the triangle and its neighbor.
-      sspivot(testtri, neighborsubseg);
-      // Check if the neighbor is nonexistent or already infected.
-      if ((neighbor.sh == dummysh) || sinfected(neighbor)) {
-        if (neighborsubseg.sh != dummysh) {
-          // There is a subsegment separating the triangle from its
-          //   neighbor, but both triangles are dying, so the subsegment
-          //   dies too.
-          shellfacedealloc(subsegs, neighborsubseg.sh);
-          if (neighbor.sh != dummysh) {
-            // Make sure the subsegment doesn't get deallocated again
-            //   later when the infected neighbor is visited.
-            ssdissolve(neighbor);
-          }
-        }
-      } else {                   // The neighbor exists and is not infected.
-        if (neighborsubseg.sh == dummysh) {
-          // There is no subsegment protecting the neighbor, so the
-          //   neighbor becomes infected.
-          sinfect(neighbor);
-          // Ensure that the neighbor's neighbors will be infected.
-          deadshellface = (shellface **) viri->alloc();
-          *deadshellface = neighbor.sh;
-        } else {               // The neighbor is protected by a subsegment.
-          // Remove this triangle from the subsegment.
-          ssbond(neighbor, neighborsubseg);
-        }
-      }
-      senextself(testtri);
-    }
-    virusloop = (shellface **) viri->traverse();
-  }
+  if (range == 0.0) return 0.0;
 
-  ghostsh.sh = dummysh; // A handle of outer space.
-  viri->traversalinit();
-  virusloop = (shellface **) viri->traverse();
-  while (virusloop != (shellface **) NULL) {
-    testtri.sh = *virusloop;
-    // Record changes in the number of boundary edges, and disconnect
-    //   dead triangles from their neighbors. 
-    for (i = 0; i < 3; i++) {
-      spivot(testtri, neighbor);
-      if (neighbor.sh != dummysh) {
-        // Disconnect the triangle from its neighbor.
-        // sdissolve(neighbor);
-        sbond(neighbor, ghostsh); 
-      }
-      senextself(testtri);
+  expo = 0;
+  worknumber = fabs(range);
+  // Normalize worknumber (i.e., 1.xxxExx)
+  if (worknumber > 10.0) {
+    while (worknumber > 10.0) {
+      worknumber /= 10.0;
+      expo++;
+    }
+  } else if (worknumber < 1.0) {
+    while (worknumber < 1.0) {
+      worknumber *= 10.0;
+      expo--;
     }
-    // Return the dead triangle to the pool of triangles.
-    shellfacedealloc(subfaces, testtri.sh);
-    virusloop = (shellface **) viri->traverse();
   }
-  // Empty the virus pool.
-  viri->restart();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// carveholessub()    Find the holes and infect them.  Find the area         //
-//                    constraints and infect them.  Infect the convex hull.  //
-//                    Spread the infection and kill triangles.  Spread the   //
-//                    area constraints.                                      //
-//                                                                           //
-// This routine mainly calls other routines to carry out all these functions.//
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-void tetgenmesh::carveholessub(int holes, REAL* holelist)
-{
-  face searchtri, triangleloop;
-  shellface **holetri;
-  memorypool *viri;
-  enum locateresult intersect;
-  int i;
-
-  // Initialize a pool of viri to be used for holes, concavities.
-  viri = new memorypool(sizeof(shellface *), 1024, POINTER, 0);
-
-  // Mark as infected any unprotected triangles on the boundary.
-  //   This is one way by which concavities are created.
-  infecthullsub(viri);
+#ifdef SELF_CHECK
+  assert(worknumber >= 1.0 && worknumber <= 10.0);
+#endif
 
-  if (holes > 0) {
-    // Infect each triangle in which a hole lies.
-    for (i = 0; i < 3 * holes; i += 3) {
-      // Ignore holes that aren't within the bounds of the mesh.
-      if ((holelist[i] >= xmin) && (holelist[i] <= xmax)
-          && (holelist[i + 1] >= ymin) && (holelist[i + 1] <= ymax)
-          && (holelist[i + 2] >= zmin) && (holelist[i + 2] <= zmax)) {
-        // Start searching from some triangle on the outer boundary.
-        searchtri.sh = dummysh;
-        // Find a triangle that contains the hole.
-        intersect = locatesub(&holelist[i], &searchtri, 0);
-        if ((intersect != OUTSIDE) && (!sinfected(searchtri))) {
-          // Infect the triangle.  This is done by marking the triangle
-          //   as infected and including the triangle in the virus pool.
-          sinfect(searchtri);
-          holetri = (shellface **) viri->alloc();
-          *holetri = searchtri.sh;
-        }
-      }
+  // Enlarge worknumber 1000 times.
+  worknumber *= 1e+3;
+  expo -= 3;
+  // Generate a randome number between (0, worknumber).
+  result = (double) randomnation((int) worknumber);
+  
+  // Scale result back into the original size.
+  if (expo > 0) {
+    while (expo != 0) {
+      result *= 10.0;
+      expo--;
+    }
+  } else if (expo < 0) {
+    while (expo != 0) {
+      result /= 10.0;
+      expo++;
     }
   }
+#ifdef SELF_CHECK
+  assert((result >= 0.0) && (result <= fabs(range)));
+#endif
 
-  if (viri->items > 0) {
-    // Carve the holes and concavities.
-    plaguesub(viri);
-  }
-  // The virus pool should be empty now.
-
-  // Free up memory.
-  delete viri;
+  return result;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// triangulatefacet()    Create a constrained Delaunay triang. for a facet.  //
+// checksub4cocir()    Test a subface to find co-circular pair of subfaces.  //
 //                                                                           //
-// 'facetidx' is the index of the facet in 'in->facetlist' (starts from 1),  //
-// 'idx2verlist' is a map from indices to vertices.  'ptlist' and 'conlist'  //
-// are two lists used to assemble the input data for each facet, 'ptlist'    //
-// stores the index set of its vertices, 'conlist' stores the set of its     //
-// segments, they should be empty on input and output.                       //
+// 'eps' is a relative tolerance for testing approximately cospherical case. //
+// Set it to zero if only exact test is desired.                             //
 //                                                                           //
-// The duplicated points (marked with the type DUPLICATEDVERTEX by routine   //
-// "incrflipdelaunay()") are handled before starting to mesh the facet.  Let //
-// p and q are duplicated, i.e., they have exactly the same coordinates, and //
-// the index of p is larger than q, p is substituted by q.  In a STL mesh,   //
-// duplicated points are implicitly included.                                //
+// An edge(not a segment) of 'testsub' is locally degenerate if the opposite //
+// vertex of the adjacent subface is cocircular with the vertices of testsub.//
+// If 'once' is TRUE, operate on the edge only if the pointer 'testsub->sh'  //
+// is smaller than its neighbor (for each edge is considered only once).     //
 //                                                                           //
-// On completion, the CDT of this facet is constructed in pool 'subfaces'.   //
-// Every isolated point on the facet will be set a type of FACETVERTEX.      //
+// Return TRUE if find an edge of testsub is locally degenerate.             //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-triangulatefacet(int facetidx, list* ptlist, list* conlist, point* idx2verlist,
-                 queue* flipqueue)
+bool tetgenmesh::checksub4cocir(face* testsub, REAL eps, bool once,
+  bool enqflag)
 {
-  tetgenio::facet *f;
-  tetgenio::polygon *p; 
-  point tstart, tend;
-  int *cons, idx1, idx2;
-  int end1, end2;
-  int i, j;
+  badface *cocirsub;
+  face subloop, neighsub;
+  face checkseg;
+  point pa, pb, pc, pd;
+  REAL sign;
+  int i;
   
-  if (b->verbose > 1) {
-    printf("  Triangulate facet %d.\n", facetidx);
+  subloop = *testsub;
+  subloop.shver = 0; // Keep the CCW orientation.
+  // Get the abovepoint of the facet.
+  abovepoint = facetabovepointarray[shellmark(subloop)];
+  // Do we need to calculate the abovepoint?
+  if (abovepoint == (point) NULL) {
+    getfacetabovepoint(&subloop);
   }
-
-  // Get the pointer of the facet.  
-  f = &in->facetlist[facetidx - 1];
-
-  // Are there duplicated points? 
-  if ((b->object == tetgenbehavior::STL) || dupverts) {
-    // Loop all polygons of this facet.
-    for (i = 0; i < f->numberofpolygons; i++) {
-      p = &(f->polygonlist[i]);
-      // Loop other vertices of this polygon.
-      for (j = 0; j < p->numberofvertices; j++) {
-        idx1 = p->vertexlist[j];
-        tstart = idx2verlist[idx1 - in->firstnumber];
-        if (pointtype(tstart) == DUPLICATEDVERTEX) {
-          // Reset the index of vertex-j.
-          tend = point2pt(tstart);
-          idx2 = pointmark(tend);
-          p->vertexlist[j] = idx2;
+  // Check the three edges of subloop.
+  for (i = 0; i < 3; i++) {
+    sspivot(subloop, checkseg);
+    if (checkseg.sh == dummysh) {
+      // It is not a segment, get the adjacent subface.
+      spivot(subloop, neighsub);
+      // assert(neighsub.sh != dummysh);
+      if (!once || (once && (neighsub.sh > subloop.sh))) {
+        pa = sorg(subloop);
+        pb = sdest(subloop);
+        pc = sapex(subloop);
+        pd = sapex(neighsub);
+        sign = insphere(pa, pb, pc, abovepoint, pd);
+        if ((sign != 0.0) && (eps > 0.0)) {
+          if (iscospheric(pa, pb, pc, abovepoint, pd, sign, eps)) sign = 0.0;
+        }
+        if (sign == 0.0) {
+          // It's locally degenerate!
+          if (enqflag && badsubfaces != (memorypool *) NULL) {
+            // Save it.
+            cocirsub = (badface *) badsubfaces->alloc();
+            cocirsub->ss = subloop;
+            cocirsub->forg = pa;
+            cocirsub->fdest = pb;
+            cocirsub->fapex = pc;
+            cocirsub->foppo = pd;
+            setshell2badface(cocirsub->ss, cocirsub);
+          }
+          if (b->verbose > 1) {
+            printf("    Found set (%d, %d, %d, %d).\n", pointmark(pa),
+                   pointmark(pb), pointmark(pc), pointmark(pd));
+          }
+          return true;
         }
       }
     }
+    senextself(subloop);
   }
 
-  // Loop all polygons of this facet, get the sets of vertices and segments.
-  for (i = 0; i < f->numberofpolygons; i++) {
-    p = &(f->polygonlist[i]);
-    // Get the first vertex.
-    end1 = p->vertexlist[0];
-    if ((end1 < in->firstnumber) || 
-        (end1 >= in->firstnumber + in->numberofpoints)) {
-      if (!b->quiet) {
-        printf("Warning:  Invalid the 1st vertex %d of polygon", end1);
-        printf(" %d in facet %d.\n", i + 1, facetidx);
-      }
-      break; // Skip to mesh this facet.
-    }
-    // Save it in 'ptlist' if it didn't be added, and set its position.
-    idx1 = ptlist->hasitem(&end1);
-    if (idx1 == -1) {
-      ptlist->append(&end1);
-      idx1 = ptlist->len() - 1;
-    }
-    // Loop other vertices of this polygon.
-    for (j = 1; j <= p->numberofvertices; j++) {
-      // get a vertex.
-      if (j < p->numberofvertices) {
-        end2 = p->vertexlist[j];
-      } else {
-        end2 = p->vertexlist[0];  // Form a loop from last to first.
-      }
-      if ((end2 < in->firstnumber) ||
-          (end2 >= in->firstnumber + in->numberofpoints)) {
-        if (!b->quiet) {
-          printf("Warning:  Invalid vertex %d in polygon %d", end2, i + 1);
-          printf(" in facet %d.\n", facetidx);
-        }
-      } else {
-        if (end1 != end2) {
-          // 'end1' and 'end2' form a segment.  Save 'end2' in 'ptlist' if
-          //   it didn't be added before.
-          idx2 = ptlist->hasitem(&end2);
-          if (idx2 == -1) {
-            ptlist->append(&end2);
-            idx2 = ptlist->len() - 1;
-          }
-          // Save the segment in 'conlist'.
-	        cons = (int *) conlist->append(NULL);
-          cons[0] = idx1;
-          cons[1] = idx2;
-          // Set the start for next continuous segment.
-          end1 = end2;
-          idx1 = idx2;
-        } else {
-          // It's a (degenerate) segment with identical endpoints, which
-          //   represents an isolate vertex in facet.
-          if (p->numberofvertices > 2) {
-            // This may be an error in the input, anyway, we can continue
-            //   by simply skipping this segment.
-            if (!b->quiet) {
-              printf("Warning:  Polygon %d has two identical vertices", i + 1);
-              printf(" in facet %d.\n", facetidx);
-            }
-          } 
-          // Ignore this vertex.
-        } 
-      }
-      if (p->numberofvertices == 2) {
-        // This case the polygon is either a segment or an isolated vertex.
-        break;  
-      }
-    } 
-  } 
+  return false;
+}
 
-  // Have got the vertex list and segment list.
-  if (b->verbose > 1) {
-    printf("    %d vertices, %d segments", ptlist->len(), conlist->len());
-    if (f->numberofholes > 0) {
-      printf(", %d holes", f->numberofholes);
-    }
-    printf(".\n");
-  }
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tallcocirsubs()    Find all co-circular subfaces and save them in list.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
-  if (ptlist->len() > 2) {
-    // Construct an initial triangulation.
-    if (incrflipinitsub(facetidx, ptlist, idx2verlist)) {
-      if (ptlist->len() > 3) {
-        // Create the Delaunay triangulation of 'ptlist'.
-        incrflipdelaunaysub(facetidx, ptlist, idx2verlist, flipqueue);
-      }
-      // Insert segments (in 'conlist') into the Delaunay triangulation.
-      for (i = 0; i < conlist->len(); i++) {
-        cons = (int *)(* conlist)[i];
-        idx1 = * (int *)(* ptlist)[cons[0]];
-        tstart = idx2verlist[idx1 - in->firstnumber];
-        idx2 = * (int *)(* ptlist)[cons[1]];
-        tend = idx2verlist[idx2 - in->firstnumber];
-        insertsegmentsub(tstart, tend);        
-      }
-      if (ptlist->len() > 3 && conlist->len() > 3) {
-        // Carve holes and concavities.
-        carveholessub(f->numberofholes, f->holelist);
-      }
-    }
-  }
+void tetgenmesh::tallcocirsubs(REAL eps, bool enqflag)
+{
+  face subloop;
 
-  // Clear working lists.
-  ptlist->clear();
-  conlist->clear();
+  // Loop over all subfaces.
+  subfaces->traversalinit();
+  subloop.sh = shellfacetraverse(subfaces);
+  while (subloop.sh != (shellface *) NULL) {
+    checksub4cocir(&subloop, eps, true, enqflag);
+    subloop.sh = shellfacetraverse(subfaces);
+  }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// unifysegments()    Unify identical segments and build facet connections.  //
-//                                                                           //
-// After creating the surface mesh. Each facet has its own segments.  There  //
-// are duplicated segments between adjacent facets.  This routine has three  //
-// purposes:                                                                 //
-//   (1) identify the set of segments which have the same endpoints and      //
-//       unify them into one segment, remove redundant ones;                 //
-//   (2) create the face rings of the unified segments, hence setup the      //
-//       connections between facets; and                                     //
-//   (3) set a unique marker (1-based) for each segment.                     //
-// On finish, each segment is unique and the face ring around it (right-hand //
-// rule) is constructed. The connections between facets-facets are setup.    //
+// tallencsegsfsubs()    Check for encroached segs from a list of subfaces.  //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::unifysegments()
+bool tetgenmesh::tallencsegsfsubs(point testpt, list* cavsublist)
 {
-  list *sfacelist;
-  shellface **facesperverlist;
-  face subsegloop, testseg;
-  face sface, sface1, sface2;
-  point torg, tdest;
-  REAL da1, da2;
-  int *idx2facelist;
-  int segmarker;
-  int idx, k, m;
+  face startsub, checkseg;
+  long oldencnum;
+  int i, j;
 
-  if (b->verbose) {
-    printf("  Unifying segments.\n");
-  }
+  // Remember the current number of encroached segments.
+  oldencnum = badsubsegs->items;
 
-  // Compute a mapping from indices of vertices to subfaces.
-  makesubfacemap(idx2facelist, facesperverlist);
-  // Initialize 'sfacelist' for constructing the face link of each segment.
-  sfacelist = new list(sizeof(face), NULL); 
-  
-  segmarker = 1;
-  subsegs->traversalinit();
-  subsegloop.sh = shellfacetraverse(subsegs);
-  while (subsegloop.sh != (shellface *) NULL) {
-    subsegloop.shver = 0; // For sure.
-    torg = sorg(subsegloop);
-    tdest = sdest(subsegloop);
-    idx = pointmark(torg) - in->firstnumber;
-    // Loop through the set of subfaces containing 'torg'.  Get all the
-    //   subfaces containing the edge (torg, tdest). Save and order them
-    //   in 'sfacelist', the ordering is defined by the right-hand rule
-    //   with thumb points from torg to tdest.
-    for (k = idx2facelist[idx]; k < idx2facelist[idx + 1]; k++) {
-      sface.sh = facesperverlist[k];
-      sface.shver = 0;
-      // sface may be died due to the removing of duplicated subfaces.
-      if (!isdead(&sface) && isfacehasedge(&sface, torg, tdest)) {
-        // 'sface' contains this segment.
-        findedge(&sface, torg, tdest);
-        // Save it in 'sfacelist'.
-        if (sfacelist->len() < 2) {
-          sfacelist->append(&sface);
-        } else {
-          for (m = 0; m < sfacelist->len() - 1; m++) {
-            sface1 = * (face *)(* sfacelist)[m];
-            sface2 = * (face *)(* sfacelist)[m + 1];
-            da1 = facedihedral(torg, tdest, sapex(sface1), sapex(sface));
-            da2 = facedihedral(torg, tdest, sapex(sface1), sapex(sface2));
-            if (da1 < da2) {
-              break;  // Insert it after m.
-            }
-          }
-          sfacelist->insert(m + 1, &sface);
-        }
-      }
-    }
-    if (b->verbose > 1) {
-      printf("    Identifying %d segments of (%d  %d).\n", sfacelist->len(),
-             pointmark(torg), pointmark(tdest));
-    }
-    // Set the connection between this segment and faces containing it,
-    //   at the same time, remove redundant segments.
-    for (k = 0; k < sfacelist->len(); k++) {
-      sface = *(face *)(* sfacelist)[k];
-      sspivot(sface, testseg);
-      // If 'testseg' is not 'subsegloop', it is a redundant segment that
-      //   needs be removed. BE CAREFUL it may already be removed. Do not
-      //   remove it twice, i.e., do test 'isdead()' together.
-      if ((testseg.sh != subsegloop.sh) && !isdead(&testseg)) {
-        shellfacedealloc(subsegs, testseg.sh);
-      }
-      // 'ssbond' bonds the subface and the segment together, and dissloves
-      //   the old bond as well.
-      ssbond(sface, subsegloop);
-    }
-    // Set connection between these faces.
-    sface = *(face *)(* sfacelist)[0];
-    for (k = 1; k <= sfacelist->len(); k++) {
-      if (k < sfacelist->len()) {
-        sface1 = *(face *)(* sfacelist)[k];
-      } else {
-        sface1 = *(face *)(* sfacelist)[0];    // Form a face loop.
-      }
-      /*
-      // Check if these two subfaces are the same. It is possible when user
-      //   defines one facet (or polygon) two or more times. If they are,
-      //   they should not be bonded together, instead of that, one of them
-      //   should be delete from the surface mesh.
-      if ((sfacelist->len() > 1) && sapex(sface) == sapex(sface1)) {
-        // They are duplicated faces.
-        if (b->verbose) {
-          printf("  A duplicated subface (%d, %d, %d) is removed.\n",
-                 pointmark(torg), pointmark(tdest), pointmark(sapex(sface)));
-        }
-        if (k == sfacelist->len()) {
-          // 'sface' is the last face, however, it is same as the first one.
-          //   In order to form the ring, we have to let the second last
-          //   face bond to the first one 'sface1'.
-          shellfacedealloc(subfaces, sface.sh);
-          assert(sfacelist->len() >= 2);
-          assert(k == sfacelist->len());
-          sface = *(face *)(* sfacelist)[k - 2];
-        } else {
-          // 'sface1' is in the middle and may be the last one. 
-          shellfacedealloc(subfaces, sface1.sh);
-          // Skip this face and go to the next one.
-          continue;
+  // Check segments in the list of subfaces.
+  for (i = 0; i < cavsublist->len(); i++) {
+    startsub = * (face *)(* cavsublist)[i];
+    // Test all three edges of startsub.
+    for (j = 0; j < 3; j++) {
+      sspivot(startsub, checkseg);
+      if (checkseg.sh != dummysh) {
+        if (!shell2badface(checkseg)) {
+          checkseg4encroach(&checkseg, testpt, NULL, true);
         }
       }
-      */ 
-      if (b->verbose > 2) {
-        printf("    Bond subfaces (%d, %d, %d) and (%d, %d, %d).\n",
-               pointmark(torg), pointmark(tdest), pointmark(sapex(sface)),
-               pointmark(torg), pointmark(tdest), pointmark(sapex(sface1)));
-      }
-      sbond1(sface, sface1);
-      sface = sface1;
+      senextself(startsub);
     }
-    // Set the unique segment marker into the unified segment.
-    setshellmark(subsegloop, segmarker);
-    // Increase the marker.
-    segmarker++;
-    // Clear the working list.
-    sfacelist->clear(); 
-    subsegloop.sh = shellfacetraverse(subsegs);
   }
 
-  delete [] idx2facelist;
-  delete [] facesperverlist;
-  delete sfacelist;
+  return (badsubsegs->items > oldencnum);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// mergefacets()    Merge adjacent facets to be one facet if they are        //
-//                  coplanar and have the same boundary marker.              //
+// collectflipedges()    Collect edges of split subfaces for flip checking.  //
 //                                                                           //
-// 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.                                    //
+// 'inspoint' is a newly inserted segment point (inserted by insertsite()).  //
+// 'splitseg' is one of the two split subsegments. Some subfaces may be non- //
+// Delaunay since they're still not bonded to CDT. This routine collect all  //
+// such possible subfaces in 'flipqueue'.                                    //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::mergefacets(queue* flipqueue)
+void tetgenmesh::
+collectflipedges(point inspoint, face* splitseg, queue* flipqueue)
 {
-  face parentsh, neighsh, neineighsh;
-  face segloop;
-  point eorg, edest;
-  REAL ori;
-  bool mergeflag, pbcflag;
-  int* segspernodelist;
-  int fidx1, fidx2;
-  int i, j;
+  face startsh, spinsh, checksh;
+  face nextseg;
+  point pa, pb;
 
-  if (b->verbose) {
-    printf("  Merging coplanar facets.\n");
-  }
-  // Create and initialize 'segspernodelist'.
-  segspernodelist = new int[points->items + 1];
-  for (i = 0; i < points->items + 1; i++) {
-    segspernodelist[i] = 0;
+  // Let the dest of splitseg be inspoint.
+  splitseg->shver = 0;
+  if (sdest(*splitseg) != inspoint) {
+    sesymself(*splitseg);
   }
+#ifdef SELF_CHECK
+  assert(sdest(*splitseg) == inspoint);
+#endif
+  pa = sorg(*splitseg);
+  spivot(*splitseg, startsh);
+  spinsh = startsh;
+  do {
+    findedge(&spinsh, pa, inspoint);
+    senext2(spinsh, checksh);
+    enqueueflipedge(checksh, flipqueue);
+    spivotself(spinsh);
+  } while (spinsh.sh != startsh.sh);
 
-  // Loop the segments, counter the number of segments sharing each vertex.
-  subsegs->traversalinit();
-  segloop.sh = shellfacetraverse(subsegs);
-  while (segloop.sh != (shellface *) NULL) {
-    // Increment the number of sharing segments for each endpoint.
-    for (i = 0; i < 2; i++) {
-      j = pointmark((point) segloop.sh[3 + i]);
-      segspernodelist[j]++;
-    }
-    segloop.sh = shellfacetraverse(subsegs);
+  // Get the next subsegment.
+  senext(*splitseg, nextseg);
+  spivotself(nextseg);
+#ifdef SELF_CHECK
+  assert(nextseg.sh != (shellface *) NULL);
+#endif
+  
+  // Let the org of nextseg be inspoint.
+  nextseg.shver = 0;
+  if (sorg(nextseg) != inspoint) {
+    sesymself(nextseg);
   }
+#ifdef SELF_CHECK
+  assert(sorg(nextseg) == inspoint);
+#endif
+  pb = sdest(nextseg);
+  spivot(nextseg, startsh);
+  spinsh = startsh;
+  do {
+    findedge(&spinsh, inspoint, pb);
+    senext(spinsh, checksh);
+    enqueueflipedge(checksh, flipqueue);
+    spivotself(spinsh);
+  } while (spinsh.sh != startsh.sh);
+}
 
-  // Loop the segments, find out dead segments.
-  subsegs->traversalinit();
-  segloop.sh = shellfacetraverse(subsegs);
-  while (segloop.sh != (shellface *) NULL) {
-    eorg = sorg(segloop);
-    edest = sdest(segloop);
-    spivot(segloop, parentsh);
-    spivot(parentsh, neighsh);
-    spivot(neighsh, neineighsh);
-    if (parentsh.sh != neighsh.sh && parentsh.sh == neineighsh.sh) {
-      // Exactly two subfaces at this segment.
-      fidx1 = shellmark(parentsh) - 1;
-      fidx2 = shellmark(neighsh) - 1;
-      pbcflag = false;
-      if (checkpbcs) {
-        pbcflag = (shellpbcgroup(parentsh) >= 0)
-          || (shellpbcgroup(neighsh) >= 0);
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// perturbrepairencsegs()    Repair all encroached segments.                 //
+//                                                                           //
+// All encroached segments are stored in 'badsubsegs'.  Each segment will be //
+// split by adding a perturbed point near its circumcenter.                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::perturbrepairencsegs(queue* flipqueue)
+{
+  badface *encloop;
+  tetrahedron encodedtet;
+  triface splittet;
+  face splitsub, symsplitsub;
+  face splitseg, symsplitseg;
+  point newpoint, sympoint;
+  point pa, pb, pc;
+  enum insertsiteresult success;
+  enum locateresult loc, symloc;
+  REAL cent[3], d1, ps, rs;
+  int i, j;
+
+  // Note that steinerleft == -1 if an unlimited number of Steiner points 
+  //   is allowed.  Loop until 'badsubsegs' is empty.
+  badsubsegs->traversalinit();
+  encloop = badfacetraverse(badsubsegs);
+  while ((encloop != (badface *) NULL) && (steinerleft != 0)) {
+    splitseg = encloop->ss;
+#ifdef SELF_CHECK
+    assert(shell2badface(splitseg) == encloop);
+#endif
+    setshell2badface(splitseg, NULL);
+    pa = sorg(splitseg);
+    pb = sdest(splitseg);
+    if ((pa == encloop->forg) && (pb == encloop->fdest)) {
+      if (b->verbose > 1) {
+        printf("  Get seg (%d, %d).\n", pointmark(pa), pointmark(pb));
       }
-      // Possibly merge them if they are not in the same facet.
-      if ((fidx1 != fidx2) && !pbcflag) {
-        // Test if they are coplanar.
-        ori = orient3d(eorg, edest, sapex(parentsh), sapex(neighsh));
-        if (ori != 0.0) {
-          if (iscoplanar(eorg, edest, sapex(parentsh), sapex(neighsh), ori,
-                         b->epsilon)) {
-            ori = 0.0; // They are assumed as coplanar.
-          }
-        }
-        if (ori == 0.0) {
-          mergeflag = (in->facetmarkerlist == (int *) NULL || 
-          in->facetmarkerlist[fidx1] == in->facetmarkerlist[fidx2]);
-          if (mergeflag) {
-            // This segment becomes dead.
-            if (b->verbose > 1) {
-              printf("  Removing segment (%d, %d).\n", pointmark(eorg),
-                     pointmark(edest));
+      // Create the newpoint.
+      makepoint(&newpoint);
+      // Get the circumcenter and radius of ab.
+      for (i = 0; i < 3; i++) cent[i] = 0.5 * (pa[i] + pb[i]);
+      d1 = 0.5 * distance(pa, pb);
+      // Add a random perturbation to newpoint along the vector ab.
+      ps = randgenerator(d1 * 1.0e-3);
+      rs = ps / d1;
+      // Set newpoint (be at the perturbed circumcenter of ab).
+      for (i = 0; i < 3; i++) newpoint[i] = cent[i] + rs * (cent[i] - pa[i]);
+      setpointtype(newpoint, FREESEGVERTEX);
+      // Set splitseg into the newpoint.
+      setpoint2sh(newpoint, sencode(splitseg));        
+
+      // Is there periodic boundary condition?
+      if (checkpbcs) {
+        // Insert points on other segments of incident pbcgroups.
+        i = shellmark(splitseg) - 1;
+        for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++) {
+          makepoint(&sympoint);
+          symloc = getsegpbcsympoint(newpoint, &splitseg, sympoint,
+                                     &symsplitseg, segpglist[j]);
+#ifdef SELF_CHECK
+          assert(symloc != OUTSIDE);
+#endif
+          // Note: the symsplitseg and splitseg may be identical, in case
+          //   when the the splitseg is the axis of the rotational sym.
+          if ((symloc == ONEDGE) && (symsplitseg.sh != splitseg.sh)) {
+            setpointtype(sympoint, FREESEGVERTEX);
+            setpoint2sh(sympoint, sencode(symsplitseg));
+            // Insert sympoint into DT.
+            pc = sorg(symsplitseg);
+            splittet.tet = dummytet;
+            // Find a good start point to search.
+            encodedtet = point2tet(pc);
+            if (encodedtet != (tetrahedron) NULL) {
+              decode(encodedtet, splittet);
+              if (isdead(&splittet)) {
+                splittet.tet = dummytet; 
+              }
             }
-            ssdissolve(parentsh);
-            ssdissolve(neighsh);
-            shellfacedealloc(subsegs, segloop.sh);
-            j = pointmark(eorg);
-            segspernodelist[j]--;
-            if (segspernodelist[j] == 0) {
-              setpointtype(eorg, FACETVERTEX);
+            // Locate sympoint in DT.  Do exact location.
+            success = insertsite(sympoint, &splittet, false, flipqueue);
+#ifdef SELF_CHECK
+            assert(success != DUPLICATEPOINT);
+#endif
+            if (success == OUTSIDEPOINT) {
+              inserthullsite(sympoint, &splittet, flipqueue);
             }
-            j = pointmark(edest);
-            segspernodelist[j]--;
-            if (segspernodelist[j] == 0) {
-              setpointtype(edest, FACETVERTEX);
+            if (steinerleft > 0) steinerleft--;
+            // Let sympoint remember splittet.
+            setpoint2tet(sympoint, encode(splittet));
+            // Do flip in DT.
+            flip(flipqueue, NULL);
+            // Insert sympoint into F.
+            symloc = locateseg(sympoint, &symsplitseg);
+            if (symloc == ONEDGE) {
+              symsplitseg.shver = 0;
+              spivot(symsplitseg, symsplitsub);
+              // sympoint should on the edge of symsplitsub.
+              splitsubedge(sympoint, &symsplitsub, flipqueue);
+            } else {
+              // insertsite() has done the whole job.
+#ifdef SELF_CHECK
+              assert(symloc == ONVERTEX);
+              assert(checksubfaces);
+#endif
+              // Some edges may need to be flipped.
+              collectflipedges(sympoint, &symsplitseg, flipqueue);
             }
-            // Add 'parentsh' to queue checking for flip.
-            enqueueflipedge(parentsh, flipqueue);
+            // Do flip in facet.
+            flipsub(flipqueue);
+          } else { // if (symloc == ONVERTEX) {
+            // The symmtric point already exists. It is possible when two
+            //   pbc group are idebtical. Omit sympoint.
+            pointdealloc(sympoint);
+          }
+        }
+      }
+
+      // Insert newpoint into DT.
+      splittet.tet = dummytet;
+      // Find a good start point to search.
+      encodedtet = point2tet(pa);
+      if (encodedtet != (tetrahedron) NULL) {
+        decode(encodedtet, splittet);
+        if (isdead(&splittet)) {
+          splittet.tet = dummytet; 
+        }
+      }
+      if (splittet.tet == dummytet) { // Try pb.
+        encodedtet = point2tet(pb);
+        if (encodedtet != (tetrahedron) NULL) {
+          decode(encodedtet, splittet);
+          if (isdead(&splittet)) {
+            splittet.tet = dummytet;
           }
         }
       }
+      // Locate the newpoint in DT.  Do exact location.
+      success = insertsite(newpoint, &splittet, false, flipqueue);
+#ifdef SELF_CHECK
+      assert(success != DUPLICATEPOINT);
+#endif
+      if (success == OUTSIDEPOINT) {
+        // A convex hull edge is mssing, and the inserting point lies
+        //   (slightly) outside the convex hull due to the significant
+        //   digits lost in the calculation. Enlarge the convex hull.
+        inserthullsite(newpoint, &splittet, flipqueue);
+      }
+      if (steinerleft > 0) steinerleft--;
+      // Let newpoint remember splittet.
+      setpoint2tet(newpoint, encode(splittet));
+      // Do flip in DT.
+      flip(flipqueue, NULL);
+      // Insert newpoint into F.
+      loc = locateseg(newpoint, &splitseg);
+      if (loc == ONEDGE) {
+        splitseg.shver = 0;
+        spivot(splitseg, splitsub);
+        // newpoint should on the edge of splitsub.
+        splitsubedge(newpoint, &splitsub, flipqueue);
+      } else {
+        // insertsite() has done the whole job.
+#ifdef SELF_CHECK
+        assert(loc == ONVERTEX);
+        assert(checksubfaces);
+#endif
+        // Some edges may need to be flipped.
+        collectflipedges(newpoint, &splitseg, flipqueue);
+      }
+      // Do flip in facet.
+      flipsub(flipqueue);
     }
-    segloop.sh = shellfacetraverse(subsegs);
-  }
-
-  if (!flipqueue->empty()) {
-    // Restore the Delaunay property in the facet triangulation.
-    flipsub(flipqueue);
+    // Remove this entry from list.
+    badfacedealloc(badsubsegs, encloop);  
+    // Get the next encroached segments.
+    encloop = badfacetraverse(badsubsegs);
   }
-
-  delete [] segspernodelist;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// assignvarconstraints()    Assign constraints to facets, segs, and nodes.  //
-//                                                                           //
-// The variant constraints of facets, segments and nodes are defined in file //
-// 'filename.cons'. These information have been loaded in 'in'.              //
+// perturbrepairencsubs()    Repair all encroached subfaces.                 //
 //                                                                           //
-// This routine will be called in meshsurface() (when -p switch is in use),  //
-// and in reconstructmesh() (when -r switch is in use).                      //
+// All encroached subfaces are stored in 'badsubfaces'. Each subface will be //
+// split by adding a perturbed point near its circumcenter. However, if the  //
+// point encroaches some segments, it will not be inserted.  Instead, the    //
+// encroached segments are split.                                            //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::assignvarconstraints(point *idx2verlist)
+void tetgenmesh::perturbrepairencsubs(list* cavsublist, queue* flipqueue)
 {
-  face subloop, segloop;
-  point p1, p2;
-  REAL area;
-  int fmarker, fidx;
-  int end1, end2;
+  badface *encloop, *encsubseg;
+  tetrahedron encodedtet;
+  triface splittet;
+  face splitsub, symsplitsub;
+  face checkseg, symsplitseg;
+  point newpoint, sympoint;
+  point pa, pb, pc, pd;
+  enum insertsiteresult success;
+  enum locateresult loc, symloc;
+  REAL cent[3], d1, ps, rs;
+  bool reject;
   int i;
 
-  if (in->facetconstraintlist != (REAL *) NULL) {
-    if (b->verbose) {
-      printf("  Assigning facet constraints.\n");
-    }
-    for (i = 0; i < in->numberoffacetconstraints; i++) {
-      fmarker = (int) in->facetconstraintlist[i * 2];
-      area = in->facetconstraintlist[i * 2 + 1];
-      // Assign 'area' to all subfaces which having 'fmarker'.
-      subfaces->traversalinit();
-      subloop.sh = shellfacetraverse(subfaces);
-      while (subloop.sh != (shellface *) NULL) {
-        fidx = shellmark(subloop) - 1;
-        if (in->facetmarkerlist[fidx] == fmarker) {
-          setareabound(subloop, area);
+  // Note that steinerleft == -1 if an unlimited number of Steiner points
+  //   is allowed.  Loop until the list 'badsubfaces' is empty.
+  while ((badsubfaces->items > 0) && (steinerleft != 0)) {
+    badsubfaces->traversalinit();
+    encloop = badfacetraverse(badsubfaces);
+    while ((encloop != (badface *) NULL) && (steinerleft != 0)) {
+      splitsub = encloop->ss;
+#ifdef SELF_CHECK
+      assert(shell2badface(splitsub) == encloop);
+#endif
+      setshell2badface(splitsub, NULL);
+      pa = sorg(splitsub);
+      pb = sdest(splitsub);
+      pc = sapex(splitsub);
+      // The subface may be not the same one when it was determined to be
+      //   encroached.  If its adjacent encroached subface was split, the
+      //   consequent flips may change it into another subface.
+      if ((pa == encloop->forg) && (pb == encloop->fdest) &&
+          (pc == encloop->fapex)) {
+        if (b->verbose > 1) {
+          printf("  Get subface (%d, %d, %d).\n", pointmark(pa),
+                 pointmark(pb), pointmark(pc));
         }
-        subloop.sh = shellfacetraverse(subfaces);
-      }
-    }
-  }
+        // Create the newpoint.
+        makepoint(&newpoint);
+        // Get the circumcenter of abc.
+        circumsphere(pa, pb, pc, NULL, cent, &d1);
+#ifdef SELF_CHECK
+        assert(d1 > 0.0);
+#endif
+        // Add a random perturbation to newpoint along the vector a->cent.
+        //   This way, the perturbed point still lies in the plane of abc.
+        ps = randgenerator(d1 * 1.0e-3);
+        rs = ps / d1;
+        // Set newpoint (be at the perturbed circumcenter of abc).
+        for (i = 0; i < 3; i++) newpoint[i] = cent[i] + rs * (cent[i] - pa[i]);
+        // Get the abovepoint of the facet.
+        abovepoint = facetabovepointarray[shellmark(splitsub)];
+        // Do we need to calculate the abovepoint?
+        if (abovepoint == (point) NULL) {
+          getfacetabovepoint(&splitsub);
+        }
+        loc = locatesub(newpoint, &splitsub, 1, 0.0);
+#ifdef SELF_CHECK
+        assert(loc != ONVERTEX);
+#endif
+        if (loc != OUTSIDE) {
+          // Add 'splitsub' into 'cavsublist'.
+          cavsublist->append(&splitsub);
+          // Collect all subfaces that encroached by newpoint.
+          collectcavsubs(newpoint, cavsublist);
+          // Find if there are encroached segments.
+          reject = tallencsegsfsubs(newpoint, cavsublist);
+          // Clear cavsublist for the next use.
+          cavsublist->clear();
+        } else {
+          // newpoint lies outside. splitsub contains the boundary segment.
+          sspivot(splitsub, checkseg);
+#ifdef SELF_CHECK
+          assert(checkseg.sh != dummysh);
+#endif
+          // Add this segment into list for splitting.
+          if (b->verbose > 2) {
+            printf("    Queuing boundary segment (%d, %d).\n",
+                   pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
+          }
+          encsubseg = (badface *) badsubsegs->alloc();
+          encsubseg->ss = checkseg;
+          encsubseg->forg = sorg(checkseg);
+          encsubseg->fdest = sdest(checkseg);
+          encsubseg->foppo = (point) NULL;
+          setshell2badface(encsubseg->ss, encsubseg);
+          // Reject newpoint.
+          reject = true;
+        }
+
+        if (!reject) {
+          // newpoint is going to be inserted.
+          
+          // Is there periodic boundary condition?
+          if (checkpbcs) {
+            if (shellpbcgroup(splitsub) >= 0) {
+              // Insert a point on another facet of the pbcgroup.
+              makepoint(&sympoint);
+              // Note: 'abovepoint' will be changed.
+              symloc = getsubpbcsympoint(newpoint, &splitsub, sympoint,
+                                         &symsplitsub);
+#ifdef SELF_CHECK
+              assert(symloc != ONVERTEX);
+#endif
+              setpoint2pbcpt(newpoint, sympoint);
+              setpoint2pbcpt(sympoint, newpoint);
+              setpointtype(sympoint, FREESUBVERTEX);
+              // setpoint2sh(sympoint, sencode(symsplitsub));
+              // Insert sympoint into DT.
+              pd = sorg(symsplitsub);
+              splittet.tet = dummytet;
+              // Find a good start point to search.
+              encodedtet = point2tet(pd);
+              if (encodedtet != (tetrahedron) NULL) {
+                decode(encodedtet, splittet);
+                if (isdead(&splittet)) {
+                  splittet.tet = dummytet; 
+                }
+              }
+              // Locate sympoint in DT.  Do exact location.
+              success = insertsite(sympoint, &splittet, false, flipqueue);
+#ifdef SELF_CHECK
+              assert(success != DUPLICATEPOINT);
+#endif
+              if (success == OUTSIDEPOINT) {
+                inserthullsite(sympoint, &splittet, flipqueue);
+              }
+              if (steinerleft > 0) steinerleft--;
+              // Let sympoint remember splittet.
+              setpoint2tet(sympoint, encode(splittet));
+              // Do flip in DT.
+              flip(flipqueue, NULL);
+              // Insert sympoint into F.
+              // getabovepoint(&symsplitsub);
+              // symloc = locatesub(sympoint, &symsplitsub, 1, 0.0);
+              if (symloc == ONFACE) {
+                splitsubface(sympoint, &symsplitsub, flipqueue);
+              } else if (symloc == ONEDGE) {
+                splitsubedge(sympoint, &symsplitsub, flipqueue);
+              } else {
+                // 'insertsite()' has done the whole job.
+#ifdef SELF_CHECK
+                assert(symloc == ONVERTEX);
+                assert(checksubfaces);
+#endif
+                // Split subfaces have been flipped.
+                flipqueue->clear();
+              }
+              // Do flip in facet.
+              flipsub(flipqueue);
+            }
+          }
+
+          // Insert newpoint into DT.
+          splittet.tet = dummytet;
+          // Find a good start point to search.
+          encodedtet = point2tet(pa);
+          if (encodedtet != (tetrahedron) NULL) {
+            decode(encodedtet, splittet);
+            if (isdead(&splittet)) {
+              splittet.tet = dummytet; 
+            }
+          }
+          if (splittet.tet == dummytet) { // Try pb.
+            encodedtet = point2tet(pb);
+            if (encodedtet != (tetrahedron) NULL) {
+              decode(encodedtet, splittet);
+              if (isdead(&splittet)) {
+                splittet.tet = dummytet;
+              }
+            }
+          }
+          // Locate the newpoint in DT.  Do exact location.
+          success = insertsite(newpoint, &splittet, false, flipqueue);
+#ifdef SELF_CHECK
+          assert(success != DUPLICATEPOINT);
+#endif
+          if (success == OUTSIDEPOINT) {
+            inserthullsite(newpoint, &splittet, flipqueue);
+          }
+          if (steinerleft > 0) steinerleft--;
+          // Let newpoint remember splittet.
+          setpoint2tet(newpoint, encode(splittet));
+          // Do flip in DT.
+          flip(flipqueue, NULL);
+          // Insert newpoint into F.
+          // if (checkpbcs) {
+            // 'abovepoint' has been changed.
+            // getabovepoint(&splitsub);
+            // loc = locatesub(newpoint, &splitsub, 1, 0.0);
+          // }
+          if (loc == ONFACE) {
+            // Insert the newpoint in facet.
+            splitsubface(newpoint, &splitsub, flipqueue);
+          } else if (loc == ONEDGE) {
+            // Insert the newpoint in facet.
+            splitsubedge(newpoint, &splitsub, flipqueue);
+          } else {
+            // 'insertsite()' has done the whole job.
+#ifdef SELF_CHECK
+            assert(loc == ONVERTEX);
+            assert(checksubfaces);
+#endif
+            // Split subfaces have been flipped.
+            flipqueue->clear();
+          }
+          // Set the type of the newpoint.
+          setpointtype(newpoint, FREESUBVERTEX);
+          // Set splitsub into the newpoint.
+          // setpoint2sh(newpoint, sencode(splitsub));
+          // Do flip in the facet.
+          flipsub(flipqueue);
 
-  if (in->segmentconstraintlist != (REAL *) NULL) {
-    if (b->verbose) {
-      printf("  Assigning segment constraints.\n");
-    }
-    for (i = 0; i < in->numberofsegmentconstraints; i++) {
-      end1 = (int) in->segmentconstraintlist[i * 3];
-      end2 = (int) in->segmentconstraintlist[i * 3 + 1];
-      area = in->segmentconstraintlist[i * 3 + 2];
-      // Assign 'area' to segment has (end1, end2).
-      subsegs->traversalinit();
-      segloop.sh = shellfacetraverse(subsegs);
-      while (segloop.sh != (shellface *) NULL) {
-	p1 = (point) segloop.sh[3];
-        p2 = (point) segloop.sh[4];
-        if (((pointmark(p1) == end1) && (pointmark(p2) == end2)) ||
-            ((pointmark(p1) == end2) && (pointmark(p2) == end1))) {
-          setareabound(segloop, area);
-          break;
+          // Remove this entry from list.
+          badfacedealloc(badsubfaces, encloop);
+        } else {
+          // newpoint is rejected. Remove it from points.
+          pointdealloc(newpoint);
+          // Repair all encroached segments.
+          perturbrepairencsegs(flipqueue);
+          // Do not remove 'encloop'. Later it will be tested again.
+          setshell2badface(encloop->ss, encloop);
         }
-        segloop.sh = shellfacetraverse(subsegs);
-      }
-    }
-  }
-
-  if (in->nodeconstraintlist != (REAL *) NULL) {
-    if (b->verbose) {
-      printf("  Assigning node constraints.\n");
-    }
-    for (i = 0; i < in->numberofnodeconstraints; i++) {
-      end1 = (int) in->nodeconstraintlist[i * 2];
-      area = in->nodeconstraintlist[i * 2 + 1];
-      end1 -= in->firstnumber;
-      if ((end1 >= 0) && (end1 < in->numberofpoints)) {
-        p1 = idx2verlist[end1];
-        setedgebound(p1, area);
+      } else {
+        // This subface has been changed. Remove this entry from list.
+        badfacedealloc(badsubfaces, encloop);
+        // It may be co-circular with its neighbors.
+        // checksub4cocir(&splitsub, eps, false, true); 
       }
+      // Get the next encroached subfaces.
+      encloop = badfacetraverse(badsubfaces);
     }
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// meshsurface()    Create the surface mesh of a PLC.                        //
-//                                                                           //
-// The surface mesh of a PLC X is a triangulation consists of subfaces and   //
-// segments. Subfaces are 2-dimensional constrained Delaunay triangulations  //
-// of the facets of X, segments are edges bounded the facets.                //
+// incrperturbvertices()    Remove the local degeneracies in DT.             //
 //                                                                           //
-// Subfaces of each facet are connecting each other. Each segment contains a //
-// ring of subfaces which saves the connection between facets sharing at it. //
+// A local degeneracy of a DT D is a set of 5 or more vertices which share a //
+// common sphere S and no other vertex of D in S.  D is not unique if it has //
+// local degeneracies. This routine removes the local degeneracies from D by //
+// inserting break points (as described in reference [2]).                   //
 //                                                                           //
-// This routine first creates the CDTs of facets separatly, i.e., each facet //
-// will be meshed into a set of subfaces and segments. As a result, subfaces //
-// only have connections to subfaces which are belong to the same facet. And //
-// segments are over-created. Routine unifysegment() is called to remove the //
-// redundant segments and create the subface ring around segments.           //
+// 'eps' is a user-provided error tolerance. It is used to detect whether or //
+// not five points are approximate cospherical (evaluated in iscospheric()). //
+// Set it to 0.0 to disable it, i.e., only test pure degenerate point set.   //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-long tetgenmesh::meshsurface()
+void tetgenmesh::incrperturbvertices(REAL eps)
 {
-  list *ptlist, *conlist;
   queue *flipqueue;
-  point *idx2verlist;
-  int i;
+  list *cavsublist;
+  long vertcount;
 
   if (!b->quiet) {
-    printf("Creating surface mesh.\n");
-  }
-
-  // Compute a mapping from indices to points.
-  makeindex2pointmap(idx2verlist);
-  // Initialize 'flipqueue'.
-  flipqueue = new queue(sizeof(badface));
-  // Two re-useable lists 'ptlist' and 'conlist'.
-  ptlist = new list("int");
-  conlist = new list(sizeof(int) * 2, NULL);
-  // Initialize 'liftpointarray'.
-  liftpointarray = new REAL[in->numberoffacets * 3];
-  
-  if (checkpbcs) {
-    // Create the 'subpbcgrouptable'.
-    createsubpbcgrouptable();
-  }
-
-  // Loop the facet list, triangulate each facet. On finish, all subfaces
-  //   are in 'subfaces', all segments are in 'subsegs' (Note: there exist
-  //   duplicated segments).
-  for (i = 0; i < in->numberoffacets; i++) {
-    triangulatefacet(i + 1, ptlist, conlist, idx2verlist, flipqueue);
-  }
-
-  // Unify segments in 'subsegs', remove redundant segments.  Face links
-  //   of segments are also built.
-  unifysegments();
-
-  if (checkpbcs) {
-    // Create the 'segpbcgrouptable'.
-    createsegpbcgrouptable();
+    printf("Perturbing vertices.\n");
   }
 
-  if (b->object == tetgenbehavior::STL) {
-    // Remove redundant vertices (for .stl input mesh).
-    jettisonnodes();
-  }
+  vertcount = points->items;
+  // Create a map from points to tets for fastening search.
+  // makepoint2tetmap();  // This has been done in meshsurface().
 
-  if (!b->nomerge) {
-    // Merge adjacent facets if they are coplanar.
-    mergefacets(flipqueue);
+  // Initialize working queues, lists.
+  flipqueue = new queue(sizeof(badface));
+  cavsublist = new list(sizeof(face), NULL, 256);
+  // Initialize the pool of encroached subfaces and subsegments.
+  badsubsegs = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
+  badsubfaces = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
+  // Find all pairs of co-circular subfaces.
+  tallcocirsubs(eps, true);
+  if (b->verbose && badsubfaces->items > 0) {
+    printf("  Removing degenerate subfaces.\n");
   }
+  perturbrepairencsubs(cavsublist, flipqueue);
 
-  if (b->quality && varconstraint) {
-    // Assign constraints on facets, segments, and nodes.
-    assignvarconstraints(idx2verlist);
+  if (b->verbose > 0) {
+    printf("  %ld break points.\n", points->items - vertcount);
   }
-
-  delete [] idx2verlist;
+  
+  delete cavsublist;
   delete flipqueue;
-  delete conlist;
-  delete ptlist;
-
-  return subsegs->items;
+  delete badsubfaces;
+  delete badsubsegs; 
+  badsubsegs = (memorypool *) NULL;
+  badsubfaces = (memorypool *) NULL;
 }
 
-//
-// End of surface triangulation routines
-//
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// interecursive()    Recursively do intersection test on a set of triangles.//
-//                                                                           //
-// Recursively split the set 'subfacearray' of subfaces into two sets using  //
-// a cut plane parallel to x-, or, y-, or z-axies.  The split criteria are   //
-// follows. Assume the cut plane is H, and H+ denotes the left halfspace of  //
-// H, and H- denotes the right halfspace of H; and s be a subface:           //
-//                                                                           //
-//    (1) If all points of s lie at H+, put it into left array;              //
-//    (2) If all points of s lie at H-, put it into right array;             //
-//    (3) If some points of s lie at H+ and some of lie at H-, or some       //
-//        points lie on H, put it into both arraies.                         //
-//                                                                           //
-// Partitions by x-axis if axis == '0'; by y-axis if axis == '1'; by z-axis  //
-// if axis == '2'. If current cut plane is parallel to the x-axis, the next  //
-// one will be parallel to y-axis, and the next one after the next is z-axis,//
-// and then alternately return back to x-axis.                               //
-//                                                                           //
-// Stop splitting when the number of triangles of the input array is not     //
-// decreased anymore. Do tests on the current set.                           //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-void tetgenmesh::
-interecursive(shellface** subfacearray, int arraysize, int axis, REAL bxmin,
-              REAL bxmax, REAL bymin, REAL bymax, REAL bzmin, REAL bzmax,
-              int* internum)
-{
-  shellface **leftarray, **rightarray;
-  face sface1, sface2;
-  point p1, p2, p3;
-  point p4, p5, p6;
-  enum interresult intersect;
-  REAL split;
-  bool toleft, toright;
-  int leftsize, rightsize;
-  int i, j;
-
-  if (b->verbose > 1) {
-    printf("  Recur %d faces. Bbox (%g, %g, %g),(%g, %g, %g). %s-axis\n",
-           arraysize, bxmin, bymin, bzmin, bxmax, bymax, bzmax,
-           axis == 0 ? "x" : (axis == 1 ? "y" : "z"));
-  }
-    
-  leftarray = new shellface*[arraysize];
-  if (leftarray == NULL) {
-    printf("Error in interecursive():  Insufficient memory.\n");
-    exit(1);
-  }
-  rightarray = new shellface*[arraysize];
-  if (rightarray == NULL) {
-    printf("Error in interecursive():  Insufficient memory.\n");
-    exit(1);
-  }
-  leftsize = rightsize = 0;
-
-  if (axis == 0) {
-    // Split along x-axis.
-    split = 0.5 * (bxmin + bxmax);
-  } else if (axis == 1) {
-    // Split along y-axis.
-    split = 0.5 * (bymin + bymax);
-  } else {
-    // Split along z-axis.
-    split = 0.5 * (bzmin + bzmax);
-  }
-
-  for (i = 0; i < arraysize; i++) {
-    sface1.sh = subfacearray[i];
-    p1 = (point) sface1.sh[3];
-    p2 = (point) sface1.sh[4];
-    p3 = (point) sface1.sh[5];
-    toleft = toright = false;
-    if (p1[axis] < split) {
-      toleft = true;
-      if (p2[axis] >= split || p3[axis] >= split) {
-        toright = true;
-      } 
-    } else if (p1[axis] > split) {
-      toright = true;
-      if (p2[axis] <= split || p3[axis] <= split) {
-        toleft = true;
-      } 
-    } else {
-      // p1[axis] == split;
-      toleft = true;
-      toright = true;
-    }
-    // At least one is true;
-    assert(!(toleft == false && toright == false));
-    if (toleft) {
-      leftarray[leftsize] = sface1.sh;
-      leftsize++;
-    }
-    if (toright) {
-      rightarray[rightsize] = sface1.sh;
-      rightsize++;
-    }
-  }
-
-  if (leftsize < arraysize && rightsize < arraysize) {
-    // Continue to partition the input set. Now 'subfacearray' has been
-    //   split into two sets, it's memory can be freed. 'leftarray' and
-    //   'rightarray' will be freed in the next recursive (after they're
-    //   partitioned again or performing tests).
-    delete [] subfacearray;
-    // Continue to split these two sets.
-    if (axis == 0) {
-      interecursive(leftarray, leftsize, 1, bxmin, split, bymin, bymax,
-                    bzmin, bzmax, internum);
-      interecursive(rightarray, rightsize, 1, split, bxmax, bymin, bymax,
-                    bzmin, bzmax, internum);
-    } else if (axis == 1) {
-      interecursive(leftarray, leftsize, 2, bxmin, bxmax, bymin, split,
-                    bzmin, bzmax, internum);
-      interecursive(rightarray, rightsize, 2, bxmin, bxmax, split, bymax,
-                    bzmin, bzmax, internum);
-    } else {
-      interecursive(leftarray, leftsize, 0, bxmin, bxmax, bymin, bymax,
-                    bzmin, split, internum);
-      interecursive(rightarray, rightsize, 0, bxmin, bxmax, bymin, bymax,
-                    split, bzmax, internum);
-    }
-  } else {
-    if (b->verbose > 1) {
-      printf("  Checking intersecting faces.\n");
-    }
-    // Perform a brute-force compare on the set.
-    for (i = 0; i < arraysize; i++) {
-      sface1.sh = subfacearray[i];
-      p1 = (point) sface1.sh[3];
-      p2 = (point) sface1.sh[4];
-      p3 = (point) sface1.sh[5];
-      for (j = i + 1; j < arraysize; j++) {
-        sface2.sh = subfacearray[j];
-        p4 = (point) sface2.sh[3];
-        p5 = (point) sface2.sh[4];
-        p6 = (point) sface2.sh[5];
-        intersect = tri_tri_inter(p1, p2, p3, p4, p5, p6);
-        if (intersect == INTERSECT || intersect == SHAREFACE) {
-          if (!b->quiet) {
-            if (intersect == INTERSECT) {
-              printf("  Facet #%d intersects facet #%d at triangles:\n",
-                     shellmark(sface1), shellmark(sface2));
-              printf("    (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
-                     pointmark(p1), pointmark(p2), pointmark(p3),
-                     pointmark(p4), pointmark(p5), pointmark(p6));
-            } else {
-              printf("  Facet #%d duplicates facet #%d at triangle:\n",
-                     shellmark(sface1), shellmark(sface2));
-              printf("    (%4d, %4d, %4d)\n", pointmark(p1), pointmark(p2),
-                     pointmark(p3));
+//
+// End of vertex perturbation routines
+//
+
+//
+// Begin of segment recovery routines
+//
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// markacutevertices()    Mark each vertex to be ACUTE or NACUTE.            //
+//                                                                           //
+// A vertex is acute if at least two segments incident at it with an angle   //
+// smaller than a given angle bound (e.g. 90 degree).                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::markacutevertices(REAL acuteangle)
+{
+  shellface **segsperverlist;
+  face segloop, workseg, inciseg;
+  point eorg, edest, eapex;
+  REAL cosbound, anglearc;
+  REAL v1[3], v2[3], L, D;
+  bool isacute;
+  int *idx2seglist;
+  int idx, i, j, k;
+
+  if (b->verbose > 0) {
+    printf("  Marking segments have acute corners.\n");
+  }
+
+  anglearc = acuteangle * PI / 180.0;
+  cosbound = cos(anglearc);
+  // 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; 
             }
           }
-          // Increase the number of intersecting pairs.
-          (*internum)++; 
-          // Infect these two faces (although they may already be infected).
-          sinfect(sface1);
-          sinfect(sface2);
+        }
+        if (isacute) {
+          setpointtype(eorg, ACUTEVERTEX);
+        } else {
+          setpointtype(eorg, NACUTEVERTEX);
         }
       }
     }
-    // Don't forget to free all three arrays. No further partition.
-    delete [] leftarray;
-    delete [] rightarray;  
-    delete [] subfacearray;
+    segloop.sh = shellfacetraverse(subsegs);
   }
+
+  delete [] idx2seglist;
+  delete [] segsperverlist;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// detectinterfaces()    Detect intersecting triangles.                      //
+// finddirection()    Find the first tetrahedron on the path from one point  //
+//                    to another.                                            //
 //                                                                           //
-// Given a set of triangles,  find the pairs of intersecting triangles from  //
-// them.  Here the set of triangles is in 'subfaces' which is a surface mesh //
-// of a PLC (.poly or .smesh).                                               //
+// Find the tetrahedron that intersects a line segment L (from the origin of //
+// 'searchtet' to the point 'tend'), and returns the result in 'searchtet'.  //
+// The origin of 'searchtet' does not change, even though the tetrahedron    //
+// returned may differ from the one passed in.  This routine is used to find //
+// the direction to move in to get from one point to another.                //
 //                                                                           //
-// To detect whether two triangles are intersecting is done by the routine   //
-// 'tri_tri_inter()'.  The algorithm for the test is very simple and stable. //
-// It is based on geometric orientation test which uses exact arithmetics.   //
+// The return value notes the location of the line segment L with respect to //
+// 'searchtet':                                                              //
+//   - Returns RIGHTCOLLINEAR indicates L is collinear with the line segment //
+//     from the origin to the destination of 'searchtet'.                    //
+//   - Returns LEFTCOLLINEAR indicates L is collinear with the line segment  //
+//     from the origin to the apex of 'searchtet'.                           //
+//   - Returns TOPCOLLINEAR indicates L is collinear with the line segment   //
+//     from the origin to the opposite of 'searchtet'.                       //
+//   - Returns ACROSSEDGE indicates L intersects with the line segment from  //
+//     the destination to the apex of 'searchtet'.                           //
+//   - Returns ACROSSFACE indicates L intersects with the face opposite to   //
+//     the origin of 'searchtet'.                                            //
+//   - Returns BELOWHULL indicates L crosses outside the mesh domain. This   //
+//     can only happen when the domain is non-convex.                        //
 //                                                                           //
-// Use divide-and-conquer algorithm for reducing the number of intersection  //
-// tests.  Start from the bounding box of the input point set, recursively   //
-// partition the box into smaller boxes, until the number of triangles in a  //
-// box is not decreased anymore. Then perform triangle-triangle tests on the //
-// remaining set of triangles.  The memory allocated in the input set is     //
-// freed immediately after it has been partitioned into two arrays.  So it   //
-// can be re-used for the consequent partitions.                             //
+// NOTE: This routine only works correctly when the mesh is exactly Delaunay.//
 //                                                                           //
-// On return, the pool 'subfaces' will be cleared, and only the intersecting //
-// triangles remain for output (to a .face file).                            //
+// If 'maxtetnumber' > 0, stop the searching process if the number of passed //
+// tets is larger than it. Return BELOWHULL.                                 //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::detectinterfaces()
+enum tetgenmesh::finddirectionresult tetgenmesh::
+finddirection(triface *searchtet, point tend, long maxtetnumber)
 {
-  shellface **subfacearray;
-  face shloop;
-  int internum;
-  int i;
+  triface neightet;
+  point tstart, tdest, tapex, toppo;
+  REAL ori1, ori2, ori3;
+  long tetnumber;
 
-  if (!b->quiet) {
-    printf("Detecting intersecting facets.\n");
+  tstart = org(*searchtet);
+#ifdef SELF_CHECK
+  assert(tstart != tend);
+#endif
+  adjustedgering(*searchtet, CCW);
+  if (tstart != org(*searchtet)) {
+    enextself(*searchtet); // For keeping the same origin.
   }
-
-  // Construct a map from indices to subfaces;
-  subfacearray = new shellface*[subfaces->items];
-  subfaces->traversalinit();
-  shloop.sh = shellfacetraverse(subfaces);
-  i = 0;
-  while (shloop.sh != (shellface *) NULL) {
-    subfacearray[i] = shloop.sh;
-    shloop.sh = shellfacetraverse(subfaces);
-    i++;
+  tdest = dest(*searchtet);
+  if (tdest == tend) {
+    return RIGHTCOLLINEAR;
   }
+  tapex = apex(*searchtet); 
+  if (tapex == tend) {
+    return LEFTCOLLINEAR;
+  } 
 
-  internum = 0;
-  // Recursively split the set of triangles into two sets using a cut plane
-  //   parallel to x-, or, y-, or z-axies.  Stop splitting when the number
-  //   of subfaces is not decreasing anymore. Do tests on the current set.
-  interecursive(subfacearray, subfaces->items, 0, xmin, xmax, ymin, ymax,
-                zmin, zmax, &internum);
-
-  if (!b->quiet) {
-    if (internum > 0) {
-      printf("\n!! Found %d pairs of faces are intersecting.\n\n", internum);
+  ori1 = orient3d(tstart, tdest, tapex, tend);
+  if (ori1 > 0.0) {
+    // 'tend' is below the face, get the neighbor of this side.
+    sym(*searchtet, neightet);
+    if (neightet.tet != dummytet) {
+      findorg(&neightet, tstart); 
+      adjustedgering(neightet, CCW);
+      if (org(neightet) != tstart) {
+        enextself(neightet); // keep the same origin.
+      }
+      // Set the changed configuratiuon.
+      *searchtet = neightet; 
+      ori1 = -1.0; 
+      tdest = dest(*searchtet);
+      tapex = apex(*searchtet);
     } else {
-      printf("\nNo faces are intersecting.\n\n");
+      // A hull face. Only possible for a nonconvex mesh.
+#ifdef SELF_CHECK
+      assert(nonconvex);
+#endif
+      return BELOWHULL; 
     }
   }
 
-  if (internum > 0) {
-    // Traverse all subfaces, deallocate those have not been infected (they
-    //   are not intersecting faces). Uninfect those have been infected.
-    //   After this loop, only intersecting faces remain.
-    subfaces->traversalinit();
-    shloop.sh = shellfacetraverse(subfaces);
-    while (shloop.sh != (shellface *) NULL) {
-      if (sinfected(shloop)) {
-        suninfect(shloop);
+  // Repeatedly change the 'searchtet', remain 'tstart' be its origin, until
+  //   find a tetrahedron contains 'tend' or is crossed by the line segment
+  //   from 'tstart' to 'tend'.
+  tetnumber = 0l;
+  while ((maxtetnumber > 0) && (tetnumber <= maxtetnumber)) {
+    tetnumber++;
+    toppo = oppo(*searchtet);
+    if (toppo == tend) {
+      return TOPCOLLINEAR;
+    }
+    ori2 = orient3d(tstart, toppo, tdest, tend);
+    if (ori2 > 0.0) {
+      // 'tend' is below the face, get the neighbor at this side.
+      fnext(*searchtet, neightet);
+      symself(neightet);
+      if (neightet.tet != dummytet) {
+        findorg(&neightet, tstart); 
+        adjustedgering(neightet, CCW);
+        if (org(neightet) != tstart) {
+          enextself(neightet); // keep the same origin.
+        }
+        // Set the changed configuration.
+        *searchtet = neightet; 
+        ori1 = -1.0; 
+        tdest = dest(*searchtet);
+        tapex = apex(*searchtet);
+        // Continue the search from the changed 'searchtet'.
+        continue;
+      } else {
+        // A hull face. Only possible for a nonconvex mesh.
+#ifdef SELF_CHECK
+        assert(nonconvex);
+#endif
+        return BELOWHULL; 
+      }
+    }
+    ori3 = orient3d(tapex, toppo, tstart, tend);
+    if (ori3 > 0.0) {
+      // 'tend' is below the face, get the neighbor at this side.
+      enext2fnext(*searchtet, neightet);
+      symself(neightet);
+      if (neightet.tet != dummytet) {
+        findorg(&neightet, tstart); 
+        adjustedgering(neightet, CCW);
+        if (org(neightet) != tstart) {
+          enextself(neightet); // keep the same origin.
+        }
+        // Set the changed configuration.
+        *searchtet = neightet; 
+        ori1 = -1.0; 
+        tdest = dest(*searchtet);
+        tapex = apex(*searchtet);
+        // Continue the search from the changed 'searchtet'.
+        continue;
       } else {
-        shellfacedealloc(subfaces, shloop.sh);
+        // A hull face. Only possible for a nonconvex mesh.
+#ifdef SELF_CHECK
+        assert(nonconvex);
+#endif
+        return BELOWHULL; 
+      }
+    }
+    // Now 'ori1', 'ori2' and 'ori3' are possible be 0.0 or all < 0.0;
+    if (ori1 < 0.0) {
+      // Possible cases are: ACROSSFACE, ACROSSEDGE, TOPCOLLINEAR.
+      if (ori2 < 0.0) {
+        if (ori3 < 0.0) {
+          return ACROSSFACE;
+        } else { // ori3 == 0.0;
+          // Cross edge (apex, oppo)
+          enext2fnextself(*searchtet);
+          esymself(*searchtet); // org(*searchtet) == tstart;
+          return ACROSSEDGE;
+        }
+      } else { // ori2 == 0.0; 
+        if (ori3 < 0.0) {
+          // Cross edge (dest, oppo)
+          fnextself(*searchtet);
+          esymself(*searchtet);
+          enextself(*searchtet); // org(*searchtet) == tstart;
+          return ACROSSEDGE;
+        } else { // ori3 == 0.0;
+          // Collinear with edge (org, oppo)
+          return TOPCOLLINEAR;
+        }
+      }
+    } else { // ori1 == 0.0;
+      // Possible cases are: RIGHTCOLLINEAR, LEFTCOLLINEAR, ACROSSEDGE.
+      if (ori2 < 0.0) {
+        if (ori3 < 0.0) {
+          // Cross edge (tdest, tapex)
+          return ACROSSEDGE;
+        } else { // ori3 == 0.0
+          // Collinear with edge (torg, tapex)
+          return LEFTCOLLINEAR;
+        }
+      } else { // ori2 == 0.0;
+#ifdef SELF_CHECK
+        assert(ori3 != 0.0);
+#endif
+        // Collinear with edge (torg, tdest)
+        return RIGHTCOLLINEAR;
       }
-      shloop.sh = shellfacetraverse(subfaces);
     }
-  } else {
-    // Deallocate all subfaces.
-    subfaces->restart();
   }
+  // Loop breakout. It may happen when the mesh is non-Delaunay.
+  return BELOWHULL;
 }
 
-//
-// Begin of periodic boundary condition routines
-//
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// createsubpbcgrouptable()    Create the 'subpbcgrouptable'.                //
+// getsearchtet()    Find a tetrahedron whose origin is either 'p1' or 'p2'. //
 //                                                                           //
-// Allocate the memory for 'subpbcgrouptable'.  Each entry i (a pbcdata) of  //
-// the table represents a pbcgroup.  Most of the fields of a group-i are set //
-// in this routine. 'fmark[0]', 'fmark[1]', and 'transmat[0]' are directly   //
-// copied from the corresponding data of 'in->numberofpbcgroups'. 'transmat  //
-// [1]' is calculated as the inverse matrix of 'transmat[0]'.  'ss[0]' and   //
-// 'ss[1]' are initilized be 'dummysh'. They are set in 'trangulatefacet()'  //
-// (when -p is in use) or 'reconstructmesh()' (when -r is in use).           //
+// On return, the origin of 'searchtet' is either 'p1' or 'p2',  and 'tend'  //
+// returns the other point.  'searchtet' serves as the starting tetrahedron  //
+// for searching of the line segment from 'p1' to 'p2' or vice versa.        //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::createsubpbcgrouptable()
+void tetgenmesh::getsearchtet(point p1, point p2, triface* searchtet,
+  point* tend)
 {
-  tetgenio::pbcgroup *pg;
-  pbcdata *pd;
-  REAL A[4][4], rhs[4], D;
-  int indx[4];
-  int i, j, k;
+  tetrahedron encodedtet1, encodedtet2;
 
-  subpbcgrouptable = new pbcdata[in->numberofpbcgroups];
-  for (i = 0; i < in->numberofpbcgroups; i++) {
-    pg = &(in->pbcgrouplist[i]);
-    pd = &(subpbcgrouptable[i]);
-    // Copy data from pg to pd.
-    pd->fmark[0] = pg->fmark1;
-    pd->fmark[1] = pg->fmark2;
-    // Initialize array 'pd->ss'.
-    pd->ss[0].sh = dummysh;
-    pd->ss[1].sh = dummysh;
-    // Copy the transform matrix from pg to pd->transmat[0].
-    for (j = 0; j < 4; j++) {
-      for (k = 0; k < 4; k++) {
-        pd->transmat[0][j][k] = pg->transmat[j][k];
-        // Prepare for inverting the matrix.
-        A[j][k] = pg->transmat[j][k];
+  // Is there a valid handle provided by the user?
+  if ((searchtet->tet != (tetrahedron *) NULL) && !isdead(searchtet)) {
+    // Find which endpoint the handle holds.
+    if (findorg(searchtet, p1)) {
+      *tend = p2;
+      return;
+    } else {
+      if (findorg(searchtet, p2)) {
+        *tend = p1;
+        return;
       }
     }
-    // Calculate the inverse matrix (pd->transmat[1]) of pd->transmat[0].
-    lu_decmp(A, 4, indx, &D, 0);
-    for (j = 0; j < 4; j++) {
-      for (k = 0; k < 4; k++) rhs[k] = 0.0;
-      rhs[j] = 1.0;
-      lu_solve(A, 4, indx, rhs, 0);
-      for (k = 0; k < 4; k++) pd->transmat[1][k][j] = rhs[k];
+  }
+  // If not, search the tet handle stored in 'p1' or 'p2'.
+  *tend = (point) NULL;
+  encodedtet1 = point2tet(p1);
+  encodedtet2 = point2tet(p2);
+  if (encodedtet1 != (tetrahedron) NULL) {
+    decode(encodedtet1, *searchtet);
+    // Be careful, here 'searchtet' may be dead.
+    if (findorg(searchtet, p1)) {
+      *tend = p2;
+    }
+  } else if (encodedtet2 != (tetrahedron) NULL) {
+    decode(encodedtet2, *searchtet);
+    // Be careful, here 'searchtet' may be dead.
+    if (findorg(searchtet, p2)) {
+      *tend = p1;
+    }
+  }
+  // If still not, perform a full point location.  The starting tet is
+  //   chosen as follows: Use the handle stored in 'p1' or 'p2' if it is
+  //   alive; otherwise, start from a tet on the convex hull.
+  if (*tend == (point) NULL) {
+    if (encodedtet1 != (tetrahedron) NULL) {
+      decode(encodedtet1, *searchtet);
+      // Be careful, here 'searchtet' may be dead.
+    }
+    if (isdead(searchtet)) {
+      if (encodedtet2 != (tetrahedron) NULL) {
+        decode(encodedtet2, *searchtet);
+        // Be careful, here 'searchtet' may be dead.
+      }
+      if (isdead(searchtet)) {
+        searchtet->tet = dummytet;
+        searchtet->loc = 0;
+        symself(*searchtet);
+      }
+#ifdef SELF_CHECK
+      assert(!isdead(searchtet));
+#endif
+    }
+    if (locate(p1, searchtet) != ONVERTEX) {
+      printf("Internal error in getsearchtet():  Failed to locate point\n");
+      internalerror();
     }
+    // Remember this handle in 'p1' to enhance the search speed.
+    setpoint2tet(p1, encode(*searchtet));
+    *tend = p2;
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// getsubpbcgroup()    Get the pbcgroup of a subface.                        //
+// isedgeencroached()    Check whether or not a subsegment is encroached.    //
 //                                                                           //
-// 'pbcsub' has pbc defined. Its pbcgroup is returned in 'pd'. In addition,  //
-// 'f1' (0 or 1) indicates the position of 'pbcsub' in 'pd'; 'f2' (= 1 - f1) //
-// is the position where the symmetric subface of 'pbcsub' is found.         //
+// A segment with endpoints 'p1' and 'p2' is encroached by the point 'testpt'//
+// if it lies in the diametral sphere of this segment.  The degenerate case  //
+// that 'testpt' lies on the sphere is treated as encroached if 'degflag' is //
+// set to be TRUE.                                                           //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::getsubpbcgroup(face* pbcsub, pbcdata** pd, int *f1, int *f2)
+bool tetgenmesh::isedgeencroached(point p1, point p2, point testpt,
+  bool degflag)
 {
-  int groupid, fmark, idx;
+  REAL dotproduct;
 
-  groupid = shellpbcgroup(*pbcsub);
-  *pd = &subpbcgrouptable[groupid];
-  
-  // Get the facet index (1 - based).
-  idx = shellmark(*pbcsub);
-  // Get the facet marker from array (0 - based).
-  fmark = in->facetmarkerlist[idx - 1];
-  if ((*pd)->fmark[0] == fmark) {
-    *f1 = 0;
+  // Check if the segment is facing an angle larger than 90 degree?
+  dotproduct = (p1[0] - testpt[0]) * (p2[0] - testpt[0])
+             + (p1[1] - testpt[1]) * (p2[1] - testpt[1])
+             + (p1[2] - testpt[2]) * (p2[2] - testpt[2]);
+  if (dotproduct < 0) {
+    return true;
+  } else if (dotproduct == 0 && degflag) {
+    return true;
   } else {
-    assert((*pd)->fmark[1] == fmark);
-    *f1 = 1;
+    return false;
   }
-  *f2 = 1 - (*f1);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// getsubpbcsympoint()    Compute the symmetric point for a subface point.   //
+// scoutrefpoint()    Search the reference point of a missing segment.       //
 //                                                                           //
-// 'newpoint' lies on 'splitsub'. This routine calculates a 'sympoint' which //
-// locates on 'symsplitsub' and symmtric to 'newpoint'.  Return the location //
-// of sympoint wrt. symsplitsub.                                             //
+// A segment S is missing in current Delaunay tetrahedralization DT and will //
+// be split by inserting a point V in it.  The two end points of S are the   //
+// origin of 'searchtet' and 'tend'. And we know that S is crossing the face //
+// of 'searchtet' opposite to its origin (may be intersecting with the edge  //
+// from the destination to the apex of the 'searchtet').  The search of P is //
+// completed by walking through all faces of DT across by S.                 //
+//                                                                           //
+// Warning:  This routine is correct when the tetrahedralization is Delaunay //
+// and convex. Otherwise, the search loop may not terminate.                 //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::locateresult tetgenmesh::
-getsubpbcsympoint(point newpoint, face* splitsub, point sympoint,
-                  face* symsplitsub)
+tetgenmesh::point tetgenmesh::scoutrefpoint(triface* searchtet, point tend)
 {
-  pbcdata *pd;
-  face subloop;
-  enum locateresult symloc;
-  int f1, f2, i;
+  triface checkface;
+  point tstart, testpt, refpoint;
+  REAL cent[3], radius, largest;
+  REAL ahead;
+  bool ncollinear;
+  int sides;
 
-  // Get the pbcgroup of 'splitsub'.
-  getsubpbcgroup(splitsub, &pd, &f1, &f2);
-      
-  // Transform newpoint from f1 -> f2.
-  for (i = 0; i < 3; i++) {
-    sympoint[i] = pd->transmat[f1][i][0] * newpoint[0]
-                + pd->transmat[f1][i][1] * newpoint[1]
-                + pd->transmat[f1][i][2] * newpoint[2]
-                + pd->transmat[f1][i][3] * 1.0;
+  if (b->verbose > 2) {
+    printf("  Scout the reference point of segment (%d, %d).\n",
+           pointmark(org(*searchtet)), pointmark(tend));
   }
-  // Locate sympoint in f2.
-  symloc = OUTSIDE;
-  *symsplitsub = pd->ss[f2];
-  // Is the stored subface valid? Hole removal may delete the subface.  
-  if ((symsplitsub->sh != dummysh) && !isdead(symsplitsub)) {
-    // 'symsplitsub' should lie on the symmetric facet. Check it.
-    i = shellmark(*symsplitsub);
-    if (in->facetmarkerlist[i - 1] == pd->fmark[f2]) {
-      // Locate sympoint in facet. Don't stop at subsegment.
-      symloc = locatesub(sympoint, symsplitsub, 0);
-    }
+
+  tstart = org(*searchtet);
+  refpoint = (point) NULL;
+  largest = 0; // avoid compile warning.
+  
+  // Check the three vertices of the crossing face.
+  testpt = apex(*searchtet);
+  if (isedgeencroached(tstart, tend, testpt, true)) {
+    ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
+#ifdef SELF_CHECK
+    assert(ncollinear);
+#endif
+    refpoint = testpt;
+    largest = radius;
   }
-  if (symloc == OUTSIDE) {
-    // Locate sympoint in the pool of subfaces (with fmark pd->fmark[f2]).
-    subfaces->traversalinit();
-    subloop.sh = shellfacetraverse(subfaces);
-    while (subloop.sh != (shellface *) NULL) {
-      i = shellmark(subloop);
-      if (in->facetmarkerlist[i - 1] == pd->fmark[f2]) {
-        // subloop is on the facet, search sympoint.
-        symloc = locatesub(sympoint, &subloop, 0);
-        if (symloc != OUTSIDE) break;
+  testpt = dest(*searchtet);
+  if (isedgeencroached(tstart, tend, testpt, true)) {
+    ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
+#ifdef SELF_CHECK
+    assert(ncollinear);
+#endif
+    if (refpoint == (point) NULL) {
+      refpoint = testpt;
+      largest = radius;
+    } else {
+      if (radius > largest) {
+        refpoint = testpt;
+        largest = radius;
       }
-      subloop.sh = shellfacetraverse(subfaces);
     }
-    // Set the returning subface.
-    *symsplitsub = subloop;
-    // Update the stored subface for next searching.
-    pd->ss[f2] = *symsplitsub;
   }
-  // sympoint should be inside the facet.
-  assert(symloc != OUTSIDE);
-
-  return adjustlocatesub(sympoint, symsplitsub, symloc, b->epsilon);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// createsegpbcgrouptable()    Create the 'segpbcgrouptable'.                //
-//                                                                           //
-// Each segment may belong to more than one pbcgroups. 'segpbcgrouptable' is //
-// implemented as a list of pbcdatas. Each item i represents a pbcgroup.     //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-void tetgenmesh::createsegpbcgrouptable()
-{
-  pbcdata *pd, *pd1, *pd2;
-  face segloop, symseg;
-  face startsh, spinsh, symsh;
-  point pa, pb;
-  enum locateresult symloc;
-  REAL testpt[3], sympt[3];
-  bool inflag;
-  int segid1, segid2;
-  int f1, f2;
-  int i, j, k, l;
-
-  // Allocate memory for 'subpbcgrouptable'.
-  segpbcgrouptable = new list(sizeof(pbcdata), NULL, 256);
-
-  // Loop through the segment list.
-  subsegs->traversalinit();
-  segloop.sh = shellfacetraverse(subsegs);
-  while (segloop.sh != (shellface *) NULL) {
-    // Loop the subface ring of segloop ab.
-    pa = sorg(segloop);
-    pb = sdest(segloop);
-    segid1 = shellmark(segloop);
-    spivot(segloop, startsh);
-    spinsh = startsh;
-    do {
-      // Adjust spinsh be edge ab.
-      if (sorg(spinsh) != pa) {
-        sesymself(spinsh);
+  testpt = oppo(*searchtet);
+  if (isedgeencroached(tstart, tend, testpt, true)) {
+    ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
+#ifdef SELF_CHECK
+    assert(ncollinear);
+#endif
+    if (refpoint == (point) NULL) {
+      refpoint = testpt;
+      largest = radius;
+    } else {
+      if (radius > largest) {
+        refpoint = testpt;
+        largest = radius;
       }
-      // 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);
-        assert(symloc == ONEDGE);
-        sspivot(symsh, symseg);
-        assert(symseg.sh != dummysh);
-        // Check whether this group has already been created in list.
-        segid2 = shellmark(symseg);
-        inflag = false;
-        for (i = 0; i < segpbcgrouptable->len() && !inflag; i++) {
-          pd = (pbcdata *)(* segpbcgrouptable)[i];
-          if (pd->segid[0] == segid1) {
-            if (pd->segid[1] == segid2) inflag = true;
-          } else if (pd->segid[0] == segid2) {
-            if (pd->segid[1] == segid1) inflag = true;
-          }
-        }
-        if (!inflag) {
-          // Create a segment pbcgroup in list for ab and cd.
-          pd = (pbcdata *) segpbcgrouptable->append(NULL);
-          // Save the markers of ab and cd.
-          pd->segid[0] = segid1;
-          pd->segid[1] = segid2;
-          // Save the handles of ab and cd.
-          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];
-          // 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];
-            }
-          }
-          // 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];
-            }
-          }
+    }
+  }
+  // Check the opposite vertex of the neighboring tet in case the segment
+  //   crosses the edge (leftpoint, rightpoint) of the crossing face.
+  sym(*searchtet, checkface);
+  if (checkface.tet != dummytet) {
+    testpt = oppo(checkface);
+    if (isedgeencroached(tstart, tend, testpt, true)) {
+      ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
+#ifdef SELF_CHECK
+      assert(ncollinear);
+#endif
+      if (refpoint == (point) NULL) {
+        refpoint = testpt;
+        largest = radius;
+      } else {
+        if (radius > largest) {
+          refpoint = testpt;
+          largest = radius;
         }
       }
-      // Go to the next subface in the ring of ab.
-      spivotself(spinsh);
-    } while (spinsh.sh != startsh.sh);
-    segloop.sh = shellfacetraverse(subsegs);
+    }
   }
 
-  // Create the indirect segment pbcgroups.
-  for (i = 0; i < segpbcgrouptable->len(); i++) {
-    pd1 = (pbcdata *)(* segpbcgrouptable)[i];
-    for (f1 = 0; f1 < 2; 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];
-        f2 = -1;
-        if (pd1->segid[f1] == pd2->segid[0]) {
-          f2 = 0;
-        } else if (pd1->segid[f1] == pd2->segid[1]) {
-          f2 = 1;
-        }
-        if (f2 != -1) {
-          assert(pd1->segid[f1] == pd2->segid[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++) {
-            pd = (pbcdata *)(* segpbcgrouptable)[k];
-            if (pd->segid[0] == segid1) {
-              if (pd->segid[1] == segid2) inflag = true;
-            } else if (pd->segid[0] == segid2) {
-              if (pd->segid[1] == segid1) inflag = true;
-            }
+  // Walk through all crossing faces.
+  enextfnext(*searchtet, checkface);
+  sym(checkface, *searchtet);
+  while (true) {
+    // Check if we are reaching the boundary of the triangulation.
+#ifdef SELF_CHECK
+    assert(searchtet->tet != dummytet);
+#endif
+    // Search for an adjoining tetrahedron we can walk through.
+    searchtet->ver = 0;
+    // 'testpt' is the shared vertex for the following orientation tests.
+    testpt = oppo(*searchtet);
+    if (testpt == tend) {
+      // The searching is finished.
+      break; 
+    } else {
+      // 'testpt' may encroach the segment.
+      if ((testpt != tstart) && (testpt != refpoint)) {
+        if (isedgeencroached(tstart, tend, testpt, true)) {
+          ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
+          if (!ncollinear) {
+            // 'testpt' is collinear with the segment. It may happen when a
+            //   set of collinear and continuous segments is defined by two
+            //   extreme endpoints.  In this case, we should choose 'testpt'
+            //   as the splitting point immediately.  No new point should be
+            //   created.
+            refpoint = testpt;
+            break;
           }
-          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];
-            // 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].
-            for (k = 0; k < 4; k++) {
-              for (l = 0; l < 4; l++) { 
-                pd->transmat[0][k][l] = pd2->transmat[f2][k][l];
-              }
-            }
-            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].
-            for (k = 0; k < 4; k++) {
-              for (l = 0; l < 4; l++) { 
-                pd->transmat[1][k][l] = pd1->transmat[f1][k][l];
-              }
+          if (refpoint == (point) NULL) {
+            refpoint = testpt;
+            largest = radius;
+          } else {
+            if (radius > largest) {
+              refpoint = testpt;
+              largest = radius;
             }
-            m4xm4(pd->transmat[1], pd2->transmat[1 - f2]);
           }
         }
       }
     }
-  }
-
-  // Form a map from segment index to pbcgroup list of this segment.
-  idx2segpglist = new int[subsegs->items + 1];
-  for (i = 0; i < subsegs->items + 1; i++) idx2segpglist[i] = 0;
-  // Loop through 'segpbcgrouptable', counter the number of pbcgroups of
-  //   each segment.
-  for (i = 0; i < segpbcgrouptable->len(); i++) {
-    pd = (pbcdata *)(* segpbcgrouptable)[i];
-    for (j = 0; j < 2; j++) {
-      k = pd->segid[j] - 1;
-      idx2segpglist[k]++;
-    }
-  }
-  // Calculate the total length of array 'segpglist'.
-  j = idx2segpglist[0];
-  idx2segpglist[0] = 0;  // Array starts from 0 element.
-  for (i = 0; i < subsegs->items; i++) {
-    k = idx2segpglist[i + 1];
-    idx2segpglist[i + 1] = idx2segpglist[i] + j;
-    j = k;
-  }
-  // The total length is in the last unit of idx2segpglist.
-  segpglist = new int[idx2segpglist[i]];
-  // Loop the set of pbcgroups again, set the data into segpglist.
-  for (i = 0; i < segpbcgrouptable->len(); i++) {
-    pd = (pbcdata *)(* segpbcgrouptable)[i];
-    for (j = 0; j < 2; j++) {
-      k = pd->segid[j] - 1;
-      segpglist[idx2segpglist[k]] = i;
-      idx2segpglist[k]++;
+    // Check three side-faces of 'searchtet' to find the one through
+    //   which we can walk next.
+    for (sides = 0; sides < 3; sides++) {
+      fnext(*searchtet, checkface);
+      ahead = orient3d(org(checkface), dest(checkface), testpt, tend);
+      if (ahead < 0.0) {
+        // We can walk through this face and continue the searching. 
+        sym(checkface, *searchtet);
+        break;
+      }
+      enextself(*searchtet);
     }
+#ifdef SELF_CHECK
+    assert (sides < 3);
+#endif
   }
-  // Contents in 'idx2segpglist' are shifted, now shift them back.
-  for (i = subsegs->items - 1; i >= 0; i--) {
-    idx2segpglist[i + 1] = idx2segpglist[i];
-  }
-  idx2segpglist[0] = 0;
+
+#ifdef SELF_CHECK
+  assert(refpoint != (point) NULL);
+#endif
+  return refpoint;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// locateseg()    Find a point in subsegments.                               //
-//                                                                           //
-// Searching begins from the input 'searchseg', it should be a subsegment of //
-// the whole segment.                                                        //
+// getsegmentorigin()    Return the origin of the (unsplit) segment.         //
 //                                                                           //
-// On completion, 'searchseg' is a subsegment that contains 'searchpt'.      //
-//   - Returns ONVERTEX if the point lies on an existing vertex. 'searchseg' //
-//     is a handle whose origin is the existing vertex.                      //
-//   - Returns ONEDGE if the point lies inside 'searchseg'.                  //
-//   - Returns OUTSIDE if the point lies outside the segment.                //
+// After a segment (or a subsegment) is split. Two resulting subsegments are //
+// connecting each other through the pointers saved in their data fields.    //
+// With these pointers, the whole (unsplit) segment can be found. 'splitseg' //
+// may be a split subsegment.  Returns the origin of the unsplit segment.    //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::locateresult tetgenmesh::
-locateseg(point searchpt, face* searchseg)
+tetgenmesh::point tetgenmesh::getsegmentorigin(face* splitseg)
 {
-  face backtraceseg;
-  point pa, pb;
-  int moveleft;
-  int i;
+  face workseg;
+  point farorg;
 
-  while (1) {
-    searchseg->shver = 0;
-    pa = sorg(*searchseg);
-    pb = sdest(*searchseg);
-    for (i = 0; i < 3; i++) {
-      if (pa[i] < pb[i]) {
-        if (searchpt[i] < pa[i]) {
-          moveleft = 1;
-          break;
-        } else if (searchpt[i] > pa[i]) {
-          if (searchpt[i] < pb[i]) {
-            return ONEDGE;
-          } else if (searchpt[i] > pb[i]) {
-            moveleft = 0;
-            break;
-          } else {
-            assert(searchpt[i] == pb[i]);
-            sesymself(*searchseg);
-            return ONVERTEX;
-          }
-        } else {
-          assert(searchpt[i] == pa[i]);
-          return ONVERTEX;
-        }
-      } else if (pa[i] > pb[i]) {
-        if (searchpt[i] < pb[i]) {
-          moveleft = 0;
-          break;
-        } else if (searchpt[i] > pb[i]) {
-          if (searchpt[i] < pa[i]) {
-            return ONEDGE;
-          } else if (searchpt[i] > pa[i]) {
-            moveleft = 1;
-            break;
-          } else {
-            assert(searchpt[i] == pa[i]);
-            return ONVERTEX;
-          }
-        } else {
-          assert(searchpt[i] == pb[i]);
-          sesymself(*searchseg);
-          return ONVERTEX;
+  farorg = sorg(*splitseg);
+  if ((pointtype(farorg) != ACUTEVERTEX) &&
+      (pointtype(farorg) != NACUTEVERTEX)) {
+    workseg = *splitseg;
+    do {
+      senext2self(workseg);
+      spivotself(workseg);
+      if (workseg.sh != dummysh) {
+        workseg.shver = 0;  // It's a subsegment.
+        if (sdest(workseg) != farorg) {
+          sesymself(workseg);
+#ifdef SELF_CHECK
+          assert(sdest(workseg) == farorg);
+#endif
         }
+        farorg = sorg(workseg);
+        if ((pointtype(farorg) == ACUTEVERTEX) ||
+            (pointtype(farorg) == NACUTEVERTEX)) break;
       }
-    }
-    assert(i < 3);
-    backtraceseg = *searchseg;
-    if (moveleft) {
-      senext2self(*searchseg);
-    } else {
-      senextself(*searchseg);
-    }
-    spivotself(*searchseg);
-    if (searchseg->sh == dummysh) {
-      *searchseg = backtraceseg;
-      break;
-    }
+    } while (workseg.sh != dummysh);
   }
-
-  return OUTSIDE;
+#ifdef SELF_CHECK
+  assert((pointtype(farorg) == ACUTEVERTEX) ||
+         (pointtype(farorg) == NACUTEVERTEX));
+#endif
+  return farorg;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// adjustlocateseg()    Adjust the precise location of a vertex on segment.  //
+// getsplitpoint()    Get a point for splitting a segment.                   //
 //                                                                           //
-// 'searchpt' is either inside or ouside the segment 'searchseg'. It will be //
-// adjusted to on vertex if it is very close to an endpoint of 'searchseg'.  //
-// 'epspp' is the given relative tolerance.                                  //
+// 'splitseg' is the segment will be split. 'refpoint' is a reference point  //
+// for splitting this segment. Moreover, it should not collinear with the    //
+// splitting segment. (The collinear case will be detected by iscollinear()  //
+// before entering this routine.)  The calculation of the splitting point is //
+// governed by three rules introduced in my paper.                           //
+//                                                                           //
+// After the position is calculated, a new point is created at this location.//
+// The new point has one of the two pointtypes: FREESEGVERTEX indicating it  //
+// is an inserting vertex on segment, and NACUTEVERTEX indicating it is an   //
+// endpoint of a segment which original has type-3 now becomes type-2.       //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::locateresult tetgenmesh::
-adjustlocateseg(point searchpt, face* searchseg, enum locateresult precise,
-                REAL epspp)
+tetgenmesh::point tetgenmesh::getsplitpoint(face* splitseg, point refpoint)
 {
-  point pa, pb;
-  REAL L, d, r;
+  point splitpoint;
+  point farorg, fardest;
+  point ei, ej, ek, c;
+  REAL v[3], r, split;
+  REAL d1, ps, rs;
+  bool acuteorg, acutedest;
+  int stype, rule;
+  int i;   
 
-  pa = sorg(*searchseg);
-  pb = sdest(*searchseg);
-  L = distance(pa, pb);
+  // First determine the type of the segment (type-1, type-2, or type-3).
+  farorg = getsegmentorigin(splitseg);
+  acuteorg = (pointtype(farorg) == ACUTEVERTEX);
+  sesymself(*splitseg);
+  fardest = getsegmentorigin(splitseg);
+  acutedest = (pointtype(fardest) == ACUTEVERTEX);
+  sesymself(*splitseg);
 
-  // Is searchpt approximate to pa?
-  d = distance(pa, searchpt);
-  r = d / L;
-  if (r <= epspp) {
-    return ONVERTEX;
+  ek = (point) NULL; // avoid a compilation warning.
+
+  if (acuteorg) {
+    if (acutedest) {
+      stype = 3;
+    } else {
+      stype = 2;
+      ek = farorg;
+    }
+  } else {
+    if (acutedest) {
+      stype = 2;
+      // Adjust splitseg, so that its origin is acute.
+      sesymself(*splitseg);
+      ek = fardest;
+    } else {
+      stype = 1;
+    }
   }
-  // Is searchpt approximate to pb?
-  d = distance(pb, searchpt);
-  r = d / L;
-  if (r <= epspp) {
-    sesymself(*searchseg);
-    return ONVERTEX;
+  ei = sorg(*splitseg);
+  ej = sdest(*splitseg);
+
+  if (b->verbose > 1) {
+    printf("  Splitting segment (%d, %d) type-%d with refpoint %d.\n",
+           pointmark(ei), pointmark(ej), stype, pointmark(refpoint));
   }
 
-  return precise;
-}
+  if (stype == 1 || stype == 3) {
+    // Use rule-1.
+    REAL eij, eip, ejp;
+    eij = distance(ei, ej);
+    eip = distance(ei, refpoint);
+    ejp = distance(ej, refpoint);
+    if ((eip < ejp) && (eip < 0.5 * eij)) {
+      c = ei;
+      r = eip;
+    } else if ((eip > ejp) && (ejp < 0.5 * eij)) {
+      c = ej;
+      ej = ei;
+      r = ejp;
+    } else {
+      c = ei;
+      r = 0.5 * eij;
+    }
+    split = r / eij;
+    for (i = 0; i < 3; i++) {
+      v[i] = c[i] + split * (ej[i] - c[i]);
+    }
+    rule = 1;
+  } else {
+    // Use rule-2 or rule-3.
+    REAL eki, ekj, ekp, evj, evp, eiv;
+    c = ek;
+    eki = distance(ek, ei);  // eki may equal zero.
+    ekj = distance(ek, ej);
+    ekp = distance(ek, refpoint);
+    // Calculate v (the going to split position between ei, ej).
+    r = ekp;
+    // Check the validity of the position.
+    if (!(eki < r && r < ekj)) {
+      printf("Error:  Invalid PLC.\n");
+      printf("  Hint:  Use -d switch to check it.\n");
+      terminatetetgen(1);
+    }
+    split = r / ekj;
+    for (i = 0; i < 3; i++) {
+      v[i] = c[i] + split * (ej[i] - c[i]);
+    }
+    rule = 2;
+    evj = ekj - r; // distance(v, ej);
+    evp = distance(v, refpoint);
+    if (evj < evp) {
+      // v is rejected, use rule-3.
+      eiv = distance(ei, v);
+      if (evp <= 0.5 * eiv) {
+        r = eki + eiv - evp;
+      } else {
+        r = eki + 0.5 * eiv;
+      }
+#ifdef SELF_CHECK
+      assert(eki < r && r < ekj);
+#endif
+      split = r / ekj;
+      for (i = 0; i < 3; i++) {
+        v[i] = c[i] + split * (ej[i] - c[i]);
+      }
+      if (b->verbose > 1) {
+        printf("    Using rule-3.\n");
+      }
+      rule = 3;
+    }
+  }
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// getsegpbcsympoint()    Compute the symmetric point for a segment point.   //
-//                                                                           //
-// 'newpoint' lies on 'splitseg'. This routine calculates a 'sympoint' which //
-// locates on 'symsplitseg' and symmtric to 'newpoint'.  Return the location //
-// of sympoint wrt. symsplitseg.                                             //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
+  // Accumulate the corresponding counters.
+  if (rule == 1) r1count++;
+  else if (rule == 2) r2count++;
+  else if (rule == 3) r3count++;
+  else if (rule == 4) r4count++;
 
-enum tetgenmesh::locateresult tetgenmesh::
-getsegpbcsympoint(point newpoint, face* splitseg, point sympoint,
-                  face* symsplitseg, int groupid)
-{
-  pbcdata *pd;
-  enum locateresult symloc;
-  int segid, f1, f2, i;
+  if (b->verbose > 1) {
+    if (stype == 2) {
+      printf("    Split = %.12g.\n", distance(ei, v) / distance(ei, ej));
+    } else {
+      printf("    Split = %.12g.\n", distance(c, v) / distance(c, ej));
+    }
+  }
 
-  pd = (pbcdata *)(* segpbcgrouptable)[groupid];
-  segid = shellmark(*splitseg);
-  if (pd->segid[0] == segid) {
-    f1 = 0;
+  // Create the newpoint.
+  makepoint(&splitpoint);
+  // Add a random perturbation on splitpoint.
+  d1 = distance(c, v);
+  if (stype == 1 || stype == 3) {
+    ps = randgenerator(d1 * 1.0e-3);
   } else {
-    assert(pd->segid[1] == segid);
-    f1 = 1;
+    // For type-2 segment, add a smaller perturbation.
+    // ps = randgenerator(d1 * 1.0e-5);
+    REAL d2 = distance(refpoint, v);
+    ps = randgenerator(d2 * 1.0e-5);
   }
-  f2 = 1 - f1;
-
-  // Transform newpoint from f1 -> f2.
+  rs = ps / d1;
+  // Perturb splitpoint away from c.
   for (i = 0; i < 3; i++) {
-    sympoint[i] = pd->transmat[f1][i][0] * newpoint[0]
-                + pd->transmat[f1][i][1] * newpoint[1]
-                + pd->transmat[f1][i][2] * newpoint[2]
-                + pd->transmat[f1][i][3] * 1.0;
+    splitpoint[i] = c[i] + (1.0 + rs) * (v[i] - c[i]);
   }
-  // Locate sympoint in f2.
-  *symsplitseg = pd->ss[f2];
-  assert(symsplitseg->sh != dummysh);
-  // Locate sympoint in facet. Stop at subsegment.
-  symloc = locateseg(sympoint, symsplitseg);
+  // for (i = 0; i < in->numberofpointattributes; i++) {
+  //   splitpoint[i + 3] = c[i + 3] + (split + rs) * (ej[i + 3] - c[i + 3]);
+  // }
+  if (stype == 3) {
+    // Change a type-3 segment into two type-2 segments. 
+    setpointtype(splitpoint, NACUTEVERTEX);
+  } else {
+    // Set it's type be FREESEGVERTEX.
+    setpointtype(splitpoint, FREESEGVERTEX);
+  }
+  setpoint2sh(splitpoint, sencode(*splitseg));
 
-  return adjustlocateseg(sympoint, symsplitseg, symloc, b->epsilon);
+  return splitpoint;
 }
 
-//
-// End of periodic boundary condition routines
-//
-
-//
-// Begin of vertex perturbation routines
-//
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// randgenerator()    Generate a random REAL number between (0, |range|).    //
+// delaunizesegments()    Split segments repeatedly until they appear in a   //
+//                        Delaunay tetrahedralization.                       //
+//                                                                           //
+// Given a PLC X, which has a set V of vertices and a set of segments. Start //
+// from a Delaunay tetrahedralization D of V, this routine recovers segments //
+// of X in D by incrementally inserting points on missing segments, updating //
+// D with the newly inserted points into D', which remains to be a Delaunay  //
+// tetrahedralization and respects the segments of X. Hence, each segment of //
+// X appears as a union of edges in D'.                                      //
+//                                                                           //
+// This routine dynamically maintains two meshes, one is DT, another is the  //
+// surface mesh F of X.  DT and F have exactly the same vertices.  They are  //
+// updated simultaneously with the newly inserted points.                    //
+//                                                                           //
+// Missing segments are found by looping the set S of segments, checking the //
+// existence of each segment in DT.  Once a segment is found missing in DT,  //
+// it is split into two subsegments by inserting a point into both DT and F, //
+// and S is updated accordingly.  However, the inserted point may cause some //
+// other existing segments be non-Delaunay,  hence are missing from the DT.  //
+// In order to force all segments to appear in DT, we have to loop S again   //
+// after some segments are split. (A little ugly method)  Use a handle to    //
+// remember the last segment be split in one loop, hence all segments after  //
+// it are existing and need not be checked.                                  //
+//                                                                           //
+// In priciple, a segment on the convex hull should exist in DT. However, if //
+// there are four coplanar points on the convex hull, and the DT only can    //
+// contain one diagonal edge which is unfortunately not the segment, then it //
+// is missing. During the recovery of the segment, it is possible that the   //
+// calculated inserting point for recovering this convex hull segment is not //
+// exact enough and lies (slightly) outside the DT. In order to insert the   //
+// point, we enlarge the convex hull of the DT, so it can contain the point  //
+// and remains convex.  'inserthullsite()' is called for this case.          //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-REAL tetgenmesh::randgenerator(REAL range)
+void tetgenmesh::delaunizesegments()
 {
-  REAL worknumber, result;
-  int expo;
-
-  if (range == 0.0) return 0.0;
-
-  expo = 0;
-  worknumber = fabs(range);
-  // Normalize worknumber (i.e., 1.xxxExx)
-  if (worknumber > 10.0) {
-    while (worknumber > 10.0) {
-      worknumber /= 10.0;
-      expo++;
-    }
-  } else if (worknumber < 1.0) {
-    while (worknumber < 1.0) {
-      worknumber *= 10.0;
-      expo--;
-    }
-  }
-  assert(worknumber >= 1.0 && worknumber <= 10.0);
+  queue *flipqueue;
+  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;
+  long vertcount;
+  int i, j;
 
-  // Enlarge worknumber 1000 times.
-  worknumber *= 1e+3;
-  expo -= 3;
-  // Generate a randome number between (0, worknumber).
-  result = (double) randomnation((int) worknumber);
-  
-  // Scale result back into the original size.
-  if (expo > 0) {
-    while (expo != 0) {
-      result *= 10.0;
-      expo--;
-    }
-  } else if (expo < 0) {
-    while (expo != 0) {
-      result /= 10.0;
-      expo++;
-    }
+  if (!b->quiet) {
+    printf("Delaunizing segments.\n");
   }
-  assert((result >= 0.0) && (result <= fabs(range)));
 
-  return result;
-}
+  // Mark segment vertices (acute or not) for determining segment types.
+  markacutevertices(89.0);
+  // Construct a map from points to tetrahedra for speeding point location.
+  // makepoint2tetmap(); // This is done in above routine.
+  // Initialize a queue for returning non-Delaunay faces and edges.
+  flipqueue = new queue(sizeof(badface));
+  // 'lastsplit' is the last segment be split in one loop, all segments
+  //   after it are existing. At first, set it be NULL;
+  lastsplit.sh = (shellface *) NULL;
+  // Remember the current number of points.
+  vertcount = points->items;
+  // Initialize the counters.
+  r1count = r2count = r3count = r4count = 0l;
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// checksub4cocir()    Test a subface to find co-circular pair of subfaces.  //
-//                                                                           //
-// 'eps' is a relative tolerance for testing approximately cospherical case. //
-// Set it to zero if only exact test is desired.                             //
-//                                                                           //
-// An edge(not a segment) of 'testsub' is locally degenerate if the opposite //
-// vertex of the adjacent subface is cocircular with the vertices of testsub.//
-// If 'once' is TRUE, operate on the edge only if the pointer 'testsub->sh'  //
-// is smaller than its neighbor (for each edge is considered only once).     //
-//                                                                           //
-// Return TRUE if find an edge of testsub is locally degenerate.             //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
+  finish = false;
+  while (!finish && (steinerleft != 0)) {
+    subsegs->traversalinit();
+    segloop.sh = shellfacetraverse(subsegs);
+    while ((segloop.sh != (shellface *) NULL) && (steinerleft != 0)) {
+      // Search segment ab in DT.
+      p1 = sorg(segloop);  // p1 = a;
+      p2 = sdest(segloop);  // p2 = b;
+      if (b->verbose > 2) {
+        printf("  Checking segment (%d, %d).\n", pointmark(p1), pointmark(p2));
+      }
+      getsearchtet(p1, p2, &searchtet, &tend);
+      collinear = finddirection(&searchtet, tend, tetrahedrons->items);
+      if (collinear == LEFTCOLLINEAR) {
+        checkpoint = apex(searchtet);
+      } else if (collinear == RIGHTCOLLINEAR) {
+        checkpoint = dest(searchtet);
+      } else if (collinear == TOPCOLLINEAR) {
+        checkpoint = oppo(searchtet);
+      } else {
+#ifdef SELF_CHECK
+        assert(collinear == ACROSSFACE || collinear == ACROSSEDGE);
+#endif
+        checkpoint = (point) NULL;
+      }
+      if (checkpoint != tend) {
+        // ab is missing.
+        splitpoint = (point) NULL;
+        if (checkpoint != (point) NULL) {
+          // An existing point c is found on the segment. It can happen when
+          //   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) {
+            // c is not a segment vertex yet. It becomes NACUTEVERTEX.
+            setpointtype(splitpoint, NACUTEVERTEX);  
+          } else if (pointtype(checkpoint) == ACUTEVERTEX) {
+            // c is an acute vertex. The definition of PLC is wrong.
+          } else if (pointtype(checkpoint) == NACUTEVERTEX) {
+            // c is an nonacute vertex. The definition of PLC is wrong.
+          } else {
+            // assert(0);
+          }
+        } else {
+          // Find a reference point p of ab.
+          refpoint = scoutrefpoint(&searchtet, tend);
+          if (pointtype(refpoint) == VOLVERTEX) {
+            // p is an input point, check if it is nearly collinear with ab.
+            coll = iscollinear(p1, p2, refpoint, b->epsilon);
+            if (coll) {
+              // a, b, and p are collinear. We insert p into ab. p becomes
+              //   a segment vertex with type NACUTEVERTEX.
+              splitpoint = refpoint;
+              setpointtype(splitpoint, NACUTEVERTEX);
+            }
+          }
+          if (splitpoint == (point) NULL) {
+            // Calculate a split point v using rule 1, or 2, or 3.
+            splitpoint = getsplitpoint(&segloop, refpoint);
+            
+            // Is there periodic boundary conditions?
+            if (checkpbcs) {
+              // Yes! Insert points on other segments of incident pbcgroups.
+              i = shellmark(segloop) - 1;
+              for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++) {
+                makepoint(&sympoint);
+                symloc = getsegpbcsympoint(splitpoint, &segloop, sympoint,
+                                           &symsplitseg, segpglist[j]);
+#ifdef SELF_CHECK
+                assert(symloc != OUTSIDE);
+#endif
+                if ((symloc == ONEDGE) && (symsplitseg.sh != segloop.sh)) {
+#ifdef SELF_CHECK
+                  assert(symsplitseg.sh != dummysh);
+#endif
+                  setpointtype(sympoint, FREESEGVERTEX);
+                  setpoint2sh(sympoint, sencode(symsplitseg));
+                  // Insert sympoint into DT.
+                  pa = sorg(symsplitseg);
+                  splittet.tet = dummytet;
+                  // Find a good start point to search.
+                  encodedtet = point2tet(pa);
+                  if (encodedtet != (tetrahedron) NULL) {
+                    decode(encodedtet, splittet);
+                    if (isdead(&splittet)) {
+                      splittet.tet = dummytet; 
+                    }
+                  }
+                  // Locate sympoint in DT.  Do exact location.
+                  success = insertsite(sympoint, &splittet, false, flipqueue);
+#ifdef SELF_CHECK
+                  assert(success != DUPLICATEPOINT);
+#endif
+                  if (success == OUTSIDEPOINT) {
+                    inserthullsite(sympoint, &splittet, flipqueue);
+                  }
+                  if (steinerleft > 0) steinerleft--;
+                  // Let sympoint remember splittet.
+                  setpoint2tet(sympoint, encode(splittet));
+                  // Do flip in DT.
+                  flip(flipqueue, NULL);
+                  // Insert sympoint into F.
+                  symsplitseg.shver = 0;
+                  spivot(symsplitseg, symsplitsub);
+                  // sympoint should on the edge of symsplitsub.
+                  splitsubedge(sympoint, &symsplitsub, flipqueue);
+                  // Do flip in facet.
+                  flipsub(flipqueue);
+                } else { // if (symloc == ONVERTEX) {
+                  // The sympoint already exists. It is possible when two
+                  //   pbc groups are exactly the same. Omit this point.
+                  pointdealloc(sympoint);
+                }
+              }
+            }
 
-bool tetgenmesh::
-checksub4cocir(face* testsub, REAL eps, bool once, bool enqflag)
-{
-  badface *cocirsub;
-  face subloop, neighsub;
-  face checkseg;
-  point pa, pb, pc, pd;
-  point liftpt;
-  REAL sign;
-  int i;
-  
-  subloop = *testsub;
-  // Get the liftpoint.
-  liftpt = getliftpoint(shellmark(subloop));
-  subloop.shver = 0; // Keep the CCW orientation.
-  // Check the three edges of subloop.
-  for (i = 0; i < 3; i++) {
-    sspivot(subloop, checkseg);
-    if (checkseg.sh == dummysh) {
-      // It is not a segment, get the adjacent subface.
-      spivot(subloop, neighsub);
-      assert(neighsub.sh != dummysh);
-      if (!once || (once && (neighsub.sh > subloop.sh))) {
-        pa = sorg(subloop);
-        pb = sdest(subloop);
-        pc = sapex(subloop);
-        pd = sapex(neighsub);
-        sign = insphere(pa, pb, pc, liftpt, pd);
-        if ((sign != 0.0) && (eps > 0.0)) {
-          if (iscospheric(pa, pb, pc, liftpt, pd, sign, eps)) sign = 0.0;
-        }
-        if (sign == 0.0) {
-          // It's locally degenerate!
-          if (enqflag && badsubfaces != (memorypool *) NULL) {
-            // Save it.
-            cocirsub = (badface *) badsubfaces->alloc();
-            cocirsub->ss = subloop;
-            cocirsub->forg = pa;
-            cocirsub->fdest = pb;
-            cocirsub->fapex = pc;
-            cocirsub->foppo = pd;
-            setshell2badface(cocirsub->ss, cocirsub);
-          }
-          if (b->verbose > 1) {
-            printf("    Found set (%d, %d, %d, %d).\n", pointmark(pa),
-                   pointmark(pb), pointmark(pc), pointmark(pd));
+            // Insert 'splitpoint' into DT.
+            if (isdead(&searchtet)) searchtet.tet = dummytet;
+            success = insertsite(splitpoint, &searchtet, false, flipqueue);
+            if (success == OUTSIDEPOINT) {
+              // A convex hull edge is missing, and the inserting point lies
+              //   (slightly) outside the convex hull due to the significant
+              //   digits lost in the calculation. Enlarge the convex hull.
+              inserthullsite(splitpoint, &searchtet, flipqueue);
+            }
+            if (steinerleft > 0) steinerleft--;
+            // Remember a handle in 'splitpoint' to enhance the speed of
+            //   consequent point location.
+            setpoint2tet(splitpoint, encode(searchtet));
+            // Maintain Delaunayness in DT.
+            flip(flipqueue, NULL);
           }
-          return true;
+        }
+        // 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;
         }
       }
+      segloop.sh = shellfacetraverse(subsegs);
+    }
+    if (lastsplit.sh == (shellface *) NULL) {
+      // No missing segment!
+      finish = true;
     }
-    senextself(subloop);
   }
 
-  return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// checktet4cosph()    Test a tetrahedron to find co-spherical pair of tets. //
-//                                                                           //
-// 'eps' is a relative tolerance for testing approximately cospherical case. //
-// Set it to zero if only exact test is desired.                             //
-//                                                                           //
-// A face of 'testtet' is locally degenerate if the opposite vertex of the   //
-// adjacent tetrahedron is co-sphere with the vertices of testtet. If 'once' //
-// is TRUE operate on the face only if the pointer 'testtet->tet' is smaller //
-// than its neighbor (for each face is considered only once).                //
-//                                                                           //
-// Return TRUE if find a face of testtet is locally degenerate.              //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-bool tetgenmesh::
-checktet4cosph(triface* testtet, REAL eps, bool once, bool enqflag)
-{
-  badface *cosphtet;
-  triface tetloop, neightet;
-  point pa, pb, pc, pd, pe;
-  REAL sign;
-
-  tetloop = *testtet;
-  tetloop.ver = 0; // Keep the CCW orientation in each face.
-  for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
-    sym(tetloop, neightet);
-    if (neightet.tet != dummytet) {
-      // It is not a hull face.
-      if (!once || (once && (tetloop.tet < neightet.tet))) {
-        pa = org(tetloop);
-        pb = dest(tetloop);
-        pc = apex(tetloop);
-        pd = oppo(tetloop);
-        pe = oppo(neightet);
-        sign = insphere(pa, pb, pc, pd, pe);
-        // Approximate sign.
-        if (eps > 0.0) {
-          if (iscospheric(pa, pb, pc, pd, pe, sign, eps)) sign = 0.0;
-        }
-        if (sign == 0.0) {
-          // It's degenerate!
-          if (enqflag && (badtetrahedrons != (memorypool *) NULL)) {
-            cosphtet = (badface *) badtetrahedrons->alloc();
-            cosphtet->tt = tetloop;
-            cosphtet->forg = pa;
-            cosphtet->fdest = pb;
-            cosphtet->fapex = pc;
-            cosphtet->foppo = pd;
-            cosphtet->noppo = pe;
-          }
-          if (b->verbose > 1) {
-            printf("    Found set (%d, %d, %d, %d, %d).\n", pointmark(pa),
-                   pointmark(pb), pointmark(pc), pointmark(pd), pointmark(pe));
-          }
-          return true;
-        }
-      }
-    }
+  if (b->verbose > 0) {
+    printf("  %ld protect points.\n", points->items - vertcount);
   }
 
-  return false;
+  delete flipqueue;
 }
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// tallcocirsubs()    Find all co-circular subfaces and save them in list.   //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-void tetgenmesh::tallcocirsubs(REAL eps, bool enqflag)
-{
-  face subloop;
+//
+// End of segments recovery routines
+//
 
-  // Loop over all subfaces.
-  subfaces->traversalinit();
-  subloop.sh = shellfacetraverse(subfaces);
-  while (subloop.sh != (shellface *) NULL) {
-    checksub4cocir(&subloop, eps, true, enqflag);
-    subloop.sh = shellfacetraverse(subfaces);
-  }
-}
+//
+// Begin of facet recovery routines
+//
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// tallcosphtets()    Find all co-spherical tets and save them in list.      //
+// insertsubface()    Fix a subface in place.                                //
 //                                                                           //
-// If 'testtetlist' is not NULL, only test the tetrahedra saved in the list. //
-// Otherwise, test all tetrahedra of current mesh.                           //
+// Search a subface s in current tetrahedralization T.  If s is found a face //
+// face of T, it is inserted into T.  Return FALSE if s is not found in T.   //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::tallcosphtets(list* testtetlist, REAL eps, bool enqflag)
+bool tetgenmesh::insertsubface(face* insertsh, triface* searchtet)
 {
-  triface tetloop;
-  int i;
+  triface spintet, symtet;
+  face testsh, testseg;
+  face spinsh, casin, casout;
+  point tapex, checkpoint;
+  enum finddirectionresult collinear;
+  int hitbdry;
 
-  if (testtetlist != (list *) NULL) {
-    for (i = 0; i < testtetlist->len(); i++) {
-      tetloop = * (triface *)(* testtetlist)[i];
-      checktet4cosph(&tetloop, eps, false, enqflag);
-    }
-  } else {
-    tetrahedrons->traversalinit();
-    tetloop.tet = tetrahedrontraverse();
-    while (tetloop.tet != (tetrahedron *) NULL) {
-      checktet4cosph(&tetloop, eps, true, enqflag);
-      tetloop.tet = tetrahedrontraverse();
-    }
+  // Search an edge of s.
+  getsearchtet(sorg(*insertsh), sdest(*insertsh), searchtet, &checkpoint);
+  collinear = finddirection(searchtet, checkpoint, tetrahedrons->items);
+  if (collinear == LEFTCOLLINEAR) {
+    enext2self(*searchtet);
+    esymself(*searchtet);
+  } else if (collinear == TOPCOLLINEAR) {
+    fnextself(*searchtet);
+    enext2self(*searchtet);
+    esymself(*searchtet);
+  }
+  if (dest(*searchtet) != checkpoint) {
+    // The edge doesn't exist => s is missing.
+    return false;
   }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// tallencsegsfsubs()    Check for encroached segs from a list of subfaces.  //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-bool tetgenmesh::tallencsegsfsubs(point testpt, list* cavsublist)
-{
-  face startsub, checkseg;
-  long oldencnum;
-  int i, j;
-
-  // Remember the current number of encroached segments.
-  oldencnum = badsubsegs->items;
 
-  // Check segments in the list of subfaces.
-  for (i = 0; i < cavsublist->len(); i++) {
-    startsub = * (face *)(* cavsublist)[i];
-    // Test all three edges of startsub.
-    for (j = 0; j < 3; j++) {
-      sspivot(startsub, checkseg);
-      if (checkseg.sh != dummysh) {
-        if (!shell2badface(checkseg)) {
-          checkseg4encroach(&checkseg, testpt, NULL, true);
+  // Search s by spinning faces around the edge.
+  tapex = sapex(*insertsh);
+  spintet = *searchtet;
+  hitbdry = 0;
+  do {
+    if (apex(spintet) == tapex) {
+      // Found s in T. Check if s has already been inserted.
+      tspivot(spintet, testsh);
+      if (testsh.sh == dummysh) {
+        adjustedgering(spintet, CCW);
+        findedge(insertsh, org(spintet), dest(spintet));
+        tsbond(spintet, *insertsh);
+        sym(spintet, symtet); // 'symtet' maybe outside, use it anyway.
+        sesymself(*insertsh);
+        tsbond(symtet, *insertsh);
+      } else {
+        // Found a duplicated subface (due to the redundant input).
+        if (!b->quiet) {
+          printf("Warning:  Two subfaces are found duplicated at ");
+          printf("(%d, %d, %d)\n", pointmark(sorg(testsh)),
+                 pointmark(sdest(testsh)), pointmark(sapex(testsh)));
+          printf("  Subface of facet #%d is deleted.\n", shellmark(*insertsh));
+          // printf("  Hint: -d switch can find all duplicated facets.\n");
         }
+        shellfacedealloc(subfaces, insertsh->sh);
       }
-      senextself(startsub);
-    }
-  }
-
-  return (badsubsegs->items > oldencnum);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// tallencsubsfsubs()    Check for encroached subs from a list of subfaces.  //
-//                                                                           //
-// 'cavtetlist' is a list of tetrahedra whose circumspheres include 'testpt'.//
-// By the time this routine is called, there is still no connection between  //
-// tetrahedra and subfaces.  We have to find out the subfaces related to the //
-// list of tetrahedra. Here the trick is to mark all vertices of the tets,   //
-// then loop in the pool of subfaces, for each subface, only do test if at   //
-// least one of its three vertices are marked.                               //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-bool tetgenmesh::tallencsubsfsubs(point testpt, list* cavtetlist)
-{
-  triface *cavtet;
-  face checksh;
-  point pt;
-  long oldencnum;
-  int *worklist;
-  int mcount;
-  int i, j;
-
-  // Initialize a worklist for vertices markers.
-  worklist = new int[points->items + 1];
-  for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
-  
-  // Loop through the list of tets.
-  for (i = 0; i < cavtetlist->len(); i++) {
-    cavtet = (triface *)(* cavtetlist)[i];
-    // Mark vertices of cavtet. Some vertices may be marked more than once,
-    //   but do not matter.
-    for (j = 0; j < 4; j++) {
-      pt = (point) cavtet->tet[4 + j];
-      worklist[pointmark(pt)] = 1;
-    }
-  }
-
-  // Remember the current number of encroached segments.
-  oldencnum = badsubsegs->items;
-
-  // Check the entire list of subfaces.
-  subfaces->traversalinit();
-  checksh.sh = shellfacetraverse(subfaces);
-  while (checksh.sh != (shellface *) NULL) {
-    // Find out how many vertices of cehcksh are marked.
-    mcount = 0;
-    for (i = 0; i < 3; i++) {
-      pt = (point) checksh.sh[3 + i];
-      mcount += worklist[pointmark(pt)];
+      return true;
     }
-    // If all three vertcies are marked, test it.
-    if (mcount >= 1) {
-      checksub4encroach(&checksh, testpt, true);
+    if (!fnextself(spintet)) {
+      hitbdry ++;
+      if (hitbdry < 2) {
+        esym(*searchtet, spintet);
+        if (!fnextself(spintet)) {
+          hitbdry ++;
+        }
+      }
     }
-    checksh.sh = shellfacetraverse(subfaces);
-  }
+  } while (hitbdry < 2 && apex(spintet) != apex(*searchtet));
 
-  delete [] worklist;
-  return (badsubfaces->items > oldencnum);
+  // s is missing.
+  return false;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// collectflipedges()    Collect edges of split subfaces for flip checking.  //
-//                                                                           //
-// 'inspoint' is a newly inserted segment point (inserted by insertsite()).  //
-// 'splitseg' is one of the two split subsegments. Some subfaces may be non- //
-// Delaunay since they're still not bonded to CDT. This routine collect all  //
-// such possible subfaces in 'flipqueue'.                                    //
-//                                                                           //
+// tritritest()    Test if two triangles are intersecting in their interior. //
+//                                                                           //
+// One triangle t1 is the face of 'checktet', the other t2 is given by three //
+// corners 'p1', 'p2' and 'p3'. This routine calls tri_tri_inter() to detect //
+// whether t1 and t2 exactly intersect in their interior. Cases like share a //
+// vertex, share an edge, or coincidence are considered not intersect.       //
+//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-collectflipedges(point inspoint, face* splitseg, queue* flipqueue)
+bool tetgenmesh::tritritest(triface* checktet, point p1, point p2, point p3)
 {
-  face startsh, spinsh, checksh;
-  face nextseg;
-  point pa, pb;
+  point forg, fdest, fapex;
+  enum interresult intersect;
 
-  // Let the dest of splitseg be inspoint.
-  splitseg->shver = 0;
-  if (sdest(*splitseg) != inspoint) {
-    sesymself(*splitseg);
-  }
-  assert(sdest(*splitseg) == inspoint);
-  pa = sorg(*splitseg);
-  spivot(*splitseg, startsh);
-  spinsh = startsh;
-  do {
-    findedge(&spinsh, pa, inspoint);
-    senext2(spinsh, checksh);
-    enqueueflipedge(checksh, flipqueue);
-    spivotself(spinsh);
-  } while (spinsh.sh != startsh.sh);
+  forg = org(*checktet);
+  fdest = dest(*checktet);
+  fapex = apex(*checktet);
 
-  // Get the next subsegment.
-  senext(*splitseg, nextseg);
-  spivotself(nextseg);
-  assert(nextseg.sh != (shellface *) NULL);
-  
-  // Let the org of nextseg be inspoint.
-  nextseg.shver = 0;
-  if (sorg(nextseg) != inspoint) {
-    sesymself(nextseg);
-  }
-  assert(sorg(nextseg) == inspoint);
-  pb = sdest(nextseg);
-  spivot(nextseg, startsh);
-  spinsh = startsh;
-  do {
-    findedge(&spinsh, inspoint, pb);
-    senext(spinsh, checksh);
-    enqueueflipedge(checksh, flipqueue);
-    spivotself(spinsh);
-  } while (spinsh.sh != startsh.sh);
+#ifdef SELF_CHECK
+  REAL ax, ay, az, bx, by, bz;
+  REAL n[3];
+  // face (torg, tdest, tapex) should not be degenerate. However p1, p2,
+  //   and p3 may be collinear. Check it.
+  ax = forg[0] - fdest[0];
+  ay = forg[1] - fdest[1];
+  az = forg[2] - fdest[2];
+  bx = forg[0] - fapex[0];
+  by = forg[1] - fapex[1];
+  bz = forg[2] - fapex[2];
+  n[0] = ay * bz - by * az;
+  n[1] = az * bx - bz * ax;
+  n[2] = ax * by - bx * ay;
+  assert(fabs(n[0]) + fabs(n[1]) + fabs(n[2]) > 0.0);
+  // The components of n should not smaller than the machine epsilon.
+
+  ax = p1[0] - p2[0];
+  ay = p1[1] - p2[1];
+  az = p1[2] - p2[2];
+  bx = p1[0] - p3[0];
+  by = p1[1] - p3[1];
+  bz = p1[2] - p3[2];
+  n[0] = ay * bz - by * az;
+  n[1] = az * bx - bz * ax;
+  n[2] = ax * by - bx * ay;
+  assert(fabs(n[0]) + fabs(n[1]) + fabs(n[2]) > 0.0);
+  // The components of n should not smaller than the machine epsilon.
+#endif
+
+  intersect = tri_tri_inter(forg, fdest, fapex, p1, p2, p3);
+  return intersect == INTERSECT;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// perturbrepairencsegs()    Repair all encroached segments.                 //
+// initializecavity()    Initialize the cavity.                              //
 //                                                                           //
-// All encroached segments are stored in 'badsubsegs'.  Each segment will be //
-// split by adding a perturbed point near its circumcenter.                  //
+// A cavity C is bounded by a list of faces, called fronts.  Each front f is //
+// hold by a tet t adjacent to C, t is not in C (uninfected). If f is a hull //
+// face, t does't exist, a fake tet t' is created to hold f. t' has the same //
+// vertices as f but no opposite.  t' will be removed automatically after C  //
+// is filled with new tets (by carvecavity()).                               //
+//                                                                           //
+// The faces of C are given in two lists. 'floorlist' is a set of subfaces,  //
+// each subface has been oriented to face to the inside of C.  'ceillist' is //
+// a set of tetrahedral faces. 'frontlist' returns the initialized fronts.   //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::perturbrepairencsegs(queue* flipqueue)
+void tetgenmesh::initializecavity(list* floorlist, list* ceillist,
+  list* frontlist)
 {
-  badface *encloop;
-  tetrahedron encodedtet;
-  triface splittet;
-  face splitsub, symsplitsub;
-  face splitseg, symsplitseg;
-  point newpoint, sympoint;
-  point pa, pb, pc;
-  enum insertsiteresult success;
-  enum locateresult loc, symloc;
-  REAL cent[3], d1, ps, rs;
-  int i, j;
-
-  // Note that steinerleft == -1 if an unlimited number of Steiner points 
-  //   is allowed.  Loop until 'badsubsegs' is empty.
-  badsubsegs->traversalinit();
-  encloop = badfacetraverse(badsubsegs);
-  while ((encloop != (badface *) NULL) && (steinerleft != 0)) {
-    splitseg = encloop->ss;
-    assert(shell2badface(splitseg) == encloop);
-    setshell2badface(splitseg, NULL);
-    pa = sorg(splitseg);
-    pb = sdest(splitseg);
-    if ((pa == encloop->forg) && (pb == encloop->fdest)) {
-      if (b->verbose > 1) {
-        printf("  Get seg (%d, %d).\n", pointmark(pa), pointmark(pb));
-      }
-      // Create the newpoint.
-      makepoint(&newpoint);
-      // Get the circumcenter and radius of ab.
-      for (i = 0; i < 3; i++) cent[i] = 0.5 * (pa[i] + pb[i]);
-      d1 = 0.5 * distance(pa, pb);
-      // Add a random perturbation to newpoint along the vector ab.
-      ps = randgenerator(d1 * 1.0e-3);
-      rs = ps / d1;
-      // Set newpoint (be at the perturbed circumcenter of ab).
-      for (i = 0; i < 3; i++) newpoint[i] = cent[i] + rs * (cent[i] - pa[i]);
-      setpointtype(newpoint, FREESEGVERTEX);
-      // Set splitseg into the newpoint.
-      // setpoint2sh(newpoint, sencode(splitseg));        
-
-      // Is there periodic boundary condition?
-      if (checkpbcs) {
-        // Insert points on other segments of incident pbcgroups.
-        i = shellmark(splitseg) - 1;
-        for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++) {
-          makepoint(&sympoint);
-          symloc = getsegpbcsympoint(newpoint, &splitseg, sympoint,
-                                     &symsplitseg, segpglist[j]);
-          assert(symloc != OUTSIDE);
-          if (symloc == ONEDGE) {
-            assert(symsplitseg.sh != dummysh);
-            setpointtype(sympoint, FREESEGVERTEX);
-            // setpoint2sh(sympoint, sencode(symsplitseg));
-            // Insert sympoint into DT.
-            pc = sorg(symsplitseg);
-            splittet.tet = dummytet;
-            // Find a good start point to search.
-            encodedtet = point2tet(pc);
-            if (encodedtet != (tetrahedron) NULL) {
-              decode(encodedtet, splittet);
-              if (isdead(&splittet)) {
-                splittet.tet = dummytet; 
-              }
-            }
-            // Locate sympoint in DT.  Do exact location.
-            success = insertsite(sympoint, &splittet, false, flipqueue);
-            assert(success != DUPLICATEPOINT);
-            if (success == OUTSIDEPOINT) {
-              inserthullsite(sympoint, &splittet, flipqueue, NULL, NULL);
-            }
-            if (steinerleft > 0) steinerleft--;
-            // Let sympoint remember splittet.
-            setpoint2tet(sympoint, encode(splittet));
-            // Do flip in DT.
-            flip(flipqueue, NULL, false, false, false);
-            // Insert sympoint into F.
-            symloc = locateseg(sympoint, &symsplitseg);
-            if (symloc == ONEDGE) {
-              symsplitseg.shver = 0;
-              spivot(symsplitseg, symsplitsub);
-              // sympoint should on the edge of symsplitsub.
-              splitsubedge(sympoint, &symsplitsub, flipqueue);
-            } else {
-              // insertsite() has done the whole job.
-              assert(symloc == ONVERTEX);
-              assert(checksubfaces);
-              // Some edges may need to be flipped.
-              collectflipedges(sympoint, &symsplitseg, flipqueue);
-            }
-            // Do flip in facet.
-            flipsub(flipqueue);
-          } else if (symloc == ONVERTEX) {
-            // The symmtric point already exists. It is possible when two
-            //   pbc group are idebtical. Omit sympoint.
-            pointdealloc(sympoint);
-          }
-        }
-      }
+  triface neightet, casingtet;
+  triface faketet;
+  face worksh;
+  int i;
 
-      // Insert newpoint into DT.
-      splittet.tet = dummytet;
-      // Find a good start point to search.
-      encodedtet = point2tet(pa);
-      if (encodedtet != (tetrahedron) NULL) {
-        decode(encodedtet, splittet);
-        if (isdead(&splittet)) {
-          splittet.tet = dummytet; 
-        }
-      }
-      if (splittet.tet == dummytet) { // Try pb.
-        encodedtet = point2tet(pb);
-        if (encodedtet != (tetrahedron) NULL) {
-          decode(encodedtet, splittet);
-          if (isdead(&splittet)) {
-            splittet.tet = dummytet;
-          }
-        }
-      }
-      // Locate the newpoint in DT.  Do exact location.
-      success = insertsite(newpoint, &splittet, false, flipqueue);
-      assert(success != DUPLICATEPOINT);
-      if (success == OUTSIDEPOINT) {
-        // A convex hull edge is mssing, and the inserting point lies
-        //   (slightly) outside the convex hull due to the significant
-        //   digits lost in the calculation. Enlarge the convex hull.
-        inserthullsite(newpoint, &splittet, flipqueue, NULL, NULL);
-      }
-      if (steinerleft > 0) steinerleft--;
-      // Let newpoint remember splittet.
-      setpoint2tet(newpoint, encode(splittet));
-      // Do flip in DT.
-      flip(flipqueue, NULL, false, false, false);
-      // Insert newpoint into F.
-      loc = locateseg(newpoint, &splitseg);
-      if (loc == ONEDGE) {
-        splitseg.shver = 0;
-        spivot(splitseg, splitsub);
-        // newpoint should on the edge of splitsub.
-        splitsubedge(newpoint, &splitsub, flipqueue);
-      } else {
-        // insertsite() has done the whole job.
-        assert(loc == ONVERTEX);
-        assert(checksubfaces);
-        // Some edges may need to be flipped.
-        collectflipedges(newpoint, &splitseg, flipqueue);
-      }
-      // Do flip in facet.
-      flipsub(flipqueue);
+  // Initialize subfaces of C.
+  for (i = 0; i < floorlist->len(); i++) {
+    // Get a subface s.
+    worksh = * (face *)(* floorlist)[i];
+#ifdef SELF_CHECK
+    // Current side of s should be empty.
+    stpivot(worksh, neightet);
+    assert(neightet.tet == dummytet);
+#endif
+    // Get the adjacent tet t.
+    sesymself(worksh);
+    stpivot(worksh, casingtet);
+    // Does t exist?
+    if (casingtet.tet == dummytet) {
+      // Create a fake tet t' to hold f temporarily.
+      maketetrahedron(&faketet);
+      setorg(faketet, sorg(worksh));
+      setdest(faketet, sdest(worksh));
+      setapex(faketet, sapex(worksh));
+      setoppo(faketet, (point) NULL); // Indicates it is 'fake'.
+      tsbond(faketet, worksh);
+      frontlist->append(&faketet);
+    } else {
+      frontlist->append(&casingtet);
+    }
+  }
+  // Initialize tet faces of C.
+  for (i = 0; i < ceillist->len(); i++) {
+    // Get a tet face c.
+    neightet = * (triface *) (* ceillist)[i];
+#ifdef SELF_CHECK
+    // The tet of c must be inside C (going to be deleted).
+    assert(infected(neightet));
+#endif
+    // Get the adjacent tet t.
+    sym(neightet, casingtet);
+    // Does t exist?
+    if (casingtet.tet == dummytet) {
+      // No. Create a fake tet t' to hold f temporarily.
+      maketetrahedron(&faketet);
+      // Be sure that the vertices of t' are CCW oriented.
+      adjustedgering(neightet, CW); // CW edge ring.
+      setorg(faketet, org(neightet));
+      setdest(faketet, dest(neightet));
+      setapex(faketet, apex(neightet));
+      setoppo(faketet, (point) NULL); // Indicates it is 'fake'.
+      // Bond t' to a subface if it exists.
+      tspivot(neightet, worksh);
+      if (worksh.sh != dummysh) {
+        sesymself(worksh);
+        tsbond(faketet, worksh);
+      } 
+      // Bond c <--> t'. So we're able to find t' and remove it.
+      bond(faketet, neightet);
+      // c may become uninfected due to the bond().
+      infect(neightet);
+      frontlist->append(&faketet);
+    } else {
+      frontlist->append(&casingtet);
     }
-    // Remove this entry from list.
-    badfacedealloc(badsubsegs, encloop);  
-    // Get the next encroached segments.
-    encloop = badfacetraverse(badsubsegs);
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// perturbrepairencsubs()    Repair all encroached subfaces.                 //
+// retrievenewtets()    Retrieve the newly created tets.                     //
 //                                                                           //
-// All encroached subfaces are stored in 'badsubfaces'. Each subface will be //
-// split by adding a perturbed point near its circumcenter. However, if the  //
-// point encroaches some segments, it will not be inserted.  Instead, the    //
-// encroached segments are split.                                            //
+// On input, 'newtetlist' contains at least one alive new tet. From this tet,//
+// other new tets can be found by a broadth-first searching.                 //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-perturbrepairencsubs(REAL eps, list* cavsublist, queue* flipqueue)
+void tetgenmesh::retrievenewtets(list* newtetlist)
 {
-  badface *encloop, *encsubseg;
-  tetrahedron encodedtet;
-  triface splittet;
-  face splitsub, symsplitsub;
-  face checkseg, symsplitseg;
-  point newpoint, sympoint;
-  point pa, pb, pc, pd;
-  enum insertsiteresult success;
-  enum locateresult loc, symloc;
-  REAL cent[3], d1, ps, rs;
-  bool reject;
+  triface searchtet, casingtet;
   int i;
 
-  // Note that steinerleft == -1 if an unlimited number of Steiner points
-  //   is allowed.  Loop until the list 'badsubfaces' is empty.
-  while ((badsubfaces->items > 0) && (steinerleft != 0)) {
-    badsubfaces->traversalinit();
-    encloop = badfacetraverse(badsubfaces);
-    while ((encloop != (badface *) NULL) && (steinerleft != 0)) {
-      splitsub = encloop->ss;
-      assert(shell2badface(splitsub) == encloop);
-      setshell2badface(splitsub, NULL);
-      pa = sorg(splitsub);
-      pb = sdest(splitsub);
-      pc = sapex(splitsub);
-      // The subface may be not the same one when it was determined to be
-      //   encroached.  If its adjacent encroached subface was split, the
-      //   consequent flips may change it into another subface.
-      if ((pa == encloop->forg) && (pb == encloop->fdest) &&
-          (pc == encloop->fapex)) {
-        if (b->verbose > 1) {
-          printf("  Get subface (%d, %d, %d).\n", pointmark(pa),
-                 pointmark(pb), pointmark(pc));
-        }
-        // Create the newpoint.
-        makepoint(&newpoint);
-        // Get the circumcenter of abc.
-        circumsphere(pa, pb, pc, NULL, cent, &d1);
-        assert(d1 > 0.0);
-        // Add a random perturbation to newpoint along the vector a->cent.
-        //   This way, the perturbed point still lies in the plane of abc.
-        ps = randgenerator(d1 * 1.0e-3);
-        rs = ps / d1;
-        // Set newpoint (be at the perturbed circumcenter of abc).
-        for (i = 0; i < 3; i++) newpoint[i] = cent[i] + rs * (cent[i] - pa[i]);
-        // Locate newpoint in facet. Stop at subsegment.
-        loc = locatesub(newpoint, &splitsub, 1);
-        assert(loc != ONVERTEX);
-        if (loc != OUTSIDE) {
-          // Add 'splitsub' into 'cavsublist'.
-          cavsublist->append(&splitsub);
-          // Collect all subfaces that encroached by newpoint.
-          collectcavsubs(newpoint, cavsublist);
-          // Find if there are encroached segments.
-          reject = tallencsegsfsubs(newpoint, cavsublist);
-          // Clear cavsublist for the next use.
-          cavsublist->clear();
-        } else {
-          // newpoint lies outside. splitsub contains the boundary segment.
-          sspivot(splitsub, checkseg);
-          assert(checkseg.sh != dummysh);
-          // Add this segment into list for splitting.
-          if (b->verbose > 2) {
-            printf("    Queuing boundary segment (%d, %d).\n",
-                   pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
-          }
-          encsubseg = (badface *) badsubsegs->alloc();
-          encsubseg->ss = checkseg;
-          encsubseg->forg = sorg(checkseg);
-          encsubseg->fdest = sdest(checkseg);
-          encsubseg->foppo = (point) NULL;
-          setshell2badface(encsubseg->ss, encsubseg);
-          // Reject newpoint.
-          reject = true;
-        }
+  // There may be dead tets due to flip32(). Delete them first.
+  for (i = 0; i < newtetlist->len(); i++) {
+    searchtet = * (triface *)(* newtetlist)[i];
+    if (isdead(&searchtet)) {
+      newtetlist->del(i, 0); i--;
+      continue;
+    }
+    infect(searchtet);
+  }
+  // Find all new tets.
+  for (i = 0; i < newtetlist->len(); i++) {
+    searchtet = * (triface *)(* newtetlist)[i];
+    for (searchtet.loc = 0; searchtet.loc < 4; searchtet.loc++) {
+      sym(searchtet, casingtet);
+      if ((casingtet.tet != dummytet) && !infected(casingtet)) {
+        infect(casingtet);
+        newtetlist->append(&casingtet);
+      }
+    }
+  }
+  // Uninfect new tets.
+  for (i = 0; i < newtetlist->len(); i++) {
+    searchtet = * (triface *)(* newtetlist)[i];
+    uninfect(searchtet);
+  }
+}
 
-        if (!reject) {
-          // newpoint is going to be inserted.
-          
-          // Is there periodic boundary condition?
-          if (checkpbcs) {
-            if (shellpbcgroup(splitsub) >= 0) {
-              // Insert a point on another facet of the pbcgroup.
-              makepoint(&sympoint);
-              symloc = getsubpbcsympoint(newpoint, &splitsub, sympoint,
-                                         &symsplitsub);
-              assert(symloc != ONVERTEX);
-              setpoint2pbcpt(newpoint, sympoint);
-              setpoint2pbcpt(sympoint, newpoint);
-              setpointtype(sympoint, FREESUBVERTEX);
-              // setpoint2sh(sympoint, sencode(symsplitsub));
-              // Insert sympoint into DT.
-              pd = sorg(symsplitsub);
-              splittet.tet = dummytet;
-              // Find a good start point to search.
-              encodedtet = point2tet(pd);
-              if (encodedtet != (tetrahedron) NULL) {
-                decode(encodedtet, splittet);
-                if (isdead(&splittet)) {
-                  splittet.tet = dummytet; 
-                }
-              }
-              // Locate sympoint in DT.  Do exact location.
-              success = insertsite(sympoint, &splittet, false, flipqueue);
-              assert(success != DUPLICATEPOINT);
-              if (success == OUTSIDEPOINT) {
-                inserthullsite(sympoint, &splittet, flipqueue, NULL, NULL);
-              }
-              if (steinerleft > 0) steinerleft--;
-              // Let sympoint remember splittet.
-              setpoint2tet(sympoint, encode(splittet));
-              // Do flip in DT.
-              flip(flipqueue, NULL, false, false, false);
-              // Insert sympoint into F.
-              symloc = locatesub(sympoint, &symsplitsub, 1);
-              if (symloc == ONFACE) {
-                splitsubface(sympoint, &symsplitsub, flipqueue);
-              } else if (symloc == ONEDGE) {
-                splitsubedge(sympoint, &symsplitsub, flipqueue);
-              } else {
-                // 'insertsite()' has done the whole job.
-                assert(symloc == ONVERTEX);
-                assert(checksubfaces);
-                // Split subfaces have been flipped.
-                flipqueue->clear();
-              }
-              // Do flip in facet.
-              flipsub(flipqueue);
-            }
-          }
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// delaunizecavvertices()    Form a DT of the vertices of a cavity.          //
+//                                                                           //
+// 'floorptlist' and 'ceilptlist' are the vertices of the cavity.            //
+//                                                                           //
+// The tets of the DT are created directly in the pool 'tetrahedrons', i.e., //
+// no auxiliary data structure and memory are required.  The trick is at the //
+// time they're created, there are no connections between them to the other  //
+// tets in the pool. You can imagine they form an ioslated island.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
-          // Insert newpoint into DT.
-          splittet.tet = dummytet;
-          // Find a good start point to search.
-          encodedtet = point2tet(pa);
-          if (encodedtet != (tetrahedron) NULL) {
-            decode(encodedtet, splittet);
-            if (isdead(&splittet)) {
-              splittet.tet = dummytet; 
-            }
-          }
-          if (splittet.tet == dummytet) { // Try pb.
-            encodedtet = point2tet(pb);
-            if (encodedtet != (tetrahedron) NULL) {
-              decode(encodedtet, splittet);
-              if (isdead(&splittet)) {
-                splittet.tet = dummytet;
-              }
-            }
-          }
-          // Locate the newpoint in DT.  Do exact location.
-          success = insertsite(newpoint, &splittet, false, flipqueue);
-          assert(success != DUPLICATEPOINT);
-          if (success == OUTSIDEPOINT) {
-            inserthullsite(newpoint, &splittet, flipqueue, NULL, NULL);
-          }
-          if (steinerleft > 0) steinerleft--;
-          // Let newpoint remember splittet.
-          setpoint2tet(newpoint, encode(splittet));
-          // Do flip in DT.
-          flip(flipqueue, NULL, false, false, false);
-          // Insert newpoint into F.
-          loc = locatesub(newpoint, &splitsub, 1);
-          if (loc == ONFACE) {
-            // Insert the newpoint in facet.
-            splitsubface(newpoint, &splitsub, flipqueue);
-          } else if (loc == ONEDGE) {
-            // Insert the newpoint in facet.
-            splitsubedge(newpoint, &splitsub, flipqueue);
-          } else {
-            // 'insertsite()' has done the whole job.
-            assert(loc == ONVERTEX);
-            assert(checksubfaces);
-            // Split subfaces have been flipped.
-            flipqueue->clear();
-          }
-          // Set the type of the newpoint.
-          setpointtype(newpoint, FREESUBVERTEX);
-          // Set splitsub into the newpoint.
-          // setpoint2sh(newpoint, sencode(splitsub));
-          // Do flip in facet.
-          flipsub(flipqueue);
+void tetgenmesh::delaunizecavvertices(triface* oldtet, list* floorptlist,
+  list* ceilptlist, list* newtetlist, queue* flipque)
+{
+  point *insertarray;
+  triface bakhulltet, newtet;
+  long bakhullsize;
+  long arraysize;
+  int bakchksub;
+  int i, j;
 
-          // Remove this entry from list.
-          badfacedealloc(badsubfaces, encloop);
-        } else {
-          // newpoint is rejected. Remove it from points.
-          pointdealloc(newpoint);
-          // Repair all encroached segments.
-          perturbrepairencsegs(flipqueue);
-          // Do not remove 'encloop'. Later it will be tested again.
-          setshell2badface(encloop->ss, encloop);
-        }
-      } else {
-        // This subface has been changed. Remove this entry from list.
-        badfacedealloc(badsubfaces, encloop);
-        // It may be co-circular with its neighbors.
-        checksub4cocir(&splitsub, eps, false, true); 
-      }
-      // Get the next encroached subfaces.
-      encloop = badfacetraverse(badsubfaces);
+  // Prepare the array of points for inserting.
+  arraysize = floorptlist->len();
+  if (ceilptlist != (list *) NULL) {
+    arraysize += ceilptlist->len();
+  }
+  insertarray = new point[arraysize];
+  for (i = 0; i < floorptlist->len(); i++) {
+    insertarray[i] = * (point *)(* floorptlist)[i];
+  }
+  if (ceilptlist != (list *) NULL) {
+    for (j = 0; j < ceilptlist->len(); j++) {
+      insertarray[i + j] = * (point *)(* ceilptlist)[j];
     }
   }
+
+  // The incrflipdelaunay() is re-used. Backup global variables.
+  decode(dummytet[0], bakhulltet);
+  bakhullsize = hullsize;
+  bakchksub = checksubfaces;
+  checksubfaces = 0;
+  b->verbose--;
+
+  // Form the DT by incremental flip Delaunay algorithm. Do not jump for
+  //   point location, do not merge points.
+  incrflipdelaunay(oldtet, insertarray, arraysize, false, false, 0.0, flipque);
+  
+  // Get a tet in D.
+  decode(dummytet[0], newtet);
+  newtetlist->append(&newtet);
+  // Get all tets of D.
+  retrievenewtets(newtetlist);
+
+  // Restore global variables.
+  dummytet[0] = encode(bakhulltet);
+  hullsize = bakhullsize;
+  checksubfaces = bakchksub;
+  b->verbose++;
+  
+  delete [] insertarray;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertauxsubface()    Fix an auxilary subface in place.                   //
+//                                                                           //
+// An auxilary subface s is fixed in D as it is a real subface, but s has no //
+// vertices and neighbors. It has two uses: (1) it protects an identfied     //
+// front f in D; (2) it serves the link to bond a tet in C and f later. The  //
+// first neighbor of s (s->sh[0]) stores a pointer to f.                     //
+//                                                                           //
+// 'front' is a front f of C. idfront' t is a tet in D where f is identified //
+// be a face of it. s will be fixed between t and its neighbor.              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::insertauxsubface(triface* front, triface* idfront)
+{
+  triface neightet;
+  face auxsh;
+
+  // Create the aux subface s.
+  makeshellface(subfaces, &auxsh);
+  // Bond s <--> t.
+  tsbond(*idfront, auxsh);
+  // Does t's neighbor n exist?
+  sym(*idfront, neightet);
+  if (neightet.tet != dummytet) {
+    // Bond s <--> n.
+    sesymself(auxsh);
+    tsbond(neightet, auxsh);
+  }
+  // Let s remember f.
+  auxsh.sh[0] = (shellface) encode(*front);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// perturbrepairbadtets()    Repair all bad tetrahedra.                      //
-//                                                                           //
-// Bad tetrahedra are saved in 'badtetrahedrons'. Each bad tetrahedron will  //
-// be split by inserting a perturbed point near its circumcenter.  However,  //
-// if the point encroaches upon some subfaces, it is rejected.  Instead, all //
-// encroached subfaces are split.                                            //
+// scoutfront()    Scout a face in D.                                        //
 //                                                                           //
-// 'eps', and 'cavsublist' are not used in this routine, they are passed to  //
-// 'perturbrepairencsubs()'. 'cavtetlist' is re-used in 'collectcavtets()'.  //
+// Search a 'front' f in D. If f is found, return TRUE and the face of D is  //
+// returned in 'idfront'. Otherwise, return FALSE.                           //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-perturbrepairbadtets(REAL eps, list* cavsublist, list* cavtetlist,
-                     queue* flipqueue)
+bool tetgenmesh::scoutfront(triface* front, triface* idfront, list* newtetlist)
 {
-  badface *tetloop;
-  triface splittet, neightet;
-  point pa, pb, pc, pd, pe;
-  point newpoint;
-  enum insertsiteresult success;
+  triface spintet;
+  point pa, pb, pc;
   enum locateresult loc;
-  REAL cent[3], d1, ps, rs;
-  REAL vol1, vol2, vol3;
-  REAL ori1, ori2, ori3, epspp;
-  bool reject;
-  int zerocount, restart;
+  enum finddirectionresult col;
+  int hitbdry;
   int i;
 
-  while ((badtetrahedrons->items > 0) && (steinerleft != 0)) {
-    badtetrahedrons->traversalinit();
-    tetloop = badfacetraverse(badtetrahedrons);
-    while ((tetloop != (badface *) NULL) && (steinerleft != 0)) {
-      splittet = tetloop->tt;
-      if (!isdead(&splittet)) {
-        pa = org(splittet);
-        pb = dest(splittet);
-        pc = apex(splittet);
-        pd = oppo(splittet);
-        sym(splittet, neightet);
-        if (neightet.tet != dummytet) {
-          pe = oppo(neightet);
-        } else {
-          pe = (point) NULL;
-        }
-      } else {
-        pa = (point) NULL;
+  // Let the front we're searching is abc.
+  pa = org(*front);
+  pb = dest(*front);
+  // Get a tet in D for searching.
+  *idfront = recenttet;
+  // Make sure the tet is valid (it may be killed by flips).
+  if (isdead(idfront)) {
+    // The tet is dead. Search a live tet in D. !!!
+    for (i = 0; i < newtetlist->len(); i++) {
+      recenttet = * (triface *)(* newtetlist)[i];
+      if (!isdead(&recenttet)) break;
+    }
+    assert(i < newtetlist->len());
+  }
+
+  // Search a tet having vertex a.
+  loc = preciselocate(pa, idfront, (long) newtetlist->len());
+  assert(loc == ONVERTEX);
+  recenttet = *idfront;
+  // Search a tet having edge ab.
+  col = finddirection(idfront, pb, (long) newtetlist->len());
+  if (col == RIGHTCOLLINEAR) {
+    // b is just the destination.
+  } else if (col == LEFTCOLLINEAR) {
+    enext2self(*idfront);
+    esymself(*idfront);
+  } else if (col == TOPCOLLINEAR) {
+    fnextself(*idfront);
+    enext2self(*idfront);
+    esymself(*idfront);
+  }
+
+  if (dest(*idfront) == pb) {
+    // Search a tet having face abc
+    pc = apex(*front);
+    spintet = *idfront;
+    hitbdry = 0;
+    do {
+      if (apex(spintet) == pc) {
+        // Found abc. Insert an auxilary subface s at idfront.
+        // insertauxsubface(front, &spintet);
+        *idfront = spintet;
+        return true;
       }
-      // Make sure that 'splitet' is still the same one when it was tested.
-      //   Subsequent transformations may have made it a different tet.
-      if ((pa == tetloop->forg) && (pb == tetloop->fdest) &&
-          (pc == tetloop->fapex) && (pd == tetloop->foppo) &&
-          (pe == tetloop->noppo)) {
-        if (b->verbose > 1) {
-          printf("  Get deg-tets (%d, %d, %d, %d, %d).\n", pointmark(pa),
-                 pointmark(pb), pointmark(pc), pointmark(pd), pointmark(pe));
-        }
-        // Find out if there are four coplanar points.  Since abc is the
-        //   common face of the two tets. It should not be coplanar with e
-        //   (at it's opposite).  We test the other three faces of abcd
-        //   to see if they are coplanar with e.
-        vol1 = orient3d(pa, pb, pd, pe);
-        vol2 = orient3d(pb, pc, pd, pe);
-        vol3 = orient3d(pc, pa, pd, pe);
-        epspp = b->epsilon * 1e+2;
-        restart = 0;
-        while (restart < 32) {
-          zerocount = 0;
-          ori1 = vol1;
-          if (ori1 != 0.0) {
-            if (iscoplanar(pa, pb, pd, pe, ori1, epspp)) ori1 = 0.0;
-          }
-          ori2 = vol2;
-          if (ori2 != 0.0) {
-            if (iscoplanar(pb, pc, pd, pe, ori2, epspp)) ori2 = 0.0;
-          }
-          ori3 = vol3;
-          if (ori3 != 0.0) {
-            if (iscoplanar(pc, pa, pd, pe, ori3, epspp)) ori3 = 0.0;
-          }
-          if (ori1 == 0.0) zerocount++;
-          if (ori2 == 0.0) zerocount++;
-          if (ori3 == 0.0) zerocount++;
-          // Only (zerocount == 0) or (zerocount == 1) is valid.
-          if (zerocount > 1) {
-            epspp *= 1e-1;
-            restart++;
-            continue;
-          }
-          break;
-        }
-        assert(restart < 32);
-        
-        // Create the newpoint.
-        makepoint(&newpoint);
-        // Get the circumcenter.  If there are four coplanar points, take
-        //   the circumcenter of the circle.
-        if (ori1 == 0.0) {
-          circumsphere(pa, pb, pd, NULL, cent, &d1);
-        } else if (ori2 == 0.0) {
-          circumsphere(pb, pc, pd, NULL, cent, &d1);
-        } else if (ori3 == 0.0) {
-          circumsphere(pc, pa, pd, NULL, cent, &d1);
-        } else {
-          // Get the circumcenter of the tet abcd.
-          circumsphere(pa, pb, pc, pd, cent, &d1);
-        }
-        assert(d1 > 0.0);
-        // Add a random perturbation to newpoint along the vector d->cent.
-        //   This way, the perturbed point will be in the plane if there
-        //   are four points coplanar (d must be one of them).
-        ps = randgenerator(d1 * 1.0e-3);
-        rs = ps / d1;
-        // Set newpoint (be at the perturbed circumcenter).
-        for (i = 0; i < 3; i++) newpoint[i] = cent[i] + rs * (cent[i] - pd[i]);
-        // Set it's type be FREEVOLVERTEX.
-        setpointtype(newpoint, FREEVOLVERTEX);
-
-        // Locate newpoint in DT.
-        loc = preciselocate(newpoint, &splittet);
-        // Note that newpoint may be outside the DT.
-        if (loc == OUTSIDE) {
-          // The following lines only do check.
-          sym(splittet, neightet);
-          assert(neightet.tet == dummytet);
-        }
-        // Look if the newpoint encroaches upon some subfaces.
-        cavtetlist->append(&splittet);
-        collectcavtets(newpoint, cavtetlist);
-        assert(cavtetlist->len() > 0);
-        reject = tallencsubsfsubs(newpoint, cavtetlist);
-        // Clear the list for the next use.
-        cavtetlist->clear();
-        if (!reject) {
-          // Insert the newpoint into DT.
-          success = insertsite(newpoint, &splittet, false, flipqueue);
-          assert(success != DUPLICATEPOINT);
-          if (success == OUTSIDEPOINT) {
-            inserthullsite(newpoint, &splittet, flipqueue, NULL, NULL);
+      if (!fnextself(spintet)) {
+        hitbdry ++;
+        if (hitbdry < 2) {
+          esym(*idfront, spintet);
+          if (!fnextself(spintet)) {
+            hitbdry ++;
           }
-          if (steinerleft > 0) steinerleft--;
-          // Let newpoint remember splittet.
-          setpoint2tet(newpoint, encode(splittet));
-          // Do flip in DT.
-          flip(flipqueue, NULL, false, false, false);
-          // Remove this entry from list.
-          badfacedealloc(badtetrahedrons, tetloop);
-        } else {
-          // newpoint is rejected. Remove it from points.
-          pointdealloc(newpoint);
-          // Repair all encroached segments.
-          perturbrepairencsubs(eps, cavsublist, flipqueue);
-          // Do not remove 'tetloop'. Later it will be tested again.
-        }
-      } else {
-        // This tet has been changed. Remove this entry from list.
-        badfacedealloc(badtetrahedrons, tetloop);
-        if (!isdead(&splittet)) {
-          // It may be co-sphere with its neighbors.
-          checktet4cosph(&splittet, eps, false, true); 
         }
       }
-      // Get the next badtetrahedron.
-      tetloop = badfacetraverse(badtetrahedrons);
-    }
+      if (apex(spintet) == apex(*idfront)) break;
+    } while (hitbdry < 2);  
+  }
+
+  // f is missing in D.
+  if (b->verbose > 2) {
+    printf("    Front (%d, %d, %d) is missing.\n", pointmark(pa),
+           pointmark(pb), pointmark(apex(*front)));
   }
+  return false;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// incrperturbvertices()    Remove the local degeneracies in DT.             //
-//                                                                           //
-// A local degeneracy of a DT D is a set of 5 or more vertices which share a //
-// common sphere S and no other vertex of D in S.  D is not unique if it has //
-// local degeneracies. This routine removes the local degeneracies from D by //
-// inserting break points (as described in reference [2]).                   //
+// gluefronts()    Glue two fronts together.                                 //
 //                                                                           //
-// 'eps' is a user-provided error tolerance. It is used to detect whether or //
-// not five points are approximate cospherical (evaluated in iscospheric()). //
-// Set it to 0.0 to disable it, i.e., only test pure degenerate point set.   //
+// This is a support routine for identifyfront().  Two fronts f and f1 are   //
+// found indentical. This is caused by the non-coplanarity of vertices of a  //
+// facet. Hence f and f1 are a subface and a tet. They are not fronts of the //
+// cavity anymore. This routine glues f and f1 together.                     //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::incrperturbvertices(REAL eps)
+void tetgenmesh::gluefronts(triface* front, triface* front1)
 {
-  queue *flipqueue;
-  list *cavsublist, *cavtetlist;
-  long vertcount;
-  int i;
+  face consh;
 
-  if (!b->quiet) {
-    printf("Perturbing vertices.\n");
-  }
-
-  vertcount = points->items;
-  // Create a map from points to tets for fastening search.
-  makepoint2tetmap();
+  // Glue f and f1 together. There're four cases:
+  //   (1) both f and f1 are not fake;
+  //   (2) f is not fake, f1 is fake;
+  //   (3) f is fake and f1 is not fake;
+  //   (4) both f and f1 are fake.
+  // Case (4) should be not possible. 
 
-  // Initialize working queues, lists.
-  flipqueue = new queue(sizeof(badface));
-  cavsublist = new list(sizeof(face), NULL, 256);
-  // Initialize the pool of encroached subfaces and subsegments.
-  badsubsegs = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
-  badsubfaces = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
-  // Find all pairs of co-circular subfaces.
-  tallcocirsubs(eps, true);
-  if (b->verbose && badsubfaces->items > 0) {
-    printf("  Removing degenerate subfaces.\n");
+  // Is there a concrete subface c at f.
+  tspivot(*front, consh);
+  if (consh.sh != dummysh) {
+    sesymself(consh);
+    tsbond(*front1, consh); // Bond: f1 <--> c.
+    sesymself(consh);
   }
-  perturbrepairencsubs(eps, cavsublist, flipqueue);
-
-  if (b->dofullperturb) {
-    cavtetlist = new list(sizeof(triface), NULL, 256);
-    // Initialize the pool of bad tetrahedra.
-    badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0);
-    // Initialize the queues of badfaces.
-    for (i = 0; i < 2; i++) subquefront[i] = (badface *) NULL;
-    for (i = 0; i < 2; i++) subquetail[i] = &subquefront[i];
-    // Find all pairsof co-sphere tets.
-    tallcosphtets(NULL, eps, true);
-    if (b->verbose && badtetrahedrons->items > 0) {
-      printf("  Removing degenerate tetrahedra.\n");
+  // Does f hold by a fake tet.
+  if (oppo(*front) == (point) NULL) {
+    // f is fake. Case (3) or (4).
+    assert(oppo(*front1) != (point) NULL); // Eliminate (4).
+    // Case (3).
+    if (consh.sh != dummysh) {
+      stdissolve(consh);  // Dissolve: c -x-> f.
+    }
+    // Dealloc f.
+    tetrahedrondealloc(front->tet);
+    // f1 becomes a hull. let 'dummytet' bond to it.
+    dummytet[0] = encode(*front1);
+  } else {
+    // Case (1) or (2).
+    bond(*front, *front1); // Bond f1 <--> f. 
+  }
+  // Is f a fake tet?
+  if (!isdead(front)) {
+    // No. Check for case (2).
+    tspivot(*front1, consh);
+    // Is f1 fake?
+    if (oppo(*front1) == (point) NULL) {
+      // Case (2) or (4)
+      assert(oppo(*front) != (point) NULL); // Eliminate (4).
+      // Case (2).
+      if (consh.sh != dummysh) {
+        stdissolve(consh);  // Dissolve: c -x-> f1.
+        sesymself(consh); // Bond: f <--> c.
+        tsbond(*front, consh);
+      }
+      // Dissolve: f -x->f1.
+      dissolve(*front);
+      // Dealloc f1.
+      tetrahedrondealloc(front1->tet);
+      // f becomes a hull. let 'dummytet' bond to it.
+      dummytet[0] = encode(*front);
+    } else {
+      // Case (1).
+      if (consh.sh != dummysh) {
+        sesymself(consh);
+        tsbond(*front, consh); // Bond: f <--> c.
+      } 
     }
-    // do {
-      perturbrepairbadtets(eps, cavsublist, cavtetlist, flipqueue);
-      // tallcosphtets(NULL, eps, true);
-    // } while (badtetrahedrons->items > 0);
-    delete cavtetlist;
-    delete badtetrahedrons;
-    badtetrahedrons = (memorypool *) NULL;
-  }
-
-  if (b->verbose) {
-    printf("  %ld break points are inserted.\n", points->items - vertcount);
   }
-  
-  delete cavsublist;
-  delete flipqueue;
-  delete badsubfaces;
-  delete badsubsegs; 
-  badsubsegs = (memorypool *) NULL;
-  badsubfaces = (memorypool *) NULL;
 }
 
-//
-// End of vertex perturbation routines
-//
-
-//
-// Begin of segment recovery routines
-//
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// markacutevertices()    Set the type (ACUTEVERTEX, NACUTEVERTEX) of verts. //
+// identifyfronts()    Identify cavity faces in D.                           //
 //                                                                           //
-// Parameter 'acuteangle' gives the upperbound (in degree). Angles which are //
-// smaller or equal than it are assumed as acute angles.  A vertex is acute  //
-// if at least two segments incident at it with an acute angle.              //
+// 'frontlist' are fronts of C need indentfying.  This routine searches each //
+// front f in D. Once f is found, an auxilary subface s is inserted in D at  //
+// the face. If f is not found in D, remove it from frontlist and save it in //
+// 'misfrontlist'.                                                           //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::markacutevertices(REAL acuteangle)
+bool tetgenmesh::identifyfronts(list* frontlist, list* misfrontlist,
+  list* newtetlist)
 {
-  shellface** segsperverlist;
-  face segloop, workseg, inciseg;
-  point eorg, edest, eapex;
-  REAL cosbound, anglearc;
-  REAL v1[3], v2[3], L, D;
-  bool isacute;
-  int* idx2seglist;
-  int idx, i, j, k;
-
-  if (b->verbose) {
-    printf("  Marking segments have acute corners.\n");
-  }
-
-  // Constructing a map from vertex to segments.
-  makesegmentmap(idx2seglist, segsperverlist);
+  triface front, front1, tfront;
+  triface idfront, neightet;
+  face auxsh;
+  int len, i, j;
 
-  // Initialize all vertices be unknown.
-  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);
-      setpointtype(eorg, FACETVERTEX);
-    }
-    segloop.sh = shellfacetraverse(subsegs);
-  }
+  misfrontlist->clear();
+  // Set a new tet in D for searching.
+  recenttet = * (triface *)(* newtetlist)[0];
 
-  anglearc = acuteangle * PI / 180.0;
-  cosbound = cos(anglearc);
-  
-  // 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)) {
-        // 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);
-          }
-          assert(sorg(workseg) == eorg);
-          edest = sdest(workseg);
-          for (j = i + 1; j < idx2seglist[idx + 1] && !isacute; j++) {
-            inciseg.sh = segsperverlist[j];
-            inciseg.shver = 0;
-            assert(inciseg.sh != workseg.sh);
-            if (sorg(inciseg) != eorg) {
-              sesymself(inciseg);
-            }
-            assert(sorg(inciseg) == eorg);
-            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; 
-            }
-          }
+  // Identify all fronts in D.
+  for (i = 0; i < frontlist->len(); i++) {
+    // Get a front f.
+    front = * (triface *)( *frontlist)[i];
+    if (scoutfront(&front, &idfront, newtetlist)) {
+      // Found f. Insert an aux subface s.
+      assert((idfront.tet != dummytet) && !isdead(&idfront));
+      // Does s already exist?
+      tspivot(idfront, auxsh);
+      if (auxsh.sh != dummysh) {
+        // There're two identical fronts, f (front) and f1 (s.sh[0])!
+        decode((tetrahedron) auxsh.sh[0], front1);
+        assert((front1.tet != dummytet) && !infected(front1));
+        // Detach s in D.
+        tsdissolve(idfront);
+        sym(idfront, neightet);
+        if (neightet.tet != dummytet) {
+          tsdissolve(neightet);
         }
-        if (isacute) {
-          setpointtype(eorg, ACUTEVERTEX);
-        } else {
-          setpointtype(eorg, NACUTEVERTEX);
+        // s has fulfilled its duty. Can be deleted.
+        shellfacedealloc(subfaces, auxsh.sh);
+        // Remove f from frontlist.
+        frontlist->del(i, 1); i--;
+        // Remove f1 from frontlist.
+        len = frontlist->len();
+        for (j = 0; j < frontlist->len(); j++) {
+          tfront = * (triface *)(* frontlist)[j];
+          if ((tfront.tet == front1.tet) && (tfront.loc == front1.loc)) {
+            // Found f1 in list.  Check f1 != f.
+            assert((tfront.tet != front.tet) || (tfront.loc != front.loc));
+            frontlist->del(j, 1); i--;
+            break;
+          }
         }
+        assert((frontlist->len() + 1) == len);
+        // Glue f and f1 together.
+        gluefronts(&front, &front1);        
+      } else {
+        // Insert an aux subface to protect f in D.
+        insertauxsubface(&front, &idfront);
+      }
+    } else {
+      // f is missing.
+      frontlist->del(i, 1); i--;
+      // Are there two identical fronts, f (front) and f1 (front1)?
+      for (j = 0; j < misfrontlist->len(); j++) {
+        front1 = * (triface *)(* misfrontlist)[j];
+        if (isfacehaspoint(&front1, org(front)) &&
+            isfacehaspoint(&front1, dest(front)) &&
+            isfacehaspoint(&front1, apex(front))) break;
+      }
+      if (j < misfrontlist->len()) {
+        // Found an identical front f1. Remove f1 from the list.
+        misfrontlist->del(j, 1);
+        // Glue f and f1 together.
+        gluefronts(&front, &front1); 
+      } else {
+        // Add f into misfrontlist.
+        misfrontlist->append(&front);
       }
     }
-    segloop.sh = shellfacetraverse(subsegs);
   }
-
-  delete [] idx2seglist;
-  delete [] segsperverlist;
+  return misfrontlist->len() == 0;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// finddirection()    Find the first tetrahedron on the path from one point  //
-//                    to another.                                            //
-//                                                                           //
-// Find the tetrahedron that intersects a line segment L (from the origin of //
-// 'searchtet' to the point 'tend'), and returns the result in 'searchtet'.  //
-// The origin of 'searchtet' does not change, even though the tetrahedron    //
-// returned may differ from the one passed in.  This routine is used to find //
-// the direction to move in to get from one point to another.                //
-//                                                                           //
-// The return value notes the location of the line segment L with respect to //
-// 'searchtet':                                                              //
-//   - Returns RIGHTCOLLINEAR indicates L is collinear with the line segment //
-//     from the origin to the destination of 'searchtet'.                    //
-//   - Returns LEFTCOLLINEAR indicates L is collinear with the line segment  //
-//     from the origin to the apex of 'searchtet'.                           //
-//   - Returns TOPCOLLINEAR indicates L is collinear with the line segment   //
-//     from the origin to the opposite of 'searchtet'.                       //
-//   - Returns ACROSSEDGE indicates L intersects with the line segment from  //
-//     the destination to the apex of 'searchtet'.                           //
-//   - Returns ACROSSFACE indicates L intersects with the face opposite to   //
-//     the origin of 'searchtet'.                                            //
-//   - Returns BELOWHULL indicates L crosses outside the mesh domain. This   //
-//     can only happen when the domain is non-convex.                        //
+// detachauxsubfaces()    Detach auxilary subfaces in D.                     //
 //                                                                           //
-// NOTE: This routine only works correctly when the mesh is exactly Delaunay.//
+// This is a reverse routine of identifyfronts(). Some fronts are missing in //
+// D. C can not be easily tetrahedralized. It needs remediation (expansion,  //
+// or constrained flips, or adding a Steiner point).  This routine detaches  //
+// the auxilary subfaces have been inserted in D and delete them.            //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-enum tetgenmesh::finddirectionresult tetgenmesh::
-finddirection(triface *searchtet, point tend)
+void tetgenmesh::detachauxsubfaces(list* newtetlist)
 {
-  triface neightet;
-  point tstart, tdest, tapex, toppo;
-  REAL ori1, ori2, ori3;
-
-  tstart = org(*searchtet);
-  assert(tstart != tend);
-  adjustedgering(*searchtet, CCW);
-  if (tstart != org(*searchtet)) {
-    enextself(*searchtet); // For keeping the same origin.
-  }
-  tdest = dest(*searchtet);
-  if (tdest == tend) {
-    return RIGHTCOLLINEAR;
-  }
-  tapex = apex(*searchtet); 
-  if (tapex == tend) {
-    return LEFTCOLLINEAR;
-  } 
+  triface newtet, neightet;
+  face auxsh;
+  int i;
 
-  ori1 = orient3d(tstart, tdest, tapex, tend);
-  if (ori1 > 0.0) {
-    // 'tend' is below the face, get the neighbor of this side.
-    sym(*searchtet, neightet);
-    if (neightet.tet != dummytet) {
-      findorg(&neightet, tstart); 
-      adjustedgering(neightet, CCW);
-      if (org(neightet) != tstart) {
-        enextself(neightet); // keep the same origin.
+  for (i = 0; i < newtetlist->len(); i++) {
+    // Get a new tet t.
+    newtet = * (triface *)(* newtetlist)[i];
+    // t may e dead due to flips.
+    if (isdead(&newtet)) continue;
+    assert(!infected(newtet));
+    // Check the four faces of t.
+    for (newtet.loc = 0; newtet.loc < 4; newtet.loc++) {
+      tspivot(newtet, auxsh);
+      if (auxsh.sh != dummysh) {
+        // An auxilary subface s.
+        assert(sorg(auxsh) == (point) NULL);
+        tsdissolve(newtet);  // t -x-> s.
+        sym(newtet, neightet);
+        if (neightet.tet != dummytet) {
+          assert(!isdead(&neightet));
+          tsdissolve(neightet); // n -x-> s.
+        }
+        // Delete s.
+        shellfacedealloc(subfaces, auxsh.sh);
       }
-      // Set the changed configuratiuon.
-      *searchtet = neightet; 
-      ori1 = -1.0; 
-      tdest = dest(*searchtet);
-      tapex = apex(*searchtet);
-    } else {
-      // A hull face. Only possible for a nonconvex mesh.
-#ifdef SELF_CHECK
-      assert(nonconvex);
-#endif
-      return BELOWHULL; 
     }
   }
+}
 
-  // Repeatedly change the 'searchtet', remain 'tstart' be its origin, until
-  //   find a tetrahedron contains 'tend' or is crossed by the line segment
-  //   from 'tstart' to 'tend'.
-  while (true) {
-    toppo = oppo(*searchtet);
-    if (toppo == tend) {
-      return TOPCOLLINEAR;
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// expandcavity()    Expand the cavity by adding new fronts.                 //
+//                                                                           //
+// This is the support routine for delaunizecavity().  Some fronts of C are  //
+// missing in D since they're not strongly Delaunay. Such fronts are removed //
+// and the faces of the tets abutting to them are added. C is then expanded. //
+// Some removed faces may be subfaces, they're queued to recover later. D is //
+// expanded simultaneously with the new vertices of the new fronts.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::expandcavity(list* frontlist, list* misfrontlist,
+  list* newtetlist, list* crosstetlist, queue* missingshqueue, queue* flipque)
+{
+  triface misfront, newfront, casingtet, crosstet;
+  triface searchtet, faketet, bakhulltet;
+  face checksh;
+  point pd;
+  enum insertsiteresult success;
+  long bakhullsize;
+  int bakchksub;
+  int i, j, k;
+
+  if (b->verbose > 1) {
+    printf("    Expand cavity (%d missing fronts).\n", misfrontlist->len());
+  }
+  // Increase the number of expanded times.
+  expcavcount++;
+  // The incrflipdelaunay() is re-used. Backup global variables.
+  decode(dummytet[0], bakhulltet);
+  bakhullsize = hullsize;
+  bakchksub = checksubfaces;
+  checksubfaces = 0;
+  b->verbose--;
+
+  // Choose a tet in D for searching.
+  recenttet = * (triface *)(* newtetlist)[0];
+  assert((recenttet.tet != dummytet) && !isdead(&recenttet));
+
+  // Loop through 'misfrontlist'.
+  for (i = 0; i < misfrontlist->len(); i++) {
+    // Get a missing front f.
+    misfront = * (triface *)(* misfrontlist)[i];
+    // C will be expanded at f.
+    if (b->verbose > 1) {
+      printf("    Get misfront (%d, %d, %d).\n", pointmark(org(misfront)),
+             pointmark(dest(misfront)), pointmark(apex(misfront)));
     }
-    ori2 = orient3d(tstart, toppo, tdest, tend);
-    if (ori2 > 0.0) {
-      // 'tend' is below the face, get the neighbor at this side.
-      fnext(*searchtet, neightet);
-      symself(neightet);
-      if (neightet.tet != dummytet) {
-        findorg(&neightet, tstart); 
-        adjustedgering(neightet, CCW);
-        if (org(neightet) != tstart) {
-          enextself(neightet); // keep the same origin.
-        }
-        // Set the changed configuration.
-        *searchtet = neightet; 
-        ori1 = -1.0; 
-        tdest = dest(*searchtet);
-        tapex = apex(*searchtet);
-        // Continue the search from the changed 'searchtet'.
+    // Is f has a subface s?
+    tspivot(misfront, checksh);
+    if (checksh.sh != dummysh) {
+      // A subface s is found. Check whether f is expandable at s.
+      sym(misfront, crosstet);
+      if (!infected(crosstet)) {
+        // f is not expandable. In principle is should not happen. However,
+        //   it can happen when PBC is in use.
+        assert(checkpbcs);
+        // Skip expanding f. It will be processed later.
         continue;
-      } else {
-        // A hull face. Only possible for a nonconvex mesh.
-#ifdef SELF_CHECK
-        assert(nonconvex);
-#endif
-        return BELOWHULL; 
       }
+      // Temporarily remove s. Queue and recover it later.
+      if (b->verbose > 1) {
+        printf("    Queuing subface (%d, %d, %d).\n",
+               pointmark(sorg(checksh)), pointmark(sdest(checksh)),
+               pointmark(sapex(checksh)));
+      }
+      // Detach s from tets at its both sides.
+      tsdissolve(misfront);
+      tsdissolve(crosstet);
+      // Detach tets at from s.
+      stdissolve(checksh);
+      sesymself(checksh);
+      stdissolve(checksh);
+      // Mark and queue it.
+      sinfect(checksh);
+      missingshqueue->push(&checksh);
     }
-    ori3 = orient3d(tapex, toppo, tstart, tend);
-    if (ori3 > 0.0) {
-      // 'tend' is below the face, get the neighbor at this side.
-      enext2fnext(*searchtet, neightet);
-      symself(neightet);
-      if (neightet.tet != dummytet) {
-        findorg(&neightet, tstart); 
-        adjustedgering(neightet, CCW);
-        if (org(neightet) != tstart) {
-          enextself(neightet); // keep the same origin.
-        }
-        // Set the changed configuration.
-        *searchtet = neightet; 
-        ori1 = -1.0; 
-        tdest = dest(*searchtet);
-        tapex = apex(*searchtet);
-        // Continue the search from the changed 'searchtet'.
-        continue;
-      } else {
-        // A hull face. Only possible for a nonconvex mesh.
+    // f may already be processed (become a cross tet of C).
+    if (infected(misfront)) continue;
+    // Get the point p = oppo(t), t is the tet holds f.
+    pd = oppo(misfront);
 #ifdef SELF_CHECK
-        assert(nonconvex);
+    // t must not be fake.
+    assert(pd != (point) NULL);
 #endif
-        return BELOWHULL; 
+    // Insert p in D. p may not be inserted if it is one of the two cases:
+    //   (1) p is already a vertex of D;
+    //   (2) p lies outside the CH of D;
+    searchtet = recenttet;
+    // Make sure the tet is valid (it may be killed by flips).
+    if (isdead(&searchtet)) {
+      // The tet is dead. Get a live tet in D. !!!
+      for (j = 0; j < newtetlist->len(); j++) {
+        recenttet = * (triface *)(* newtetlist)[j];
+        if (!isdead(&recenttet)) break;
       }
+      assert(j < newtetlist->len());
+      searchtet = recenttet;
     }
-    // Now 'ori1', 'ori2' and 'ori3' are possible be 0.0 or all < 0.0;
-    if (ori1 < 0.0) {
-      // Possible cases are: ACROSSFACE, ACROSSEDGE, TOPCOLLINEAR.
-      if (ori2 < 0.0) {
-        if (ori3 < 0.0) {
-          return ACROSSFACE;
-        } else { // ori3 == 0.0;
-          // Cross edge (apex, oppo)
-          enext2fnextself(*searchtet);
-          esymself(*searchtet); // org(*searchtet) == tstart;
-          return ACROSSEDGE;
+    success = insertsite(pd, &searchtet, false, flipque);
+    if (success == OUTSIDEPOINT) {
+      // case (2). Insert p onto CH of D.
+      inserthullsite(pd, &searchtet, flipque);
+    }
+    if (success != DUPLICATEPOINT) {
+      // p is inserted. Recover Delaunness of D by flips.
+      flip(flipque, NULL);
+    }
+    // Expand C by adding new fronts. The three faces of t which have p as a
+    //   vertex become new fronts. However, if a new front is coincident with
+    //   an old front of C, it is not added and the old front is removed. 
+    adjustedgering(misfront, CCW);
+    for (j = 0; j < 3; j++) {
+      // Notice: Below I mis-used the names. 'newfront' is not exactly a new
+      //   front, instead the 'casingtet' should be called new front. 
+      // Get a new front f_n.
+      fnext(misfront, newfront);
+      // Get the neighbor tet n at f_n.
+      sym(newfront, casingtet);
+      // Is n a cross tet?
+      if (!infected(casingtet)) {
+        // f_n becomes a new front of C.
+        // Does n exist?
+        if (casingtet.tet == dummytet) {
+          // Create a fake tet n' to hold f_n temporarily.
+          maketetrahedron(&faketet);
+          // Be sure that the vertices of fake tet are CCW oriented.
+          adjustedgering(newfront, CW); // CW edge ring.
+          setorg(faketet, org(newfront));
+          setdest(faketet, dest(newfront));
+          setapex(faketet, apex(newfront));
+          setoppo(faketet, (point) NULL); // Indicates it is 'fake'.
+          // Bond n' to a subface if it exists.
+          tspivot(newfront, checksh);
+          if (checksh.sh != dummysh) {
+            sesymself(checksh);
+            tsbond(faketet, checksh);
+          } 
+          // Bond f_n <--> n'. So we're able to find n' and remove it.
+          bond(faketet, newfront);
+          frontlist->append(&faketet);
+        } else {
+          // Add n to frontlist.
+          frontlist->append(&casingtet);
         }
-      } else { // ori2 == 0.0; 
-        if (ori3 < 0.0) {
-          // Cross edge (dest, oppo)
-          fnextself(*searchtet);
-          esymself(*searchtet);
-          enextself(*searchtet); // org(*searchtet) == tstart;
-          return ACROSSEDGE;
-        } else { // ori3 == 0.0;
-          // Collinear with edge (org, oppo)
-          return TOPCOLLINEAR;
+      } else {
+        // f_n is coincident with an existing front f' of C. f' is no longer
+        //   a front, remove it from frontlist.  Use the inverse order to
+        //   search f' (most likely, a newly added front may be f').
+        for (k = frontlist->len() - 1; k >= 0; k--) {
+          searchtet = * (triface *)(* frontlist)[k];
+          if ((newfront.tet == searchtet.tet) &&
+              (newfront.loc == searchtet.loc)) {
+            frontlist->del(k, 0);
+            break;
+          }
         }
-      }
-    } else { // ori1 == 0.0;
-      // Possible cases are: RIGHTCOLLINEAR, LEFTCOLLINEAR, ACROSSEDGE.
-      if (ori2 < 0.0) {
-        if (ori3 < 0.0) {
-          // Cross edge (tdest, tapex)
-          return ACROSSEDGE;
-        } else { // ori3 == 0.0
-          // Collinear with edge (torg, tapex)
-          return LEFTCOLLINEAR;
+        // Is f_n a subface?
+        tspivot(newfront, checksh);
+        if (checksh.sh != dummysh) {
+          // Temporarily remove checksh. Make it missing. recover it later.
+          if (b->verbose > 2) {
+            printf("    Queuing subface (%d, %d, %d).\n",
+                   pointmark(sorg(checksh)), pointmark(sdest(checksh)),
+                   pointmark(sapex(checksh)));
+          }
+          tsdissolve(newfront);
+          tsdissolve(casingtet);
+          // Detach tets at the both sides of checksh.
+          stdissolve(checksh);
+          sesymself(checksh);
+          stdissolve(checksh);
+          sinfect(checksh);
+          missingshqueue->push(&checksh);
         }
-      } else { // ori2 == 0.0;
-        assert(ori3 != 0.0);
-        // Collinear with edge (torg, tdest)
-        return RIGHTCOLLINEAR;
       }
+      enextself(misfront);
+    }
+    // C has been expanded at f. t becomes a cross tet.
+    if (!infected(misfront)) {
+      // t will be deleted, queue it.
+      infect(misfront);
+      crosstetlist->append(&misfront);
+    }
+  }
+
+  // Loop through misfrontlist, remove infected misfronts.
+  for (i = 0; i < misfrontlist->len(); i++) {
+    misfront = * (triface *)(* misfrontlist)[i];
+    if (infected(misfront)) {
+      // Remove f, keep original list order.
+      misfrontlist->del(i, 1);
+      i--;
     }
   }
+
+  // Are we done?
+  if (misfrontlist->len() > 0) {
+    // No. There are unexpandable fronts.
+    // expandcavity_sos(misfrontlist);
+    assert(0); // Not done yet.
+  }
+
+  // D has been updated (by added new tets or dead tets) (due to flips).
+  retrievenewtets(newtetlist);
+
+  // Restore global variables.
+  dummytet[0] = encode(bakhulltet);
+  hullsize = bakhullsize;
+  checksubfaces = bakchksub;
+  b->verbose++;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// getsearchtet()    Find a tetrahedron whose origin is either 'p1' or 'p2'. //
+// carvecavity()    Remove redundant (outside) tetrahedra from D.            //
 //                                                                           //
-// On return, the origin of 'searchtet' is either 'p1' or 'p2',  and 'tend'  //
-// returns the other point.  'searchtet' serves as the starting tetrahedron  //
-// for searching of the line segment from 'p1' to 'p2' or vice versa.        //
+// The fronts of C have been identified in D. Hence C can be tetrahedralized //
+// by removing the tets outside C. The CDT is then updated by filling C with //
+// the remaining tets (inside C) of D.                                       //
+//                                                                           //
+// Each front is protected by an auxilary subface s in D. s has a pointer to //
+// f (s.sh[0]). f can be used to classified the in- and out- tets of C (the  //
+// CW orientation of f faces to the inside of C). The classified out-tets of //
+// C are marked (infected) for removing.                                     //
+//                                                                           //
+// Notice that the out-tets may not only the tets on the CH of C,  but also  //
+// tets completely inside D, eg., there is a "hole" in D.  Such tets must be //
+// marked during classification. The hole tets are poped up and removed too. //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-getsearchtet(point p1, point p2, triface* searchtet, point* tend)
+void tetgenmesh::carvecavity(list* newtetlist, list* outtetlist,
+  queue* flipque)
 {
-  tetrahedron encodedtet1, encodedtet2;
+  triface newtet, neightet, front, outtet;
+  face auxsh, consh;
+  point pointptr;
+  REAL ori;
+  int i;
 
-  // Is there a valid handle provided by the user?
-  if ((searchtet->tet != (tetrahedron *) NULL) && !isdead(searchtet)) {
-    // Find which endpoint the handle holds.
-    if (findorg(searchtet, p1)) {
-      *tend = p2;
-      return;
-    } else {
-      if (findorg(searchtet, p2)) {
-        *tend = p1;
-        return;
+  // Clear work list.
+  outtetlist->clear();
+
+  // Classify in- and out- tets in D. Mark and queue classified out-tets.
+  for (i = 0; i < newtetlist->len(); i++) {
+    // Get a new tet t.
+    newtet = * (triface *)(* newtetlist)[i];
+    assert(!isdead(&newtet));
+    // Look for aux subfaces attached at t.
+    for (newtet.loc = 0; newtet.loc < 4; newtet.loc++) {
+      tspivot(newtet, auxsh);
+      if (auxsh.sh != dummysh) {
+        // Has this side a neighbor n? 
+        sym(newtet, neightet);
+        if (neightet.tet != dummytet) {
+          // Classify t and n (one is "in" and another is "out").
+          // Get the front f.
+          decode((tetrahedron) auxsh.sh[0], front);
+          // Let f face to the inside of C.
+          adjustedgering(front, CW);
+          ori = orient3d(org(front), dest(front), apex(front), oppo(newtet));
+          assert(ori != 0.0);
+          if (ori < 0.0) {
+            // t is in-tet. n is out-tet.
+            outtet = neightet;
+          } else {
+            // n is in-tet. t is out-tet.
+            outtet = newtet;
+          }
+          // Add the out-tet into list.
+          if (!infected(outtet)) {
+            infect(outtet);
+            outtetlist->append(&outtet);
+          }
+        }
       }
     }
   }
-  // If not, search the handle stored in 'p1' or 'p2'.
-  *tend = (point) NULL;
-  encodedtet1 = point2tet(p1);
-  encodedtet2 = point2tet(p2);
-  if (encodedtet1 != (tetrahedron) NULL) {
-    decode(encodedtet1, *searchtet);
-    // Be careful, here 'searchtet' may be dead.
-    if (findorg(searchtet, p1)) {
-      *tend = p2;
-    }
-  } else if (encodedtet2 != (tetrahedron) NULL) {
-    decode(encodedtet2, *searchtet);
-    // Be careful, here 'searchtet' may be dead.
-    if (findorg(searchtet, p2)) {
-      *tend = p1;
+
+  // Find and mark all out-tets.
+  for (i = 0; i < outtetlist->len(); i++) {
+    outtet = * (triface *)(* outtetlist)[i];
+    for (outtet.loc = 0; outtet.loc < 4; outtet.loc++) {
+      sym(outtet, neightet);
+      // Does the neighbor exist and unmarked?
+      if ((neightet.tet != dummytet) && !infected(neightet)) {
+        // Is it protected by an aux subface?
+        tspivot(outtet, auxsh);
+        if (auxsh.sh == dummysh) {
+          // It's an out-tet.
+          infect(neightet);
+          outtetlist->append(&neightet);
+        }
+      }
     }
   }
-  // If still not, perform a full point location.  The starting tetrahedron
-  //   is chosen as follows: Use the handle stored in 'p1' or 'p2' if it is
-  //   alive; otherwise, start from a tetrahedron on the convex hull.
-  if (*tend == (point) NULL) {
-    if (encodedtet1 != (tetrahedron) NULL) {
-      decode(encodedtet1, *searchtet);
-      // Be careful, here 'searchtet' may be dead.
-    }
-    if (isdead(searchtet)) {
-      if (encodedtet2 != (tetrahedron) NULL) {
-        decode(encodedtet2, *searchtet);
-        // Be careful, here 'searchtet' may be dead.
-      }
-      if (isdead(searchtet)) {
-        searchtet->tet = dummytet;
-        searchtet->loc = 0;
-        symself(*searchtet);
+
+  // Remove the out- (and hole) tets.
+  for (i = 0; i < outtetlist->len(); i++) {
+    // Get an out-tet t.
+    outtet = * (triface *)(* outtetlist)[i];
+    // Detach t from the in-tets.
+    for (outtet.loc = 0; outtet.loc < 4; outtet.loc++) {
+      // Is there an aux subface s?
+      tspivot(outtet, auxsh);
+      if (auxsh.sh != dummysh) {
+        // Get the neighbor n.
+        sym(outtet, neightet);
+        assert(!infected(neightet)); // t must be in-tet.
+        // Detach n -x-> t.
+        dissolve(neightet);
       }
-      assert(!isdead(searchtet));
-    }
-    if (locate(p1, searchtet) != ONVERTEX) {
-      printf("Internal error in getsearchtet():  Failed to locate point\n");
-      printf("  (%.12g, %.12g, %.12g) %d.\n", p1[0], p1[1], p1[2],
-             pointmark(p1));
-      internalerror();
     }
-    // Remember this handle in 'p1' to enhance the search speed.
-    setpoint2tet(p1, encode(*searchtet));
-    *tend = p2;
+    // Dealloc the tet.
+    tetrahedrondealloc(outtet.tet);
+  }
+
+  // Connect the in-tets of C to fronts. Remove aux subfaces and fake tets.
+  for (i = 0; i < newtetlist->len(); i++) {
+    // Get a new tet t.
+    newtet = * (triface *)(* newtetlist)[i];
+    // t may be an out-tet and has got deleted.
+    if (isdead(&newtet)) continue;
+    // t is an in-tet. Look for aux subfaces attached at t.
+    for (newtet.loc = 0; newtet.loc < 4; newtet.loc++) {
+      // Is there an aux subface s?
+      tspivot(newtet, auxsh);
+      if (auxsh.sh != dummysh) {
+        // Get the front f.
+        decode((tetrahedron) auxsh.sh[0], front);
+        assert((front.tet != dummytet) && !infected(front));
+        // s has fulfilled its duty. Can be deleted.
+        tsdissolve(newtet); // dissolve: t -x-> s.
+        // Delete s.
+        shellfacedealloc(subfaces, auxsh.sh);
+        // Connect the newtet t and front f.
+        // Is there a concrete subface c at f.
+        tspivot(front, consh);
+        if (consh.sh != dummysh) {
+          sesymself(consh);
+          // Bond: t <--> c.
+          tsbond(newtet, consh);
+        }
+        // Does f hold by a fake tet.
+        if (oppo(front) == (point) NULL) {
+          // f is fake.
+          if (consh.sh != dummysh) {
+            sesymself(consh);
+            // Dissolve: c -x-> f.
+            stdissolve(consh);
+          }
+          // Dealloc f.
+          tetrahedrondealloc(front.tet);
+          // f becomes a hull. let 'dummytet' bond to it.
+          dummytet[0] = encode(newtet);
+        } else {
+          // Bond t <--> f.
+          bond(newtet, front);
+        }
+        // t may be non-locally Delaunay and flipable.
+        if (flipque != (queue *) NULL) {
+          enqueueflipface(newtet, flipque);
+        }
+      }
+    }
+    // Let the corners of t2 point to it for fast searching.
+    pointptr = org(newtet);
+    setpoint2tet(pointptr, encode(newtet));
+    pointptr = dest(newtet);
+    setpoint2tet(pointptr, encode(newtet));
+    pointptr = apex(newtet);
+    setpoint2tet(pointptr, encode(newtet));
+    pointptr = oppo(newtet);
+    setpoint2tet(pointptr, encode(newtet));
   }
+  // The cavity has been re-tetrahedralized.
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// isedgeencroached()    Check whether or not a subsegment is encroached by  //
-//                       a given point.                                      //
+// delaunizecavity()    Tetrahedralize a cavity by Delaunay tetrahedra.      //
 //                                                                           //
-// A segment with endpoints 'p1' and 'p2' is encroached by the point 'testpt'//
-// if it lies in the diametral sphere of this segment.  The degenerate case  //
-// that 'testpt' lies on the sphere can be treated as either be encroached   //
-// or not so. If you want to regard this case as be encroached, set the flag //
-// 'degflag' be TRUE.                                                        //
+// The cavity C is bounded by a set of triangles in 'floorlist' (a list of   //
+// coplanar subfaces) and 'ceillist' (a list of tetrahedral faces lie above  //
+// the subfaces). 'floorptlist' and 'ceilptlist' are the vertices of C.      //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::
-isedgeencroached(point p1, point p2, point testpt, bool degflag)
+void tetgenmesh::delaunizecavity(list* floorlist, list* ceillist,
+  list* ceilptlist, list* floorptlist, list* frontlist, list* misfrontlist,
+  list* newtetlist, list* crosstetlist, queue* missingshqueue, queue* flipque)
 {
-  REAL dotproduct;
+  int vertnum;
 
-  // Check if the segment is facing an angle larger than 90 degree?
-  dotproduct = (p1[0] - testpt[0]) * (p2[0] - testpt[0])
-             + (p1[1] - testpt[1]) * (p2[1] - testpt[1])
-             + (p1[2] - testpt[2]) * (p2[2] - testpt[2]);
-  if (dotproduct < 0) {
-    return true;
-  } else if (dotproduct == 0 && degflag) {
-    return true;
-  } else {
-    return false;
+  vertnum = floorptlist->len();
+  vertnum += (ceilptlist != (list *) NULL ? ceilptlist->len() : 0);
+  if (b->verbose > 1) {
+    printf("    Delaunizing cavity (%d floors, %d ceilings, %d vertices).\n",
+           floorlist->len(), ceillist->len(), vertnum);
+  }
+  // Save the size of the largest cavity.
+  if ((floorlist->len() + ceillist->len()) > maxcavfaces) {
+    maxcavfaces = floorlist->len() + ceillist->len();
+  }
+  if (vertnum > maxcavverts) {
+    maxcavverts = vertnum;
+  }
+
+  // Clear these lists.
+  frontlist->clear();
+  misfrontlist->clear();
+  newtetlist->clear();
+
+  // Initialize the cavity C.
+  initializecavity(floorlist, ceillist, frontlist);
+  // Form the D of the vertices of C.
+  delaunizecavvertices(NULL, floorptlist, ceilptlist, newtetlist, flipque);    
+  // Identify faces of C in D.
+  while (!identifyfronts(frontlist, misfrontlist, newtetlist)) {
+    // Remove protecting subfaces, keep new tets.
+    detachauxsubfaces(newtetlist);
+    // Expand C and updateing D.
+    expandcavity(frontlist, misfrontlist, newtetlist, crosstetlist,
+                 missingshqueue, flipque);
   }
+  // All fronts have identified in D. Get the shape of C by removing out
+  //   tets of C. 'misfrontlist' is reused for removing out tets.
+  carvecavity(newtetlist, misfrontlist, NULL);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// scoutrefpoint()    Search the reference point of a missing segment.       //
+// formmissingregion()    Form the missing region.                           //
 //                                                                           //
-// A segment S is missing in current Delaunay tetrahedralization DT and will //
-// be split by inserting a point V in it.  The two end points of S are the   //
-// origin of 'searchtet' and 'tend'. And we know that S is crossing the face //
-// of 'searchtet' opposite to its origin (may be intersecting with the edge  //
-// from the destination to the apex of the 'searchtet').  The search of P is //
-// completed by walking through all faces of DT across by S.                 //
+// 'missingsh' is a missing subface.  Start from it we can form the missing  //
+// region R (a set of connected missing subfaces).  Because all missing sub- //
+// faces have been marked (infected) before. R can be formed by checking the //
+// neighbors of 'missingsh', and the neighbors of the neighbors, and so on.  //
+// Stop checking further at either a segment or an unmarked subface.         //
 //                                                                           //
-// Warning:  This routine is correct when the tetrahedralization is Delaunay //
-// and convex. Otherwise, the search loop may not terminate.                 //
+// 'missingshlist' returns R. The edge ring of subfaces of R are oriented in //
+// the same direction. 'equatptlist' returns the vertices of R, each vertex  //
+// is marked with '1' (in 'worklist').                                       //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-tetgenmesh::point tetgenmesh::scoutrefpoint(triface* searchtet, point tend)
+void tetgenmesh::formmissingregion(face* missingsh, list* missingshlist,
+  list* equatptlist, int* worklist)
 {
-  triface checkface;
-  point tstart, testpt, refpoint;
-  REAL cent[3], radius, largest;
-  REAL ahead;
-  bool ncollinear;
-  int sides;
+  face neighsh, worksh, workseg;
+  point workpt[3];
+  int idx, i, j;
 
-  if (b->verbose > 2) {
-    printf("  Scout the reference point of segment (%d, %d).\n",
-           pointmark(org(*searchtet)), pointmark(tend));
+  // Add 'missingsh' into 'missingshlist'.
+  missingshlist->append(missingsh);
+  // Save and mark its three vertices.
+  workpt[0] = sorg(*missingsh);
+  workpt[1] = sdest(*missingsh);
+  workpt[2] = sapex(*missingsh);
+  for (i = 0; i < 3; i++) {
+    idx = pointmark(workpt[i]) - in->firstnumber;
+    worklist[idx] = 1;
+    equatptlist->append(&workpt[i]);
   }
-
-  tstart = org(*searchtet);
-  refpoint = (point) NULL;
+  // Temporarily uninfect it (avoid to save it again).
+  suninfect(*missingsh);
   
-  // Check the three vertices of the crossing face.
-  testpt = apex(*searchtet);
-  if (isedgeencroached(tstart, tend, testpt, true)) {
-    ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
-    assert(ncollinear);
-    refpoint = testpt;
-    largest = radius;
+  // Find the other missing subfaces.
+  for (i = 0; i < missingshlist->len(); i++) {
+    // Get a missing subface.
+    worksh = * (face *)(* missingshlist)[i];
+    // Check three neighbors of this face.
+    for (j = 0; j < 3; j++) {
+      sspivot(worksh, workseg);
+      if (workseg.sh == dummysh) {
+        spivot(worksh, neighsh);
+        if (sinfected(neighsh)) {
+          // Find a missing subface, adjust the face orientation.
+          if (sorg(neighsh) != sdest(worksh)) {
+            sesymself(neighsh);
+          }
+          if (b->verbose > 2) {
+            printf("    Add missing subface (%d, %d, %d).\n", 
+                   pointmark(sorg(neighsh)), pointmark(sdest(neighsh)),
+                   pointmark(sapex(neighsh)));
+          }
+          missingshlist->append(&neighsh);
+          // Save and mark its apex.
+          workpt[0] = sapex(neighsh);
+          idx = pointmark(workpt[0]) - in->firstnumber;
+          // Has workpt[0] been added?
+          if (worklist[idx] == 0) {
+            worklist[idx] = 1;
+            equatptlist->append(&workpt[0]);
+          }
+          // Temporarily uninfect it (avoid to save it again).
+          suninfect(neighsh);
+        } 
+      } 
+      senextself(worksh);
+    }
   }
-  testpt = dest(*searchtet);
-  if (isedgeencroached(tstart, tend, testpt, true)) {
-    ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
-    assert(ncollinear);
-    if (refpoint == (point) NULL) {
-      refpoint = testpt;
-      largest = radius;
+
+  // R has been formed. Infect missing subfaces again.
+  for (i = 0; i < missingshlist->len(); i++) {
+    worksh = * (face *)(* missingshlist)[i];
+    sinfect(worksh);
+  } 
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// rearrangesubfaces()    Rearrange the set of subfaces of a missing region  //
+//                        so that they conform to the faces of DT.           //
+//                                                                           //
+// The missing region formed by subfaces of 'missingshlist' contains a set   //
+// of degenerate vertices, hence the set of subfaces don't match the set of  //
+// faces in DT.  Instead of forcing them to present in DT, we re-arrange the //
+// connection of them so that the new subfaces conform to the faces of DT.   //
+// 'boundedgelist' is a set of boundary edges of the region, these edges(may //
+// be subsegments) must exist in DT.                                         //
+//                                                                           //
+// On completion, we have created and inserted a set of new subfaces which   //
+// conform to faces of DT. The set of old subfaces in 'missingshlist' are    //
+// deleted. The region vertices in 'equatptlist' are unmarked.               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::rearrangesubfaces(list* missingshlist, list* boundedgelist,
+  list* equatptlist, int* worklist)
+{
+  link *boundedgelink;
+  link *newshlink;
+  triface starttet, spintet, neightet, worktet;
+  face shloop, newsh, neighsh, spinsh, worksh;
+  face workseg, casingin, casingout;
+  point torg, tdest, workpt;
+  point spt1, spt2, spt3;
+  enum finddirectionresult collinear;
+  enum shestype shtype;
+  REAL area;
+  bool matchflag, finishflag;
+  int shmark, pbcgp, idx, hitbdry;
+  int i, j;
+
+  // Initialize the boundary edge link.
+  boundedgelink = new link(sizeof(face), NULL, 256);
+  // Initialize the new subface link.
+  newshlink = new link(sizeof(face), NULL, 256);
+  // Remember the type (skinny or not) of replaced subfaces.  They should
+  //   all have the same type since there is no segment inside the region.
+  worksh = * (face *)(* missingshlist)[0];
+  shtype = shelltype(worksh);
+  // The following loop is only for checking purpose.
+  for (i = 1; i < missingshlist->len(); i++) {
+    worksh = * (face *)(* missingshlist)[i];
+    assert(shelltype(worksh) == shtype);
+  }
+  // To avoid compilation warnings.
+  shmark = pbcgp = 0;
+  area = 0.0; 
+
+  // Create an initial boundary link.
+  for (i = 0; i < boundedgelist->len(); i++) {
+    shloop = * (face *)(* boundedgelist)[i];
+    if (i == 0) {
+      // 'shmark' will be set to all new created subfaces.
+      shmark = shellmark(shloop);
+      if (b->quality && varconstraint) {
+        // area will be copied to all new created subfaces.
+        area = areabound(shloop);
+      }
+      if (checkpbcs) {
+        // pbcgp will be copied to all new created subfaces.
+        pbcgp = shellpbcgroup(shloop);
+      }
+      // Get the abovepoint of this facet.
+      abovepoint = facetabovepointarray[shellmark(shloop)];
+      if (abovepoint == (point) NULL) {
+        getfacetabovepoint(&shloop);
+      }
+    }
+    sspivot(shloop, workseg);
+    if (workseg.sh == dummysh) {
+      // This edge is an interior edge.
+      spivot(shloop, neighsh);
+      boundedgelink->add(&neighsh);
     } else {
-      if (radius > largest) {
-        refpoint = testpt;
-        largest = radius;
+      // This side has a segment, the edge exists. 
+      boundedgelink->add(&shloop);
+    }
+  }
+
+  // Each edge ab of boundedgelink will be finished by finding a vertex c
+  //   which is a vertex of the missing region, such that:
+  //   (1) abc is inside the missing region, i.e., abc intersects at least
+  //       one of missing subfaces (saved in missingshlist);
+  //   (2) abc is not intersect with any previously created new subfaces
+  //       in the missing region (saved in newshlink).
+  //   After abc is created, it will be inserted into both the surface mesh
+  //   and the DT. The boundedgelink will be updated, ab is removed, bc and
+  //   ca will be added if they are open.
+
+  while (boundedgelink->len() > 0) {
+    // Remove an edge (ab) from the link.
+    shloop = * (face *) boundedgelink->del(1);
+    // 'workseg' indicates it is a segment or not.
+    sspivot(shloop, workseg);
+    torg = sorg(shloop);  // torg = a;
+    tdest = sdest(shloop);  // tdest = b; 
+    // Find a tetrahedron containing ab.
+    getsearchtet(torg, tdest, &starttet, &workpt);
+    collinear = finddirection(&starttet, workpt, tetrahedrons->items);
+    if (collinear == LEFTCOLLINEAR) {
+      enext2self(starttet);
+      esymself(starttet);
+    } else if (collinear == TOPCOLLINEAR) {
+      fnextself(starttet);
+      enext2self(starttet);
+      esymself(starttet);
+    }
+    assert(dest(starttet) == workpt);
+    // Checking faces around ab until a valid face is found.
+    matchflag = false;
+    spintet = starttet;
+    hitbdry = 0;
+    do {
+      workpt = apex(spintet);
+      idx = pointmark(workpt) - in->firstnumber;
+      if (worklist[idx] == 1) {
+        // (trog, tdest, workpt) is on the facet. Check if it satisfies (1).
+        finishflag = false;
+        for (i = 0; i < missingshlist->len(); i++) {
+          worksh = * (face *)(* missingshlist)[i];
+          spt1 = sorg(worksh);
+          spt2 = sdest(worksh);
+          spt3 = sapex(worksh);
+          // Does bc intersect the face?
+          if (tri_edge_cop_inter(spt1, spt2, spt3, tdest, workpt, abovepoint)
+              == INTERSECT) {
+            finishflag = true; break;
+          }
+          // Does ca intersect the face?
+          if (tri_edge_cop_inter(spt1, spt2, spt3, workpt, torg, abovepoint)
+              == INTERSECT) {
+            finishflag = true; break;
+          }
+          // Does c inside the face?
+          if (tri_vert_cop_inter(spt1, spt2, spt3, workpt, abovepoint)
+              == INTERSECT) {
+            finishflag = true; break;
+          }
+        }
+        if (finishflag) {
+          // Satisfying (1). Check if it satisfies (2).
+          matchflag = true;
+          for (i = 0; i < newshlink->len() && matchflag; i++) {
+            worksh = * (face *) newshlink->getnitem(i + 1);
+            spt1 = sorg(worksh);
+            spt2 = sdest(worksh);
+            spt3 = sapex(worksh);
+            // Does bc intersect the face?
+            if (tri_edge_cop_inter(spt1, spt2, spt3, tdest, workpt, abovepoint)
+                == INTERSECT) {
+              matchflag = false; break;
+            }
+            // Does ca intersect the face?
+            if (tri_edge_cop_inter(spt1, spt2, spt3, workpt, torg, abovepoint)
+                == INTERSECT) {
+              matchflag = false; break;
+            }
+            // Does c inside the face?
+            if (tri_vert_cop_inter(spt1, spt2, spt3, workpt, abovepoint)
+                == INTERSECT) {
+              matchflag = false; break;
+            }
+          }
+        }
+        if (matchflag == true) {
+          // Satisfying both (1) and (2). Find abc.
+          break;
+        }
+      }
+      if (!fnextself(spintet)) {
+        hitbdry ++;
+        if (hitbdry < 2) {
+          esym(starttet, spintet);
+          if (!fnextself(spintet)) {
+            hitbdry ++;
+          }
+        }
       }
+    } while (hitbdry < 2 && apex(spintet) != apex(starttet));
+    assert(matchflag == true);
+    tspivot(spintet, neighsh);
+    if (neighsh.sh != dummysh) {
+      printf("Error:  Invalid PLC.\n");
+      printf("  Facet #%d and facet #%d overlap each other.\n",
+             shellmark(neighsh), shellmark(shloop));
+      printf("  It might be caused by a facet is defined more than once.\n");
+      printf("  Hint:  Use -d switch to find all overlapping facets.\n");
+      exit(1);
     }
-  }
-  testpt = oppo(*searchtet);
-  if (isedgeencroached(tstart, tend, testpt, true)) {
-    ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
-    assert(ncollinear);
-    if (refpoint == (point) NULL) {
-      refpoint = testpt;
-      largest = radius;
+    // The side of 'spintet' is at which a new subface will be attached.
+    adjustedgering(spintet, CCW);
+    // Create the new subface.
+    makeshellface(subfaces, &newsh);
+    setsorg(newsh, org(spintet));
+    setsdest(newsh, dest(spintet));
+    setsapex(newsh, apex(spintet));
+    if (b->quality && varconstraint) {
+      setareabound(newsh, area);
+    }
+    if (checkpbcs) {
+      setshellpbcgroup(newsh, pbcgp);
+    }
+    setshellmark(newsh, shmark);
+    setshelltype(newsh, shtype);  // It may be a skinny subface.
+    // Add newsh into newshlink for intersecting checking.
+    newshlink->add(&newsh);
+    // Insert it into the current mesh.
+    tsbond(spintet, newsh);
+    sym(spintet, neightet);
+    if (neightet.tet != dummytet) {
+      sesym(newsh, neighsh);
+      tsbond(neightet, neighsh);
+    }
+    // Insert it into the surface mesh.
+    sspivot(shloop, workseg);
+    if (workseg.sh == dummysh) {
+      sbond(shloop, newsh);
     } else {
-      if (radius > largest) {
-        refpoint = testpt;
-        largest = radius;
+      // There is a subsegment, 'shloop' is the subface which is going to
+      //   die. Insert the 'newsh' at the place of 'shloop' into its face
+      //   link, so as to dettach 'shloop'.   The original connection is:
+      //   -> casingin -> shloop -> casingout ->, it will be changed with:
+      //   -> casingin ->  newsh -> casingout ->.  Pay attention to the
+      //   case when this subsegment is dangling in the mesh, i.e., 'shloop'
+      //   is bonded to itself.
+      spivot(shloop, casingout);
+      if (shloop.sh != casingout.sh) {
+        // 'shloop' is not bonded to itself.
+        spinsh = casingout;
+        do {
+          casingin = spinsh;
+          spivotself(spinsh);
+        } while (sapex(spinsh) != sapex(shloop));
+        assert(casingin.sh != shloop.sh); 
+        // Bond casingin -> newsh -> casingout.
+        sbond1(casingin, newsh);
+        sbond1(newsh, casingout);
+      } else {
+        // Bond newsh -> newsh.
+        sbond(newsh, newsh);
       }
+      // Bond the segment.
+      ssbond(newsh, workseg);
     }
-  }
-  // Check the opposite vertex of the neighboring tet in case the segment
-  //   crosses the edge (leftpoint, rightpoint) of the crossing face.
-  sym(*searchtet, checkface);
-  if (checkface.tet != dummytet) {
-    testpt = oppo(checkface);
-    if (isedgeencroached(tstart, tend, testpt, true)) {
-      ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
-      assert(ncollinear);
-      if (refpoint == (point) NULL) {
-        refpoint = testpt;
-        largest = radius;
+    // Check other two sides of this new subface.  If a side is not bonded
+    //   to any edge in the link, it will be added to the link.
+    for (i = 0; i < 2; i++) {
+      if (i == 0) {
+        senext(newsh, worksh);
       } else {
-        if (radius > largest) {
-          refpoint = testpt;
-          largest = radius;
-        }
+        senext2(newsh, worksh);
       }
-    }
-  }
-
-  // Walk through all crossing faces.
-  enextfnext(*searchtet, checkface);
-  sym(checkface, *searchtet);
-  while (true) {
-    // Check if we are reaching the boundary of the triangulation.
-    assert(searchtet->tet != dummytet);
-    // Search for an adjoining tetrahedron we can walk through.
-    searchtet->ver = 0;
-    // 'testpt' is the shared vertex for the following orientation tests.
-    testpt = oppo(*searchtet);
-    if (testpt == tend) {
-      // The searching is finished.
-      break; 
-    } else {
-      // 'testpt' may encroach the segment.
-      if ((testpt != tstart) && (testpt != refpoint)) {
-        if (isedgeencroached(tstart, tend, testpt, true)) {
-          ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
-          if (!ncollinear) {
-            // 'testpt' is collinear with the segment. It may happen when a
-            //   set of collinear and continuous segments is defined by two
-            //   extreme endpoints.  In this case, we should choose 'testpt'
-            //   as the splitting point immediately.  No new point should be
-            //   created.
-            refpoint = testpt;
-            break;
-          }
-          if (refpoint == (point) NULL) {
-            refpoint = testpt;
-            largest = radius;
+      torg = sorg(worksh);
+      tdest = sdest(worksh);
+      finishflag = false;
+      for (j = 0; j < boundedgelink->len() && !finishflag; j++) {
+        neighsh = * (face *) boundedgelink->getnitem(j + 1);
+        if ((sorg(neighsh) == torg && sdest(neighsh) == tdest) ||
+            (sorg(neighsh) == tdest && sdest(neighsh) == torg)) {
+          // Find a boundary edge.  Bond them and exit the loop.
+          sspivot(neighsh, workseg);
+          if (workseg.sh == dummysh) {
+            sbond(neighsh, worksh);
           } else {
-            if (radius > largest) {
-              refpoint = testpt;
-              largest = radius;
+            // There is a subsegment, 'neighsh' is the subface which is
+            //   going to die. Do the same as above for 'worksh'.
+            spivot(neighsh, casingout);
+            if (neighsh.sh != casingout.sh) {
+              // 'neighsh' is not bonded to itself.
+              spinsh = casingout;
+              do {
+                casingin = spinsh;
+                spivotself(spinsh);
+              } while (sapex(spinsh) != sapex(neighsh));
+              assert(casingin.sh != neighsh.sh); 
+              // Bond casingin -> worksh -> casingout.
+              sbond1(casingin, worksh);
+              sbond1(worksh, casingout);
+            } else {
+              // Bond worksh -> worksh.
+              sbond(worksh, worksh);
             }
+            // Bond the segment.
+            ssbond(worksh, workseg);
           }
+          // Remove this boundary edge from the link.
+          boundedgelink->del(j + 1);
+          finishflag = true;
         }
       }
-    }
-    // Check three side-faces of 'searchtet' to find the one through
-    //   which we can walk next.
-    for (sides = 0; sides < 3; sides++) {
-      fnext(*searchtet, checkface);
-      ahead = orient3d(org(checkface), dest(checkface), testpt, tend);
-      if (ahead < 0.0) {
-        // We can walk through this face and continue the searching. 
-        sym(checkface, *searchtet);
-        break;
+      if (!finishflag) {
+        // It's a new boundary edge, add it to link.
+        boundedgelink->add(&worksh);
       }
-      enextself(*searchtet);
     }
-    assert (sides < 3);
   }
 
-  assert(refpoint != (point) NULL);
-  return refpoint;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// getsegmentorigin()    Return the origin of the (unsplit) segment.         //
-//                                                                           //
-// After a segment (or a subsegment) is split. Two resulting subsegments are //
-// connecting each other through the pointers saved in their data fields.    //
-// With these pointers, the whole (unsplit) segment can be found. 'splitseg' //
-// may be a split subsegment.  Returns the origin of the unsplit segment.    //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-tetgenmesh::point tetgenmesh::getsegmentorigin(face* splitseg)
-{
-  face workseg;
-  point farorg;
-
-  farorg = sorg(*splitseg);
-  if ((pointtype(farorg) != ACUTEVERTEX) &&
-      (pointtype(farorg) != NACUTEVERTEX)) {
-    workseg = *splitseg;
-    do {
-      senext2self(workseg);
-      spivotself(workseg);
-      if (workseg.sh != dummysh) {
-        workseg.shver = 0;  // It's a subsegment.
-        if (sdest(workseg) != farorg) {
-          sesymself(workseg);
-          assert(sdest(workseg) == farorg);
-        }
-        farorg = sorg(workseg);
-        if ((pointtype(farorg) == ACUTEVERTEX) ||
-            (pointtype(farorg) == NACUTEVERTEX)) break;
-      }
-    } while (workseg.sh != dummysh);
+  // Deallocate the set of old missing subfaces.
+  for (i = 0; i < missingshlist->len(); i++) {
+    worksh = * (face *)(* missingshlist)[i];
+    shellfacedealloc(subfaces, worksh.sh);
+  }
+  // Unmark region vertices in 'worklist'.
+  for (i = 0; i < equatptlist->len(); i++) {
+    workpt = * (point *)(* equatptlist)[i];
+    idx = pointmark(workpt) - in->firstnumber;
+    worklist[idx] = 0;
   }
-  assert((pointtype(farorg) == ACUTEVERTEX) ||
-         (pointtype(farorg) == NACUTEVERTEX));
-  return farorg;
+
+  delete boundedgelink;
+  delete newshlink;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// getsplitpoint()    Get a point for splitting a segment.                   //
+// scoutcrossingedge()    Search an edge crossing the missing region.        //
 //                                                                           //
-// 'splitseg' is the segment will be split. 'refpoint' is a reference point  //
-// for splitting this segment. Moreover, it should not collinear with the    //
-// splitting segment. (The collinear case will be detected by iscollinear()  //
-// before entering this routine.)  The calculation of the splitting point is //
-// governed by three rules introduced in my paper.                           //
+// 'missingshlist' forms the missing region R. This routine searches for an  //
+// edge crossing R.  It first forms a 'boundedgelist' consisting of the      //
+// boundary edges of R. Such edges are existing in CDT.  A crossing edge is  //
+// found by rotating faces around one of the boundary edges. It is possible  //
+// there is no edge crosses R (e.g. R has a degenerate point set).           //
 //                                                                           //
-// After the position is calculated, a new point is created at this location.//
-// The new point has one of the two pointtypes: FREESEGVERTEX indicating it  //
-// is an inserting vertex on segment, and NACUTEVERTEX indicating it is an   //
-// endpoint of a segment which original has type-3 now becomes type-2.       //
+// If find a croosing edge, return TRUE, 'crossedgelist' contains this edge. //
+// Otherwise, return FALSE.                                                  //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-tetgenmesh::point tetgenmesh::getsplitpoint(face* splitseg, point refpoint)
+bool tetgenmesh::scoutcrossingedge(list* missingshlist, list* boundedgelist,
+  list* crossedgelist, int* worklist)
 {
-  point splitpoint;
-  point farorg, fardest;
-  point ei, ej, ek, c;
-  REAL v[3], r, split;
-  REAL d1, ps, rs;
-  bool acuteorg, acutedest;
-  int stype;
-  int i;   
-
-  // First determine the type of the segment (type-1, type-2, or type-3).
-  farorg = getsegmentorigin(splitseg);
-  acuteorg = (pointtype(farorg) == ACUTEVERTEX);
-  sesymself(*splitseg);
-  fardest = getsegmentorigin(splitseg);
-  acutedest = (pointtype(fardest) == ACUTEVERTEX);
-  sesymself(*splitseg);
+  triface starttet, spintet, worktet;
+  face startsh, neighsh, worksh, workseg;
+  point torg, tdest, tapex;
+  point workpt[3], pa, pb, pc;
+  enum finddirectionresult collinear;
+  REAL ori1, ori2;
+  bool crossflag;
+  int hitbdry;
+  int i, j, k;
 
-  if (acuteorg) {
-    if (acutedest) {
-      stype = 3;
-    } else {
-      stype = 2;
-      ek = farorg;
-    }
-  } else {
-    if (acutedest) {
-      stype = 2;
-      // Adjust splitseg, so that its origin is acute.
-      sesymself(*splitseg);
-      ek = fardest;
-    } else {
-      stype = 1;
+  // Form the 'boundedgelist'. Loop through 'missingshlist', check each
+  //   edge of these subfaces. If an edge is a segment or the neighbor
+  //   subface is uninfected, add it to 'boundedgelist'.
+  for (i = 0; i < missingshlist->len(); i++) {
+    worksh = * (face *)(* missingshlist)[i];
+    for (j = 0; j < 3; j++) {
+      sspivot(worksh, workseg);
+      if (workseg.sh == dummysh) {
+        spivot(worksh, neighsh);
+        if (!sinfected(neighsh)) {
+          boundedgelist->append(&worksh);
+        }
+      } else {
+        boundedgelist->append(&worksh);
+      }
+      senextself(worksh);
     }
   }
-  ei = sorg(*splitseg);
-  ej = sdest(*splitseg);
-
-  if (b->verbose > 1) {
-    printf("  Splitting segment (%d, %d) type-%d with refpoint %d.\n",
-           pointmark(ei), pointmark(ej), stype, pointmark(refpoint));
-  }
 
-  if (stype == 1 || stype == 3) {
-    // Use rule-1.
-    REAL eij, eip, ejp;
-    eij = distance(ei, ej);
-    eip = distance(ei, refpoint);
-    ejp = distance(ej, refpoint);
-    if ((eip < ejp) && (eip < 0.5 * eij)) {
-      c = ei;
-      r = eip;
-    } else if ((eip > ejp) && (ejp < 0.5 * eij)) {
-      c = ej;
-      ej = ei;
-      r = ejp;
-    } else {
-      c = ei;
-      r = 0.5 * eij;
-    }
-    split = r / eij;
-    for (i = 0; i < 3; i++) {
-      v[i] = c[i] + split * (ej[i] - c[i]);
-    }
-  } else {
-    // Use rule-2 or rule-3.
-    REAL eki, ekj, ekp, evj, evp, eiv;
-    c = ek;
-    eki = distance(ek, ei);  // eki may equal zero.
-    ekj = distance(ek, ej);
-    ekp = distance(ek, refpoint);
-    // Calculate v (the going to split position between ei, ej).
-    r = ekp;
-    assert(eki < r && r < ekj);
-    split = r / ekj;
-    for (i = 0; i < 3; i++) {
-      v[i] = c[i] + split * (ej[i] - c[i]);
+  crossflag = false;
+  // Find a crossing edge. It is possible there is no such edge. We need to
+  //   loop through all edges of 'boundedgelist' for sure we don't miss any.
+  for (i = 0; i < boundedgelist->len() && !crossflag; i++) {
+    startsh = * (face *)(* boundedgelist)[i];
+    // 'startsh' (abc) holds an existing edge of the DT, find it.
+    torg = sorg(startsh);
+    tdest = sdest(startsh);
+    tapex = sapex(startsh);
+    getsearchtet(torg, tdest, &starttet, &workpt[0]);
+    collinear = finddirection(&starttet, workpt[0], tetrahedrons->items);
+    if (collinear == LEFTCOLLINEAR) {
+      enext2self(starttet);
+      esymself(starttet);
+    } else if (collinear == TOPCOLLINEAR) {
+      fnextself(starttet);
+      enext2self(starttet);
+      esymself(starttet);
     }
-    evj = ekj - r; // distance(v, ej);
-    evp = distance(v, refpoint);
-    if (evj < evp) {
-      // v is rejected, use rule-3.
-      eiv = distance(ei, v);
-      if (evp <= 0.5 * eiv) {
-        r = eki + eiv - evp;
+#ifdef SELF_CHECK
+    assert(dest(starttet) == workpt[0]);
+#endif
+    // Now starttet holds edge ab. Find is edge de crossing R.
+    spintet = starttet;
+    hitbdry = 0;
+    do {
+      if (fnextself(spintet)) {
+        // splittet = abde. Check if de crosses abc.
+        workpt[1] = apex(spintet);  // workpt[1] = d.
+        workpt[2] = oppo(spintet);  // workpt[2] = e.
+        j = pointmark(workpt[1]) - in->firstnumber;
+        k = pointmark(workpt[2]) - in->firstnumber;
+        if (worklist[j] == 1) {
+          ori1 = 0.0; // d is a vertex of the missing region.
+        } else {
+          // Get the orientation of d wrt. abc.
+          ori1 = orient3d(torg, tdest, tapex, workpt[1]);
+        }
+        if (worklist[k] == 1) {
+          ori2 = 0.0; // e is a vertex of the missing region.
+        } else {
+          // Get the orientation of e wrt. abc.
+          ori2 = orient3d(torg, tdest, tapex, workpt[2]);
+        }
+        // Only do check if d and e locate on different sides of abc.
+        if (ori1 * ori2 < 0.0) {
+          // Check if de crosses any subface of R.
+          for (j = 0; j < missingshlist->len(); j++) {
+            worksh = * (face *)(* missingshlist)[j];
+            pa = sorg(worksh);
+            pb = sdest(worksh);
+            pc = sapex(worksh);
+            crossflag = (tri_tri_inter(pa, pb, pc, workpt[0], workpt[1],
+                                       workpt[2]) == INTERSECT);
+            if (crossflag) {
+              // Find a crossing edge. We're done.
+              worktet = spintet;
+              adjustedgering(worktet, CCW);
+              enextfnextself(worktet);
+              enextself(worktet);
+              // Add this edge (worktet) into 'crossedgelist'.
+              crossedgelist->append(&worktet);
+              break;
+            }
+          }
+          if (crossflag) break;
+        }
+        if (apex(spintet) == apex(starttet)) break;
       } else {
-        r = eki + 0.5 * eiv;
-      }
-      assert(eki < r && r < ekj);
-      split = r / ekj;
-      for (i = 0; i < 3; i++) {
-        v[i] = c[i] + split * (ej[i] - c[i]);
-      }
-      if (b->verbose > 1) {
-        printf("    Using rule-3.\n");
+        hitbdry++;
+        // It is only possible to hit boundary once.
+        if (hitbdry < 2) {
+          esym(starttet, spintet);
+        }
       }
-    } 
-  }
-
-  if (b->verbose > 1) {
-    if (stype == 2) {
-      printf("    Split = %.12g.\n", distance(ei, v) / distance(ei, ej));
-    } else {
-      printf("    Split = %.12g.\n", distance(c, v) / distance(c, ej));
-    }
-  }
-
-  // Create the newpoint.
-  makepoint(&splitpoint);
-  // Add a random perturbation on splitpoint.
-  d1 = distance(c, v);
-  assert(d1 > 0.0);
-  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);
-  }
-  rs = ps / d1;
-  // Perturb splitpoint away from c.
-  for (i = 0; i < 3; i++) {
-    splitpoint[i] = c[i] + (1.0 + rs) * (v[i] - c[i]);
-  }
-  for (i = 0; i < in->numberofpointattributes; i++) {
-    splitpoint[i + 3] = c[i + 3] + (split + rs) * (ej[i + 3] - c[i + 3]);
-  }  
-  if (stype == 3) {
-    // Change a type-3 segment into two type-2 segments. 
-    setpointtype(splitpoint, NACUTEVERTEX);
-  } else {
-    // Set it's type be FREESEGVERTEX.
-    setpointtype(splitpoint, FREESEGVERTEX);
+    } while (hitbdry < 2);
   }
 
-  return splitpoint;
+  return crossflag;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// delaunizesegments()    Split segments repeatedly until they appear in a   //
-//                        Delaunay tetrahedralization.                       //
-//                                                                           //
-// Given a PLC X, which has a set V of vertices and a set of segments. Start //
-// from a Delaunay tetrahedralization D of V, this routine recovers segments //
-// of X in D by incrementally inserting points on missing segments, updating //
-// D with the newly inserted points into D', which remains to be a Delaunay  //
-// tetrahedralization and respects the segments of X. Hence, each segment of //
-// X appears as a union of edges in D'.                                      //
+// formcavity()    Form the cavity for recovering the missing region.        //
 //                                                                           //
-// This routine dynamically maintains two meshes, one is DT, another is the  //
-// surface mesh F of X.  DT and F have exactly the same vertices.  They are  //
-// updated simultaneously with the newly inserted points.                    //
+// The cavity C is bounded by faces of current CDT.  All tetrahedra inside C //
+// will be removed, intead a set of constrained Delaunay tetrahedra will be  //
+// filled in and the missing region are recovered.                           //
 //                                                                           //
-// Missing segments are found by looping the set S of segments, checking the //
-// existence of each segment in DT.  Once a segment is found missing in DT,  //
-// it is split into two subsegments by inserting a point into both DT and F, //
-// and S is updated accordingly.  However, the inserted point may cause some //
-// other existing segments be non-Delaunay,  hence are missing from the DT.  //
-// In order to force all segments to appear in DT, we have to loop S again   //
-// after some segments are split. (A little ugly method)  Use a handle to    //
-// remember the last segment be split in one loop, hence all segments after  //
-// it are existing and need not be checked.                                  //
+// 'missingshlist' contains a set of subfaces forming the missing region R.  //
+// C is formed by first finding all the tetrahedra in CDT that intersect the //
+// relative interior of R; then deleting them from the CDT, this will form C //
+// inside the CDT. At the beginning, 'crossedgelist' contains an edge which  //
+// is crossing R. All tets containing this edge must cross R. Start from it, //
+// other crossing edges can be found incrementally.  The discovered crossing //
+// tets are saved in 'crosstetlist'.                                         //
 //                                                                           //
-// In priciple, a segment on the convex hull should exist in DT. However, if //
-// there are four coplanar points on the convex hull, and the DT only can    //
-// contain one diagonal edge which is unfortunately not the segment, then it //
-// is missing. During the recovery of the segment, it is possible that the   //
-// calculated inserting point for recovering this convex hull segment is not //
-// exact enough and lies (slightly) outside the DT. In order to insert the   //
-// point, we enlarge the convex hull of the DT, so it can contain the point  //
-// and remains convex.  'inserthullsite()' is called for this case.          //
+// Notice that not all tets in 'crosstetlist' are crossing R. The discovered //
+// tets are connected each other. However, there may be other tets crossing  //
+// R but disjoint with the found tets. Due to this fact we need to check the //
+// 'missingshlist' once more. Only recover those subfaces which are crossed  //
+// by the set of discovered tets, i.e., R may be shrinked to conform the set //
+// of discovered tets. The extra subfaces of R will be recovered later.      //
+//                                                                           //
+// Notice that some previous recovered subfaces may completely included in C.//
+// This can happen when R is very big and these subfaces lie above R and so  //
+// close to it. Such subfaces have to be queued (and sinfected()) to recover //
+// them later. Otherwise, we lost the connection to these subfaces forever.  //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::delaunizesegments()
+void tetgenmesh::formcavity(list* missingshlist, list* crossedgelist,
+  list* equatptlist, list* crossshlist, list* crosstetlist,
+  list* belowfacelist, list* abovefacelist, list* horizptlist,
+  list* belowptlist, list* aboveptlist, queue* missingshqueue, int* worklist)
 {
-  queue *flipqueue;
-  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;
-  long vertcount;
-  int i, j;
-
-  if (!b->quiet) {
-    printf("Delaunizing segments.\n");
-  }
+  triface starttet, spintet, neightet, worktet;
+  face startsh, neighsh, worksh, workseg;
+  point torg, tdest, tapex, workpt[3];
+  REAL checksign, orgori, destori;
+  bool crossflag, inlistflag;
+  bool belowflag, aboveflag;
+  int idx, share;
+  int i, j, k;
 
-  // 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();
-  // Initialize a queue for returning non-Delaunay faces and edges.
-  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;
-  // Remember the current number of points.
-  vertcount = points->items;
+  // Get a face at horizon.
+  startsh = * (face *)(* missingshlist)[0];
+  torg = sorg(startsh);
+  tdest = sdest(startsh);
+  tapex = sapex(startsh);
 
-  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));
+  // Collect the set of crossing tetrahedra by rotating crossing edges.
+  for (i = 0; i < crossedgelist->len(); i++) {
+    // Get a tet abcd, ab is a crossing edge.
+    starttet = * (triface *)(* crossedgelist)[i];
+    adjustedgering(starttet, CCW);
+    if (b->verbose > 2) {
+      printf("    Collect tets containing edge (%d, %d).\n",
+             pointmark(org(starttet)), pointmark(dest(starttet)));
+    }
+    orgori = orient3d(torg, tdest, tapex, org(starttet));
+    destori = orient3d(torg, tdest, tapex, dest(starttet));
+#ifdef SELF_CHECK
+    assert(orgori * destori < 0.0); 
+#endif
+    spintet = starttet;
+    do {
+      // The face rotation should not meet boundary.
+      fnextself(spintet); 
+      // Check the validity of the PLC.
+      tspivot(spintet, worksh);
+      if (worksh.sh != dummysh) {
+        printf("Error:  Invalid PLC.\n");
+        printf("  Two subfaces (%d, %d, %d) and (%d, %d, %d)\n",
+               pointmark(torg), pointmark(tdest), pointmark(tapex),
+               pointmark(sorg(worksh)), pointmark(sdest(worksh)),
+               pointmark(sapex(worksh)));
+        printf("  are found intersecting each other.\n");
+        printf("  Hint:  Use -d switch to find all intersecting facets.\n");
+        terminatetetgen(1);
       }
-      getsearchtet(p1, p2, &searchtet, &tend);
-      collinear = finddirection(&searchtet, tend);
-      if (collinear == LEFTCOLLINEAR) {
-        checkpoint = apex(searchtet);
-      } else if (collinear == RIGHTCOLLINEAR) {
-        checkpoint = dest(searchtet);
-      } else if (collinear == TOPCOLLINEAR) {
-        checkpoint = oppo(searchtet);
-      } else {
-        assert(collinear == ACROSSFACE || collinear == ACROSSEDGE);
-        checkpoint = (point) NULL;
+      if (!infected(spintet)) {
+        if (b->verbose > 2) {
+          printf("      Add crossing tet (%d, %d, %d, %d).\n",
+                 pointmark(org(spintet)), pointmark(dest(spintet)),
+                 pointmark(apex(spintet)), pointmark(oppo(spintet)));
+        }
+        infect(spintet);
+        crosstetlist->append(&spintet);
       }
-      if (checkpoint != tend) {
-        // ab is missing.
-        splitpoint = (point) NULL;
-        if (checkpoint != (point) NULL) {
-          // An existing point c is found on the segment. It can happen when
-          //   ab is defined by a long segment with c inside it. Use c to
-          //   split ab. No new point is created.
-          splitpoint = checkpoint;
-          if (pointtype(checkpoint) == FREEVOLVERTEX) {
-            // c is not a segment vertex yet. It becomes NACUTEVERTEX.
-            setpointtype(splitpoint, NACUTEVERTEX);  
-          } else if (pointtype(checkpoint) == ACUTEVERTEX) {
-            // c is an acute vertex. The definition of PLC is wrong.
-          } else if (pointtype(checkpoint) == NACUTEVERTEX) {
-            // c is an nonacute vertex. The definition of PLC is wrong.
-          } else {
-            assert(0);
-          }
+      // Check whether other two edges of 'spintet' is a crossing edge.
+      //   It can be quickly checked from the apex of 'spintet', if it is
+      //   not on the facet, then there exists a crossing edge.
+      workpt[0] = apex(spintet);
+      idx = pointmark(workpt[0]) - in->firstnumber;
+      if (worklist[idx] != 1) {
+        // Either edge (dest, apex) or edge (apex, org) crosses.
+        checksign = orient3d(torg, tdest, tapex, workpt[0]);
+#ifdef SELF_CHECK
+        assert(checksign != 0.0);
+#endif
+        if (checksign * orgori < 0.0) {
+          enext2(spintet, worktet); // edge (apex, org).
+          workpt[1] = org(spintet);
         } else {
-          // Find a reference point p of ab.
-          refpoint = scoutrefpoint(&searchtet, tend);
-          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) {
-              // a, b, and p are collinear. We insert p into ab. p becomes
-              //   a segment vertex with type NACUTEVERTEX.
-              splitpoint = refpoint;
-              setpointtype(splitpoint, NACUTEVERTEX);
-            }
-          }
-          if (splitpoint == (point) NULL) {
-            // Calculate a split point v using rule 1, or 2, or 3.
-            splitpoint = getsplitpoint(&segloop, refpoint);
-            
-            // Is there periodic boundary conditions?
-            if (checkpbcs) {
-              // Yes! Insert points on other segments of incident pbcgroups.
-              i = shellmark(segloop) - 1;
-              for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++) {
-                makepoint(&sympoint);
-                symloc = getsegpbcsympoint(splitpoint, &segloop, sympoint,
-                                           &symsplitseg, segpglist[j]);
-                assert(symloc != OUTSIDE);
-                if (symloc == ONEDGE) {
-                  assert(symsplitseg.sh != dummysh);
-                  setpointtype(sympoint, FREESEGVERTEX);
-                  // setpoint2sh(sympoint, sencode(symsplitseg));
-                  // Insert sympoint into DT.
-                  pa = sorg(symsplitseg);
-                  splittet.tet = dummytet;
-                  // Find a good start point to search.
-                  encodedtet = point2tet(pa);
-                  if (encodedtet != (tetrahedron) NULL) {
-                    decode(encodedtet, splittet);
-                    if (isdead(&splittet)) {
-                      splittet.tet = dummytet; 
-                    }
-                  }
-                  // Locate sympoint in DT.  Do exact location.
-                  success = insertsite(sympoint, &splittet, false, flipqueue);
-                  assert(success != DUPLICATEPOINT);
-                  if (success == OUTSIDEPOINT) {
-                    inserthullsite(sympoint, &splittet, flipqueue, NULL, NULL);
-                  }
-                  if (steinerleft > 0) steinerleft--;
-                  // Let sympoint remember splittet.
-                  setpoint2tet(sympoint, encode(splittet));
-                  // Do flip in DT.
-                  flip(flipqueue, NULL, false, false, false);
-                  // Insert sympoint into F.
-                  symsplitseg.shver = 0;
-                  spivot(symsplitseg, symsplitsub);
-                  // sympoint should on the edge of symsplitsub.
-                  splitsubedge(sympoint, &symsplitsub, flipqueue);
-                  // Do flip in facet.
-                  flipsub(flipqueue);
-                } else if (symloc == ONVERTEX) {
-                  // The sympoint already exists. It is possible when two
-                  //   pbc groups are exactly the same. Omit this point.
-                  pointdealloc(sympoint);
-                }
-              }
-            }
-
-            // Insert 'splitpoint' into DT.
-            if (isdead(&searchtet)) searchtet.tet = dummytet;
-            success = insertsite(splitpoint, &searchtet, false, flipqueue);
-            if (success == OUTSIDEPOINT) {
-              // A convex hull edge is missing, and the inserting point lies
-              //   (slightly) outside the convex hull due to the significant
-              //   digits lost in the calculation. Enlarge the convex hull.
-              inserthullsite(splitpoint, &searchtet, flipqueue, NULL, NULL);
-            }
-            if (steinerleft > 0) steinerleft--;
-            // Remember a handle in 'splitpoint' to enhance the speed of
-            //   consequent point location.
-            setpoint2tet(splitpoint, encode(searchtet));
-            // Maintain Delaunayness in DT.
-            flip(flipqueue, NULL, false, false, false);
+#ifdef SELF_CHECK
+          assert(checksign * destori < 0.0);
+#endif
+          enext(spintet, worktet);  // edge (dest, apex).
+          workpt[1] = dest(spintet);
+        }
+        // 'worktet' represents the crossing edge. Add it into list only
+        //   it doesn't exist in 'crossedgelist'.
+        inlistflag = false;
+        for (j = 0; j < crossedgelist->len() && !inlistflag; j++) {
+          neightet = * (triface *)(* crossedgelist)[j];
+          if (org(neightet) == workpt[0]) {
+            if (dest(neightet) == workpt[1]) inlistflag = true;
+          } else if (org(neightet) == workpt[1]) {
+            if (dest(neightet) == workpt[0]) inlistflag = true;
           }
         }
-        // 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;
+        if (!inlistflag) {
+          crossedgelist->append(&worktet);
         }
       }
-      segloop.sh = shellfacetraverse(subsegs);
-    }
-    if (lastsplit.sh == (shellface *) NULL) {
-      // No missing segment!
-      finish = true;
-    }
-  }
-
-  if (b->verbose) {
-    printf("  %ld protect points are inserted.\n", points->items - vertcount);
-  }
-
-  delete flipqueue;
-}
-
-//
-// End of segments recovery routines
-//
-
-//
-// Begin of facet recovery routines
-//
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// insertsubface()    Insert a subface into the Delaunay tetrahedralization. //
-//                                                                           //
-// Search the subface in current Delaunay tetrahedralization. Return TRUE if //
-// the subface exists, i.e., it appears as a face of the DT and is inserted. //
-// Otherwise, return FALSE indicating it is a missing face.                  //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-bool tetgenmesh::insertsubface(face* insertsh, triface* searchtet)
-{
-  triface spintet, symtet;
-  face testsh, testseg;
-  face spinsh, casin, casout;
-  point tapex, checkpoint;
-  enum finddirectionresult collinear;
-  int hitbdry;
-
-  // Search one edge of 'insertsh'.
-  getsearchtet(sorg(*insertsh), sdest(*insertsh), searchtet, &checkpoint);
-  collinear = finddirection(searchtet, checkpoint);
-  if (collinear == LEFTCOLLINEAR) {
-    enext2self(*searchtet);
-    esymself(*searchtet);
-  } else if (collinear == TOPCOLLINEAR) {
-    fnextself(*searchtet);
-    enext2self(*searchtet);
-    esymself(*searchtet);
-  }
-  if (dest(*searchtet) != checkpoint) {
-    // The edge is missing => subface is missing.
-    return false;
+    } while (apex(spintet) != apex(starttet));
   }
 
-  // Spin around the edge (torg, tdest), look for a face containing tapex.
-  tapex = sapex(*insertsh);
-  spintet = *searchtet;
-  hitbdry = 0;
-  do {
-    if (apex(spintet) == tapex) {
-      // The subface is exist in DT. We will insert this subface. Before
-      //   insertion, make sure there is no subface at this position.
-      tspivot(spintet, testsh);
-      if (testsh.sh == dummysh) {
-        adjustedgering(spintet, CCW);
-        findedge(insertsh, org(spintet), dest(spintet));
-        tsbond(spintet, *insertsh);
-        sym(spintet, symtet); // 'symtet' maybe outside, use it anyway.
-        sesymself(*insertsh);
-        tsbond(symtet, *insertsh);
+  // Identifying the boundary faces and vertices of C. Sort them into
+  //   'abovefacelist', 'aboveptlist, 'belowfacelist', and 'belowptlist',
+  //    respectively. "above" and "below" are wrt.(torg, tdest, tapex). 
+  for (i = 0; i < crosstetlist->len(); i++) {
+    // Get a tet abcd, ab is the crossing edge.
+    starttet = * (triface *)(* crosstetlist)[i];
+#ifdef SELF_CHECK
+    assert(infected(starttet));
+#endif
+    adjustedgering(starttet, CCW);
+    // abc and abd are sharing the crossing edge, the two neighbors must
+    //   be crossing tetrahedra too. They can't be boundaries of C.
+    for (j = 0; j < 2; j++) {
+      if (j == 0) {
+        enextfnext(starttet, worktet); // Check bcd.
       } else {
-        // There already exists one subface. They're Duplicated.
-        printf("Warning:  Two subfaces are found duplicated at ");
-        printf("(%d, %d, %d)\n", pointmark(sorg(testsh)),
-               pointmark(sdest(testsh)), pointmark(sapex(testsh)));
-        printf("  The one of facet #%d is ignored.\n", shellmark(*insertsh));
-        // printf("  Hint: -d switch can find all duplicated facets.\n");
+        enext2fnext(starttet, worktet); // Check acd. 
+      } 
+      sym(worktet, neightet);
+      // If the neighbor doesn't exist or exists but doesn't be infected,
+      //   it's a boundary face of C, save it.
+      if ((neightet.tet == dummytet) || !infected(neightet)) {
+        workpt[0] = org(worktet);
+        workpt[1] = dest(worktet);
+        workpt[2] = apex(worktet);
+        belowflag = aboveflag = false;
+        share = 0;
+        for (k = 0; k < 3; k++) {
+          idx = pointmark(workpt[k]) - in->firstnumber;
+          if (worklist[idx] == 0) {
+            // It's not a vertices of facet, find which side it lies.
+            checksign = orient3d(torg, tdest, tapex, workpt[k]);
+#ifdef SELF_CHECK
+            assert(checksign != 0.0);
+#endif
+            if (checksign > 0.0) {
+              // It lies "below" the facet wrt. 'startsh'.
+              worklist[idx] = 2;
+              belowptlist->append(&workpt[k]);
+            } else if (checksign < 0.0) {
+              // It lies "above" the facet wrt. 'startsh'.
+              worklist[idx] = 3;
+              aboveptlist->append(&workpt[k]);
+            }
+          }
+          if (worklist[idx] == 2) {
+            // This face lies "below" the facet wrt. 'startsh'.
+            belowflag = true;
+          } else if (worklist[idx] == 3) {
+            // This face lies "above" the facet wrt. 'startsh'.
+            aboveflag = true;
+          } else {
+#ifdef SELF_CHECK
+            // In degenerate case, this face may just be the equator.
+            assert(worklist[idx] == 1);
+#endif
+            share++;
+          }
+        }
+#ifdef SELF_CHECK
+        // The degenerate case has been ruled out.
+        assert(share < 3);
+        // Only one flag is possible for a cavity face.
+        assert(belowflag ^ aboveflag); 
+#endif
+        if (belowflag) {
+          belowfacelist->append(&worktet);
+        } else if (aboveflag) {
+          abovefacelist->append(&worktet);
+        }
       }
-      return true;
     }
-    if (!fnextself(spintet)) {
-      hitbdry ++;
-      if (hitbdry < 2) {
-        esym(*searchtet, spintet);
-        if (!fnextself(spintet)) {
-          hitbdry ++;
+  }
+
+  // Shrink R if not all its subfaces are crossing by the discovered tets.
+  //   'crossshlist' and 'horizptlist' represent the set of subfaces and
+  //   vertices of the shrinked missing region, respectively.
+  for (i = 0; i < missingshlist->len(); i++) {
+    worksh = * (face *)(* missingshlist)[i];
+#ifdef SELF_CHECK
+    assert(sinfected(worksh));
+#endif
+    workpt[0] = sorg(worksh);
+    workpt[1] = sdest(worksh);
+    workpt[2] = sapex(worksh);
+    crossflag = false;
+    for (j = 0; j < crosstetlist->len() && !crossflag; j++) {
+      // Get a tet abcd, ab is a crossing edge.
+      starttet = * (triface *)(* crosstetlist)[j];
+      adjustedgering(starttet, CCW);
+      // Only need to check two sides of worktet.
+      for (k = 0; k < 2 && !crossflag; k++) {
+        if (k == 0) {
+          worktet = starttet; // Check abc.
+        } else {
+          fnext(starttet, worktet); // Check abd.
         }
+        crossflag = tritritest(&worktet, workpt[0], workpt[1], workpt[2]);
       }
     }
-  } while (hitbdry < 2 && apex(spintet) != apex(*searchtet));
-
-  // The face is missing.
-  return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// tritritest()    Test if two triangles are intersecting in their interior. //
-//                                                                           //
-// One triangles is represented by 'checktet', the other is given by three   //
-// corners 'p1', 'p2' and 'p3'. This routine calls tri_tri_inter() to detect //
-// whether these two triangles are exactly intersecting in their interior    //
-// (excluding the cases share a vertex, share an edge, or are coincide).     //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-bool tetgenmesh::tritritest(triface* checktet, point p1, point p2, point p3)
-{
-  point forg, fdest, fapex;
-  enum interresult intersect;
+    if (crossflag) {
+      // 'worksh' is crossed by 'worktet', uninfect it.
+      suninfect(worksh);
+      crossshlist->append(&worksh);
+      // Add its corners into 'horizptlist'.
+      for (k = 0; k < 3; k++) {
+        idx = pointmark(workpt[k]) - in->firstnumber;
+        if (worklist[idx] != 4) {
+          worklist[idx] = 4;
+          horizptlist->append(&workpt[k]);
+        }
+      }
+    } 
+  }
 
-  forg = org(*checktet);
-  fdest = dest(*checktet);
-  fapex = apex(*checktet);
+  // Check 'crossingtetlist'. Queue subfaces inside them.
+  for (i = 0; i < crosstetlist->len(); i++) {
+    starttet = * (triface *)(* crosstetlist)[i];
+    for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
+      sym(starttet, neightet);
+      // If the neighbor exist and is infected, check it.
+      if ((neightet.tet != dummytet) && infected(neightet)) {
+        tspivot(starttet, worksh);
+        if (worksh.sh != dummysh) {
+          // Temporarily remove worksh. Make it missing. recover it later.
+          if (b->verbose > 2) {
+            printf("    Queuing subface (%d, %d, %d).\n",
+                   pointmark(sorg(worksh)), pointmark(sdest(worksh)),
+                   pointmark(sapex(worksh)));
+          }
+          tsdissolve(neightet);
+          tsdissolve(starttet);
+          // Detach tets at the both sides of this subface.
+          stdissolve(worksh);
+          sesymself(worksh);
+          stdissolve(worksh);
+          sinfect(worksh);
+          missingshqueue->push(&worksh);
+        }
+      }
+    }
+  }
 
+  // Clear flags set in 'worklist'.
+  for (i = 0; i < equatptlist->len(); i++) {
+    workpt[0] = * (point *)(* equatptlist)[i];
+    idx = pointmark(workpt[0]) - in->firstnumber;
+#ifdef SELF_CHECK
+    assert((worklist[idx] == 1) || (worklist[idx] == 4));
+#endif
+    worklist[idx] = 0;
+  }
+  for (i = 0; i < belowptlist->len(); i++) {
+    workpt[0] = * (point *)(* belowptlist)[i];
+    idx = pointmark(workpt[0]) - in->firstnumber;
+#ifdef SELF_CHECK
+    assert(worklist[idx] == 2);
+#endif
+    worklist[idx] = 0;
+  }
+  for (i = 0; i < aboveptlist->len(); i++) {
+    workpt[0] = * (point *)(* aboveptlist)[i];
+    idx = pointmark(workpt[0]) - in->firstnumber;
 #ifdef SELF_CHECK
-  REAL ax, ay, az, bx, by, bz;
-  REAL n[3];
-  // face (torg, tdest, tapex) should not be degenerate. However p1, p2,
-  //   and p3 may be collinear. Check it.
-  ax = forg[0] - fdest[0];
-  ay = forg[1] - fdest[1];
-  az = forg[2] - fdest[2];
-  bx = forg[0] - fapex[0];
-  by = forg[1] - fapex[1];
-  bz = forg[2] - fapex[2];
-  n[0] = ay * bz - by * az;
-  n[1] = az * bx - bz * ax;
-  n[2] = ax * by - bx * ay;
-  assert(fabs(n[0]) + fabs(n[1]) + fabs(n[2]) > 0.0);
-  // The components of n should not smaller than the machine epsilon.
-
-  ax = p1[0] - p2[0];
-  ay = p1[1] - p2[1];
-  az = p1[2] - p2[2];
-  bx = p1[0] - p3[0];
-  by = p1[1] - p3[1];
-  bz = p1[2] - p3[2];
-  n[0] = ay * bz - by * az;
-  n[1] = az * bx - bz * ax;
-  n[2] = ax * by - bx * ay;
-  assert(fabs(n[0]) + fabs(n[1]) + fabs(n[2]) > 0.0);
-  // The components of n should not smaller than the machine epsilon.
+    assert(worklist[idx] == 3);
 #endif
-
-  intersect = tri_tri_inter(forg, fdest, fapex, p1, p2, p3);
-  return intersect == INTERSECT;
+    worklist[idx] = 0;
+  }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// initializecavity()    Initialize the cavity with a list of faces.         //
-//                                                                           //
-// Initialize the cavity C with a list of faces that bound C. Each face f of //
-// C is hold by a tetrahedron t adjacent to C. t is outside the cavity (i.e.,//
-// uninfected). Such t may not exist when f is on convex hull. In this case, //
-// create a fake tetrahedron t' in order to hold f, oppo(t') = NULL. t' will //
-// be removed automatically after C is retriangulated.                       //
+// insertallsubfaces()    Insert all subfaces, queue missing subfaces.       //
 //                                                                           //
-// 'floorlist' is a list of coplanar subfaces, they are oriented in the same //
-// direction pointing to the ceiling.  'ceilinglist' is a list of faces of   //
-// tetrahedra which are crossing the cavity, they form the rest part of the  //
-// boundary of the cavity. 'frontlink' is used to return the list of fronts, //
-// it is empty on input.                                                     //
+// Loop through all subfaces, insert each into the DT. If one already exists,//
+// bond it to the tetrahedra having it. Otherwise, it is missing, infect it  //
+// and save it in 'missingshqueue'.                                          //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-initializecavity(list* floorlist, list* ceillist, link* frontlink)
+void tetgenmesh::insertallsubfaces(queue* missingshqueue)
 {
-  triface neightet, casingtet;
-  triface faketet;
-  face worksh;
-  int i;
+  triface searchtet;
+  face subloop;
 
-  // First add all faces in 'floorlist' into 'frontlink'.
-  for (i = 0; i < floorlist->len(); i++) {
-    // Get f = worksh.
-    worksh = * (face *)(* floorlist)[i];
-    // Current side of f should be empty.
-    stpivot(worksh, neightet);
-    assert(neightet.tet == dummytet);
-    // Get adjacent tetrahedron t.
-    sesymself(worksh);
-    stpivot(worksh, casingtet);
-    // Does t exist?
-    if (casingtet.tet == dummytet) {
-      // No. Create a fake tet t' to hold f temporarily. t' will be removed
-      //   after f is hold by a new tetrahedron in C.
-      maketetrahedron(&faketet);
-      setorg(faketet, sorg(worksh));
-      setdest(faketet, sdest(worksh));
-      setapex(faketet, sapex(worksh));
-      setoppo(faketet, (point) NULL); // Indicates it is 'fake'.
-      tsbond(faketet, worksh);
-      frontlink->add(&faketet);
-    } else {
-      frontlink->add(&casingtet);
-    }
-  }
-  // Second add all casing faces in 'ceilinglist' into 'frontlink'.
-  for (i = 0; i < ceillist->len(); i++) {
-    neightet = * (triface *) (* ceillist)[i];
-    // The ceil is a face of cavity tetrahedron (going to be deleted).
-    assert(infected(neightet));
-    // Get the adjacent tetrahedron t.
-    sym(neightet, casingtet);
-    // Does t exist?
-    if (casingtet.tet == dummytet) {
-      // No. Create a fake tet t' to hold f temporarily. t' will be removed
-      //   after f is hold by a new tetrahedron in C.
-      maketetrahedron(&faketet);
-      setorg(faketet, org(neightet));
-      setdest(faketet, dest(neightet));
-      setapex(faketet, apex(neightet));
-      setoppo(faketet, (point) NULL); // Indicates it is 'fake'.
-      // Bond t' to a subface if it exists.
-      tspivot(neightet, worksh);
-      if (worksh.sh != dummysh) {
-        sesymself(worksh);
-        tsbond(faketet, worksh);
-      } 
-      // We bond t and t' together. So we're able to find t' and remove it.
-      bond(faketet, neightet);
-      // 'neightet' may become uninfected due to the bond().
-      infect(neightet);
-      frontlink->add(&faketet);
-    } else {
-      frontlink->add(&casingtet);
+  searchtet.tet = (tetrahedron *) NULL;
+  subfaces->traversalinit();
+  subloop.sh = shellfacetraverse(subfaces);
+  while (subloop.sh != (shellface *) NULL) {
+    if (!insertsubface(&subloop, &searchtet)) {
+      if (b->verbose > 1) {
+        printf("    Queuing subface (%d, %d, %d).\n", pointmark(sorg(subloop)),
+               pointmark(sdest(subloop)), pointmark(sapex(subloop)));
+      }
+      sinfect(subloop);
+      missingshqueue->push(&subloop);
     }
+    subloop.sh = shellfacetraverse(subfaces);
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// delaunizevertices()    Create a DT of a set of vertices.                  //
+// constrainedfacets()    Recover subfaces in a Delaunay tetrahedralization. //
+//                                                                           //
+// This routine creates a CDT by incrementally updating a DT D into a CDT T. //
+// The process of recovering facets can be imagined by "merging" the surface //
+// mesh F into D. At the beginning, F and D are completely seperated.  Some  //
+// faces of them are matching some are not because they are crossed by some  //
+// tetrahedra of D. The non-matching subfaces will be forced to appear in T  //
+// by locally retetrahedralizing the regions where F and D are intersecting. //
 //                                                                           //
-// The routine constructs a Delaunay tetrahedralization of a set of vertices //
-// by the incrmental-flip algorithm. 'floorptlist' and 'ceilptlist' form the //
-// set of vertices.  Any vertex of 'ceilptlist' is not coplanar with all     //
-// verrices of 'floorptlist', i.e., the initial DT can be quickly setup.     //
-// 'newtetlink' returns all tetrahedra of the DT.                            //
+// When a subface s of F is found missing in D, probably some other subfaces //
+// near to s are missing too.  The set of adjoining coplanar missing faces   //
+// forms a missing region R (R may not simply connected).                    //
 //                                                                           //
-// The tetrahedra of the DT are created directly in the pool 'tetrahedrons', //
-// i.e., no auxiliary data structure and memory are required.  The trick is  //
-// at the time they're created, there are no connections between them to the //
-// other tetrahedra in the pool. You can imagine there is an ioslated island //
-// in the whole DT.                                                          //
+// There are two possibilities can result a mssing region R: (1) Some edges  //
+// of D cross R; (2) No edge of D crosses R, but some faces of D spans R, ie,//
+// D is locally degenerate at R. In case (1), D is modified so that it resp- //
+// ects R (done by a cavity retetrahedralization algorithm).  In case (2), F //
+// is modified so that the set of subfaces of R matches faces in D (done by  //
+// a face rearrangment algorithm).                                           //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-delaunizevertices(list* floorptlist, list* ceilptlist, link* newtetlink,
-                  int* worklist)
+void tetgenmesh::constrainedfacets()
 {
-  queue *flipqueue;
-  link *ptlink, *hulllink;
-  triface starttet, neightet;
-  triface newtet, bakhulltet;
-  point pa, pb, pc, pd;
-  point ptloop;
-  enum insertsiteresult success;
-  REAL ori;
-  long bakhullsize;
+  queue *missingshqueue, *flipque;
+  list *missingshlist, *equatptlist;
+  list *boundedgelist, *crossedgelist, *crosstetlist;
+  list *crossshlist, *belowfacelist, *abovefacelist;
+  list *horizptlist, *belowptlist, *aboveptlist;
+  list *frontlist, *misfrontlist, *newtetlist;
+  triface searchtet, worktet;
+  face subloop, worksh;
+  int *worklist;
   int i;
 
-  // Initialize 'ptlink'.
-  ptlink = new link(sizeof(point), NULL, 256);
-  // Initialize 'hulllink' used in inserthullsite().
-  hulllink = new link(sizeof(triface), NULL, 256);
-  // Initialize flipqueue;
-  flipqueue = new queue(sizeof(badface));
-  // The incremental-flip routines are reused. Backup global variables.
-  decode(dummytet[0], bakhulltet);
-  bakhullsize = hullsize;
-  // Decrease the debug level.
-  b->verbose--;
-
-  // Create an initial tetrahedralization containing only one tetrahedron
-  //   formed by a (floor) subface and a (ceil) point.
-  pa = * (point *)(* floorptlist)[0];
-  pb = * (point *)(* floorptlist)[1];
-  pc = * (point *)(* floorptlist)[2];
-  pd = * (point *)(* ceilptlist)[0];
-  // Adjust the orientation.
-  ori = orient3d(pa, pb, pc, pd);
-  assert(ori != 0.0);
-  if (ori > 0) {
-    ptloop = pa; pa = pb; pb = ptloop;
-  }
-  // Create the tetrahedron with corners pa, pb, pc and pd.
-  maketetrahedron(&newtet);
-  setorg(newtet, pa);
-  setdest(newtet, pb);
-  setapex(newtet, pc);
-  setoppo(newtet, pd);
-  // Bond to 'dummytet' for point location.
-  dummytet[0] = encode(newtet);
-  // At init, all faces of this tet are hull faces.
-  hullsize = 4;
-
-  // Put the rest of points into 'ptlink'.
-  for (i = 3; i < floorptlist->len(); i++) {
-    ptlink->add((point *)(* floorptlist)[i]);
-  }
-  for (i = 1; i < ceilptlist->len(); i++) {
-    ptlink->add((point *)(* ceilptlist)[i]);
-  }
-
-  // Insert the rest of points of 'ptlink' into D.
-  for (i = 0; i < ptlink->len(); i++) {
-    ptloop = * (point *) ptlink->getnitem(i + 1);
-    // Try to insert the point first.
-    starttet.tet = dummytet; // Don't use locate().
-    success = insertsite(ptloop, &starttet, false, flipqueue);
-    assert(success != DUPLICATEPOINT);
-    if (success == OUTSIDEPOINT) {
-      // Point locates outside the convex hull. Mount it.
-      inserthullsite(ptloop, &starttet, flipqueue, hulllink, worklist);
-    }
-    // Call flip algorithm to recover Delaunayness.
-    flip(flipqueue, NULL, false, false, false);
-  }
-
-  // Have created the D. Gather the all new tetrahedra of D.
-  decode(dummytet[0], starttet);
-  infect(starttet);
-  newtetlink->add(&starttet);
-  for (i = 0; i < newtetlink->len(); i++) {
-    starttet = * (triface *) newtetlink->getnitem(i + 1);
-    for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
-      sym(starttet, neightet);
-      if ((neightet.tet != dummytet) && !infected(neightet)) {
-        infect(neightet);
-        newtetlink->add(&neightet);
-      }
-    }
-  }
-  // Uninfect them.
-  for (i = 0; i < newtetlink->len(); i++) {
-    starttet = * (triface *) newtetlink->getnitem(i + 1);
-    assert(infected(starttet));
-    uninfect(starttet);
+  if (!b->quiet) {
+    printf("Constraining facets.\n");
   }
 
-  // Restore global variables.
-  dummytet[0] = encode(bakhulltet);
-  hullsize = bakhullsize;
-  // Increase the debug level.
-  b->verbose++;
-
-  delete hulllink;
-  delete ptlink;
-  delete flipqueue;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// identifyfronts()    Identify faces of a cavity in a DT.                   //
-//                                                                           //
-// 'frontlink' is a list of faces bounded the cavity C.  The tetrahedra of D //
-// are saved in 'newtetlink'.  This routine idnetifies each face of C in D.  //
-// 'newfrontlink' saves the identified fronts in D corresponding to those of //
-// 'frontlink'. Fronts saved in 'missceillist' are missing from D.           //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-void tetgenmesh::
-identifyfronts(link* frontlink, link* newtetlink, link* newfrontlink,
-               list* missceillist)
-{
-  triface front, starttet, spintet;
-  face checksh;
-  point pa, pb, pc;
-  enum locateresult loc;
-  enum finddirectionresult col;
-  int hitbdry;
-  int i;
+  // Initialize queues.
+  missingshqueue = new queue(sizeof(face));
+  flipque = new queue(sizeof(badface));
+  // Initialize the working lists.
+  missingshlist = new list(sizeof(face), NULL);
+  boundedgelist = new list(sizeof(face), NULL);
+  crossedgelist = new list(sizeof(triface), NULL);
+  equatptlist = new list("point *");
+  crossshlist = new list(sizeof(face), NULL);
+  crosstetlist = new list(sizeof(triface), NULL);
+  belowfacelist = new list(sizeof(triface), NULL);
+  abovefacelist = new list(sizeof(triface), NULL);
+  horizptlist = new list("point *");
+  belowptlist = new list("point *");
+  aboveptlist = new list("point *");
+  frontlist = new list(sizeof(triface), NULL);
+  misfrontlist = new list(sizeof(triface), NULL);
+  newtetlist = new list(sizeof(triface), NULL);
+  // Initialize the array for marking vertices.
+  worklist = new int[points->items + 1];
+  for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
 
-  // Get a new tet for starting the search in D.
-  recenttet = * (triface *) newtetlink->getnitem(1);
+  // Compute a mapping from points to tetrahedra for fast searching.
+  makepoint2tetmap();
   
-  // Identify the cavity faces in D.
-  for (i = 0; i < frontlink->len(); i++) {
-    // Get a cavity face f.
-    front = * (triface *) frontlink->getnitem(i + 1);
-    pa = org(front);
-    pb = dest(front);
-    pc = apex(front);
-    if (b->verbose > 2) {
-      printf("    Identifying front (%d, %d, %d).\n", pointmark(pa),
-             pointmark(pb), pointmark(pc));
-    }
-    // Search for a tetrahedron containing vertex pa.
-    starttet = recenttet;
-    loc = preciselocate(pa, &starttet);
-    assert(loc == ONVERTEX);
-    // Search for a tetrahedron containing edge (pa, pb).
-    col = finddirection(&starttet, pb);
-    if (col == RIGHTCOLLINEAR) {
-      // pb is just the destination.
-    } else if (col == LEFTCOLLINEAR) {
-      enext2self(starttet);
-      esymself(starttet);
-    } else if (col == TOPCOLLINEAR) {
-      fnextself(starttet);
-      enext2self(starttet);
-      esymself(starttet);
-    }
-    if (dest(starttet) != pb) {
-      // edge (pa, pb) doesn't exist. Front is missing.
-      if (b->verbose > 2) {
-        printf("    Edge (%d, %d, %d) not exists.\n", pointmark(pa),
-               pointmark(pb), pointmark(pc));
-      }
-      // Get the tet inside the cavity C.
-      symself(front);
-      assert((front.tet != dummytet) && infected(front));
-      // Put it into 'missceillist'.
-      missceillist->append(&front);
+  // Match subfaces in D, queue all missing subfaces.
+  insertallsubfaces(missingshqueue);
+
+  // Recover all missing subfaces.
+  while (!missingshqueue->empty()) {
+    // Get a queued face s.
+    subloop = * (face *) missingshqueue->pop();
+    // s may have been deleted in a face rearrangment operation.
+    if (isdead(&subloop)) continue;
+    // s may have been recovered in a previous missing region.
+    if (!sinfected(subloop)) continue;
+    // s may match a face in D now due to previous transformations.
+    if (insertsubface(&subloop, &searchtet)) {
+      suninfect(subloop);
       continue;
     }
-    // Search for a tetrahedron containing face (pa, pb, pc).
-    spintet = starttet;
-    hitbdry = 0;
-    do {
-      if (apex(spintet) == pc) {
-        // Find. The edge direction of 'spintet' may be reversed because of
-        //   the hitting of boundary. Check it.
-        if (org(spintet) != pa) {
-          esymself(spintet);
-        }
-        starttet = spintet;
-        break;
+    if (b->verbose > 1) {
+      printf("    Recover subface (%d, %d, %d).\n", pointmark(sorg(subloop)),
+             pointmark(sdest(subloop)), pointmark(sapex(subloop)));
+    }
+    // Form the missing region R containing s.
+    formmissingregion(&subloop, missingshlist, equatptlist, worklist);
+    // Is R crossing by any tetrahedron?
+    if (scoutcrossingedge(missingshlist, boundedgelist, crossedgelist,
+                          worklist)) {
+      // Form the cavity C containing R.
+      formcavity(missingshlist, crossedgelist, equatptlist, crossshlist,
+                 crosstetlist, belowfacelist, abovefacelist, horizptlist,
+                 belowptlist, aboveptlist, missingshqueue, worklist);
+      // Recover the above part of C.
+      delaunizecavity(crossshlist, abovefacelist, aboveptlist, horizptlist,
+                      frontlist, misfrontlist, newtetlist, crosstetlist,
+                      missingshqueue, flipque);
+      // Inverse the direction of subfaces in R.
+      for (i = 0; i < crossshlist->len(); i++) {
+        worksh = * (face *)(* crossshlist)[i];
+        sesymself(worksh);
+        * (face *)(* crossshlist)[i] = worksh;
+      }
+      // Recover the below part of C.
+      delaunizecavity(crossshlist, belowfacelist, belowptlist, horizptlist,
+                      frontlist, misfrontlist, newtetlist, crosstetlist,
+                      missingshqueue, flipque);
+      // Delete tetrahedra in C.
+      for (i = 0; i < crosstetlist->len(); i++) {
+        worktet = * (triface *)(* crosstetlist)[i];
+        tetrahedrondealloc(worktet.tet);
       }
-      if (!fnextself(spintet)) {
-        hitbdry ++;
-        if (hitbdry < 2) {
-          esym(starttet, spintet);
-          if (!fnextself(spintet)) {
-            hitbdry ++;
-          }
+      // There may have some un-recovered subfaces of R. Put them back into
+      //   queue. Otherwise, they will be missing on the boundary.
+      for (i = 0; i < missingshlist->len(); i++) {
+        worksh = * (face *)(* missingshlist)[i];
+        if (sinfected(worksh)) {
+          // An unrecovered subface, put it back into queue.
+          missingshqueue->push(&worksh);
         }
       }
-      if (apex(spintet) == apex(starttet)) break;
-    } while (hitbdry < 2);
-    if (apex(starttet) != pc) {
-      // Face (pa, pb, pc) doesn't exist.
-      if (b->verbose > 2) {
-        printf("    Face (%d, %d, %d) not exists.\n", pointmark(pa),
-               pointmark(pb), pointmark(pc));
-      }
-      // Get the tet inside the cavity C.
-      symself(front);
-      assert((front.tet != dummytet) && infected(front));
-      // Put it into 'missceillist'.
-      missceillist->append(&front);
-      continue;
+      crossshlist->clear();
+      belowfacelist->clear();
+      abovefacelist->clear();
+      horizptlist->clear();
+      belowptlist->clear();
+      aboveptlist->clear();
+      crosstetlist->clear();
+    } else {
+      // No. Rearrange subfaces of F conforming to that of D in R. It can
+      //   happen when the facet has non-coplanar vertices.
+      rearrangesubfaces(missingshlist, boundedgelist, equatptlist, worklist);
     }
-    // Save the handle for the next searching.
-    recenttet = starttet;
-    // Front is identified. Save the newfront.
-    newfrontlink->add(&starttet);
+    // Clear all working lists.
+    missingshlist->clear();
+    boundedgelist->clear();
+    crossedgelist->clear();
+    equatptlist->clear();
   }
 
-  if (missceillist->len() > 0) {
-    // Fail to classify all fronts. Delete the new tets.
-    for (i = 0; i < newtetlink->len(); i++) {
-      starttet = * (triface *) newtetlink->getnitem(i + 1);
-      tetrahedrondealloc(starttet.tet);
-    }
-    newtetlink->clear();
-    newfrontlink->clear();
+  // Subfaces have been merged into D.
+  checksubfaces = 1;
+
+  if (b->verbose > 0) {
+    printf("  The biggest cavity: %d faces, %d vertices\n", maxcavfaces,
+           maxcavverts);
+    printf("  Enlarged %d times\n", expcavcount);
   }
+
+  delete missingshqueue;
+  delete flipque;
+  delete missingshlist;
+  delete boundedgelist;
+  delete crossedgelist;
+  delete equatptlist;
+  delete crossshlist;
+  delete crosstetlist;
+  delete belowfacelist;
+  delete abovefacelist;
+  delete horizptlist;
+  delete belowptlist;
+  delete aboveptlist;
+  delete frontlist;
+  delete misfrontlist;
+  delete newtetlist;
+  delete [] worklist;
 }
 
+//
+// End of facet recovery routines
+//
+
+//
+// Begin of carving out holes and concavities routines
+//
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// classifynewtets()    Classify new tets of D to be "inside" ot "outside".  //
-//                                                                           //
-// 'frontlink' is a list of faces bounded the cavity C.  The tetrahedra of D //
-// are saved in 'newtetlink'. 'newfrontlink' is the list of identified faces //
-// in D corresponding to 'frontlink'.                                        //
+// infecthull()    Virally infect all of the tetrahedra of the convex hull   //
+//                 that are not protected by subfaces.  Where there are      //
+//                 subfaces, set boundary markers as appropriate.            //
 //                                                                           //
-// For each identified face f, do the following: (1) Identify the inside and //
-// outside of f and mark (infect) the outside tet (if it exists) for removal.//
-// (2) Insert an auxilary subface s at f. s is simultaneously referenced by  //
-// several tets that hold f: t1 - the tet not in D, t2 - the tet inside C,   //
-// and t3 - the tet outside C (if it exists).  However s only points to t1 ( //
-// i.e., the tet not in D).  It servers the link to bond t1 and t2 together  //
-// later. If f is a subface, it is inserted directly. Otherwise, create and  //
-// insert a 'fake' subface at f. It will be removed later.                   //
+// Memorypool 'viri' is used to return all the infected tetrahedra.          //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-classifynewtets(link* frontlink, link* newtetlink, link* newfrontlink)
+void tetgenmesh::infecthull(memorypool *viri)
 {
-  triface front, newfront, neightet;
-  face checksh;
-  point pa, pb, pc, pd;
-  REAL ori;
-  int i;
+  triface tetloop, tsymtet;
+  tetrahedron **deadtet;
+  face hullface;
+  // point horg, hdest, hapex;
 
-  assert(frontlink->len() == newfrontlink->len());
-  for (i = 0; i < frontlink->len(); i++) {
-    // Get a cavity face f.
-    front = * (triface *) frontlink->getnitem(i + 1);
-    // Let f face toward insde of the cavity. Since f is a face of tet
-    //   adjacent to C. Hence choose the CW direction of f. 
-    adjustedgering(front, CW);
-    pa = org(front);
-    pb = dest(front);
-    pc = apex(front);
-    // Get the correspond f in D.
-    newfront = * (triface *) newfrontlink->getnitem(i + 1);
-    // newfront may not the inside tet. Adjust it to be the inside one.
-    pd = oppo(newfront);
-    ori = orient3d(pa, pb, pc, pd);
-    assert(ori != 0.0);
-    if (ori > 0.0) {
-      symself(newfront);
-      assert(newfront.tet != dummytet);
-    }
-    // Insert an auxilary subface s at the place.
-    // Is there already a subface? 
-    tspivot(front, checksh);
-    if (checksh.sh == dummysh) {
-      // No. Create a 'fake' subface. It has no vertices.
-      makeshellface(subfaces, &checksh);
-      // Bond s and front (t1) together.
-      tsbond(front, checksh);
-    }
-    // Bond s to newfront (t2) but not vice versa.
-    sesymself(checksh);
-    newfront.tet[8 + newfront.loc] = (tetrahedron) sencode(checksh);
-    // Does the neighbor (t3) of newfront exists?
-    sym(newfront, neightet);
-    if (neightet.tet != dummytet) {
-      // Bond s to neightet (t3) but not vice versa.
-      sesymself(checksh);
-      neightet.tet[8 + neightet.loc] = (tetrahedron) sencode(checksh);
-      // Mark it to be "outside".
-      infect(neightet);
+  if (b->verbose > 0) {
+    printf("  Marking concavities for elimination.\n");
+  }
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    // Is this tetrahedron on the hull?
+    for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
+      sym(tetloop, tsymtet);
+      if (tsymtet.tet == dummytet) {
+        // Is the tetrahedron protected by a subface?
+        tspivot(tetloop, hullface);
+        if (hullface.sh == dummysh) {
+          // The tetrahedron is not protected; infect it.
+          if (!infected(tetloop)) {
+            infect(tetloop);
+            deadtet = (tetrahedron **) viri->alloc();
+            *deadtet = tetloop.tet;
+            break;  // Go and get next tet.
+          }
+        } else {
+          // The tetrahedron is protected; set boundary markers if appropriate.
+          if (shellmark(hullface) == 0) {
+            setshellmark(hullface, 1);
+            /*
+            horg = sorg(hullface);
+            hdest = sdest(hullface);
+            hapex = sapex(hullface);
+            if (pointmark(horg) == 0) {
+              setpointmark(horg, 1);
+            }
+            if (pointmark(hdest) == 0) {
+              setpointmark(hdest, 1);
+            }
+            if (pointmark(hapex) == 0) {
+              setpointmark(hapex, 1);
+            }
+            */
+          }
+        }
+      }
     }
+    tetloop.tet = tetrahedrontraverse();
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// carvecavity()    Remove redundant (outside) tetrahedra from DT.           //
-//                                                                           //
-// All faces of the cavity C have been identified and protected by subfaces  //
-// (may be faked) in DT. It's time to remove the outside tetrahedra and fill //
-// the remaining (inside) tetrahedra into the CDT.                           //
+// plague()    Spread the virus from all infected tets to any neighbors not  //
+//             protected by subfaces.                                        //
 //                                                                           //
-// Notice that the "outside" tets may not only the tets on the convex hull   //
-// but also tets inside the D - there is a "hole" in D. Since we have marked //
-// all outside tets during identifycavity(). The hole tets are poped up and  //
-// are removed too.                                                          //
+// This routine identifies all the tetrahedra that will die, and marks them  //
+// as infected.  They are marked to ensure that each tetrahedron is added to //
+// the virus pool only once, so the procedure will terminate. 'viri' returns //
+// all infected tetrahedra which are outside the domian.                     //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::carvecavity(link* newtetlink, list* newtetlist)
+void tetgenmesh::plague(memorypool *viri)
 {
-  triface starttet, neightet, front;
-  face checksh, frontsh;
-  point pointptr;
+  tetrahedron **virusloop;
+  tetrahedron **deadtet;
+  triface testtet, neighbor;
+  face neighsh, testseg;
+  face spinsh, casingin, casingout;
+  int firstdadsub;
   int i;
 
-  newtetlist->clear();
-  // Some outside tets have been infected. Save them in 'newtetlist'.
-  for (i = 0; i < newtetlink->len(); i++) {
-    starttet = * (triface *) newtetlink->getnitem(i + 1);
-    if (infected(starttet)) {
-      newtetlist->append(&starttet);
-    }
-  }
-  // Find and infect the rest of "outside" tetrahedra.
-  for (i = 0; i < newtetlist->len(); i++) {
-    starttet = * (triface *)(* newtetlist)[i];
-    assert(infected(starttet));
-    for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
-      sym(starttet, neightet);
-      // Is neighbor exists and uninfected?
-      if ((neightet.tet != dummytet) && !infected(neightet)) {
-        // Yes. Is it protected by a subface?
-        tspivot(starttet, checksh);
-        if (checksh.sh == dummysh) {
-          // No. It's an outside tet. Infect and save it.
-          infect(neightet);
-          newtetlist->append(&neightet);
-        }
-      }
-    }
-  }
-  // Now remove the outside (and hole) tets.
-  for (i = 0; i < newtetlink->len(); i++) {
-    starttet = * (triface *) newtetlink->getnitem(i + 1);
-    if (infected(starttet)) {
-      // starttet is an "outside" tet.
-      for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
-        // Is there a subface f?
-        tspivot(starttet, checksh);
-        if (checksh.sh != dummysh) {
-          sym(starttet, neightet);
-          // neightet must be an "inside" tet.
-          assert(!infected(neightet));
-          // Detach starttet from neightet.
-          dissolve(neightet);
-        }
-      }
-      // Dealloc the tet.
-      tetrahedrondealloc(starttet.tet);
-      // Remove the tet from newtetlink.
-      newtetlink->del(i + 1);
-      i--;
-    }
+  if (b->verbose > 0) {
+    printf("  Marking neighbors of marked tetrahedra.\n");
   }
-  // Clear the newtetlist for returning the inside tets.
-  newtetlist->clear();
-
-  // Now fill the inside tets into C. Remove fake subfaces and tets too.
-  for (i = 0; i < newtetlink->len(); i++) {
-    starttet = * (triface *) newtetlink->getnitem(i + 1);
-    // Fill it into C.
-    for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
-      // Is there a subface f?
-      tspivot(starttet, checksh);
-      if (checksh.sh != dummysh) {
-        // Yes. Find the tet holds f.
-        sesym(checksh, frontsh);
-        stpivot(frontsh, front);
-        assert((front.tet != dummytet) && !infected(front));
-        // Either front or f may be fake, and can be both.
-        if (sorg(checksh) == (point) NULL) {
-          // Detach the fake subface from front and starttet.
-          tsdissolve(front);
-          tsdissolve(starttet);
-          // Delete the fake subface.
-          shellfacedealloc(subfaces, checksh.sh);
-        } else {
-          // Bond starttet to f.
-          tsbond(starttet, checksh);
+  firstdadsub = 0;
+  // Loop through all the infected tetrahedra, spreading the virus to
+  //   their neighbors, then to their neighbors' neighbors.
+  viri->traversalinit();
+  virusloop = (tetrahedron **) viri->traverse();
+  while (virusloop != (tetrahedron **) NULL) {
+    testtet.tet = *virusloop;
+    // Temporarily uninfect this tetrahedron, not necessary.
+    uninfect(testtet);
+    // Check each of the tetrahedron's four neighbors.
+    for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) {
+      // Find the neighbor.
+      sym(testtet, neighbor);
+      // Check for a shell between the tetrahedron and its neighbor.
+      tspivot(testtet, neighsh);
+      // Check if the neighbor is nonexistent or already infected.
+      if ((neighbor.tet == dummytet) || infected(neighbor)) {
+        if (neighsh.sh != dummysh) {
+          // There is a subface separating the tetrahedron from its neighbor,
+          //   but both tetrahedra are dying, so the subface dies too.
+          // Before deallocte this subface, dissolve the connections between
+          //   other subfaces, subsegments and tetrahedra.
+          neighsh.shver = 0;
+          if (!firstdadsub) {
+            firstdadsub = 1; // Report the problem once.
+            if (!b->quiet) {
+              printf("Warning:  Detecting an open face (%d, %d, %d).\n",
+                     pointmark(sorg(neighsh)), pointmark(sdest(neighsh)),
+                     pointmark(sapex(neighsh)));
+            }
+          }
+          // For keep the same enext() direction.
+          findedge(&testtet, sorg(neighsh), sdest(neighsh));
+          for (i = 0; i < 3; i++) {
+            sspivot(neighsh, testseg);
+            if (testseg.sh != dummysh) {
+              // A subsegment is found at this side, dissolve this subface
+              //   from the face link of this subsegment.
+              testseg.shver = 0;
+              spinsh = neighsh;
+              if (sorg(spinsh) != sorg(testseg)) {
+                sesymself(spinsh);
+              }
+              spivot(spinsh, casingout);
+              if (casingout.sh == spinsh.sh) {
+                // This is a trivial face link, only 'neighsh' itself,
+                //   the subsegment at this side is also died.
+                shellfacedealloc(subsegs, testseg.sh);
+              } else {
+                spinsh = casingout;
+                do {
+                  casingin = spinsh;
+                  spivotself(spinsh);
+                } while (spinsh.sh != neighsh.sh);
+                // Set the link casingin->casingout.
+                sbond1(casingin, casingout);
+                // Bond the subsegment anyway.
+                ssbond(casingin, testseg);
+              }
+            }
+            senextself(neighsh);
+            enextself(testtet);
+          }
+          if (neighbor.tet != dummytet) {
+            // Make sure the subface doesn't get deallocated again later
+            //   when the infected neighbor is visited.
+            tsdissolve(neighbor);
+          }
+          // This subface has been separated.
+          if (in->mesh_dim > 2) {
+            shellfacedealloc(subfaces, neighsh.sh);
+          } else {
+            // Dimension is 2. keep it for output.
+            // Dissolve tets at both sides of this subface.
+            stdissolve(neighsh);
+            sesymself(neighsh);
+            stdissolve(neighsh);
+          }
         }
-        if (oppo(front) == (point) NULL) {
-          // Detach the fake tet from this side. 
-          if (!isdead(&frontsh)) {
-            stdissolve(frontsh);
+      } else {                   // The neighbor exists and is not infected.
+        if (neighsh.sh == dummysh) {
+          // There is no subface protecting the neighbor, infect it.
+          infect(neighbor);
+          // Ensure that the neighbor's neighbors will be infected.
+          deadtet = (tetrahedron **) viri->alloc();
+          *deadtet = neighbor.tet;
+        } else {               // The neighbor is protected by a subface.
+          // Remove this tetrahedron from the subface.
+          stdissolve(neighsh);
+          // The subface becomes a boundary.  Set markers accordingly.
+          if (shellmark(neighsh) == 0) {
+            setshellmark(neighsh, 1);
           }
-          // Dealloc the fake tet.
-          tetrahedrondealloc(front.tet);
-          // This side becomes a hull. let 'dummytet' bond to it.
-          dummytet[0] = encode(starttet);
-        } else {
-          // Bond front and starttet, also dissove the old bond in them.
-          bond(starttet, front);
         }
       }
     }
-    // Add it to the return list.
-    starttet.loc = 0;
-    newtetlist->append(&starttet);
-    // Let the corners of starttet point to it for point searching.
-    pointptr = org(starttet);
-    setpoint2tet(pointptr, encode(starttet));
-    pointptr = dest(starttet);
-    setpoint2tet(pointptr, encode(starttet));
-    pointptr = apex(starttet);
-    setpoint2tet(pointptr, encode(starttet));
-    pointptr = oppo(starttet);
-    setpoint2tet(pointptr, encode(starttet));
+    // Remark the tetrahedron as infected, so it doesn't get added to the
+    //   virus pool again.
+    infect(testtet);
+    virusloop = (tetrahedron **) viri->traverse();
   }
-  // The cavity has been re-tetrahedralized.
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// delaunizecavity()    Triangulate a cavity by delaunizing its vertices.    //
-//                                                                           //
-// The cavity C is bounded by a set of triangles in 'floorlist' (a list of   //
-// coplanar subfaces) and 'ceillist' (a list of tetrahedral faces lie above  //
-// the subfaces). 'floorptlist' and 'ceilptlist' are vertices of 'floorlist' //
-// and 'ceillist', respectively.  They form the set of vertices of C.        //
+// regionplague()    Spread regional attributes and/or volume constraints    //
+//                   (from a .poly file) throughout the mesh.                //
 //                                                                           //
-// The algorithm is simply desribed as follows: first form a Delaunay tetra- //
-// hedralization D from the set of vertices of C; then mark each tetrahedron //
-// of D to be "inside" and "outside"; finally, remove all tetrahedra marked  //
-// as "outside".                                                             //
+// This procedure operates in two phases.  The first phase spreads an attri- //
+// bute and/or a volume constraint through a (facet-bounded) region.  The    //
+// second phase uninfects all infected tetrahedra, returning them to normal. //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 void tetgenmesh::
-delaunizecavity(list* floorlist, list* ceillist, list* floorptlist,
-                list* ceilptlist, list* newtetlist, list* missceillist,
-                int* worklist)
+regionplague(memorypool *regionviri, REAL attribute, REAL volume)
 {
-  link *frontlink, *newtetlink, *newfrontlink;
+  tetrahedron **virusloop;
+  tetrahedron **regiontet;
+  triface testtet, neighbor;
+  face neighsh;
 
   if (b->verbose > 1) {
-    printf("    Delaunizing cavity (%d floors, %d ceilings, %d vertices).\n",
-           floorlist->len(), ceillist->len(), floorptlist->len() +
-           ceilptlist->len());
-  }
-
-  // Save the size of the largest cavity.
-  if ((floorlist->len() + ceillist->len()) > maxcavfaces) {
-    maxcavfaces = floorlist->len() + ceillist->len();
-  }
-  if (floorptlist->len() + ceilptlist->len() > maxcavverts) {
-    maxcavverts = floorptlist->len() + ceilptlist->len();
+    printf("  Marking neighbors of marked tetrahedra.\n");
   }
-
-  frontlink = new link(sizeof(triface), NULL, 256);
-  newtetlink = new link(sizeof(triface), NULL, 256);
-  newfrontlink = new link(sizeof(triface), NULL, 256);
-
-  // Initialize the cavity C.
-  initializecavity(floorlist, ceillist, frontlink);
-  // Form the D of the vertices of C.
-  delaunizevertices(floorptlist, ceilptlist, newtetlink, worklist);  
-  // Identify faces of C in D.
-  identifyfronts(frontlink, newtetlink, newfrontlink, missceillist);
-  // Is there missing fronts in D?
-  if (missceillist->len() == 0) {
-    // No! Classify "inside" and "outside" tets in D.
-    classifynewtets(frontlink, newtetlink, newfrontlink);
-    // Remove the redundant tets in D and fill the rest to C.
-    carvecavity(newtetlink, newtetlist);
+  // Loop through all the infected tetrahedra, spreading the attribute
+  //   and/or volume constraint to their neighbors, then to their neighbors'
+  //   neighbors.
+  regionviri->traversalinit();
+  virusloop = (tetrahedron **) regionviri->traverse();
+  while (virusloop != (tetrahedron **) NULL) {
+    testtet.tet = *virusloop;
+    // Temporarily uninfect this tetrahedron, not necessary.
+    uninfect(testtet);
+    if (b->regionattrib) {
+      // Set an attribute.
+      setelemattribute(testtet.tet, in->numberoftetrahedronattributes,
+                       attribute);
+    }
+    if (b->varvolume) {
+      // Set a volume constraint.
+      setvolumebound(testtet.tet, volume);
+    }
+    // Check each of the tetrahedron's four neighbors.
+    for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) {
+      // Find the neighbor.
+      sym(testtet, neighbor);
+      // Check for a subface between the tetrahedron and its neighbor.
+      tspivot(testtet, neighsh);
+      // Make sure the neighbor exists, is not already infected, and
+      //   isn't protected by a subface, or is protected by a nonsolid
+      //   subface.
+      if ((neighbor.tet != dummytet) && !infected(neighbor)
+          && (neighsh.sh == dummysh)) {
+        // Infect the neighbor.
+        infect(neighbor);
+        // Ensure that the neighbor's neighbors will be infected.
+        regiontet = (tetrahedron **) regionviri->alloc();
+        *regiontet = neighbor.tet;
+      }
+    }
+    // Remark the tetrahedron as infected, so it doesn't get added to the
+    //   virus pool again.
+    infect(testtet);
+    virusloop = (tetrahedron **) regionviri->traverse();
   }
 
-  delete frontlink;
-  delete newtetlink;
-  delete newfrontlink;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// formmissingregion()    Form the missing region.                           //
-//                                                                           //
-// 'missingsh' is a missing subface.  Start from it we can form the missing  //
-// region R. Remember that all missing subfaces have been infected.  Other   //
-// subfaces of R can be found by checking the neighbors of 'missingsh', and  //
-// the neighbors of the neighbors, and so on. Stop checking further if       //
-// either a segment or an uninfected subface is poped up.                    //
-//                                                                           //
-// 'missingshlist' returns subfaces of R, and these subfaces are oriented in //
-// the same direction. 'equatptlist' returns vertices of R, and each vertex  //
-// of R is marked with '1' (in 'worklist').                                  //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-void tetgenmesh::
-formmissingregion(face* missingsh, list* missingshlist, list* equatptlist,
-                  int* worklist)
-{
-  face neighsh, worksh, workseg;
-  point workpt[3];
-  int idx, i, j;
-
-  // Add 'missingsh' into 'missingshlist'.
-  missingshlist->append(missingsh);
-  // Save and mark its three vertices.
-  workpt[0] = sorg(*missingsh);
-  workpt[1] = sdest(*missingsh);
-  workpt[2] = sapex(*missingsh);
-  for (i = 0; i < 3; i++) {
-    idx = pointmark(workpt[i]) - in->firstnumber;
-    worklist[idx] = 1;
-    equatptlist->append(&workpt[i]);
+  // Uninfect all tetrahedra.
+  if (b->verbose > 1) {
+    printf("  Unmarking marked tetrahedra.\n");
   }
-  // Temporarily uninfect it (avoid to save it again).
-  suninfect(*missingsh);
-  
-  // Find the other missing subfaces.
-  for (i = 0; i < missingshlist->len(); i++) {
-    // Get a missing subface.
-    worksh = * (face *)(* missingshlist)[i];
-    // Check three neighbors of this face.
-    for (j = 0; j < 3; j++) {
-      sspivot(worksh, workseg);
-      if (workseg.sh == dummysh) {
-        spivot(worksh, neighsh);
-        if (sinfected(neighsh)) {
-          // Find a missing subface, adjust the face orientation.
-          if (sorg(neighsh) != sdest(worksh)) {
-            sesymself(neighsh);
-          }
-          if (b->verbose > 2) {
-            printf("    Add missing subface (%d, %d, %d).\n", 
-                   pointmark(sorg(neighsh)), pointmark(sdest(neighsh)),
-                   pointmark(sapex(neighsh)));
-          }
-          missingshlist->append(&neighsh);
-          // Save and mark its apex.
-          workpt[0] = sapex(neighsh);
-          idx = pointmark(workpt[0]) - in->firstnumber;
-          // Has workpt[0] been added?
-          if (worklist[idx] == 0) {
-            worklist[idx] = 1;
-            equatptlist->append(&workpt[0]);
-          }
-          // Temporarily uninfect it (avoid to save it again).
-          suninfect(neighsh);
-        } 
-      } 
-      senextself(worksh);
-    }
+  regionviri->traversalinit();
+  virusloop = (tetrahedron **) regionviri->traverse();
+  while (virusloop != (tetrahedron **) NULL) {
+    testtet.tet = *virusloop;
+    uninfect(testtet);
+    virusloop = (tetrahedron **) regionviri->traverse();
   }
-
-  // R has been formed. Infect missing subfaces again.
-  for (i = 0; i < missingshlist->len(); i++) {
-    worksh = * (face *)(* missingshlist)[i];
-    sinfect(worksh);
-  } 
+  // Empty the virus pool.
+  regionviri->restart();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// scoutcrossingedge()    Search an edge crossing the missing region.        //
-//                                                                           //
-// 'missingshlist' forms the missing region R. This routine searches for an  //
-// edge crossing R.  It first forms a 'boundedgelist' consisting of the      //
-// boundary edges of R. Such edges are existing in CDT.  A crossing edge is  //
-// found by rotating faces around one of the boundary edges. It is possible  //
-// there is no edge crosses R (e.g. R has a degenerate point set).           //
-//                                                                           //
-// If find a croosing edge, return TRUE, 'crossedgelist' contains this edge. //
-// Otherwise, return FALSE.                                                  //
+// removeholetets()    Remove tetrahedra which are outside the domain.       //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::
-scoutcrossingedge(list* missingshlist, list* boundedgelist,
-                  list* crossedgelist, int* worklist)
-{
-  triface starttet, spintet, worktet;
-  face startsh, neighsh, worksh, workseg;
-  point torg, tdest, tapex;
-  point workpt[3], pa, pb, pc;
-  enum finddirectionresult collinear;
-  REAL ori1, ori2;
-  bool crossflag;
-  int hitbdry;
-  int i, j, k;
-
-  // Form the 'boundedgelist'. Loop through 'missingshlist', check each
-  //   edge of these subfaces. If an edge is a segment or the neighbor
-  //   subface is uninfected, add it to 'boundedgelist'.
-  for (i = 0; i < missingshlist->len(); i++) {
-    worksh = * (face *)(* missingshlist)[i];
-    for (j = 0; j < 3; j++) {
-      sspivot(worksh, workseg);
-      if (workseg.sh == dummysh) {
-        spivot(worksh, neighsh);
-        if (!sinfected(neighsh)) {
-          boundedgelist->append(&worksh);
-        }
-      } else {
-        boundedgelist->append(&worksh);
-      }
-      senextself(worksh);
-    }
-  }
-
-  crossflag = false;
-  // Find a crossing edge. It is possible there is no such edge. We need to
-  //   loop through all edges of 'boundedgelist' for sure we don't miss any.
-  for (i = 0; i < boundedgelist->len() && !crossflag; i++) {
-    startsh = * (face *)(* boundedgelist)[i];
-    // 'startsh' (abc) holds an existing edge of the DT, find it.
-    torg = sorg(startsh);
-    tdest = sdest(startsh);
-    tapex = sapex(startsh);
-    getsearchtet(torg, tdest, &starttet, &workpt[0]);
-    collinear = finddirection(&starttet, workpt[0]);
-    if (collinear == LEFTCOLLINEAR) {
-      enext2self(starttet);
-      esymself(starttet);
-    } else if (collinear == TOPCOLLINEAR) {
-      fnextself(starttet);
-      enext2self(starttet);
-      esymself(starttet);
-    }
-    assert(dest(starttet) == workpt[0]);
-    // Now starttet holds edge ab. Find is edge de crossing R.
-    spintet = starttet;
-    hitbdry = 0;
-    do {
-      if (fnextself(spintet)) {
-        // splittet = abde. Check if de crosses abc.
-        workpt[1] = apex(spintet);  // workpt[1] = d.
-        workpt[2] = oppo(spintet);  // workpt[2] = e.
-        j = pointmark(workpt[1]) - in->firstnumber;
-        k = pointmark(workpt[2]) - in->firstnumber;
-        if (worklist[j] == 1) {
-          ori1 = 0.0; // d is a vertex of the missing region.
-        } else {
-          // Get the orientation of d wrt. abc.
-          ori1 = orient3d(torg, tdest, tapex, workpt[1]);
-        }
-        if (worklist[k] == 1) {
-          ori2 = 0.0; // e is a vertex of the missing region.
-        } else {
-          // Get the orientation of e wrt. abc.
-          ori2 = orient3d(torg, tdest, tapex, workpt[2]);
-        }
-        // Only do check if d and e locate on different sides of abc.
-        if (ori1 * ori2 < 0.0) {
-          // Check if de crosses any subface of R.
-          for (j = 0; j < missingshlist->len(); j++) {
-            worksh = * (face *)(* missingshlist)[j];
-            pa = sorg(worksh);
-            pb = sdest(worksh);
-            pc = sapex(worksh);
-            crossflag = (tri_tri_inter(pa, pb, pc, workpt[0], workpt[1],
-                                       workpt[2]) == INTERSECT);
-            if (crossflag) {
-              // Find a crossing edge. We're done.
-              worktet = spintet;
-              adjustedgering(worktet, CCW);
-              enextfnextself(worktet);
-              enextself(worktet);
-              // Add this edge (worktet) into 'crossedgelist'.
-              crossedgelist->append(&worktet);
-              break;
-            }
-          }
-          if (crossflag) break;
-        }
-        if (apex(spintet) == apex(starttet)) break;
+void tetgenmesh::removeholetets(memorypool* viri)
+{
+  tetrahedron **virusloop;
+  triface testtet, neighbor;
+  point checkpt;
+  int *tetspernodelist;
+  int i, j;
+
+  if (b->verbose > 0) {
+    printf("  Deleting marked tetrahedra.\n");
+  }
+
+  // Create and initialize 'tetspernodelist'.
+  tetspernodelist = new int[points->items + 1];
+  for (i = 0; i < points->items + 1; i++) tetspernodelist[i] = 0;
+  
+  // Loop the tetrahedra list, counter the number of tets sharing each node.
+  tetrahedrons->traversalinit();
+  testtet.tet = tetrahedrontraverse();
+  while (testtet.tet != (tetrahedron *) NULL) {
+    // Increment the number of sharing tets for each endpoint.
+    for (i = 0; i < 4; i++) {
+      j = pointmark((point) testtet.tet[4 + i]);
+      tetspernodelist[j]++;
+    }
+    testtet.tet = tetrahedrontraverse();
+  }
+
+  viri->traversalinit();
+  virusloop = (tetrahedron **) viri->traverse();
+  while (virusloop != (tetrahedron **) NULL) {
+    testtet.tet = *virusloop;
+    // Record changes in the number of boundary faces, and disconnect
+    //   dead tetrahedra from their neighbors.
+    for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) {
+      sym(testtet, neighbor);
+      if (neighbor.tet == dummytet) {
+        // There is no neighboring tetrahedron on this face, so this face
+        //   is a boundary face.  This tetrahedron is being deleted, so this
+        //   boundary face is deleted.
+        hullsize--;
       } else {
-        hitbdry++;
-        // It is only possible to hit boundary once.
-        if (hitbdry < 2) {
-          esym(starttet, spintet);
+        // Disconnect the tetrahedron from its neighbor.
+        dissolve(neighbor);
+        // There is a neighboring tetrahedron on this face, so this face
+        //   becomes a boundary face when this tetrahedron is deleted.
+        hullsize++;
+      }
+    }
+    // Check the four corners of this tet if they're isolated.
+    for (i = 0; i < 4; i++) {
+      checkpt = (point) testtet.tet[4 + i];
+      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)) { 
+          setpointtype(checkpt, UNUSEDVERTEX);
+          unuverts++;
         }
       }
-    } while (hitbdry < 2);
+    }
+    // Return the dead tetrahedron to the pool of tetrahedra.
+    tetrahedrondealloc(testtet.tet);
+    virusloop = (tetrahedron **) viri->traverse();
   }
-
-  return crossflag;
+  
+  delete [] tetspernodelist;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// rearrangesubfaces()    Rearrange the set of subfaces of a missing region  //
-//                        so that they conform to the faces of DT.           //
-//                                                                           //
-// The missing region formed by subfaces of 'missingshlist' contains a set   //
-// of degenerate vertices, hence the set of subfaces don't match the set of  //
-// faces in DT.  Instead of forcing them to present in DT, we re-arrange the //
-// connection of them so that the new subfaces conform to the faces of DT.   //
-// 'boundedgelist' is a set of boundary edges of the region, these edges(may //
-// be subsegments) must exist in DT.                                         //
+// assignregionattribs()    Assign each tetrahedron a region number.         //
 //                                                                           //
-// On completion, we have created and inserted a set of new subfaces which   //
-// conform to faces of DT. The set of old subfaces in 'missingshlist' are    //
-// deleted. The region vertices in 'equatptlist' are unmarked.               //
+// This routine is called when '-AA' switch is specified.  Every tetrahedron //
+// of a (bounded) region will get a integer number to that region.  Default, //
+// regions are numbered as 1, 2, 3, etc. However, if a number has already    //
+// been used (set by user in the region section in .poly or .smesh), it is   //
+// skipped and the next available number will be used.                       //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-rearrangesubfaces(list* missingshlist, list* boundedgelist, list* equatptlist,
-                  int* worklist)
+void tetgenmesh::assignregionattribs()
 {
-  link *boundedgelink;
-  link *newshlink;
-  triface starttet, spintet, neightet, worktet;
-  face shloop, newsh, neighsh, spinsh, worksh;
-  face workseg, casingin, casingout;
-  point torg, tdest, workpt;
-  point spt1, spt2, spt3;
-  point liftpoint;
-  enum finddirectionresult collinear;
-  enum shestype shtype;
-  REAL area;
-  bool matchflag, finishflag;
-  int shmark, idx, hitbdry;
-  int i, j;
+  list *regionnumlist;
+  list *regiontetlist;
+  triface tetloop, regiontet, neightet;
+  face checksh;
+  bool flag;
+  int regionnum, num;
+  int attridx, count;
+  int i;
 
-  // Initialize the boundary edge link.
-  boundedgelink = new link(sizeof(face), NULL, 256);
-  // Initialize the new subface link.
-  newshlink = new link(sizeof(face), NULL, 256);
-  // Remember the type (skinny or not) of replaced subfaces.  They should
-  //   all have the same type since there is no segment inside the region.
-  worksh = * (face *)(* missingshlist)[0];
-  shtype = shelltype(worksh);
-  // The following loop is only for checking purpose.
-  for (i = 1; i < missingshlist->len(); i++) {
-    worksh = * (face *)(* missingshlist)[i];
-    assert(shelltype(worksh) == shtype);
+  if (b->verbose > 0) {
+    printf("  Assign region numbers.\n");
   }
 
-  // Create an initial boundary link.
-  for (i = 0; i < boundedgelist->len(); i++) {
-    shloop = * (face *)(* boundedgelist)[i];
-    if (i == 0) {
-      if (b->quality && varconstraint) {
-        // area will be copied to all new created subfaces.
-        area = areabound(shloop);
+  regionnumlist = new list(sizeof(int), NULL, 256);
+  regiontetlist = new list(sizeof(triface), NULL, 1024);
+  attridx = in->numberoftetrahedronattributes;  
+
+  // Loop through all tets. Infect tets which already have a region number,
+  //   and save the used numbers in 'regionnumlist'.
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    if (!infected(tetloop)) {
+      regionnum = (int) elemattribute(tetloop.tet, attridx);
+      if (regionnum != 0.0) {
+        // Found a numbered region tet.
+        infect(tetloop);
+        regiontetlist->append(&tetloop);
+        // Found and infect all tets in this region.
+        for (i = 0; i < regiontetlist->len(); i++) {
+          regiontet = * (triface *)(* regiontetlist)[i];
+          for (regiontet.loc = 0; regiontet.loc < 4; regiontet.loc++) {
+            // Is there a boundary face?
+            tspivot(regiontet, checksh);
+            if (checksh.sh == dummysh) {
+              sym(regiontet, neightet);
+              if ((neightet.tet != dummytet) && !infected(neightet)) {
+#ifdef SELF_CHECK
+                // neightet should have the same region number. Check it.
+                num = (int) elemattribute(neightet.tet, attridx);
+                assert(num == regionnum);
+#endif
+                infect(neightet);
+                regiontetlist->append(&neightet);
+              }
+            }
+          }
+        }
+        // Add regionnum to list if it is not exist.
+        flag = false;
+        for (i = 0; i < regionnumlist->len() && !flag; i++) {
+          num = * (int *)(* regionnumlist)[i];
+          flag = (num == regionnum);
+        }
+        if (!flag) regionnumlist->append(&regionnum);
+        // Clear list for the next region.
+        regiontetlist->clear();
       }
-      // 'shmark' will be set to all new created subfaces.
-      shmark = shellmark(shloop);
-      // Get the liftpoint of this facet for later checking.
-      liftpoint = getliftpoint(shmark);
-    }
-    sspivot(shloop, workseg);
-    if (workseg.sh == dummysh) {
-      // This edge is an interior edge.
-      spivot(shloop, neighsh);
-      boundedgelink->add(&neighsh);
-    } else {
-      // This side has a segment, the edge exists. 
-      boundedgelink->add(&shloop);
     }
+    tetloop.tet = tetrahedrontraverse();
+  }
+  
+  if (b->verbose > 0) {
+    printf("  %d user-specified regions.\n", regionnumlist->len());
   }
 
-  // Each edge ab of boundedgelink will be finished by finding a vertex c
-  //   which is a vertex of the missing region, such that:
-  //   (1) abc is inside the missing region, i.e., abc intersects at least
-  //       one of missing subfaces (saved in missingshlist);
-  //   (2) abc is not intersect with any previously created new subfaces
-  //       in the missing region (saved in newshlink).
-  //   After abc is created, it will be inserted into both the surface mesh
-  //   and the DT. The boundedgelink will be updated, ab is removed, bc and
-  //   ca will be added if they are open.
-
-  while (boundedgelink->len() > 0) {
-    // Remove an edge (ab) from the link.
-    shloop = * (face *) boundedgelink->del(1);
-    // 'workseg' indicates it is a segment or not.
-    sspivot(shloop, workseg);
-    torg = sorg(shloop);  // torg = a;
-    tdest = sdest(shloop);  // tdest = b; 
-    // Find a tetrahedron containing ab.
-    getsearchtet(torg, tdest, &starttet, &workpt);
-    collinear = finddirection(&starttet, workpt);
-    if (collinear == LEFTCOLLINEAR) {
-      enext2self(starttet);
-      esymself(starttet);
-    } else if (collinear == TOPCOLLINEAR) {
-      fnextself(starttet);
-      enext2self(starttet);
-      esymself(starttet);
-    }
-    assert(dest(starttet) == workpt);
-    // Checking faces around ab until a valid face is found.
-    matchflag = false;
-    spintet = starttet;
-    hitbdry = 0;
-    do {
-      workpt = apex(spintet);
-      idx = pointmark(workpt) - in->firstnumber;
-      if (worklist[idx] == 1) {
-        // (trog, tdest, workpt) is on the facet. Check if it satisfies (1).
-        finishflag = false;
-        for (i = 0; i < missingshlist->len(); i++) {
-          worksh = * (face *)(* missingshlist)[i];
-          spt1 = sorg(worksh);
-          spt2 = sdest(worksh);
-          spt3 = sapex(worksh);
-          // Does bc intersect the face?
-          if (tri_edge_cop_inter(spt1, spt2, spt3, tdest, workpt, liftpoint)
-              == INTERSECT) {
-            finishflag = true; break;
-          }
-          // Does ca intersect the face?
-          if (tri_edge_cop_inter(spt1, spt2, spt3, workpt, torg, liftpoint)
-              == INTERSECT) {
-            finishflag = true; break;
-          }
-          // Does c inside the face?
-          if (tri_vert_cop_inter(spt1, spt2, spt3, workpt, liftpoint)
-              == INTERSECT) {
-            finishflag = true; break;
-          }
+  // Now loop the tets again. Assign region numbers to uninfected tets.
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  regionnum = 1;  // Start region number.
+  count = 0;
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    if (!infected(tetloop)) {
+      // An unassigned region tet.
+      count++;
+      do {
+        flag = false;
+        // Check if the region number has been used.
+        for (i = 0; i < regionnumlist->len() && !flag; i++) {
+          num = * (int *)(* regionnumlist)[i];
+          flag = (num == regionnum);
         }
-        if (finishflag) {
-          // Satisfying (1). Check if it satisfies (2).
-          matchflag = true;
-          for (i = 0; i < newshlink->len() && matchflag; i++) {
-            worksh = * (face *) newshlink->getnitem(i + 1);
-            spt1 = sorg(worksh);
-            spt2 = sdest(worksh);
-            spt3 = sapex(worksh);
-            // Does bc intersect the face?
-            if (tri_edge_cop_inter(spt1, spt2, spt3, tdest, workpt, liftpoint)
-                == INTERSECT) {
-              matchflag = false; break;
-            }
-            // Does ca intersect the face?
-            if (tri_edge_cop_inter(spt1, spt2, spt3, workpt, torg, liftpoint)
-                == INTERSECT) {
-              matchflag = false; break;
-            }
-            // Does c inside the face?
-            if (tri_vert_cop_inter(spt1, spt2, spt3, workpt, liftpoint)
-                == INTERSECT) {
-              matchflag = false; break;
+        if (flag) regionnum++;
+      } while (flag);      
+      setelemattribute(tetloop.tet, attridx, (REAL) regionnum);
+      infect(tetloop);
+      regiontetlist->append(&tetloop);
+      // Found and infect all tets in this region.
+      for (i = 0; i < regiontetlist->len(); i++) {
+        regiontet = * (triface *)(* regiontetlist)[i];
+        for (regiontet.loc = 0; regiontet.loc < 4; regiontet.loc++) {
+          // Is there a boundary face?
+          tspivot(regiontet, checksh);
+          if (checksh.sh == dummysh) {
+            sym(regiontet, neightet);
+            if ((neightet.tet != dummytet) && !infected(neightet)) {
+#ifdef SELF_CHECK
+              // neightet should have not been assigned yet. Check it.
+              num = (int) elemattribute(neightet.tet, attridx);
+              assert(num == 0);
+#endif
+              setelemattribute(neightet.tet, attridx, (REAL) regionnum);
+              infect(neightet);
+              regiontetlist->append(&neightet);
             }
           }
         }
-        if (matchflag == true) {
-          // Satisfying both (1) and (2). Find abc.
-          break;
-        }
       }
-      if (!fnextself(spintet)) {
-        hitbdry ++;
-        if (hitbdry < 2) {
-          esym(starttet, spintet);
-          if (!fnextself(spintet)) {
-            hitbdry ++;
-          }
+      regiontetlist->clear();
+      regionnum++; // The next region number.
+    }
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  // Uninfect all tets.
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+#ifdef SELF_CHECK
+    assert(infected(tetloop));
+#endif
+    uninfect(tetloop);
+    tetloop.tet = tetrahedrontraverse();
+  }
+  
+  if (b->verbose > 0) {
+    printf("  %d regions are numbered.\n", count);
+  }
+
+  delete regionnumlist;
+  delete regiontetlist;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// carveholes()    Find the holes and infect them.  Find the volume          //
+//                 constraints and infect them.  Infect the convex hull.     //
+//                 Spread the infection and kill tetrahedra.  Spread the     //
+//                 volume constraints.                                       //
+//                                                                           //
+// This routine mainly calls other routines to carry out all these functions.//
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::carveholes()
+{
+  memorypool *holeviri, *regionviri;
+  tetrahedron *tptr, **holetet, **regiontet;
+  triface searchtet, *holetets, *regiontets;
+  enum locateresult intersect;
+  int i;
+
+  if (!b->quiet) {
+    printf("Removing unwanted tetrahedra.\n");
+    if (b->verbose && (in->numberofholes > 0)) {
+      printf("  Marking holes for elimination.\n");
+    }
+  }
+
+  // Initialize a pool of viri to be used for holes, concavities.
+  holeviri = new memorypool(sizeof(tetrahedron *), 1024, POINTER, 0);
+  // Mark as infected any unprotected tetrahedra on the boundary.
+  infecthull(holeviri);
+
+  if (in->numberofholes > 0) {
+    // Allocate storage for the tetrahedra in which hole points fall.
+    holetets = (triface *) new triface[in->numberofholes];
+    // Infect each tetrahedron in which a hole lies.
+    for (i = 0; i < 3 * in->numberofholes; i += 3) {
+      // Ignore holes that aren't within the bounds of the mesh.
+      if ((in->holelist[i] >= xmin) && (in->holelist[i] <= xmax)
+          && (in->holelist[i + 1] >= ymin)
+          && (in->holelist[i + 1] <= ymax)
+          && (in->holelist[i + 2] >= zmin)
+          && (in->holelist[i + 2] <= zmax)) {
+        searchtet.tet = dummytet;
+        // Find a tetrahedron that contains the hole.
+        intersect = locate(&in->holelist[i], &searchtet);
+        if ((intersect != OUTSIDE) && (!infected(searchtet))) {
+          // Record the tetrahedron for processing carve hole.
+          holetets[i / 3] = searchtet;
         }
       }
-    } while (hitbdry < 2 && apex(spintet) != apex(starttet));
-    assert(matchflag == true);
-    tspivot(spintet, neighsh);
-    if (neighsh.sh != dummysh) {
-      printf("Error:  Invalid PLC.\n");
-      printf("  Facet #%d and facet #%d overlap each other.\n",
-             shellmark(neighsh), shellmark(shloop));
-      printf("  It might be caused by a facet is defined more than once.\n");
-      printf("  Hint:  Use -d switch to find all overlapping facets.\n");
-      exit(1);
     }
-    // The side of 'spintet' is at which a new subface will be attached.
-    adjustedgering(spintet, CCW);
-    // Create the new subface.
-    makeshellface(subfaces, &newsh);
-    setsorg(newsh, org(spintet));
-    setsdest(newsh, dest(spintet));
-    setsapex(newsh, apex(spintet));
-    if (b->quality && varconstraint) {
-      // Copy the areabound into the new subface.
-      setareabound(newsh, area);
+    // Infect the hole tetrahedron.  This is done by marking the tet as
+    //   infected and including the tetrahedron in the virus pool.
+    for (i = 0; i < in->numberofholes; i++) {
+      infect(holetets[i]);
+      holetet = (tetrahedron **) holeviri->alloc();
+      *holetet = holetets[i].tet;
     }
-    setshellmark(newsh, shmark);
-    setshelltype(newsh, shtype);  // It may be a skinny subface.
-    // Add newsh into newshlink for intersecting checking.
-    newshlink->add(&newsh);
-    // Insert it into the current mesh.
-    tsbond(spintet, newsh);
-    sym(spintet, neightet);
-    if (neightet.tet != dummytet) {
-      sesym(newsh, neighsh);
-      tsbond(neightet, neighsh);
+    // Free up memory.
+    delete [] holetets;
+  }
+
+  // Mark as infected all tets of the holes and concavities.
+  plague(holeviri);
+  // The virus pool contains all outside tets now.
+
+  // Is -A switch in use.
+  if (b->regionattrib) {
+    // Assign every tetrahedron a regional attribute of zero.
+    tetrahedrons->traversalinit();
+    tptr = tetrahedrontraverse();
+    while (tptr != (tetrahedron *) NULL) {
+      setelemattribute(tptr, in->numberoftetrahedronattributes, 0.0);
+      tptr = tetrahedrontraverse();
     }
-    // Insert it into the surface mesh.
-    sspivot(shloop, workseg);
-    if (workseg.sh == dummysh) {
-      sbond(shloop, newsh);
-    } else {
-      // There is a subsegment, 'shloop' is the subface which is going to
-      //   die. Insert the 'newsh' at the place of 'shloop' into its face
-      //   link, so as to dettach 'shloop'.   The original connection is:
-      //   -> casingin -> shloop -> casingout ->, it will be changed with:
-      //   -> casingin ->  newsh -> casingout ->.  Pay attention to the
-      //   case when this subsegment is dangling in the mesh, i.e., 'shloop'
-      //   is bonded to itself.
-      spivot(shloop, casingout);
-      if (shloop.sh != casingout.sh) {
-        // 'shloop' is not bonded to itself.
-        spinsh = casingout;
-        do {
-          casingin = spinsh;
-          spivotself(spinsh);
-        } while (sapex(spinsh) != sapex(shloop));
-        assert(casingin.sh != shloop.sh); 
-        // Bond casingin -> newsh -> casingout.
-        sbond1(casingin, newsh);
-        sbond1(newsh, casingout);
+  }
+
+  if (in->numberofregions > 0) {
+    if (!b->quiet) {
+      if (b->regionattrib) {
+        if (b->varvolume) {
+          printf("Spreading regional attributes and volume constraints.\n");
+        } else {
+          printf("Spreading regional attributes.\n");
+        }
       } else {
-        // Bond newsh -> newsh.
-        sbond(newsh, newsh);
+        printf("Spreading regional volume constraints.\n");
       }
-      // Bond the segment.
-      ssbond(newsh, workseg);
     }
-    // Check other two sides of this new subface.  If a side is not bonded
-    //   to any edge in the link, it will be added to the link.
-    for (i = 0; i < 2; i++) {
-      if (i == 0) {
-        senext(newsh, worksh);
-      } else {
-        senext2(newsh, worksh);
+    // Allocate storage for the tetrahedra in which region points fall.
+    regiontets = (triface *) new triface[in->numberofregions];
+    // Find the starting tetrahedron for each region.
+    for (i = 0; i < in->numberofregions; i++) {
+      regiontets[i].tet = dummytet;
+      // Ignore region points that aren't within the bounds of the mesh.
+      if ((in->regionlist[5 * i] >= xmin)
+           && (in->regionlist[5 * i] <= xmax)
+           && (in->regionlist[5 * i + 1] >= ymin)
+           && (in->regionlist[5 * i + 1] <= ymax)
+           && (in->regionlist[5 * i + 2] >= zmin)
+           && (in->regionlist[5 * i + 2] <= zmax)) {
+        searchtet.tet = dummytet;
+        // Find a tetrahedron that contains the region point.
+        intersect = locate(&in->regionlist[5 * i], &searchtet);
+        if ((intersect != OUTSIDE) && (!infected(searchtet))) {
+          // Record the tetrahedron for processing after the
+          //   holes have been carved.
+          regiontets[i] = searchtet;
+        }
       }
-      torg = sorg(worksh);
-      tdest = sdest(worksh);
-      finishflag = false;
-      for (j = 0; j < boundedgelink->len() && !finishflag; j++) {
-        neighsh = * (face *) boundedgelink->getnitem(j + 1);
-        if ((sorg(neighsh) == torg && sdest(neighsh) == tdest) ||
-            (sorg(neighsh) == tdest && sdest(neighsh) == torg)) {
-          // Find a boundary edge.  Bond them and exit the loop.
-          sspivot(neighsh, workseg);
-          if (workseg.sh == dummysh) {
-            sbond(neighsh, worksh);
-          } else {
-            // There is a subsegment, 'neighsh' is the subface which is
-            //   going to die. Do the same as above for 'worksh'.
-            spivot(neighsh, casingout);
-            if (neighsh.sh != casingout.sh) {
-              // 'neighsh' is not bonded to itself.
+    }
+    // Initialize a pool to be used for regional attrs, and/or regional
+    //   volume constraints.
+    regionviri = new memorypool(sizeof(tetrahedron *), 1024, POINTER, 0);
+    // Find and set all regions.
+    for (i = 0; i < in->numberofregions; i++) {
+      if (regiontets[i].tet != dummytet) {
+        // Make sure the tetrahedron under consideration still exists.
+        //   It may have been eaten by the virus.
+        if (!isdead(&(regiontets[i]))) {
+          // Put one tetrahedron in the virus pool.
+          infect(regiontets[i]);
+          regiontet = (tetrahedron **) regionviri->alloc();
+          *regiontet = regiontets[i].tet;
+          // Apply one region's attribute and/or volume constraint.
+          regionplague(regionviri, in->regionlist[5 * i + 3],
+                       in->regionlist[5 * i + 4]);
+          // The virus pool should be empty now.
+        }
+      }
+    }
+    // Free up memory.
+    delete [] regiontets;
+    delete regionviri;
+  }
+
+  // Now acutually remove the outside and hole tets.
+  removeholetets(holeviri);
+  // The mesh is nonconvex now.
+  nonconvex = 1;
+
+  if (b->regionattrib) {
+    if (b->regionattrib > 1) {
+      // -AA switch. Assign each tet a region number (> 0).
+      assignregionattribs();
+    }
+    // Note the fact that each tetrahedron has an additional attribute.
+    in->numberoftetrahedronattributes++;
+  }
+
+  // Free up memory.
+  delete holeviri;
+}
+
+//
+// End of carving out holes and concavities routines
+//
+
+//
+// Begin of boundary Steiner points removing routines
+//
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// replacepolygonsubs()    Substitute the subfaces of a polygon.             //
+//                                                                           //
+// 'oldshlist' (T_old) contains the old subfaces of P.  It will be replaced  //
+// by 'newshlist' (T_new) of new subfaces. Each boundary edge of P is bonded //
+// to 'dummysh' in T_new.                                                    //
+//                                                                           //
+// Notice that Not every boundary edge of T_new is able to bond to a subface,//
+// e.g., when it is a segment recovered by removing a Steiner point in it.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::replacepolygonsubs(list* oldshlist, list* newshlist)
+{
+  face newsh, oldsh, spinsh;
+  face casingout, casingin;
+  face checkseg;
+  point pa, pb;
+  int i, j, k, l;
+
+  for (i = 0; i < newshlist->len(); i++) {
+    // Get a new subface s.
+    newsh = * (face *)(* newshlist)[i];
+    // Check the three edges of s.
+    for (k = 0; k < 3; k++) {
+      spivot(newsh, casingout);
+      // Is it a boundary edge?
+      if (casingout.sh == dummysh) {
+        // Find the old subface s_o having the same edge as s.
+        pa = sorg(newsh);
+        pb = sdest(newsh); 
+        for (j = 0; j < oldshlist->len(); j++) {
+          oldsh = * (face *)(* oldshlist)[j];
+	  for (l = 0; l < 3; l++) {
+            if (((sorg(oldsh) == pa) && (sdest(oldsh) == pb)) ||
+                ((sorg(oldsh) == pb) && (sdest(oldsh) == pa))) break;
+            senextself(oldsh);
+          }
+          if (l < 3) break;
+        }
+        // Is there a matched edge?
+        if (j < oldshlist->len()) {
+          // Get the neighbor subface s_out.
+          spivot(oldsh, casingout);
+          sspivot(oldsh, checkseg);
+          if (checkseg.sh != dummysh) {
+            // A segment. Insert s into the face ring, ie, s_in -> s -> s_out.
+            if (oldsh.sh != casingout.sh) {
+              // s is not bonded to itself.
               spinsh = casingout;
               do {
                 casingin = spinsh;
                 spivotself(spinsh);
-              } while (sapex(spinsh) != sapex(neighsh));
-              assert(casingin.sh != neighsh.sh); 
-              // Bond casingin -> worksh -> casingout.
-              sbond1(casingin, worksh);
-              sbond1(worksh, casingout);
+              } while (sapex(spinsh) != sapex(oldsh));
+              assert(casingin.sh != oldsh.sh); 
+              // Bond s_in -> s -> s_out (and dissolve s_in -> s_old -> s_out).
+              sbond1(casingin, newsh);
+              sbond1(newsh, casingout);
             } else {
-              // Bond worksh -> worksh.
-              sbond(worksh, worksh);
+              // Bond newsh -> newsh.
+              sbond(newsh, newsh);
             }
             // Bond the segment.
-            ssbond(worksh, workseg);
+            ssbond(newsh, checkseg);
+          } else {
+            // Bond s <-> s_out (and dissolve s_out -> s_old).
+            sbond(newsh, casingout);
+          }
+          // Unbound oldsh to indicate it's neighbor has been replaced.
+          //   It will be used to indentfy the edge in the inverse.
+          sdissolve(oldsh);
+          ssdissolve(oldsh);
+        }
+      }
+      // Go to the next edge of s.
+      senextself(newsh);
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// orientnewsubs()    Orient new subfaces facing to the inside of cavity.    //
+//                                                                           //
+// 'newshlist' contains new subfaces of the cavity C (created by re-triangu- //
+// lation the polygon P). They're not necessary facing to the inside of C.   //
+// 'orientsh', faces to the inside of C, is used to adjust new subfaces. The //
+// normal of the new subfaces is returned in 'norm'.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::orientnewsubs(list* newshlist, face* orientsh, REAL* norm)
+{
+  face *newsh;
+  point pa, pb, pc;
+  REAL ref[3], ori, len;
+  int i;
+
+  // Calculate the normal of 'orientsh'.
+  pa = sorg(*orientsh);
+  pb = sdest(*orientsh);
+  pc = sapex(*orientsh);
+  facenormal(pa, pb, pc, norm, &len);
+  for (i = 0; i < 3; i++) ref[i] = pa[i] + norm[i];
+  for (i = 0; i < 3; i++) norm[i] /= len;
+  
+  // Orient new subfaces. Let the normal above each one.
+  for (i = 0; i < newshlist->len(); i++) {
+    newsh = (face *)(* newshlist)[i];
+    pa = sorg(*newsh);
+    pb = sdest(*newsh);
+    pc = sapex(*newsh);
+    ori = orient3d(pa, pb, pc, ref);
+    assert(ori != 0.0);
+    if (ori > 0.0) {
+      sesymself(*newsh);
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// constrainedflip()    Flip a non-constrained face.                         //
+//                                                                           //
+// 'flipface' f (abc) is a face we want to flip. In addition, if 'front' is  //
+// given (not a NULL), f is a crossface. f may not be flippable if it is one //
+// of the following cases:                                                   //
+//   (1) f has an aux subface attached;                                      //
+//   (2) f is on the convex hull;                                            //
+//   (3) f is not locally Delaunay (f must be recovered by a previous flip,  //
+//       we should keep it, otherwise, we may fall into a flip loop);        //
+//   (4) f is T32 at ab, but abd or abe has an aux subface attached;         //
+//   (5) f is T22 or T44 at ab, but abd, or abe, or abf has an aux subface   //
+//       attached;                                                           //
+//   (6) f is unflipable at ab, and abd, abe, ... are all unflippable due to //
+//       the cases (1) - (5).                                                //
+// If f is a crssface ('front' != NULL) and it is unflipable due to case (3),//
+// (4), (5) and (6). Try to flip the next crossing face of front first.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::constrainedflip(triface* flipface, triface* front,
+  queue* flipque)
+{
+  triface symface, spintet;
+  face checksh;
+  point pa, pb, pc, pd, pe;
+  enum fliptype fc;
+  REAL sign;
+  bool doflip;
+  int ia, ib, ic, id, ie;
+  int i;
+
+  // (1) Is f protected by an (auxilary) subface?
+  tspivot(*flipface, checksh);
+  if (checksh.sh != dummysh) return false;
+  // (2) Is f on the convex hull?
+  sym(*flipface, symface);
+  if (symface.tet == dummytet) return false;
+  // (3) Is f not locally Delaunay?
+  adjustedgering(*flipface, CCW);
+  pa = dest(*flipface);
+  pb = org(*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(pa, pb, pc, pd, pe, ia, ib, ic, id, ie);
+    assert(sign != 0.0);
+  // } else {
+  //   sign = insphere(pa, pb, pc, pd, pe);
+  // }
+  if (sign <= 0.0) {
+    // Get the fliptype of f.
+    checksubfaces = 0; // switch off subface test.
+    fc = categorizeface(*flipface);
+    checksubfaces = 1; // switch on subface test.
+    if (fc == T23) {
+      doflip = true;
+      // Avoid one tet created by the 2-3 flip is nearly degenerate.
+      /* pc = oppo(*flipface);
+      pd = oppo(symface);
+      adjustedgering(*flipface, CCW);
+      for (i = 0; i < 3; i++) {
+        pa = org(*flipface);
+        pb = dest(*flipface);
+        ori = orient3d(pa, pb, pc, pd);
+        if (iscoplanar(pa, pb, pc, pd, ori, b->epsilon)) {
+          doflip = false; break;
+        }
+        enextself(*flipface);
+      } */
+      if (doflip) {
+        flip23(flipface, flipque);
+        return true;
+      }
+    } else if (fc == T32) {
+      // (4) Is abd, or abe protected?
+      doflip = true;
+      spintet = *flipface;
+      for (i = 0; i < 2; i++) {
+        fnextself(spintet);
+        tspivot(spintet, checksh);
+        if (checksh.sh != dummysh) {
+          doflip = false; break; // f is protected. Unflipable.
+        }
+      }
+      if (doflip) {
+        flip32(flipface, flipque);
+        return true;
+      }
+    } else if (fc == T22 || fc == T44) {
+      // (5) Is abd, abe, or abf protected?
+      doflip = true;
+      if (fc == T22) {
+        for (i = 0; i < 2; i++) {
+          spintet = *flipface;
+          if (i == 1) {
+            esymself(spintet);
+          }
+          fnextself(spintet);
+          tspivot(spintet, checksh);
+          if (checksh.sh != dummysh) {
+            doflip = false; break; // f is protected. Unflipable.
+          }
+        }
+      } else if (fc == T44) {
+        spintet = *flipface;
+        for (i = 0; i < 3; i++) {
+          fnextself(spintet);
+          tspivot(spintet, checksh);
+          if (checksh.sh != dummysh) {
+            doflip = false; break; // f is protected. Unflipable.
           }
-          // Remove this boundary edge from the link.
-          boundedgelink->del(j + 1);
-          finishflag = true;
         }
       }
-      if (!finishflag) {
-        // It's a new boundary edge, add it to link.
-        boundedgelink->add(&worksh);
+      if (doflip) {
+        flip22(flipface, flipque);
+        return true;
+      }
+    } else if (fc == UNFLIPABLE) {
+      // Is f a crossface?
+      if (front != (triface *) NULL) {
+        // (6) Is any obstacle face (abd, or abe, ...) flipable?
+        spintet = *flipface;
+        while (fnextself(spintet)) {
+          if (apex(spintet) == apex(*flipface)) break;
+          // Check if spintet is flipable, no recursive.
+          if (constrainedflip(&spintet, NULL, flipque)) {
+            // One obstacle face has been flipped.
+            return true;
+          }
+          // Unflipable. Go to the next obstacle face.
+          findedge(&spintet, org(*flipface), dest(*flipface));
+        }
       }
     }
   }
 
-  // Deallocate the set of old missing subfaces.
-  for (i = 0; i < missingshlist->len(); i++) {
-    worksh = * (face *)(* missingshlist)[i];
-    shellfacedealloc(subfaces, worksh.sh);
-  }
-  // Unmark region vertices in 'worklist'.
-  for (i = 0; i < equatptlist->len(); i++) {
-    workpt = * (point *)(* equatptlist)[i];
-    idx = pointmark(workpt) - in->firstnumber;
-    worklist[idx] = 0;
+  // f is unflipable. Is f a crossface?
+  if (front != (triface *) NULL) {
+    // Look if there is another crossface.
+    pa = org(*front);
+    pb = dest(*front);
+    pc = apex(*front);
+    // sym(*flipface, symface);
+    // Have we reach the end of abc (We've started from edge ab).
+    if (oppo(symface) != pc) {
+      adjustedgering(symface, CCW);
+      for (i = 0; i < 3; i++) {
+        fnext(symface, spintet);
+        // Is c ahead of this face?
+        sign = orient3d(org(spintet), dest(spintet), apex(spintet), pc);
+        if (sign < 0.0) {
+          if (tritritest(&spintet, pa, pb, pc)) {
+            if (b->verbose > 2) {
+              printf("    Next crossface (%d, %d, %d).\n",
+                     pointmark(org(spintet)), pointmark(dest(spintet)),
+                     pointmark(apex(spintet)));
+            }
+            return constrainedflip(&spintet, front, flipque);
+            // return constrainedflip(&spintet, NULL, flipque);
+          }
+        }
+        enextself(symface);
+      }
+    }
   }
-
-  delete boundedgelink;
-  delete newshlink;
+  return false;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// formcavity()    Form the cavity for recovering missing subfaces.          //
-//                                                                           //
-// The cavity C is bounded by faces of current CDT.  All tetrahedra inside C //
-// will be removed, intead a set of constrained Delaunay tetrahedra will be  //
-// filled in and the missing subfaces are respected.                         //
-//                                                                           //
-// 'missingshlist' contains a set of subfaces forming the missing region R.  //
-// C is formed by first finding all the tetrahedra in CDT that intersect the //
-// relative interior of R; then deleting them from the CDT, this will form C //
-// inside the CDT. At the beginning, 'crossedgelist' contains an edge which  //
-// is crossing R. All tets containing this edge must cross R. Start from it, //
-// other crossing edges can be found incrementally.  The discovered crossing //
-// tets are saved in 'crosstetlist'.                                         //
-//                                                                           //
-// Notice that not all tets in 'crosstetlist' are crossing R. The discovered //
-// tets are connected each other. However, there may be other tets crossing  //
-// R but disjoint with the found tets. Due to this fact we need to check the //
-// 'missingshlist' once more. Only recover those subfaces which are crossed  //
-// by the set of discovered tets, i.e., R may be shrinked to conform the set //
-// of discovered tets. The extra subfaces of R will be recovered later.      //
+// recoverfront()    Recover a missing front by flips.                       //
 //                                                                           //
-// Notice that some previous recovered subfaces may completely included in C.//
-// This can happen when R is very big and these subfaces lie above R and so  //
-// close to it. Such subfaces have to be queued (and sinfected()) to recover //
-// them later. Otherwise, we lost the connection to these subfaces forever.  //
+// 'front' f is missing in D - it was crossed by faces of D. The cross faces //
+// may be flippable, so f can be recovered by flipping them away.            //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-formcavity(list* missingshlist, list* crossedgelist, list* equatptlist,
-           list* crossshlist, list* crosstetlist, list* belowfacelist,
-           list* abovefacelist, list* horizptlist, list* belowptlist,
-           list* aboveptlist, queue* missingshqueue, int* worklist)
+bool tetgenmesh::recoverfront(triface* front, list* newtetlist, queue* flipque)
 {
-  triface starttet, spintet, neightet, worktet;
-  face startsh, neighsh, worksh, workseg;
-  point torg, tdest, tapex, workpt[3];
-  REAL checksign, orgori, destori;
-  bool crossflag, inlistflag;
-  bool belowflag, aboveflag;
-  int idx, share;
-  int i, j, k;
+  triface idfront, starttet, spintet;
+  point pa, pb, pc, pd, ref;
+  enum locateresult loc;
+  enum finddirectionresult col;
+  REAL ori, ori1, ori2, sign;
+  int hitbdry;
+  int i, j;
 
-  // Get a face at horizon.
-  startsh = * (face *)(* missingshlist)[0];
-  torg = sorg(startsh);
-  tdest = sdest(startsh);
-  tapex = sapex(startsh);
+  // Find an existing edge of f in D to start with.
+  for (i = 0; i < 3; i++) {
+    pa = org(*front);
+    pb = dest(*front);
+    // Get a tet for searching.
+    idfront = recenttet;
+    // Make sure the tet is valid (flip32() may kill a tet).
+    if (isdead(&idfront)) {
+      // The tet is dead. Get a live tet in D. !!!
+      for (j = 0; j < newtetlist->len(); j++) {
+        recenttet = * (triface *)(* newtetlist)[j];
+        if (!isdead(&recenttet)) break;
+      }
+      assert(j < newtetlist->len());
+    }
+    loc = preciselocate(pa, &idfront, (long) newtetlist->len());
+    if (loc != ONVERTEX) {
+      // Do a brute-force search in D.
+      for (j = 0; j < newtetlist->len(); j++) {
+        idfront = * (triface *)(* newtetlist)[j];
+        if (isdead(&idfront)) continue;
+        if (findorg(&idfront, pa)) break;
+      }
+      assert(j < newtetlist->len()); // a must belong to one tet.
+    }
+    recenttet = idfront;
+    // Search for a tet having edge ab.
+    col = finddirection(&idfront, pb, (long) newtetlist->len());
+    if (col == BELOWHULL) {
+      // Do a brute-force search in D.
+      for (j = 0; j < newtetlist->len(); j++) {
+        idfront = * (triface *)(* newtetlist)[j];
+        if (isdead(&idfront)) continue;
+        if (findorg(&idfront, pa)) {
+          assert(org(idfront) == pa);
+          if (dest(idfront) == pb) {
+            col = RIGHTCOLLINEAR; break;
+          } else if (apex(idfront) == pb) {
+            col = LEFTCOLLINEAR; break;
+          } else if (oppo(idfront) == pb) {
+            col = TOPCOLLINEAR; break;
+          }
+        }
+      }
+    }
+    if (col == RIGHTCOLLINEAR) {
+      // b is just the destination.
+    } else if (col == LEFTCOLLINEAR) {
+      enext2self(idfront);
+      esymself(idfront);
+    } else if (col == TOPCOLLINEAR) {
+      fnextself(idfront);
+      enext2self(idfront);
+      esymself(idfront);
+    }
+    if (dest(idfront) == pb) break; // Found.
+    // Missing. Go to the next edge of f.
+    enextself(*front);
+  }
+  if (i == 3) {
+    // All three edges of f are missing - unrecoverable.
+    return false;
+  }
 
-  // Collect the set of crossing tetrahedra by rotating crossing edges.
-  for (i = 0; i < crossedgelist->len(); i++) {
-    // Get a tet abcd, ab is a crossing edge.
-    starttet = * (triface *)(* crossedgelist)[i];
-    adjustedgering(starttet, CCW);
-    if (b->verbose > 2) {
-      printf("    Collect tets containing edge (%d, %d).\n",
-             pointmark(org(starttet)), pointmark(dest(starttet)));
+  // Search for a tet having f (abc).
+  pc = apex(*front);
+  spintet = idfront;
+  hitbdry = 0;
+  do {
+    if (apex(spintet) == pc) {
+      // Found abc. Insert an auxilary subface s at idfront.
+      insertauxsubface(front, &spintet);
+      return true;
     }
-    orgori = orient3d(torg, tdest, tapex, org(starttet));
-    destori = orient3d(torg, tdest, tapex, dest(starttet));
-    assert(orgori * destori < 0.0); 
-    spintet = starttet;
-    do {
-      // The face rotation should not meet boundary.
-      fnextself(spintet); 
-      // Check the validity of the PLC.
-      tspivot(spintet, worksh);
-      if (worksh.sh != dummysh) {
-        printf("Error:  Invalid PLC.\n");
-        printf("  Two subfaces (%d, %d, %d) and (%d, %d, %d)\n",
-               pointmark(torg), pointmark(tdest), pointmark(tapex),
-               pointmark(sorg(worksh)), pointmark(sdest(worksh)),
-               pointmark(sapex(worksh)));
-        printf("  are found intersecting each other.\n");
-        printf("  Hint:  Use -d switch to find all intersecting facets.\n");
-        exit(1);
+    if (!fnextself(spintet)) {
+      hitbdry ++;
+      if (hitbdry < 2) {
+        esym(idfront, spintet);
+        if (!fnextself(spintet)) {
+          hitbdry ++;
+        }
       }
-      if (!infected(spintet)) {
-        if (b->verbose > 2) {
-          printf("      Add crossing tet (%d, %d, %d, %d).\n",
-                 pointmark(org(spintet)), pointmark(dest(spintet)),
-                 pointmark(apex(spintet)), pointmark(oppo(spintet)));
+    }
+    if (apex(spintet) == apex(idfront)) break;
+  } while (hitbdry < 2);
+
+  // Search for a crossing face to flip.
+  pd = apex(idfront);
+  assert(pd != pc);
+  // Decide the orientation of d with abc.
+  ori = orient3d(pa, pb, pc, pd);
+  if (ori < 0.0) {
+    // d is above abc. Rotate downwards.
+    esym(idfront, starttet);
+    sign = -1.0;
+  } else if (ori > 0.0) {
+    // d is below abc. Rotate upwards.
+    starttet = idfront;
+    sign = 1.0;
+  } else {
+    assert(ori == 0.0);
+    // d is coplanar with abc. Do abc and abd intersect?
+    ref = oppo(idfront);
+    ori1 = orient3d(pa, pb, ref, pc);
+    ori2 = orient3d(pa, pb, ref, pd);
+    assert(ori1 * ori2 != 0.0);
+    if (ori1 * ori2 > 0) {
+      // abc and abd intersect.  There're two possible intersections: 
+      //   ad and bc, or ac and bd.  Find it out.
+      ori1 = orient3d(pb, pc, ref, pd);
+      ori2 = orient3d(pb, pc, ref, pa);
+      assert(ori1 * ori2 != 0.0);
+      if (ori1 * ori2 > 0) {
+        // ac intersects bd.
+        enextself(idfront); // go to edge bd.
+      } else {
+        // ad intersects bc.
+        enext2self(idfront); // go to edge ad.
+      }
+      adjustedgering(idfront, CCW);
+      fnextself(idfront); // face ade or bce need a 4-to-4 flip.
+      if (b->verbose > 2) {
+        printf("    Get crossface (%d, %d, %d).\n", pointmark(org(idfront)),
+               pointmark(dest(idfront)), pointmark(apex(idfront)));
+      }
+      if (constrainedflip(&idfront, front, flipque)) {
+        // A crossface has been flipped. Continue to recover f.
+        return recoverfront(front, newtetlist, flipque);
+      }
+      // Unable to recover f.
+      return false; // sign = 0.0;
+    } else {
+      // Not intersect. We can go either direction.
+      starttet = idfront;
+      if (fnextself(starttet)) {
+        // Choose to rotate upwards.
+        sign = 1.0;
+      } else {
+        // Hit convex hull. Choose to rotate downwrads.
+        esym(idfront, starttet);
+        sign = -1.0;
+      }
+    }
+  }
+
+  assert(sign != 0.0);
+  if (sign == -1) {
+    // The edge ab has be changed. Reverse it.
+    pa = org(starttet);
+    pb = dest(starttet);
+    // The sign has been reversed as well.
+    sign = -sign;
+  }
+  // Rotate face abd around edge ab. Moreover, we've chosen the rotate
+  //   direction such that no convex hull face will be reach.
+  spintet = starttet;
+  while (fnextself(spintet)) {
+    pd = apex(spintet);
+    assert(pd != pc);
+    // Check if the orientation of d (with abc) has changed.
+    ori = orient3d(pa, pb, pc, pd);
+    if (ori == 0.0) {
+      // abc and abd must coplanar intersect (4-to-4 flip is needed).
+      ref = oppo(spintet);
+      ori1 = orient3d(pb, pc, ref, pd);
+      ori2 = orient3d(pb, pc, ref, pa);
+      assert(ori1 * ori2 != 0.0);
+      if (ori1 * ori2 > 0) {
+        // ac intersects bd.
+        enextself(spintet); // go to edge bd.
+      } else {
+        // ad intersects bc.
+        enext2self(spintet); // go to edge ad.
+      }
+      adjustedgering(spintet, CCW);
+      fnextself(spintet); // face ade or bce need a 4-to-4 flip.
+      if (b->verbose > 2) {
+        printf("    Get crossface (%d, %d, %d).\n", pointmark(org(spintet)),
+               pointmark(dest(spintet)), pointmark(apex(spintet)));
+      }
+      if (constrainedflip(&spintet, front, flipque)) {
+        // A crossface has been flipped. Continue to recover f.
+        return recoverfront(front, newtetlist, flipque);
+      }
+      // Unable to recover f.
+      return false; // sign = 0.0;
+    } else if (ori * sign < 0.0) {
+      // Sign has changed. The face dea or deb must cross abc.
+      adjustedgering(spintet, CCW);
+      enextself(spintet);
+      for (i = 0; i < 2; i++) {
+        // Get the face dea or deb.
+        fnext(spintet, starttet);
+        if (tritritest(&starttet, pa, pb, pc)) {
+          if (b->verbose > 2) {
+            printf("    Get crossface (%d, %d, %d).\n",
+                   pointmark(org(starttet)), pointmark(dest(starttet)),
+                   pointmark(apex(starttet)));
+          }
+          if (constrainedflip(&starttet, front, flipque)) {
+            // A crossface has been flipped. Continue to recover f.
+            return recoverfront(front, newtetlist, flipque);
+          }
         }
-        infect(spintet);
-        crosstetlist->append(&spintet);
+        enextself(spintet);
       }
-      // Check whether other two edges of 'spintet' is a crossing edge.
-      //   It can be quickly checked from the apex of 'spintet', if it is
-      //   not on the facet, then there exists a crossing edge.
-      workpt[0] = apex(spintet);
-      idx = pointmark(workpt[0]) - in->firstnumber;
-      if (worklist[idx] != 1) {
-        // Either edge (dest, apex) or edge (apex, org) crosses.
-        checksign = orient3d(torg, tdest, tapex, workpt[0]);
-        assert(checksign != 0.0);
-        if (checksign * orgori < 0.0) {
-          enext2(spintet, worktet); // edge (apex, org).
-          workpt[1] = org(spintet);
-        } else {
-          assert(checksign * destori < 0.0);
-          enext(spintet, worktet);  // edge (dest, apex).
-          workpt[1] = dest(spintet);
+      // Unable to recover f.
+      return false;
+    }
+  }
+  // Impossible to be here.
+  assert(0);
+  return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// repairflips()    Flip non-Delaunay and non-constrained faces.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::repairflips(queue* flipque)
+{
+  badface *qface;
+  triface flipface, symface, spintet;
+  face checksh;
+  point pa, pb, pc, pd, pe;
+  enum fliptype fc;
+  REAL sign;
+  long flipcount;
+  bool doflip;
+  int ia, ib, ic, id, ie;
+  int i;
+
+  if (b->verbose > 1) {
+    printf("    Repair flip %ld faces.\n", flipque->len());
+  }
+  flipcount = flip23s + flip32s + flip22s + flip44s;
+  // Loop until the queue is empty.
+  while (!flipque->empty()) {
+    qface = (badface *) flipque->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;
+    // (1) Is f protected by an (auxilary) subface?
+    tspivot(flipface, checksh);
+    if (checksh.sh != dummysh) continue;
+    // (2) Is f on the convex hull?
+    sym(flipface, symface);
+    if (symface.tet == dummytet) continue;
+    // For positive orientation that insphere() test requires.
+    adjustedgering(flipface, CW);
+    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(pa, pb, pc, pd, pe, ia, ib, ic, id, ie);
+      assert(sign != 0.0);
+    // } else {
+    //   sign = insphere(pa, pb, pc, pd, pe);
+    // }
+    if (sign > 0.0) {
+      // f is non-lcally Delaunay. Get the fliptype of f.
+      checksubfaces = 0; // switch off subface test.
+      fc = categorizeface(flipface);
+      checksubfaces = 1; // switch on subface test.
+      if (fc == T23) {
+        doflip = true;
+        // Avoid to create a nearly degenerate tet.
+        /* pc = oppo(flipface);
+        pd = oppo(symface);
+        adjustedgering(flipface, CCW);
+        for (i = 0; i < 3; i++) {
+          pa = org(flipface);
+          pb = dest(flipface);
+          ori = orient3d(pa, pb, pc, pd);
+          if (iscoplanar(pa, pb, pc, pd, ori, b->epsilon)) {
+            doflip = false; break;
+          }
+          enextself(flipface);
+        } */
+        if (doflip) {
+          flip23(&flipface, flipque);
         }
-        // 'worktet' represents the crossing edge. Add it into list only
-        //   it doesn't exist in 'crossedgelist'.
-        inlistflag = false;
-        for (j = 0; j < crossedgelist->len() && !inlistflag; j++) {
-          neightet = * (triface *)(* crossedgelist)[j];
-          if (org(neightet) == workpt[0]) {
-            if (dest(neightet) == workpt[1]) inlistflag = true;
-          } else if (org(neightet) == workpt[1]) {
-            if (dest(neightet) == workpt[0]) inlistflag = true;
+      } else if (fc == T32) {
+        // (4) Is abd, or abe protected?
+        doflip = true;
+        spintet = flipface;
+        for (i = 0; i < 2; i++) {
+          fnextself(spintet);
+          tspivot(spintet, checksh);
+          if (checksh.sh != dummysh) {
+            doflip = false; break; // f is protected. Unflipable.
+          }
+        }
+        if (doflip) {
+          flip32(&flipface, flipque);
+        }
+      } else if (fc == T22 || fc == T44) {
+        // (5) Is abd, abe, or abf protected?
+        doflip = true;
+        if (fc == T22) {
+          for (i = 0; i < 2; i++) {
+            spintet = flipface;
+            if (i == 1) {
+              esymself(spintet);
+            }
+            fnextself(spintet);
+            tspivot(spintet, checksh);
+            if (checksh.sh != dummysh) {
+              doflip = false; break; // f is protected. Unflipable.
+            }
           }
+        } else if (fc == T44) {
+          spintet = flipface;
+          for (i = 0; i < 3; i++) {
+            fnextself(spintet);
+            tspivot(spintet, checksh);
+            if (checksh.sh != dummysh) {
+              doflip = false; break; // f is protected. Unflipable.
+            }
+          }
+        }
+        if (doflip) {
+          flip22(&flipface, flipque);
+        }
+      }
+    }
+  }
+  flipcount = flip23s + flip32s + flip22s + flip44s - flipcount;
+  if (b->verbose > 1) {
+    printf("    %ld flips.\n", flipcount);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// constrainedcavity()    Tetrahedralize a cavity by constrained tetrahedra. //
+//                                                                           //
+// The cavity C is bounded by faces F in 'floorlist' and 'ceillist'. 'ptlist'//
+// V is the set of vertices of C.                                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::constrainedcavity(triface* oldtet, list* floorlist,
+  list* ceillist, list* ptlist, list* frontlist, list* misfrontlist,
+  list* newtetlist, queue* flipque)
+{
+  triface misfront, newtet;
+  long facenum;
+  int i;
+
+  if (b->verbose > 1) {
+    printf("    Constrained cavity (%d floors, %d ceilings, %d vertices).\n",
+           floorlist->len(), ceillist->len(), ptlist->len());
+  }
+
+  symbolic = 1;
+  
+  // Initialize the cavity C.
+  initializecavity(floorlist, ceillist, frontlist);
+  // Form the D of the vertices of C.
+  delaunizecavvertices(oldtet, ptlist, NULL, newtetlist, flipque);
+  
+  // Identify faces of C in D.
+  if (!identifyfronts(frontlist, misfrontlist, newtetlist)) {
+    // Some faces are missing.
+    recenttet = * (triface *)(* newtetlist)[0];
+    assert((recenttet.tet != dummytet) && !isdead(&recenttet));
+    // Try to recover missing faces by flips.
+    do {
+      facenum = misfrontlist->len();
+      for (i = 0; i < misfrontlist->len(); i++) {
+        // Get a missing front f.
+        misfront = * (triface *)(* misfrontlist)[i];
+        // Let f face toward the inside of C.
+        adjustedgering(misfront, CW);
+        if (b->verbose > 1) {
+          printf("    Recover face (%d, %d, %d).\n", pointmark(org(misfront)),
+                 pointmark(dest(misfront)), pointmark(apex(misfront)));
         }
-        if (!inlistflag) {
-          crossedgelist->append(&worktet);
+        if (recoverfront(&misfront, newtetlist, flipque)) {
+          // f has been recovered.
+          frontlist->append(&misfront);
+          misfrontlist->del(i, 0); i--;
         }
+        // Flip non-locally non-constrained Delaunay faces.
+        repairflips(flipque);
       }
-    } while (apex(spintet) != apex(starttet));
+      // Have all faces been recovered?
+      if (misfrontlist->len() == 0) break;
+      // No! There are still un-recovered faces. Continue the loop if any
+      //   face has been recovered.
+    } while (misfrontlist->len() < facenum);
+    // Retrieve new tets and purge dead tets in D.
+    retrievenewtets(newtetlist);
+  }
+  
+  symbolic = 0;
+
+  if (misfrontlist->len() == 0) {
+    // All fronts have identified in D. Get the shape of C by removing out
+    //   tets of C. 'misfrontlist' is reused for removing out tets.
+    //   Don't do flip since the new tets may get deleted later.
+    carvecavity(newtetlist, misfrontlist, NULL);
+    // Recover locally Delaunay faces.
+    // flip(flipque, NULL);
+    return true;
+  } else {
+    // Fail to tetrahedralize C.
+    // Remove aux subfaces.
+    detachauxsubfaces(newtetlist);
+    // Remove new tets.
+    for (i = 0; i < newtetlist->len(); i++) {
+      newtet = * (triface *)(* newtetlist)[i];
+      assert(!isdead(&newtet));
+      tetrahedrondealloc(newtet.tet);
+    }
+    newtetlist->clear();
+    // Restore faces of C in frontlist.
+    for (i = 0; i < misfrontlist->len(); i++) {
+      misfront = * (triface *)(* misfrontlist)[i];
+      frontlist->append(&misfront);
+    }
+    return false;
   }
+}
 
-  // Identifying the boundary faces and vertices of C. Sort them into
-  //   'abovefacelist', 'aboveptlist, 'belowfacelist', and 'belowptlist',
-  //    respectively. "above" and "below" are wrt.(torg, tdest, tapex). 
-  for (i = 0; i < crosstetlist->len(); i++) {
-    // Get a tet abcd, ab is the crossing edge.
-    starttet = * (triface *)(* crosstetlist)[i];
-    assert(infected(starttet));
-    adjustedgering(starttet, CCW);
-    // abc and abd are sharing the crossing edge, the two neighbors must
-    //   be crossing tetrahedra too. They can't be boundaries of C.
-    for (j = 0; j < 2; j++) {
-      if (j == 0) {
-        enextfnext(starttet, worktet); // Check bcd.
-      } else {
-        enext2fnext(starttet, worktet); // Check acd. 
-      } 
-      sym(worktet, neightet);
-      // If the neighbor doesn't exist or exists but doesn't be infected,
-      //   it's a boundary face of C, save it.
-      if ((neightet.tet == dummytet) || !infected(neightet)) {
-        workpt[0] = org(worktet);
-        workpt[1] = dest(worktet);
-        workpt[2] = apex(worktet);
-        belowflag = aboveflag = false;
-        share = 0;
-        for (k = 0; k < 3; k++) {
-          idx = pointmark(workpt[k]) - in->firstnumber;
-          if (worklist[idx] == 0) {
-            // It's not a vertices of facet, find which side it lies.
-            checksign = orient3d(torg, tdest, tapex, workpt[k]);
-            assert(checksign != 0.0);
-            if (checksign > 0.0) {
-              // It lies "below" the facet wrt. 'startsh'.
-              worklist[idx] = 2;
-              belowptlist->append(&workpt[k]);
-            } else if (checksign < 0.0) {
-              // It lies "above" the facet wrt. 'startsh'.
-              worklist[idx] = 3;
-              aboveptlist->append(&workpt[k]);
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// expandsteinercavity()    Expand the cavity of a Steiner point.            //
+//                                                                           //
+// Expand the cavity C if there fronts (except fronts having subfaces) which //
+// are either (nearly) coplanar or invisible by the Steiner point.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::expandsteinercavity(point steinpt, REAL eps, list* frontlist,
+  list* oldtetlist)
+{
+  triface front, symfront, newfront, oldfront;
+  face frontsh;
+  point pa, pb, pc;
+  REAL ori;
+  bool expflag, newflag;
+  int i, j;
+
+  do {
+    expflag = false;
+    for (i = 0; i < frontlist->len(); i++) {
+      // Get a front f.
+      front =  * (triface *)(* frontlist)[i];
+      // f can be expanded if it is not a subface.
+      tspivot(front, frontsh);
+      if (frontsh.sh == dummysh) {
+        // Let f face to the inside of C.
+        adjustedgering(front, CW);
+        pa = org(front);
+        pb = dest(front);
+        pc = apex(front);
+        ori = orient3d(pa, pb, pc, steinpt);
+        if (ori != 0.0) {
+          if (iscoplanar(pa, pb, pc, steinpt, ori, eps)) {
+            ori = 0.0; // f is nearly coplanar with p.
+          }
+        }
+        if (ori >= 0.0) {
+          // f is either invisible or coplanar with p.
+          if (b->verbose > 2) {
+            printf("    Remove front (%d, %d, %d).\n", pointmark(pa),
+                   pointmark(pb), pointmark(pc));
+          }
+          frontlist->del(i, 1);
+          expflag = true;
+          break;
+        }
+      }
+    }
+    if (expflag) {
+      assert(!infected(front) && (oppo(front) != NULL));
+      // Expand C at f by including new fronts.
+      adjustedgering(front, CCW);
+      for (i = 0; i < 3; i++) {
+        newflag = true;
+        // Get a new boundary n of the cavity.
+        fnext(front, symfront);
+        tspivot(symfront, frontsh);
+        sym(symfront, newfront);
+        if (frontsh.sh == dummysh) {
+          assert(newfront.tet != dummytet);
+          // Is n a front of the unexp. cavity?
+          if (infected(newfront)) {
+            for (j = 0; j < frontlist->len(); j++) {
+              oldfront = * (triface *)(* frontlist)[j];
+              if ((oldfront.tet == symfront.tet) &&
+                  (oldfront.loc == symfront.loc)) {
+                // n is not a front anymore.
+                if (b->verbose > 2) {
+                  printf("    Remove front (%d, %d, %d).\n",
+                         pointmark(org(oldfront)), pointmark(dest(oldfront)),
+                         pointmark(apex(oldfront)));
+                }
+                frontlist->del(j, 1);
+                newflag = false;
+                break;
+              }
             }
           }
-          if (worklist[idx] == 2) {
-            // This face lies "below" the facet wrt. 'startsh'.
-            belowflag = true;
-          } else if (worklist[idx] == 3) {
-            // This face lies "above" the facet wrt. 'startsh'.
-            aboveflag = true;
+        } else {
+          // n is a subface.
+          if (newfront.tet == dummytet) {
+            sesymself(frontsh);
+            // Create a fake tet to hold n.
+            maketetrahedron(&newfront);
+            setorg(newfront, sorg(frontsh));
+            setdest(newfront, sdest(frontsh));
+            setapex(newfront, sapex(frontsh));
+            setoppo(newfront, (point) NULL);
+            tsbond(newfront, frontsh);
           } else {
-            // In degenerate case, this face may just be the equator.
-            assert(worklist[idx] == 1);
-            share++;
+            // n should not be a front of cavity yet.
+            assert(!infected(newfront));
           }
         }
-        // The degenerate case has been ruled out.
-        assert(share < 3);
-        // Only one flag is possible for a cavity face.
-        assert(belowflag ^ aboveflag); 
-        if (belowflag) {
-          belowfacelist->append(&worktet);
-        } else if (aboveflag) {
-          abovefacelist->append(&worktet);
+        if (newflag) {
+          if (b->verbose > 2) {
+            printf("    Add front (%d, %d, %d).\n", pointmark(org(newfront)),
+                   pointmark(dest(newfront)), pointmark(apex(newfront)));
+          }
+          frontlist->append(&newfront);
         }
+        enextself(front);
       }
+      // Add f into oldtetlist (to be deleted).
+      infect(front);
+      oldtetlist->append(&front);
+      expcavcount++;
     }
+  } while (expflag);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// findrelocatepoint()    Find new location for relocating a point.          //
+//                                                                           //
+// 'frontlist' contains the boundary faces of the cavity C.  Some fronts are //
+// visible by 'stpt' p, some are coplanar with p.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::findrelocatepoint(point sp, point np, REAL* n,
+  list* frontlist, list* oldtetlist)
+{
+  triface front;
+  point pa, pb, pc;
+  REAL tp[3], tvol, mvol;
+  REAL ori, eps;
+  bool visible;
+  int i, j, k;
+
+  if (b->verbose > 1) {
+    printf("    Find new location for point %d.\n", pointmark(sp));
   }
 
-  // Shrink R if not all its subfaces are crossing by the discovered tets.
-  //   'crossshlist' and 'horizptlist' represent the set of subfaces and
-  //   vertices of the shrinked missing region, respectively.
-  for (i = 0; i < missingshlist->len(); i++) {
-    worksh = * (face *)(* missingshlist)[i];
-    assert(sinfected(worksh));
-    workpt[0] = sorg(worksh);
-    workpt[1] = sdest(worksh);
-    workpt[2] = sapex(worksh);
-    crossflag = false;
-    for (j = 0; j < crosstetlist->len() && !crossflag; j++) {
-      // Get a tet abcd, ab is a crossing edge.
-      starttet = * (triface *)(* crosstetlist)[j];
-      adjustedgering(starttet, CCW);
-      // Only need to check two sides of worktet.
-      for (k = 0; k < 2 && !crossflag; k++) {
-        if (k == 0) {
-          worktet = starttet; // Check abc.
+  // Avoid compilation warnings.
+  tvol = mvol = 0.0;
+  visible = false;
+
+  eps = b->epsilon;
+  // Initialize np far enough from p (outside C).
+  for (i = 0; i < 3; i++) np[i] = sp[i] + longest * n[i];
+  // Let tp = np;
+  for (i = 0; i < 3; i++) tp[i] = np[i];
+  // Interation to adjust np until it is visible by all fronts.
+  j = 0;
+  do {
+    for (i = 0; i < frontlist->len(); i++) {
+      // Get a front face f.
+      front = * (triface *)(* frontlist)[i];
+      // Let f face to the interior of C.
+      adjustedgering(front, CW);
+      pa = org(front);
+      pb = dest(front);
+      pc = apex(front);
+      ori = orient3d(pa, pb, pc, np);
+      visible = (ori < 0.0);
+      if (!visible) {
+        // A front is invisible by np. Move it towards p along the normal.
+        for (i = 0; i < 3; i++) np[i] = sp[i] + 0.5 * (sp[i] - np[i]);
+        // Failed if tp = np.
+        if ((tp[0] == np[0]) && (tp[1] == np[1]) && (tp[2] == np[2])) {
+          // Try to expand the cavity.
+          expandsteinercavity(sp, eps, frontlist, oldtetlist);
+          eps *= 10.0;
+          if (eps > b->epsilon * 1000.0) {
+          // printf("Internal error: Fail to relocate pt %d.\n",pointmark(sp));
+            // internalerror();
+            return false;
+          }
+          // Restart the point relocation.
+          for (i = 0; i < 3; i++) np[i] = sp[i] + longest * n[i];
+        }
+        if (j % 2) {
+          // Set tp = np (at every 2 steps) to catch the stop state.
+          for (i = 0; i < 3; i++) tp[i] = np[i];
+        }
+        break;
+      } else {
+        // Save the smallest volume.
+        if (i == 0) {
+          mvol = fabs(ori);
         } else {
-          fnext(starttet, worktet); // Check abd.
+          mvol = fabs(ori) < mvol ? fabs(ori) : mvol;
         }
-        crossflag = tritritest(&worktet, workpt[0], workpt[1], workpt[2]);
       }
     }
-    if (crossflag) {
-      // 'worksh' is crossed by 'worktet', uninfect it.
-      suninfect(worksh);
-      crossshlist->append(&worksh);
-      // Add its corners into 'horizptlist'.
-      for (k = 0; k < 3; k++) {
-        idx = pointmark(workpt[k]) - in->firstnumber;
-        if (worklist[idx] != 4) {
-          worklist[idx] = 4;
-          horizptlist->append(&workpt[k]);
-        }
-      }
-    } 
+    j++;
+  } while (!visible);
+  
+  if (b->verbose > 1) {
+    printf("    %d iterations. minvol = %.12g.\n", j, mvol);
   }
 
-  // Check 'crossingtetlist'. Queue subfaces inside them.
-  for (i = 0; i < crosstetlist->len(); i++) {
-    starttet = * (triface *)(* crosstetlist)[i];
-    for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
-      sym(starttet, neightet);
-      // If the neighbor exist and is infected, check it.
-      if ((neightet.tet != dummytet) && infected(neightet)) {
-        tspivot(starttet, worksh);
-        if (worksh.sh != dummysh) {
-          // Temporarily remove worksh. Make it missing. recover it later.
-          if (b->verbose > 2) {
-            printf("    Queuing subface (%d, %d, %d).\n",
-                   pointmark(sorg(worksh)), pointmark(sdest(worksh)),
-                   pointmark(sapex(worksh)));
+  // Continue to adjust np until the minimal volume of tets formed by
+  //   fronts and np doesn't increase (all fronts are visible by np).
+  k = 0;
+  do {
+    j = 0;
+    do {
+      if (k == 0) {
+        // Initial tp := np + 0.9 * (p - np). Move toward p.
+        for (i = 0; i < 3; i++) tp[i] = sp[i] + 0.9 * (np[i] - sp[i]);
+      } else {
+        // Initial tp := np + 1.1 * (p - np). Move away from p.
+        for (i = 0; i < 3; i++) tp[i] = sp[i] + 1.1 * (np[i] - sp[i]);
+      }
+      // Get the minial volume formed by tp with one of the fronts.
+      for (i = 0; i < frontlist->len(); i++) {
+        // Get a front face f.
+        front = * (triface *)(* frontlist)[i];
+        // Let f face to the interior of C.
+        adjustedgering(front, CW);
+        pa = org(front);
+        pb = dest(front);
+        pc = apex(front);
+        ori = orient3d(pa, pb, pc, tp);
+        visible = (ori < 0.0);
+        if (visible) {
+          // Save the smallest volume.
+          if (i == 0) {
+            tvol = fabs(ori);
+          } else {
+            tvol = fabs(ori) < tvol ? fabs(ori) : tvol;
           }
-          tsdissolve(neightet);
-          tsdissolve(starttet);
-          // Detach tets at the both sides of this subface.
-          stdissolve(worksh);
-          sesymself(worksh);
-          stdissolve(worksh);
-          sinfect(worksh);
-          missingshqueue->push(&worksh);
+        } else {
+          // A front is invisible by tp. Stop.
+          tvol = 0.0;
+          break;
         }
       }
-    }
+      if (tvol > mvol) {
+        // Get a larger minimal volume.
+        for (i = 0; i < 3; i++) np[i] = tp[i];
+        mvol = tvol;
+      } else {
+        // Minimal volume decreases. Stop.
+        break;
+      }
+      // Continue to adjust np.
+      j++;
+    } while (true);
+    // Has np been adjusted?
+    if (j > 0) break;
+    // Try to move np to anoter direction.
+    k++;
+  } while (k < 2);
+
+  if (b->verbose > 1) {
+    printf("    %d adjust iterations. minvol = %.12g.\n", j, mvol);
   }
+  return true;
+}
 
-  // Clear flags set in 'worklist'.
-  for (i = 0; i < equatptlist->len(); i++) {
-    workpt[0] = * (point *)(* equatptlist)[i];
-    idx = pointmark(workpt[0]) - in->firstnumber;
-    assert((worklist[idx] == 1) || (worklist[idx] == 4));
-    worklist[idx] = 0;
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// relocatepoint()    Relocate a point into the cavity.                      //
+//                                                                           //
+// 'frontlist' contains the boundary faces of the cavity C. All fronts must  //
+// be visible by 'steinpt'.  Some fronts may hold by 'fake' tets (they are   //
+// hull faces).  Fake tets will be removed when they're finished.            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::relocatepoint(point steinpt, triface* oldtet, list* frontlist,
+  list* newtetlist, queue* flipque)
+{
+  triface front, newtet, newface, neightet;
+  face checksh;
+  point pa, pb;
+  REAL attrib, volume;
+  bool bdflag;
+  int i, j, k, l;
+
+  if (b->verbose > 1) {
+    printf("    Insert Steiner point (%.12g, %.12g, %.12g) %d.\n",
+           steinpt[0], steinpt[1], steinpt[2], pointmark(steinpt));
   }
-  for (i = 0; i < belowptlist->len(); i++) {
-    workpt[0] = * (point *)(* belowptlist)[i];
-    idx = pointmark(workpt[0]) - in->firstnumber;
-    assert(worklist[idx] == 2);
-    worklist[idx] = 0;
+  // Clear the list first.
+  newtetlist->clear();
+
+  // Create the tets formed by fronts and 'steinpt'.
+  for (i = 0; i < frontlist->len(); i++) {
+    // Get a front f.
+    front = * (triface *)(* frontlist)[i];
+    // Let f face inside C. (f is a face of tet adjacent to C).
+    adjustedgering(front, CW);
+    if (b->verbose > 2) {
+      printf("    Get front (%d, %d, %d).\n", pointmark(org(front)),
+             pointmark(dest(front)), pointmark(apex(front)));
+    }
+    maketetrahedron(&newtet);
+    newtetlist->append(&newtet);
+    setorg(newtet, org(front));
+    setdest(newtet, dest(front));
+    setapex(newtet, apex(front));
+    setoppo(newtet, steinpt);
+    if (oldtet != (triface *) NULL) {
+      for (j = 0; j < in->numberoftetrahedronattributes; j++) {
+        attrib = elemattribute(oldtet->tet, j);
+        setelemattribute(newtet.tet, j, attrib);
+      }
+      if (b->varvolume) {
+        volume = volumebound(oldtet->tet);
+        setvolumebound(newtet.tet, volume);
+      }
+    }
+    // 'front' may be a 'fake' tet.
+    tspivot(front, checksh);
+    if (oppo(front) == (point) NULL) {
+      if (checksh.sh != dummysh) {
+        stdissolve(checksh);
+      }
+      // Dealloc the 'fake' tet.
+      tetrahedrondealloc(front.tet);
+      // This side (newtet) is a boundary face, let 'dummytet' bond to it.
+      //   Otherwise, 'dummytet' may point to a dead tetrahedron after the
+      //   old cavity tets are removed.
+      dummytet[0] = encode(newtet);
+    } else {
+      // Bond two tetrahedra, also dissolve the old bond at 'front'.
+      bond(newtet, front);
+    }
+    if (checksh.sh != dummysh) {
+      sesymself(checksh);
+      tsbond(newtet, checksh);
+    }
+    if (flipque != (queue *) NULL) {
+      // f may be non-locally Delaunay and flipable.
+      enqueueflipface(newtet, flipque);
+    }
+    // The three neighbors are open. Will be finished later.
+  }
+
+  // Connect new tets in C. All connecting faces must contain 'steinpt'.
+  for (i = 0; i < newtetlist->len(); i++) {
+    newtet = * (triface *)(* newtetlist)[i];
+    newtet.ver = 0;
+    for (j = 0; j < 3; j++) {
+      fnext(newtet, newface);
+      sym(newface, neightet);
+      if (neightet.tet == dummytet) {
+        // Find a neightet to connect it.
+        bdflag = false;
+        pa = org(newface);
+        pb = dest(newface);
+        assert(apex(newface) == steinpt);
+        for (k = i + 1; k < newtetlist->len() && !bdflag; k++) {
+          neightet = * (triface *)(* newtetlist)[k];
+          neightet.ver = 0;
+          for (l = 0; l < 3; l++) {
+            if ((org(neightet) == pa && dest(neightet) == pb) ||
+                (org(neightet) == pb && dest(neightet) == pa)) {
+              // Find the neighbor.
+              fnextself(neightet);
+              assert(apex(neightet) == steinpt);
+              // Now neightet is a face same as newface, bond them.
+              bond(newface, neightet);
+              bdflag = true;
+              break;
+            }
+            enextself(neightet);
+          }
+        }
+        assert(bdflag);
+      }
+      enextself(newtet);
+    }
+    // Let the corners of newtet point to it for fast searching.
+    pa = org(newtet);
+    setpoint2tet(pa, encode(newtet));
+    pa = dest(newtet);
+    setpoint2tet(pa, encode(newtet));
+    pa = apex(newtet);
+    setpoint2tet(pa, encode(newtet));
+    pa = oppo(newtet);
+    setpoint2tet(pa, encode(newtet));
   }
-  for (i = 0; i < aboveptlist->len(); i++) {
-    workpt[0] = * (point *)(* aboveptlist)[i];
-    idx = pointmark(workpt[0]) - in->firstnumber;
-    assert(worklist[idx] == 3);
-    worklist[idx] = 0;
+
+  if (flipque != (queue *) NULL) { 
+    // Recover locally Delaunay faces.
+    flip(flipque, NULL);
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// enlargecavity()    Enlarge the cavity by expanding the faces on ceil.     //
-//                                                                           //
-// 'missceillist' contains missing faces of the cavity C in D.  These faces  //
-// will be removed from 'ceillist', instead new faces will be added.         //
+// findcollapseedge()    Find collapseable edge to suppress an endpoint.     //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-enlargecavity(list* missceillist, list* ceillist, list* ceilptlist,
-              list* floorptlist, list* crosstetlist, queue* missingshqueue,
-              int* worklist)
+bool tetgenmesh::findcollapseedge(point suppt, point *conpt, list* oldtetlist,
+  list* ptlist)
 {
-  triface missceil, neightet, newceil;
-  triface neineitet, worktet;
-  face checksh;
-  point pd;
-  int i, j, k;
-
-  if (b->verbose > 1) {
-    printf("    Enlarge cavity (%d missing faces).\n", missceillist->len());
-  }
-
-  // Increase the number of enlarged cavities.
-  enlcavtimes++;
-
-  // Mark all vertices in 'floorptlist'.
-  for (i = 0; i < floorptlist->len(); i++) {
-    pd = * (point *)(* floorptlist)[i];
-    worklist[pointmark(pd)] = 1;
-  }
-  // Mark all vertices in 'ceilptlist'.
-  for (i = 0; i < ceilptlist->len(); i++) {
-    pd = * (point *)(* ceilptlist)[i];
-    worklist[pointmark(pd)] = 2;
-  }
+  triface front;
+  point pt, pa, pb, pc;
+  REAL *lenarray, ltmp, ori;
+  bool visflag;
+  int *idxarray, itmp;
+  int n, i, j;
 
-  // Loop through 'missceillist'.
-  for (i = 0; i < missceillist->len(); i++) {
-    // Get a missing front f.
-    missceil = * (triface *)(* missceillist)[i];
-    // f is the face of a tet inside C. 
-    assert(infected(missceil));
-    // f is no longer a front face, delete it from 'ceillist'.
-    for (j = 0; j < ceillist->len(); j++) {
-      worktet = * (triface *)(* ceillist)[j];
-      if ((missceil.tet == worktet.tet) && (missceil.loc == worktet.loc)) {
-        ceillist->del(j);
-        break;
-      }
-    }
-    // Get the neighbor tet (adjacent to C) at f.
-    sym(missceil, neightet);
-    // The neighbor may have been added in C.
-    pd = oppo(neightet);
-    // It shouldn't be a 'fake' tet.
-    assert(pd != (point) NULL);
-    j = pointmark(pd);
-    // Is pd in list?
-    if ((worklist[j] != 1) && (worklist[j] != 2)) {
-      // pd is a new ceil point. Add it into 'ceilptlist'.
-      worklist[j] = 2;
-      ceilptlist->append(&pd);
-    }
-    // Is f a subface?
-    tspivot(neightet, checksh);
-    if (checksh.sh != dummysh) {
-      // Temporarily remove checksh. Make it missing. recover it later.
-      if (b->verbose > 2) {
-        printf("    Queuing subface (%d, %d, %d).\n",
-               pointmark(sorg(checksh)), pointmark(sdest(checksh)),
-               pointmark(sapex(checksh)));
-      }
-      tsdissolve(neightet);
-      tsdissolve(missceil);
-      // Detach tets at the both sides of checksh.
-      stdissolve(checksh);
-      sesymself(checksh);
-      stdissolve(checksh);
-      sinfect(checksh);
-      missingshqueue->push(&checksh);
-    }
-    // Enlarge the cavity by adding three sides of the neightet.
-    adjustedgering(neightet, CCW);
-    for (j = 0; j < 3; j++) {
-      fnext(neightet, newceil);
-      sym(newceil, neineitet);
-      // Is neineitet inside C?
-      if (!infected(neineitet)) {
-        // No. newceil becomes a front.
-        ceillist->append(&newceil);
-      } else {
-        // Yes. neineitet is not a front anymore. remove it from ceillist.
-        for (k = 0; k < ceillist->len(); k++) {
-          worktet = * (triface *)(* ceillist)[k];
-          if ((neineitet.tet == worktet.tet) &&
-              (neineitet.loc == worktet.loc)) {
-            ceillist->del(k);
-            break;
-          }
+  if (b->verbose > 2) {
+    printf("    Search an edge (in %d edges) for collapse %d.\n",
+           ptlist->len(), pointmark(suppt));
+  }
+
+  // Candidate edges are p to the points of B(p) (in 'ptlist').
+  n = ptlist->len();
+  lenarray = new REAL[n];
+  idxarray = new int[n];
+  // Sort the points of B(p) by distance to p.
+  for (i = 0; i < n; i++) {
+    pt = * (point *)(* ptlist)[i];
+    lenarray[i] = distance(suppt, pt);
+    idxarray[i] = i;
+  }
+  // Bubble sort.
+  for (i = 0; i < n - 1; i++) {
+    for (j = 0; j < n - 1 - i; j++) {
+      if (lenarray[j + 1] < lenarray[j]) {  // compare the two neighbors
+        ltmp = lenarray[j];           // swap a[j] and a[j + 1]
+        lenarray[j] = lenarray[j + 1];
+        lenarray[j + 1] = ltmp;
+        itmp = idxarray[j];           // swap a[j] and a[j + 1]
+        idxarray[j] = idxarray[j + 1];
+        idxarray[j + 1] = itmp;
+      }
+    }
+  }
+  // For each point q of B(p), test if the edge (p, q) can be collapseed.
+  for (i = 0; i < n; i++) {
+    pt = * (point *)(* ptlist)[idxarray[i]];
+    // Is q visible by faces of B(p) not with q as a vertex.
+    lenarray[i] = 0.0; // zero volume.
+    visflag = true;
+    for (j = 0; j < oldtetlist->len() && visflag; j++) {
+      front = * (triface *)(* oldtetlist)[j];
+      // Let f face to inside of B(p).
+      adjustedgering(front, CCW);
+      pa = org(front);
+      pb = dest(front);
+      pc = apex(front);
+      // Is f contains q?
+      if ((pa != pt) && (pb != pt) && (pc != pt)) {
+        ori = orient3d(pa, pb, pc, pt);
+        if (ori != 0.0) {
+          if (iscoplanar(pa, pb, pc, pt, ori, b->epsilon * 1e+2)) ori = 0.0;
         }
-        // Is newceil a subface?
-        tspivot(newceil, checksh);
-        if (checksh.sh != dummysh) {
-          // Temporarily remove checksh. Make it missing. recover it later.
-          if (b->verbose > 2) {
-            printf("    Queuing subface (%d, %d, %d).\n",
-                   pointmark(sorg(checksh)), pointmark(sdest(checksh)),
-                   pointmark(sapex(checksh)));
+        visflag = ori < 0.0;
+        if (visflag) {
+          // Visible, set the smallest volume.
+          if (j == 0) {
+            lenarray[i] = fabs(ori);
+          } else {
+            lenarray[i] = fabs(ori) < lenarray[i] ? fabs(ori) : lenarray[i];
           }
-          tsdissolve(neineitet);
-          tsdissolve(newceil);
-          // Detach tets at the both sides of checksh.
-          stdissolve(checksh);
-          sesymself(checksh);
-          stdissolve(checksh);
-          sinfect(checksh);
-          missingshqueue->push(&checksh);
+        } else {
+          // Invisible. Do not collapse (p, q).
+          lenarray[i] = 0.0;
         }
       }
-      enextself(neightet);
     }
-    // neightet may have already been queued.
-    if (!infected(neightet)) {
-      // neightet beomes a cavity tet, will be removed later.
-      infect(neightet);
-      crosstetlist->append(&neightet);
+    if ((b->verbose > 2) && visflag) {
+      printf("    Got candidate %d vol(%g).\n", pointmark(pt), lenarray[i]);
     }
   }
 
-  // Unmark all vertices in 'floorptlist'.
-  for (i = 0; i < floorptlist->len(); i++) {
-    pd = * (point *)(* floorptlist)[i];
-    worklist[pointmark(pd)] = 0;
+  // Select the largest non-zero volume (result in ltmp).
+  ltmp = lenarray[0];
+  itmp = idxarray[0];
+  for (i = 1; i < n; i++) {
+    if (lenarray[i] != 0.0) {
+      if (lenarray[i] > ltmp) {
+        ltmp = lenarray[i];
+        itmp = idxarray[i]; // The index to find the point.
+      }
+    }
   }
-  // Unmark all vertices in 'ceilptlist'.
-  for (i = 0; i < ceilptlist->len(); i++) {
-    pd = * (point *)(* ceilptlist)[i];
-    worklist[pointmark(pd)] = 0;
+
+  delete [] lenarray;
+  delete [] idxarray;
+
+  if (ltmp == 0.0) {
+    // No edge can be collapseed.
+    *conpt = (point) NULL;
+    return false;
+  } else {
+    pt = * (point *)(* ptlist)[itmp];
+    *conpt = pt;
+    return true;
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// insertallsubfaces()    Insert all subfaces, queue missing subfaces.       //
-//                                                                           //
-// Loop through all subfaces, insert each into the DT. If one already exists,//
-// bond it to the tetrahedra having it. Otherwise, it is missing, infect it  //
-// and save it in 'missingshqueue'.                                          //
+// collapseedge()    Remove a point by edge collapse.                        //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::insertallsubfaces(queue* missingshqueue)
+void tetgenmesh::collapseedge(point suppt, point conpt, list* oldtetlist,
+  list* deadtetlist)
 {
-  triface searchtet;
-  face subloop;
+  triface oldtet, deadtet;
+  triface adjtet1, adjtet2;
+  face adjsh;
+  point pa, pb, pc;
+  int i, j;
 
-  searchtet.tet = (tetrahedron *) NULL;
-  subfaces->traversalinit();
-  subloop.sh = shellfacetraverse(subfaces);
-  while (subloop.sh != (shellface *) NULL) {
-    if (!insertsubface(&subloop, &searchtet)) {
-      if (b->verbose > 1) {
-        printf("    Queuing subface (%d, %d, %d).\n", pointmark(sorg(subloop)),
-               pointmark(sdest(subloop)), pointmark(sapex(subloop)));
-      }
-      sinfect(subloop);
-      missingshqueue->push(&subloop);
+  if (b->verbose > 2) {
+    printf("    Collapse edge (%d,%d).\n", pointmark(suppt), pointmark(conpt));
+  }
+
+  // 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));
+    pa = org(oldtet);
+    pb = dest(oldtet);
+    pc = apex(oldtet);
+    assert(oppo(oldtet) == suppt);
+    setoppo(oldtet, conpt);
+    if ((pa == conpt) || (pb == conpt) || (pc == conpt)) {
+      deadtetlist->append(&oldtet); // a collpased tet.
+    }
+  }
+  // Loop in deadtetlist, glue adjacent tets of dead tets.
+  for (i = 0; i < deadtetlist->len(); i++) {
+    deadtet = * (triface *)(* deadtetlist)[i];
+    // Get the adjacent tet n1 (outside B(p)).
+    sym(deadtet, adjtet1);
+    tspivot(deadtet, adjsh);
+    // Find the edge in deadtet opposite to conpt.
+    adjustedgering(deadtet, CCW);
+    for (j = 0; j < 3; j++) {
+      if (apex(deadtet) == conpt) break;
+      enextself(deadtet);
+    }
+    assert(j < 3);
+    // Get another adjacent tet n2.
+    fnext(deadtet, adjtet2);
+    symself(adjtet2);
+    assert(adjtet2.tet != dummytet); // n2 is inside B(p).
+    if (adjtet1.tet != dummytet) {
+      bond(adjtet1, adjtet2); // Bond n1 <--> n2.
+    } else {
+      dissolve(adjtet2); // Dissolve at n2.
+      dummytet[0] = encode(adjtet2); // Let dummytet holds n2.
     }
-    subloop.sh = shellfacetraverse(subfaces);
+    if (adjsh.sh != dummysh) {
+      tsbond(adjtet2, adjsh); // Bond s <--> n2.
+    }
+    // Collapse deadtet.
+    tetrahedrondealloc(deadtet.tet);
   }
+  deadtetlist->clear();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// constrainedfacets()    Recover subfaces in a Delaunay tetrahedralization. //
-//                                                                           //
-// This routine creates a CDT by incrementally updating a DT D into a CDT T. //
-// The process of recovering facets can be imagined by "merging" the surface //
-// mesh F into D. At the beginning, F and D are completely seperated.  Some  //
-// faces of them are matching some are not because they are crossed by some  //
-// tetrahedra of D. The non-matching subfaces will be forced to appear in T  //
-// by locally retetrahedralizing the regions where F and D are intersecting. //
-//                                                                           //
-// When a subface s of F is found missing in D, probably some other subfaces //
-// near to s are missing too.  The set of adjoining coplanar missing faces   //
-// forms a missing region R (R may not simply connected).                    //
+// deallocfaketets()    Deleted fake tets at fronts.                         //
 //                                                                           //
-// There are two possibilities can result a mssing region R: (1) Some edges  //
-// of D cross R; (2) No edge of D crosses R, but some faces of D spans R, ie,//
-// D is locally degenerate at R. In case (1), D is modified so that it resp- //
-// ects R (done by a cavity retetrahedralization algorithm).  In case (2), F //
-// is modified so that the set of subfaces of R matches faces in D (done by  //
-// a face rearrangment algorithm).                                           //
+// This routine is only called when the findrelocatepoint() routine fails.   //
+// In other cases, the fake tets are removed automatically in carvecavity()  //
+// or relocatepoint().                                                       //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::constrainedfacets()
+void tetgenmesh::deallocfaketets(list* frontlist)
 {
-  queue *missingshqueue;
-  list *missingshlist, *equatptlist;
-  list *boundedgelist, *crossedgelist, *crosstetlist;
-  list *crossshlist, *belowfacelist, *abovefacelist;
-  list *horizptlist, *belowptlist, *aboveptlist;
-  list *newtetlist, *missceillist;
-  triface searchtet, worktet;
-  face subloop, worksh;
-  int *worklist;
+  triface front, neightet;
+  face checksh;
+  bool infectflag;
   int i;
 
-  if (!b->quiet) {
-    printf("Constraining facets.\n");
-  }
-
-  // Initialize the queue.
-  missingshqueue = new queue(sizeof(face));
-  // Initialize the working lists.
-  missingshlist = new list(sizeof(face), NULL);
-  boundedgelist = new list(sizeof(face), NULL);
-  crossedgelist = new list(sizeof(triface), NULL);
-  equatptlist = new list("point *");
-  crossshlist = new list(sizeof(face), NULL);
-  crosstetlist = new list(sizeof(triface), NULL);
-  belowfacelist = new list(sizeof(triface), NULL);
-  abovefacelist = new list(sizeof(triface), NULL);
-  horizptlist = new list("point *");
-  belowptlist = new list("point *");
-  aboveptlist = new list("point *");
-  newtetlist = new list(sizeof(triface), NULL);
-  missceillist = new list(sizeof(triface), NULL);
-  // Initialize the array for marking vertices.
-  worklist = new int[points->items + 1];
-  for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
-
-  // Compute a mapping from points to tetrahedra for fast searching.
-  makepoint2tetmap();
-  
-  // Match subfaces in D, queue all missing subfaces.
-  insertallsubfaces(missingshqueue);
-
-  // Recover all missing subfaces.
-  while (!missingshqueue->empty()) {
-    // Get a queued face s.
-    subloop = * (face *) missingshqueue->pop();
-    // s may have been deleted in a face rearrangment operation.
-    if (isdead(&subloop)) continue;
-    // s may have been recovered in a previous missing region.
-    if (!sinfected(subloop)) continue;
-    // s may match a face in D now due to previous transformations.
-    if (insertsubface(&subloop, &searchtet)) {
-      suninfect(subloop);
-      continue;
-    }
-    if (b->verbose > 1) {
-      printf("    Recover subface (%d, %d, %d).\n", pointmark(sorg(subloop)),
-             pointmark(sdest(subloop)), pointmark(sapex(subloop)));
-    }
-    // Form the missing region R containing s.
-    formmissingregion(&subloop, missingshlist, equatptlist, worklist);
-    // Is R crossing by any tetrahedron?
-    if (scoutcrossingedge(missingshlist, boundedgelist, crossedgelist,
-                          worklist)) {
-      // Form the cavity C containing R.
-      formcavity(missingshlist, crossedgelist, equatptlist, crossshlist,
-                 crosstetlist, belowfacelist, abovefacelist, horizptlist,
-                 belowptlist, aboveptlist, missingshqueue, worklist);
-      // Recover the above part of C.
-      do {
-        delaunizecavity(crossshlist, abovefacelist, horizptlist, aboveptlist,
-                        newtetlist, missceillist, worklist);
-        if (missceillist->len() > 0) {
-          // There're unrecovered faces. Enlarge the above part of C.
-          enlargecavity(missceillist, abovefacelist, aboveptlist, horizptlist,
-                        crosstetlist, missingshqueue, worklist);
-          missceillist->clear();
-          continue;
-        }
-        break;
-      } while (true);
-      // Inverse the direction of subfaces in R.
-      for (i = 0; i < crossshlist->len(); i++) {
-        worksh = * (face *)(* crossshlist)[i];
-        sesymself(worksh);
-        * (face *)(* crossshlist)[i] = worksh;
-      }
-      // Recover the below part of C.
-      do {
-        delaunizecavity(crossshlist, belowfacelist, horizptlist, belowptlist,
-                        newtetlist, missceillist, worklist);
-        if (missceillist->len() > 0) {
-          // There're unrecovered faces. Enlarge the lower part of C.
-          enlargecavity(missceillist, belowfacelist, belowptlist, horizptlist,
-                        crosstetlist, missingshqueue, worklist);
-          missceillist->clear();
-          continue;
-        }
-        break;
-      } while (true);
-      // Delete tetrahedra in C.
-      for (i = 0; i < crosstetlist->len(); i++) {
-        worktet = * (triface *)(* crosstetlist)[i];
-        tetrahedrondealloc(worktet.tet);
+  for (i = 0; i < frontlist->len(); i++) {
+    // Get a front f.
+    front = * (triface *)(* frontlist)[i];
+    // Let f face inside C. (f is a face of tet adjacent to C).
+    adjustedgering(front, CW);
+    sym(front, neightet);
+    tspivot(front, checksh);
+    if (oppo(front) == (point) NULL) {
+      if (b->verbose > 2) {
+        printf("    Get fake tet (%d, %d, %d).\n", pointmark(org(front)),
+               pointmark(dest(front)), pointmark(apex(front)));
       }
-      // There may have some un-recovered subfaces of R. Put them back into
-      //   queue. Otherwise, they will be missing on the boundary.
-      for (i = 0; i < missingshlist->len(); i++) {
-        worksh = * (face *)(* missingshlist)[i];
-        if (sinfected(worksh)) {
-          // An unrecovered subface, put it back into queue.
-          missingshqueue->push(&worksh);
+      if (neightet.tet != dummytet) {
+        // The neightet may be infected. After dissolve it, the infect flag
+        //   will be lost. Save the flag and restore it later.
+        infectflag = infected(neightet);
+        dissolve(neightet);
+        if (infectflag) {
+          infect(neightet);
         }
       }
-      crossshlist->clear();
-      crosstetlist->clear();
-      belowfacelist->clear();
-      abovefacelist->clear();
-      horizptlist->clear();
-      belowptlist->clear();
-      aboveptlist->clear();
-      newtetlist->clear();
-    } else {
-      // No. Rearrange subfaces of F conforming to that of D in R.
-      rearrangesubfaces(missingshlist, boundedgelist, equatptlist, worklist);
-    }
-    // Clear all working lists.
-    missingshlist->clear();
-    boundedgelist->clear();
-    crossedgelist->clear();
-    equatptlist->clear();
-  }
-
-  // Subfaces have been merged into D.
-  checksubfaces = 1;
-
-  if (b->verbose) {
-    printf("  The biggest cavity: %d faces, %d vertices\n", maxcavfaces,
-           maxcavverts);
-    printf("  Enlarged %d times\n", enlcavtimes);
-  }
-
-  delete missingshqueue;
-  delete missingshlist;
-  delete boundedgelist;
-  delete crossedgelist;
-  delete equatptlist;
-  delete crossshlist;
-  delete crosstetlist;
-  delete belowfacelist;
-  delete abovefacelist;
-  delete horizptlist;
-  delete belowptlist;
-  delete aboveptlist;
-  delete newtetlist;
-  delete missceillist;
-  delete [] worklist;
-}
-
-//
-// End of facet recovery routines
-//
-
-//
-// Begin of carving out holes and concavities routines
-//
+      if (checksh.sh != dummysh) {
+        infectflag = sinfected(checksh);
+        stdissolve(checksh);
+        if (infectflag) {
+          sinfect(checksh);
+        }
+      }
+      // Dealloc the 'fake' tet.
+      tetrahedrondealloc(front.tet);
+      // This side (neightet) is a boundary face, let 'dummytet' bond to it.
+      dummytet[0] = encode(neightet);
+    }
+  }
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// infecthull()    Virally infect all of the tetrahedra of the convex hull   //
-//                 that are not protected by subfaces.  Where there are      //
-//                 subfaces, set boundary markers as appropriate.            //
+// restorepolyhedron()    Restore the tetrahedralization in a polyhedron.    //
 //                                                                           //
-// Memorypool 'viri' is used to return all the infected tetrahedra.          //
+// This routine is only called when the operation of suppressing a point is  //
+// aborted (eg., findrelocatepoint() routine fails). The polyhedron has been //
+// remeshed by new tets. This routine restore the old tets in it.            //
+//                                                                           //
+// 'oldtetlist' contains the list of old tets. Each old tet t_o assumes that //
+// it still connects to a tet t_b of the mesh, however, t_b does not connect //
+// to t_o, this routine resets the connection such that t_b <--> t_o.        //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::infecthull(memorypool *viri)
+void tetgenmesh::restorepolyhedron(list* oldtetlist)
 {
-  triface tetloop, tsymtet;
-  tetrahedron **deadtet;
-  face hullface;
-  // point horg, hdest, hapex;
+  triface oldtet, neightet, neineitet;
+  face checksh;
+  int i;
 
-  if (b->verbose) {
-    printf("  Marking concavities for elimination.\n");
-  }
-  tetrahedrons->traversalinit();
-  tetloop.tet = tetrahedrontraverse();
-  while (tetloop.tet != (tetrahedron *) NULL) {
-    // Is this tetrahedron on the hull?
-    for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
-      sym(tetloop, tsymtet);
-      if (tsymtet.tet == dummytet) {
-        // Is the tetrahedron protected by a subface?
-        tspivot(tetloop, hullface);
-        if (hullface.sh == dummysh) {
-          // The tetrahedron is not protected; infect it.
-          if (!infected(tetloop)) {
-            infect(tetloop);
-            deadtet = (tetrahedron **) viri->alloc();
-            *deadtet = tetloop.tet;
-            break;  // Go and get next tet.
-          }
-        } else {
-          // The tetrahedron is protected; set boundary markers if appropriate.
-          if (shellmark(hullface) == 0) {
-            setshellmark(hullface, 1);
-            /*
-            horg = sorg(hullface);
-            hdest = sdest(hullface);
-            hapex = sapex(hullface);
-            if (pointmark(horg) == 0) {
-              setpointmark(horg, 1);
-            }
-            if (pointmark(hdest) == 0) {
-              setpointmark(hdest, 1);
-            }
-            if (pointmark(hapex) == 0) {
-              setpointmark(hapex, 1);
-            }
-            */
+  for (i = 0; i < oldtetlist->len(); i++) {
+    // Get an old tet t_o.
+    oldtet = * (triface *)(* oldtetlist)[i];
+    // Check the four sides of t_o.
+    for (oldtet.loc = 0; oldtet.loc < 4; oldtet.loc++) {
+      sym(oldtet, neightet);
+      tspivot(oldtet, checksh);
+      if (neightet.tet != dummytet) {
+        sym(neightet, neineitet);
+        if (neineitet.tet != oldtet.tet) {
+          // This face of t_o is a boundary of P.
+          bond(neightet, oldtet);
+          if (checksh.sh != dummysh) {
+            tsbond(oldtet, checksh);
           }
         }
+      } else {
+        // t_o has a hull face. It should be the boundary of P.
+#ifdef SELF_CHECK
+        assert(checksh.sh != dummysh);
+        stpivot(checksh, neineitet);
+        assert(neineitet.tet != oldtet.tet);
+#endif
+        tsbond(oldtet, checksh);
+        // Let dummytet[0] points to it.
+        dummytet[0] = encode(oldtet);
       }
     }
-    tetloop.tet = tetrahedrontraverse();
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// plague()    Spread the virus from all infected tets to any neighbors not  //
-//             protected by subfaces.                                        //
+// suppressfacetpoint()    Suppress a point inside a facet.                  //
 //                                                                           //
-// This routine identifies all the tetrahedra that will die, and marks them  //
-// as infected.  They are marked to ensure that each tetrahedron is added to //
-// the virus pool only once, so the procedure will terminate. 'viri' returns //
-// all infected tetrahedra which are outside the domian.                     //
+// The point p inside a facet F will be suppressed from F by either being    //
+// deleted from the mesh or being relocated into the volume.                 //
+//                                                                           //
+// '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.               //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::plague(memorypool *viri)
+bool tetgenmesh::suppressfacetpoint(face* supsh, list* frontlist,
+  list* misfrontlist, list* ptlist, list* conlist, memorypool* viri,
+  queue* flipque)
 {
-  tetrahedron **virusloop;
-  tetrahedron **deadtet;
-  triface testtet, neighbor;
-  face neighsh, testseg;
-  face spinsh, casingin, casingout;
-  int i;
+  list *oldtetlist[2], *newtetlist[2];
+  list *oldshlist, *newshlist;
+  triface oldtet, newtet;
+  face oldsh, newsh;
+  point suppt, newpt[2];
+  point *cons;
+  REAL norm[3];
+  bool success;
+  int shmark;
+  int i, j;
 
-  if (b->verbose) {
-    printf("  Marking neighbors of marked tetrahedra.\n");
-  }
-  // Loop through all the infected tetrahedra, spreading the virus to
-  //   their neighbors, then to their neighbors' neighbors.
-  viri->traversalinit();
-  virusloop = (tetrahedron **) viri->traverse();
-  while (virusloop != (tetrahedron **) NULL) {
-    testtet.tet = *virusloop;
-    // Temporarily uninfect this tetrahedron, not necessary.
-    uninfect(testtet);
-    // Check each of the tetrahedron's four neighbors.
-    for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) {
-      // Find the neighbor.
-      sym(testtet, neighbor);
-      // Check for a shell between the tetrahedron and its neighbor.
-      tspivot(testtet, neighsh);
-      // Check if the neighbor is nonexistent or already infected.
-      if ((neighbor.tet == dummytet) || infected(neighbor)) {
-        if (neighsh.sh != dummysh) {
-          // There is a subface separating the tetrahedron from its neighbor,
-          //   but both tetrahedra are dying, so the subface dies too.
-          // Before deallocte this subface, dissolve the connections between
-          //   other subfaces, subsegments and tetrahedra.
-          neighsh.shver = 0;
-          // For keep the same enext() direction.
-          findedge(&testtet, sorg(neighsh), sdest(neighsh));
-          for (i = 0; i < 3; i++) {
-            sspivot(neighsh, testseg);
-            if (testseg.sh != dummysh) {
-              // A subsegment is found at this side, dissolve this subface
-              //   from the face link of this subsegment.
-              testseg.shver = 0;
-              spinsh = neighsh;
-              if (sorg(spinsh) != sorg(testseg)) {
-                sesymself(spinsh);
-              }
-              spivot(spinsh, casingout);
-              if (casingout.sh == spinsh.sh) {
-                // This is a trivial face link, only 'neighsh' itself,
-                //   the subsegment at this side is also died.
-                shellfacedealloc(subsegs, testseg.sh);
-              } else {
-                spinsh = casingout;
-                do {
-                  casingin = spinsh;
-                  spivotself(spinsh);
-                } while (spinsh.sh != neighsh.sh);
-                // Set the link casingin->casingout.
-                sbond1(casingin, casingout);
-                // Bond the subsegment anyway.
-                ssbond(casingin, testseg);
-              }
+  suppt = sapex(*supsh);
+  if (b->verbose > 1) {
+    printf("    Suppress point %d in facet.\n", pointmark(suppt));
+  }
+
+  // Initialize working lists, variables.
+  for (i = 0; i < 2; i++) {
+    oldtetlist[i] = (list *) NULL;
+    newtetlist[i] = (list *) NULL;
+    newpt[i] = (point) NULL;
+  }
+  oldshlist = new list(sizeof(face), NULL, 256);
+  newshlist = new list(sizeof(face), NULL, 256);
+  success = true; // Assume p can be suppressed.
+
+  // Find subs of C(p).
+  oldshlist->append(supsh);
+  formstarpolygon(suppt, oldshlist, ptlist);
+  // Get the edges of C(p). They form a closed polygon.
+  for (i = 0; i < oldshlist->len(); i++) {
+    oldsh = * (face *)(* oldshlist)[i];    
+    cons = (point *) conlist->append(NULL);
+    cons[0] = sorg(oldsh);
+    cons[1] = sdest(oldsh);
+  }
+  // Re-triangulate the old C(p).
+  shmark = shellmark(*supsh);
+  triangulate(shmark, b->epsilon, ptlist, conlist, 0, NULL, viri, flipque);
+  // Get new subs of C(p), remove protected segments.
+  retrievenewsubs(newshlist, true);
+  // Substitute the old C(p) with the new C(p)
+  replacepolygonsubs(oldshlist, newshlist);
+  // Clear work lists.
+  ptlist->clear();
+  conlist->clear();
+  flipque->clear();
+  viri->restart();
+
+  // B(p) (tets with p as a vertex) has been separated into two parts
+  //   (B_0(p) and B_1(p)) by F. Process them individually.
+  for (i = 0; i < 2 && success; i++) { 
+    if (i == 1) sesymself(*supsh);
+    // Get a tet containing p.
+    stpivot(*supsh, oldtet);
+    // Is this part empty?
+    if (oldtet.tet == dummytet) continue;
+    // Allocate spaces for storing (old and new) B_i(p).
+    oldtetlist[i] = new list(sizeof(triface), NULL, 256);
+    newtetlist[i] = new list(sizeof(triface), NULL, 256);
+    // Form old B_i(p) in oldtetlist[i].
+    assert(!isdead(&oldtet));
+    oldtetlist[i]->append(&oldtet);
+    formstarpolyhedron(suppt, oldtetlist[i], ptlist, false);
+    // Infect the tets in old B_i(p) (they're going to be delete).
+    for (j = 0; j < oldtetlist[i]->len(); j++) {
+      oldtet = * (triface *)(* (oldtetlist[i]))[j];
+      infect(oldtet);
+    }
+    // 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.
+      makepoint(&(newpt[i]));
+      success = findrelocatepoint(suppt, newpt[i], norm, frontlist,
+                                  oldtetlist[i]);
+      if (success) {
+        // p is relocated by newpt[i]. Now insert it. Don't do flip since
+        //   the new tets may get deleted again.
+        relocatepoint(newpt[i], &oldtet, frontlist, newtetlist[i], NULL);
+        setpointtype(newpt[i], FREEVOLVERTEX);
+        relverts++;
+      } else {
+        // Fail to relocate p. Clean fake tets and quit this option.
+        deallocfaketets(frontlist);
+        pointdealloc(newpt[i]);
+        newpt[i] = (point) NULL;
+        assert(newtetlist[i]->len() == 0);
+      }
+    }
+    // Clear work lists.
+    ptlist->clear();
+    frontlist->clear();
+    misfrontlist->clear();
+    flipque->clear();
+  }
+
+  if (success) {
+    // p has been removed! (Still in the pool).
+    setpointtype(suppt, UNUSEDVERTEX);
+    unuverts++;
+    // Delete old C(p).
+    for (i = 0; i < oldshlist->len(); i++) {
+      oldsh = * (face *)(* oldshlist)[i];
+      if (i == 0) {
+        // Update the 'hullsize' if C(p) is on the hull.
+        stpivot(oldsh, oldtet);
+        if (oldtet.tet != dummytet) {
+          sesymself(oldsh);
+          stpivot(oldsh, oldtet);
+        }
+        if (oldtet.tet == dummytet) {
+          // A boundary face. Update the 'hullsize'.
+          j = oldshlist->len() - newshlist->len();
+          assert(j > 0);
+          hullsize -= j;
+        }
+      }
+      shellfacedealloc(subfaces, oldsh.sh);
+    }
+    // Delete old B_i(p).
+    for (i = 0; i < 2; i++) {
+      if (oldtetlist[i] != (list *) NULL) {
+        // Delete tets of the old B_i(p).
+        for (j = 0; j < oldtetlist[i]->len(); j++) {
+          oldtet = * (triface *)(* (oldtetlist[i]))[j];
+          assert(!isdead(&oldtet));
+          tetrahedrondealloc(oldtet.tet);
+        }
+      }
+    }
+  } else {
+    // p is not suppressed. Recover the original state.
+    unsupverts++;
+    // Restore the old C(p).
+    replacepolygonsubs(newshlist, oldshlist);
+    // Delete subs of the new C(p)
+    for (i = 0; i < newshlist->len(); i++) {
+      newsh = * (face *)(* newshlist)[i];
+      shellfacedealloc(subfaces, newsh.sh);
+    }
+    // Restore old B_i(p).
+    for (i = 0; i < 2; i++) {
+      if (oldtetlist[i] != (list *) NULL) {
+        // Uninfect tets of old B_i(p).
+        for (j = 0; j < oldtetlist[i]->len(); j++) {
+          oldtet = * (triface *)(* (oldtetlist[i]))[j];
+          assert(infected(oldtet));
+          uninfect(oldtet);
+        }
+        // Has it been re-meshed?
+        if (newtetlist[i]->len() > 0) {
+          // Restore the old B_i(p).
+          restorepolyhedron(oldtetlist[i]);
+          // Delete tets of the new B_i(p);
+          for (j = 0; j < newtetlist[i]->len(); j++) {
+            newtet = * (triface *)(* (newtetlist[i]))[j];
+            // Some new tets may already be deleted (by carvecavity()).
+            if (!isdead(&newtet)) {
+              tetrahedrondealloc(newtet.tet);
             }
-            senextself(neighsh);
-            enextself(testtet);
-          }
-          shellfacedealloc(subfaces, neighsh.sh);
-          if (neighbor.tet != dummytet) {
-            // Make sure the subface doesn't get deallocated again later
-            //  when the infected neighbor is visited.
-            tsdissolve(neighbor);
           }
         }
-      } else {                   // The neighbor exists and is not infected.
-        if (neighsh.sh == dummysh) {
-          // There is no subface protecting the neighbor, infect it.
-          infect(neighbor);
-          // Ensure that the neighbor's neighbors will be infected.
-          deadtet = (tetrahedron **) viri->alloc();
-          *deadtet = neighbor.tet;
-        } else {               // The neighbor is protected by a subface.
-          // Remove this tetrahedron from the subface.
-          stdissolve(neighsh);
-          // The subface becomes a boundary.  Set markers accordingly.
-          if (shellmark(neighsh) == 0) {
-            setshellmark(neighsh, 1);
-          }
+        // Dealloc newpt[i] if it exists.
+        if (newpt[i] != (point) NULL) {
+          pointdealloc(newpt[i]);
+          relverts--;
         }
       }
     }
-    // Remark the tetrahedron as infected, so it doesn't get added to the
-    //   virus pool again.
-    infect(testtet);
-    virusloop = (tetrahedron **) viri->traverse();
   }
+
+  // Delete work lists.
+  delete oldshlist;
+  delete newshlist;
+  for (i = 0; i < 2; i++) {
+    if (oldtetlist[i] != (list *) NULL) {
+      delete oldtetlist[i];
+      delete newtetlist[i];
+    }
+  }
+
+  return success;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// regionplague()    Spread regional attributes and/or volume constraints    //
-//                   (from a .poly file) throughout the mesh.                //
+// suppresssegpoint()    Suppress a point on a segment.                      //
 //                                                                           //
-// This procedure operates in two phases.  The first phase spreads an attri- //
-// bute and/or a volume constraint through a (facet-bounded) region.  The    //
-// second phase uninfects all infected tetrahedra, returning them to normal. //
+// The point p on a segment S will be suppressed from S by either being      //
+// deleted from the mesh or being relocated into the volume.                 //
+//                                                                           //
+// 'supseg' is the segment S, and p = sdest(S); the other parameters are     //
+// working lists which are empty at the beginning and the end.               //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::
-regionplague(memorypool *regionviri, REAL attribute, REAL volume)
+bool tetgenmesh::suppresssegpoint(face* supseg, list* spinshlist,
+  list* newsegshlist, list* frontlist, list* misfrontlist, list* ptlist,
+  list* conlist, memorypool* viri, queue* flipque)
 {
-  tetrahedron **virusloop;
-  tetrahedron **regiontet;
-  triface testtet, neighbor;
-  face neighsh;
+  list **oldtetlist, **newtetlist;
+  list **oldshlist, **newshlist;
+  list *pnewshlist, *dnewshlist;
+  triface oldtet, newtet;
+  face oldsh, newsh;
+  face startsh, spinsh, segsh1, segsh2;
+  face nsupseg, newseg, prevseg, nextseg;
+  point suppt, *newpt;
+  point pa, pb, *cons;
+  REAL norm[3], pnorm[2][3];
+  bool success;
+  int shmark;
+  int n, i, j, k;
 
+  // Get the Steiner point p.
+  assert(supseg->shver == 0);
+  suppt = sdest(*supseg);
+  // Find the segment ab split by p.
+  senext(*supseg, nsupseg);
+  spivotself(nsupseg);
+  assert(nsupseg.sh != dummysh);
+  nsupseg.shver = 0;
+  assert(sorg(nsupseg) == suppt);
+  pa = sorg(*supseg);
+  pb = sdest(nsupseg);
   if (b->verbose > 1) {
-    printf("  Marking neighbors of marked tetrahedra.\n");
+    printf("    Remove point %d on segment (%d, %d).\n",
+           pointmark(suppt), pointmark(pa), pointmark(pb));
   }
-  // Loop through all the infected tetrahedra, spreading the attribute
-  //   and/or volume constraint to their neighbors, then to their neighbors'
-  //   neighbors.
-  regionviri->traversalinit();
-  virusloop = (tetrahedron **) regionviri->traverse();
-  while (virusloop != (tetrahedron **) NULL) {
-    testtet.tet = *virusloop;
-    // Temporarily uninfect this tetrahedron, not necessary.
-    uninfect(testtet);
-    if (b->regionattrib) {
-      // Set an attribute.
-      setelemattribute(testtet.tet, in->numberoftetrahedronattributes,
-                       attribute);
+
+  // Let startsh s containing p.
+  spivot(*supseg, startsh);
+  spinsh = startsh;
+  do {
+    // Save it in list.
+    spinshlist->append(&spinsh);
+    // Go to the next facet.
+    spivotself(spinsh);
+  } while (spinsh.sh != startsh.sh);
+  if (spinshlist->len() == 1) {
+    // This case has not handled yet.
+    // printf("Unhandled case: segment only belongs to one facet.\n");
+    spinshlist->clear();
+    unsupverts++;
+    return false;
+  }
+
+  // Suppose ab is shared by n facets (n > 1), then there are n B(p) (tets
+  //   with p as a vertex). Some B(p) may be empty, eg, outside.
+  n = spinshlist->len();
+  oldtetlist = new list*[n];
+  newtetlist = new list*[n];
+  oldshlist = new list*[n];
+  newshlist = new list*[n];
+  newpt = new point[n];
+  for (i = 0; i < n; i++) {
+    oldtetlist[i] = (list *) NULL;
+    newtetlist[i] = (list *) NULL;
+    oldshlist[i] = (list *) NULL;
+    newshlist[i] = (list *) NULL;
+    newpt[i] = (point) NULL;
+  }
+
+  // Create a new segment ab (result in newseg).
+  makeshellface(subsegs, &newseg);
+  setsorg(newseg, pa);
+  setsdest(newseg, pb);
+  // ab gets the same mark and segment type as ap.
+  setshellmark(newseg, shellmark(*supseg));
+  setshelltype(newseg, shelltype(*supseg));
+  if (b->quality && varconstraint) {
+    // Copy the areabound into the new subsegment.
+    setareabound(newseg, areabound(*supseg));
+  }
+  // Save the old connection at a.
+  senext2(*supseg, prevseg);
+  spivotself(prevseg);
+  if (prevseg.sh != dummysh) {
+    prevseg.shver = 0;
+    assert(sdest(prevseg) == pa);
+    senextself(prevseg);
+    senext2self(newseg);
+    sbond(newseg, prevseg);
+    newseg.shver = 0;
+  }
+  // Save the old connection at b.
+  senext(nsupseg, nextseg);
+  spivotself(nextseg);
+  if (nextseg.sh != dummysh) {
+    nextseg.shver = 0;
+    assert(sorg(nextseg) == pb);
+    senext2self(nextseg);
+    senextself(newseg);
+    sbond(newseg, nextseg);
+    newseg.shver = 0;
+  }
+
+  // Re-triangulate C(p) (subs with p as a vertex) to remove p.
+  for (i = 0; i < spinshlist->len(); i++) {
+    spinsh = * (face *)(* spinshlist)[i];
+    // Allocate spaces for C_i(p).
+    oldshlist[i] = new list(sizeof(face), NULL, 256);
+    newshlist[i] = new list(sizeof(face), NULL, 256);
+    // Get the subs of C_i(p).
+    oldshlist[i]->append(&spinsh);
+    formstarpolygon(suppt, oldshlist[i], ptlist);
+    // Find the edges of C_i(p). It DOES NOT form a closed polygon.
+    for (j = 0; j < oldshlist[i]->len(); j++) {
+      oldsh = * (face *)(* (oldshlist[i]))[j];    
+      cons = (point *) conlist->append(NULL);
+      cons[0] = sorg(oldsh);
+      cons[1] = sdest(oldsh);
+    }
+    // The C_i(p) isn't closed without ab. Add it to it.
+    cons = (point *) conlist->append(NULL);
+    cons[0] = pa;
+    cons[1] = pb;
+    // Re-triangulate C_i(p).
+    shmark = shellmark(spinsh);
+    triangulate(shmark, b->epsilon, ptlist, conlist, 0, NULL, viri, flipque);
+    // Get new subs of C_i(p), remove protected segments.
+    retrievenewsubs(newshlist[i], true);
+    // Substitute old C_i(p) with the new C_i(p). !IT IS NOT COMPLETE!
+    replacepolygonsubs(oldshlist[i], newshlist[i]);
+    // Find the new subface s having edge ab.
+    for (j = 0; j < newshlist[i]->len(); j++) {
+      segsh1 = * (face *)(* (newshlist[i]))[j];
+      for (k = 0; k < 3; k++) {
+        if (((sorg(segsh1) == pa) && (sdest(segsh1) == pb)) ||
+            ((sorg(segsh1) == pb) && (sdest(segsh1) == pa))) break;
+        senextself(segsh1);
+      }
+      if (k < 3) break; // Found.
+    }
+    assert(j < newshlist[i]->len()); // ab must exist.
+    // Bond s and ab together. The C_i(p) is completedly substituted.
+    ssbond(segsh1, newseg);
+    // Save s for forming the face ring of ab.
+    newsegshlist->append(&segsh1);
+    // Clear work lists.
+    ptlist->clear();
+    conlist->clear();
+    flipque->clear();
+    viri->restart();
+  }
+  // Form the face ring of ab.
+  for (i = 0; i < newsegshlist->len(); i++) {
+    segsh1 = * (face *)(* newsegshlist)[i];
+    if ((i + 1) == newsegshlist->len()) {
+      segsh2 = * (face *)(* newsegshlist)[0];
+    } else {
+      segsh2 = * (face *)(* newsegshlist)[i + 1];
+    }
+    sbond1(segsh1, segsh2);
+  }
+
+  // A work list for keeping subfaces from two facets.
+  dnewshlist = new list(sizeof(face), NULL, 256);
+  success = true; // Assume p is suppressable.
+
+  // Suppress p in all B(p). B_i(p) is looped wrt the right-hand rule of ab.
+  for (i = 0; i < spinshlist->len() && success; i++) {
+    // Get an old  subface s (ap) of a facet.
+    spinsh = * (face *)(* spinshlist)[i];
+    // Let the edge direction of s be a->b. Hence all subfaces follow
+    //   the right-hand rule of ab.
+    if (sorg(spinsh) != pa) sesymself(spinsh);
+    // Get a tet t of B_i(p).
+    stpivot(spinsh, oldtet);
+    // Is B_i(p) empty?
+    if (oldtet.tet == dummytet) continue;
+    // Allocate spaces for B_i(p).
+    oldtetlist[i] = new list(sizeof(triface), NULL, 256);
+    newtetlist[i] = new list(sizeof(triface), NULL, 256);
+    // Find all tets of old B_i(p).
+    oldtetlist[i]->append(&oldtet);
+    formstarpolyhedron(suppt, oldtetlist[i], ptlist, false);
+    // Infect tets of old B_i(p) (they're going to be deleted).
+    for (j = 0; j < oldtetlist[i]->len(); j++) {
+      oldtet = * (triface *)(* (oldtetlist[i]))[j];
+      infect(oldtet);
+    }
+    // Collect new subfaces (of two facets) bounded B_i(p).
+    for (k = 0; k < 2; k++) {
+      if ((i + k) < spinshlist->len()) {
+        pnewshlist = newshlist[i + k];
+        segsh1 = * (face *)(* spinshlist)[i + k];
+      } else {
+        pnewshlist = newshlist[0];
+        segsh1 = * (face *)(* spinshlist)[0];
+      }
+      // Adjust the orientation of segsh1 to face to the inside of C.
+      if (k == 0) {
+        if (sorg(segsh1) != pa) sesymself(segsh1);
+        assert(sorg(segsh1) == pa);
+      } else {
+        if (sdest(segsh1) != pa) sesymself(segsh1);
+        assert(sdest(segsh1) == pa);
+      }
+      // Preparation for re-tetrahedralzing old B_i(p).
+      orientnewsubs(pnewshlist, &segsh1, pnorm[k]);
+      for (j = 0; j < pnewshlist->len(); j++) {
+        dnewshlist->append((face *)(* pnewshlist)[j]);
+      }
+    }
+    // Tetrahedralize B_i(p).
+    if (!constrainedcavity(&oldtet, dnewshlist, oldtetlist[i], ptlist,
+          frontlist, misfrontlist, newtetlist[i], flipque)) {
+      // C must be finished by re-locating the steiner point.
+      makepoint(&(newpt[i]));
+      for (j = 0; j < 3; j++) norm[j] = 0.5 * (pnorm[0][j] + pnorm[1][j]);
+      success = findrelocatepoint(suppt, newpt[i], norm, frontlist,
+                                  oldtetlist[i]);
+      if (success) {
+        // p is relocated by newpt[i]. Now insert it. Don't do flip since
+        //   the new tets may get deleted again.
+        relocatepoint(newpt[i], &oldtet, frontlist, newtetlist[i], NULL);
+        setpointtype(newpt[i], FREEVOLVERTEX);
+        relverts++;
+      } else {
+        // Fail to relocate p. Clean fake tets and quit this option.
+        deallocfaketets(frontlist);
+        pointdealloc(newpt[i]);
+        newpt[i] = (point) NULL;
+        assert(newtetlist[i]->len() == 0);
+      }
+    }
+    // Clear work lists.
+    dnewshlist->clear();
+    ptlist->clear();
+    frontlist->clear();
+    misfrontlist->clear();
+    flipque->clear();
+  }
+
+  if (success) {
+    // p has been suppressed. (Still in the pool).
+    setpointtype(suppt, UNUSEDVERTEX);
+    unuverts++;
+    // Delete old segments ap, pb.
+    shellfacedealloc(subsegs, supseg->sh);
+    shellfacedealloc(subsegs, nsupseg.sh);
+    // Delete subs of old C_i(p).
+    for (i = 0; i < spinshlist->len(); i++) {
+      for (j = 0; j < oldshlist[i]->len(); j++) {
+        oldsh = * (face *)(* (oldshlist[i]))[j];
+        if (j == 0) {
+          // Update 'hullsize' if C_i(p) is on the hull.
+          stpivot(oldsh, oldtet);
+          if (oldtet.tet != dummytet) {
+            sesymself(oldsh);
+            stpivot(oldsh, oldtet);
+          }
+          if (oldtet.tet == dummytet) {
+            // Update 'hullsize'.
+            k = oldshlist[i]->len() - newshlist[i]->len();
+            assert(k > 0);
+            hullsize -= k;
+          }
+        }
+        shellfacedealloc(subfaces, oldsh.sh);
+      }
     }
-    if (b->varvolume) {
-      // Set a volume constraint.
-      setvolumebound(testtet.tet, volume);
+    // Delete tets old B_i(p).
+    for (i = 0; i < spinshlist->len(); i++) {
+      // Delete them if it is not empty.
+      if (oldtetlist[i] != (list *) NULL) {
+        for (j = 0; j < oldtetlist[i]->len(); j++) {
+          oldtet = * (triface *)(* (oldtetlist[i]))[j];
+          assert(!isdead(&oldtet));
+          tetrahedrondealloc(oldtet.tet);
+        }
+      }
     }
-    // Check each of the tetrahedron's four neighbors.
-    for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) {
-      // Find the neighbor.
-      sym(testtet, neighbor);
-      // Check for a subface between the tetrahedron and its neighbor.
-      tspivot(testtet, neighsh);
-      // Make sure the neighbor exists, is not already infected, and
-      //   isn't protected by a subface, or is protected by a nonsolid
-      //   subface.
-      if ((neighbor.tet != dummytet) && !infected(neighbor)
-          && (neighsh.sh == dummysh)) {
-        // Infect the neighbor.
-        infect(neighbor);
-        // Ensure that the neighbor's neighbors will be infected.
-        regiontet = (tetrahedron **) regionviri->alloc();
-        *regiontet = neighbor.tet;
+  } else {
+    // p is not suppressed. Recover the original state.
+    unsupverts++;
+    // Restore old connection at a.
+    senext2(*supseg, prevseg);
+    spivotself(prevseg);
+    if (prevseg.sh != dummysh) {
+      prevseg.shver = 0;
+      assert(sdest(prevseg) == pa);
+      senextself(prevseg);
+      senext2self(*supseg);
+      sbond(*supseg, prevseg);
+      supseg->shver = 0;
+    }
+    // Restore old connection at b.
+    senext(nsupseg, nextseg);
+    spivotself(nextseg);
+    if (nextseg.sh != dummysh) {
+      nextseg.shver = 0;
+      assert(sorg(nextseg) == pb);
+      senext2self(nextseg);
+      senextself(nsupseg);
+      sbond(nsupseg, nextseg);
+      nsupseg.shver = 0;
+    }
+    // Delete the new segment ab.
+    shellfacedealloc(subsegs, newseg.sh);
+    // Restore old C_i(p).
+    for (i = 0; i < spinshlist->len(); i++) {
+      replacepolygonsubs(newshlist[i], oldshlist[i]);
+      // Delete subs of the new C_i(p)
+      for (j = 0; j < newshlist[i]->len(); j++) {
+        newsh = * (face *)(* (newshlist[i]))[j];
+        shellfacedealloc(subfaces, newsh.sh);
+      }
+    }
+    // Restore old B_i(p).
+    for (i = 0; i < spinshlist->len(); i++) {
+      if (oldtetlist[i] != (list *) NULL) {
+        // Uninfect tets of old B_i(p).
+        for (j = 0; j < oldtetlist[i]->len(); j++) {
+          oldtet = * (triface *)(* (oldtetlist[i]))[j];
+          assert(infected(oldtet));
+          uninfect(oldtet);
+        }
+        // Has it been re-meshed?
+        if (newtetlist[i]->len() > 0) {
+          // Restore the old B_i(p).
+          restorepolyhedron(oldtetlist[i]);
+          // Delete tets of the new B_i(p);
+          for (j = 0; j < newtetlist[i]->len(); j++) {
+            newtet = * (triface *)(* (newtetlist[i]))[j];
+            // Some new tets may already be deleted (by carvecavity()).
+            if (!isdead(&newtet)) {
+              tetrahedrondealloc(newtet.tet);
+            }
+          }
+        }
+        // Dealloc newpt[i] if it exists.
+        if (newpt[i] != (point) NULL) {
+          pointdealloc(newpt[i]);
+          relverts--;
+        }
       }
     }
-    // Remark the tetrahedron as infected, so it doesn't get added to the
-    //   virus pool again.
-    infect(testtet);
-    virusloop = (tetrahedron **) regionviri->traverse();
   }
 
-  // Uninfect all tetrahedra.
-  if (b->verbose > 1) {
-    printf("  Unmarking marked tetrahedra.\n");
-  }
-  regionviri->traversalinit();
-  virusloop = (tetrahedron **) regionviri->traverse();
-  while (virusloop != (tetrahedron **) NULL) {
-    testtet.tet = *virusloop;
-    uninfect(testtet);
-    virusloop = (tetrahedron **) regionviri->traverse();
+  // Delete work lists.
+  delete dnewshlist;
+  for (i = 0; i < spinshlist->len(); i++) {
+    delete oldshlist[i];
+    delete newshlist[i];
+  } 
+  delete [] oldshlist;
+  delete [] newshlist;
+  for (i = 0; i < spinshlist->len(); i++) {
+    if (oldtetlist[i] != (list *) NULL) {
+      delete oldtetlist[i];
+      delete newtetlist[i];
+    }
   }
-  // Empty the virus pool.
-  regionviri->restart();
+  delete [] oldtetlist;
+  delete [] newtetlist;
+  // Clear work lists.
+  newsegshlist->clear();
+  spinshlist->clear();
+
+  return success;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// removeholetets()    Remove tetrahedra which are outside the domain.       //
+// 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.                                            //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::removeholetets(memorypool* viri)
+bool tetgenmesh::suppressvolpoint(point suppt, list* frontlist,
+  list* misfrontlist, list* ptlist, queue* flipque)
 {
-  tetrahedron **virusloop;
-  triface testtet, neighbor;
-  point checkpt;
-  int *tetspernodelist;
-  int i, j;
-
-  if (b->verbose) {
-    printf("  Deleting marked tetrahedra.\n");
-  }
+  list *oldtetlist, *newtetlist;
+  list *newshlist; // a dummy list.
+  tetrahedron tetptr;
+  triface oldtet, newtet;
+  bool success;
+  int j;
 
-  // Create and initialize 'tetspernodelist'.
-  tetspernodelist = new int[points->items + 1];
-  for (i = 0; i < points->items + 1; i++) tetspernodelist[i] = 0;
-  
-  // Loop the tetrahedra list, counter the number of tets sharing each node.
-  tetrahedrons->traversalinit();
-  testtet.tet = tetrahedrontraverse();
-  while (testtet.tet != (tetrahedron *) NULL) {
-    // Increment the number of sharing tets for each endpoint.
-    for (i = 0; i < 4; i++) {
-      j = pointmark((point) testtet.tet[4 + i]);
-      tetspernodelist[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;
     }
-    testtet.tet = tetrahedrontraverse();
   }
 
-  viri->traversalinit();
-  virusloop = (tetrahedron **) viri->traverse();
-  while (virusloop != (tetrahedron **) NULL) {
-    testtet.tet = *virusloop;
-    // Record changes in the number of boundary faces, and disconnect
-    //   dead tetrahedra from their neighbors.
-    for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) {
-      sym(testtet, neighbor);
-      if (neighbor.tet == dummytet) {
-        // There is no neighboring tetrahedron on this face, so this face
-        //   is a boundary face.  This tetrahedron is being deleted, so this
-        //   boundary face is deleted.
-        hullsize--;
-      } else {
-        // Disconnect the tetrahedron from its neighbor.
-        dissolve(neighbor);
-        // There is a neighboring tetrahedron on this face, so this face
-        //   becomes a boundary face when this tetrahedron is deleted.
-        hullsize++;
-      }
+  // 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);
+  success = true; // Assume p can be suppressed.
+
+  // Form old B(p) in oldtetlist.
+  oldtetlist->append(&oldtet);
+  formstarpolyhedron(suppt, oldtetlist, ptlist, false);
+  // Infect the tets in old B(p) (they're going to be delete).
+  for (j = 0; j < oldtetlist->len(); j++) {
+    oldtet = * (triface *)(* oldtetlist)[j];
+    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.
+    deallocfaketets(frontlist);
+    assert(newtetlist->len() == 0);
+  }
+  // Clear work lists.
+  ptlist->clear();
+  frontlist->clear();
+  misfrontlist->clear();
+  flipque->clear();
+
+  if (success) {
+    // p has been removed! (Still in the pool).
+    setpointtype(suppt, UNUSEDVERTEX);
+    unuverts++;
+    suprelverts++;
+    // Delete old B(p).
+    for (j = 0; j < oldtetlist->len(); j++) {
+      oldtet = * (triface *)(* oldtetlist)[j];
+      assert(!isdead(&oldtet));
+      tetrahedrondealloc(oldtet.tet);
     }
-    // Check the four corners of this tet if they're isolated.
-    for (i = 0; i < 4; i++) {
-      checkpt = (point) testtet.tet[4 + i];
-      j = pointmark(checkpt);
-      tetspernodelist[j]--;
-      if (tetspernodelist[j] == 0) {
-        setpointtype(checkpt, UNUSEDVERTEX);
-        unuverts++;
-      }
+  } else {
+    // p is not suppressed. Recover the original state.
+    // Uninfect tets of old B(p).
+    for (j = 0; j < oldtetlist->len(); j++) {
+      oldtet = * (triface *)(* oldtetlist)[j];
+      assert(infected(oldtet));
+      uninfect(oldtet);
     }
-    // Return the dead tetrahedron to the pool of tetrahedra.
-    tetrahedrondealloc(testtet.tet);
-    virusloop = (tetrahedron **) viri->traverse();
   }
-  
-  delete [] tetspernodelist;
+
+  delete oldtetlist;
+  delete newtetlist;
+  delete newshlist;
+
+  return success;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// carveholes()    Find the holes and infect them.  Find the volume          //
-//                 constraints and infect them.  Infect the convex hull.     //
-//                 Spread the infection and kill tetrahedra.  Spread the     //
-//                 volume constraints.                                       //
+// collapseedgepoint()    Delete a point by edge collapse.                   //
 //                                                                           //
-// This routine mainly calls other routines to carry out all these functions.//
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::collapseedgepoint(point colpt, list *oldtetlist, 
+  list* deadtetlist, list *ptlist)
+{
+  tetrahedron tetptr;
+  triface oldtet, newtet;
+  point conpt;
+  bool success;
+
+  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;
+    }
+  }
+
+  // Form old B(p) in oldtetlist.
+  oldtetlist->append(&oldtet);
+  formstarpolyhedron(colpt, oldtetlist, ptlist, false);
+  // Try to collapse p.
+  success = findcollapseedge(colpt, &conpt, oldtetlist, ptlist);
+  if (success) {
+    // Collapse p by edge contraction.
+    collapseedge(colpt, conpt, oldtetlist, deadtetlist);
+    collapverts++;
+    // p has been removed! (Still in the pool).
+    setpointtype(colpt, UNUSEDVERTEX);
+    unuverts++;
+    deadtetlist->clear();
+  }
+  oldtetlist->clear();
+  ptlist->clear();
+
+  return success;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// removesteiners()    Delete or relocate Steiner points on facets.          //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::carveholes()
+void tetgenmesh::removesteiners()
 {
-  memorypool *holeviri, *regionviri;
-  tetrahedron *tptr, **holetet, **regiontet;
-  triface searchtet, *holetets, *regiontets;
-  enum locateresult intersect;
+  list *frontlist, *misfrontlist;
+  list *spinshlist, *newsegshlist;
+  list *ptlist, *conlist;
+  memorypool *viri;
+  queue *flipque;
+  triface checktet;
+  face shloop;
+  face segloop, nextseg;
+  point pa;
+  bool remflag;
+  int oldnum, rmstein;
   int i;
 
+  // Initiliaze work lists.
+  frontlist = new list(sizeof(triface), NULL);
+  misfrontlist = new list(sizeof(triface), NULL);
+  spinshlist = new list(sizeof(face), NULL);
+  newsegshlist = new list(sizeof(face), NULL);
+  ptlist = new list(sizeof(point *), NULL);
+  conlist = new list(sizeof(point *) * 2, NULL);
+  flipque = new queue(sizeof(badface));
+  viri = new memorypool(sizeof(shellface *), 1024, POINTER, 0);
+  oldnum = unuverts;
+  relverts = suprelverts = collapverts = unsupverts = 0;
+  expcavcount = 0;
+
   if (!b->quiet) {
-    printf("Removing unwanted tetrahedra.\n");
-    if (b->verbose && (in->numberofholes > 0)) {
-      printf("  Marking holes for elimination.\n");
-    }
+    printf("Removing Steiner points.\n");
   }
 
-  // Initialize a pool of viri to be used for holes, concavities.
-  holeviri = new memorypool(sizeof(tetrahedron *), 1024, POINTER, 0);
-  // Mark as infected any unprotected tetrahedra on the boundary.
-  infecthull(holeviri);
-
-  if (in->numberofholes > 0) {
-    // Allocate storage for the tetrahedra in which hole points fall.
-    holetets = (triface *) new triface[in->numberofholes];
-    // Infect each tetrahedron in which a hole lies.
-    for (i = 0; i < 3 * in->numberofholes; i += 3) {
-      // Ignore holes that aren't within the bounds of the mesh.
-      if ((in->holelist[i] >= xmin) && (in->holelist[i] <= xmax)
-          && (in->holelist[i + 1] >= ymin)
-          && (in->holelist[i + 1] <= ymax)
-          && (in->holelist[i + 2] >= zmin)
-          && (in->holelist[i + 2] <= zmax)) {
-        searchtet.tet = dummytet;
-        // Find a tetrahedron that contains the hole.
-        intersect = locate(&in->holelist[i], &searchtet);
-        if ((intersect != OUTSIDE) && (!infected(searchtet))) {
-          // Record the tetrahedron for processing carve hole.
-          holetets[i / 3] = searchtet;
+  // Suppress Steiner points inside facets.
+  do {
+    rmstein = unuverts;
+    subfaces->traversalinit();
+    shloop.sh = shellfacetraverse(subfaces);
+    while (shloop.sh != (shellface *) NULL) {
+      remflag = false;
+      // Is s contains a Steiner point?
+      shloop.shver = 0;
+      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);
+            }
+            remflag = (checktet.tet == dummytet);
+          } else {
+            // '-YY'. Remove p whatever s is a hull face or not.
+            remflag = true;
+          }
+          break;
         }
+        senextself(shloop);
       }
+      if (remflag) {
+        suppressfacetpoint(&shloop, frontlist, misfrontlist, ptlist, conlist,
+                           viri, flipque);
+      }
+      shloop.sh = shellfacetraverse(subfaces);
     }
-    // Infect the hole tetrahedron.  This is done by marking the tet as
-    //   infected and including the tetrahedron in the virus pool.
-    for (i = 0; i < in->numberofholes; i++) {
-      infect(holetets[i]);
-      holetet = (tetrahedron **) holeviri->alloc();
-      *holetet = holetets[i].tet;
-    }
-    // Free up memory.
-    delete [] holetets;
-  }
-
-  // Mark as infected all tets of the holes and concavities.
-  plague(holeviri);
-  // The virus pool contains all outside tets now.
+    // Continue if any Steiner point has been removed.
+  } while (unuverts > rmstein);
 
-  if (in->numberofregions > 0) {
-    if (!b->quiet) {
-      if (b->regionattrib) {
-        if (b->varvolume) {
-          printf("Spreading regional attributes and volume constraints.\n");
+  // Suppress Steiner points on segments.
+  do {
+    rmstein = unuverts;
+    subsegs->traversalinit();
+    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;
+            }
+          } while (pa != apex(checktet));
         } else {
-          printf("Spreading regional attributes.\n");
+          // '-YY'. Remove p whatever it is on the hull or not.
+          remflag = true;
         }
-      } else {
-        printf("Spreading regional volume constraints.\n");
       }
-    }
-    // Allocate storage for the tetrahedra in which region points fall.
-    regiontets = (triface *) new triface[in->numberofregions];
-    // Find the starting tetrahedron for each region.
-    for (i = 0; i < in->numberofregions; i++) {
-      regiontets[i].tet = dummytet;
-      // Ignore region points that aren't within the bounds of the mesh.
-      if ((in->regionlist[5 * i] >= xmin)
-           && (in->regionlist[5 * i] <= xmax)
-           && (in->regionlist[5 * i + 1] >= ymin)
-           && (in->regionlist[5 * i + 1] <= ymax)
-           && (in->regionlist[5 * i + 2] >= zmin)
-           && (in->regionlist[5 * i + 2] <= zmax)) {
-        searchtet.tet = dummytet;
-        // Find a tetrahedron that contains the region point.
-        intersect = locate(&in->regionlist[5 * i], &searchtet);
-        if ((intersect != OUTSIDE) && (!infected(searchtet))) {
-          // Record the tetrahedron for processing after the
-          //   holes have been carved.
-          regiontets[i] = searchtet;
-        }
+      if (remflag) {
+        suppresssegpoint(&segloop, spinshlist, newsegshlist, frontlist,
+                         misfrontlist, ptlist, conlist, viri, flipque);
       }
+      segloop.sh = shellfacetraverse(subsegs);
     }
-    if (b->regionattrib && !b->refine) {
-      // Assign every tetrahedron a regional attribute of zero.
-      tetrahedrons->traversalinit();
-      tptr = tetrahedrontraverse();
-      while (tptr != (tetrahedron *) NULL) {
-        setelemattribute(tptr, in->numberoftetrahedronattributes, 0.0);
-        tptr = tetrahedrontraverse();
+    // Continue if any Steiner point has been removed.
+  } while (unuverts > rmstein);
+
+  if (relverts > 0) {
+    // Suppress relocated points.
+    do {
+      rmstein = unuverts;
+      points->traversalinit();
+      pa = pointtraverse();
+      while (pa != (point) NULL) {
+        remflag = (pointtype(pa) == FREEVOLVERTEX);
+        if (remflag) {
+          suppressvolpoint(pa, frontlist, misfrontlist, ptlist, flipque);
+        }
+        pa = pointtraverse();
       }
-    }
-    // Initialize a pool to be used for regional attrs, and/or regional
-    //   volume constraints.
-    regionviri = new memorypool(sizeof(tetrahedron *), 1024, POINTER, 0);
-    // Find and set all regions.
-    for (i = 0; i < in->numberofregions; i++) {
-      if (regiontets[i].tet != dummytet) {
-        // Make sure the tetrahedron under consideration still exists.
-        //   It may have been eaten by the virus.
-        if (!isdead(&(regiontets[i]))) {
-          // Put one tetrahedron in the virus pool.
-          infect(regiontets[i]);
-          regiontet = (tetrahedron **) regionviri->alloc();
-          *regiontet = regiontets[i].tet;
-          // Apply one region's attribute and/or volume constraint.
-          regionplague(regionviri, in->regionlist[5 * i + 3],
-                       in->regionlist[5 * i + 4]);
-          // The virus pool should be empty now.
+      // 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();
       }
+      // Continue if any relocated point has been suppressed.
+    } while (unuverts > rmstein);
+  } */
+
+  if (b->verbose > 0) {
+    printf("  %d points removed from boundary.\n", unuverts - oldnum);
+    if (relverts > 0) {
+      printf("  %d points relocated into volume.\n", relverts);
     }
-    if (b->regionattrib && !b->refine) {
-      // Note the fact that each tetrahedron has an additional attribute.
-      in->numberoftetrahedronattributes++;
+    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);
     }
-    // Free up memory.
-    delete [] regiontets;
-    delete regionviri;
   }
-
-  // Now acutually remove the outside and hole tets.
-  removeholetets(holeviri);
-  // The mesh is nonconvex now.
-  nonconvex = 1;
-
-  // Free up memory.
-  delete holeviri;
+  
+  // Delete work lists.
+  delete frontlist;
+  delete misfrontlist;
+  delete spinshlist;
+  delete newsegshlist;
+  delete ptlist;
+  delete conlist;
+  delete flipque;
+  delete viri;
 }
 
 //
-// End of carving out holes and concavities routines
+// End of boundary Steiner points removing routines
 //
 
 //
@@ -19544,18 +24021,20 @@ long tetgenmesh::reconstructmesh()
     if (sign > 0.0) {
       norg = torg; torg = tdest; tdest = norg;
     } else if (sign == 0.0) {
-      printf("Warning:  Tetrahedron %d is degenerate.\n", i + in->firstnumber);
+      if (!b->quiet) {
+        printf("Warning:  Tet %d is degenerate.\n", i + in->firstnumber);
+      }
     }
     setorg(tetloop, torg);
     setdest(tetloop, tdest);
     setapex(tetloop, tapex);
     setoppo(tetloop, toppo);
-    // Temporarily set the vertices be type FREEVOLVERTEX, to indicate that
+    // Temporarily set the vertices be type VOLVERTEX, to indicate that
     //   they belong to the mesh.  These types may be changed later.
-    setpointtype(torg, FREEVOLVERTEX);
-    setpointtype(tdest, FREEVOLVERTEX);
-    setpointtype(tapex, FREEVOLVERTEX);
-    setpointtype(toppo, FREEVOLVERTEX);
+    setpointtype(torg, VOLVERTEX);
+    setpointtype(tdest, VOLVERTEX);
+    setpointtype(tapex, VOLVERTEX);
+    setpointtype(toppo, VOLVERTEX);
     // Set element attributes if they exist.
     for (j = 0; j < in->numberoftetrahedronattributes; j++) {
       index = i * in->numberoftetrahedronattributes;
@@ -19647,7 +24126,12 @@ long tetgenmesh::reconstructmesh()
     tetloop.tet = tetrahedrontraverse();
   }
 
-  // Subfaces will be inserted into the mesh.
+  // Subfaces will be inserted into the mesh. It has two phases:
+  //   (1) Insert subfaces provided by user (in->trifacelist);
+  //   (2) Create subfaces for hull faces (if they're not subface yet) and
+  //       interior faces which separate two different materials.
+
+  // Phase (1). Is there a list of user-provided subfaces?
   if (in->trifacelist != (int *) NULL) {
     // Recover subfaces from 'in->trifacelist'.
     for (i = 0; i < in->numberoftrifaces; i++) {
@@ -19703,61 +24187,63 @@ long tetgenmesh::reconstructmesh()
           tsbond(neineightet, subloop);
         }
       } else {
-        printf("Warning:  Subface %d is discarded.\n", i + in->firstnumber);
+        if (!b->quiet) {
+          printf("Warning:  Subface %d is discarded.\n", i + in->firstnumber);
+        }
       }
       worklist[iorg] = 0;
       worklist[idest] = 0;
       worklist[iapex] = 0;
     }
-  } else {
-    // Indentify subfaces from the mesh.
-    tetrahedrons->traversalinit();
-    tetloop.tet = tetrahedrontraverse();
-    while (tetloop.tet != (tetrahedron *) NULL) {
-      // Loop the four sides of the tetrahedron.
-      for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
-        tspivot(tetloop, subloop);
-        if (subloop.sh != dummysh) continue;
-        bondflag = false;
-        sym(tetloop, neightet);
-        if (neightet.tet == dummytet) {
-          // It's a hull face. Insert a subface at here.
-          bondflag = true;
-        } else {
-          // It's an interior face. Insert a subface if two tetrahedra have
-          //   different attributes (i.e., they belong to two regions).
-          if (in->numberoftetrahedronattributes > 0) {
-            if (elemattribute(neightet.tet,
-                in->numberoftetrahedronattributes - 1) != 
-                elemattribute(tetloop.tet,
-                in->numberoftetrahedronattributes - 1)) {
-              bondflag = true;
-            }
+  } 
+
+  // Phase (2). Indentify subfaces from the mesh.
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    // Loop the four sides of the tetrahedron.
+    for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
+      tspivot(tetloop, subloop);
+      if (subloop.sh != dummysh) continue;
+      bondflag = false;
+      sym(tetloop, neightet);
+      if (neightet.tet == dummytet) {
+        // It's a hull face. Insert a subface at here.
+        bondflag = true;
+      } else {
+        // It's an interior face. Insert a subface if two tetrahedra have
+        //   different attributes (i.e., they belong to two regions).
+        if (in->numberoftetrahedronattributes > 0) {
+          if (elemattribute(neightet.tet,
+              in->numberoftetrahedronattributes - 1) != 
+              elemattribute(tetloop.tet,
+              in->numberoftetrahedronattributes - 1)) {
+            bondflag = true;
           }
         }
-        if (bondflag) {
-          adjustedgering(tetloop, CCW);
-          makeshellface(subfaces, &subloop);
-          torg = org(tetloop);
-          tdest = dest(tetloop);
-          tapex = apex(tetloop);
-          setsorg(subloop, torg);
-          setsdest(subloop, tdest);
-          setsapex(subloop, tapex);
-          // Set the vertices be FACETVERTEX to indicate they belong to a
-          //   facet of the domain.  They may be changed later.
-          setpointtype(torg, FACETVERTEX);
-          setpointtype(tdest, FACETVERTEX);
-          setpointtype(tapex, FACETVERTEX);
-          tsbond(tetloop, subloop);
-          if (neightet.tet != dummytet) {
-            sesymself(subloop);
-            tsbond(neightet, subloop);
-          }
+      }
+      if (bondflag) {
+        adjustedgering(tetloop, CCW);
+        makeshellface(subfaces, &subloop);
+        torg = org(tetloop);
+        tdest = dest(tetloop);
+        tapex = apex(tetloop);
+        setsorg(subloop, torg);
+        setsdest(subloop, tdest);
+        setsapex(subloop, tapex);
+        // Set the vertices be FACETVERTEX to indicate they belong to a
+        //   facet of the domain.  They may be changed later.
+        setpointtype(torg, FACETVERTEX);
+        setpointtype(tdest, FACETVERTEX);
+        setpointtype(tapex, FACETVERTEX);
+        tsbond(tetloop, subloop);
+        if (neightet.tet != dummytet) {
+          sesymself(subloop);
+          tsbond(neightet, subloop);
         }
       }
-      tetloop.tet = tetrahedrontraverse();
     }
+    tetloop.tet = tetrahedrontraverse();
   }
 
   // Set the connection between subfaces. A subsegment may have more than
@@ -19848,7 +24334,9 @@ long tetgenmesh::reconstructmesh()
           insertsegflag = true;
         } else {
           // Only two subfaces case.
+#ifdef SELF_CHECK
           assert(subloop.sh != neighsh.sh);
+#endif
           napex = sapex(neighsh);
           sign = orient3d(torg, tdest, tapex, napex);
           if (iscoplanar(torg, tdest, tapex, napex, sign, b->epsilon)) {
@@ -19885,7 +24373,7 @@ long tetgenmesh::reconstructmesh()
     subloop.sh = shellfacetraverse(subfaces);
   }
   // Remember the number of input segments.
-  insegment = subsegs->items;
+  insegments = subsegs->items;
   // Find the acute vertices and set them be type ACUTEVERTEX.
 
   // Indentify facets and set the facet marker (1-based) for subfaces.
@@ -19912,7 +24400,9 @@ long tetgenmesh::reconstructmesh()
             spivot(neighsh, neineighsh);
             if (!sinfected(neineighsh)) {
               // 'neineighsh' is in the same facet as 'subloop'.
+#ifdef SELF_CHECK
               assert(shellmark(neineighsh) == marker);
+#endif
               setshellmark(neineighsh, facetidx);
               sinfect(neineighsh);
               neighshlist->append(&neineighsh);
@@ -19925,82 +24415,91 @@ long tetgenmesh::reconstructmesh()
     }
     subloop.sh = shellfacetraverse(subfaces);
   }
-  // Save the facet markers in 'in->facetmarkerlist'.
-  in->numberoffacets = markerlist->len();
-  in->facetmarkerlist = new int[in->numberoffacets];
-  for (i = 0; i < in->numberoffacets; i++) {
-    marker = * (int *) (* markerlist)[i];
-    in->facetmarkerlist[i] = marker;
-  }
   // Uninfect all subfaces.
   subfaces->traversalinit();
   subloop.sh = shellfacetraverse(subfaces);
   while (subloop.sh != (shellface *) NULL) {
+#ifdef SELF_CHECK
     assert(sinfected(subloop));
+#endif
     suninfect(subloop);
     subloop.sh = shellfacetraverse(subfaces);
   }
+  // Save the facet markers in 'in->facetmarkerlist'.
+  in->numberoffacets = markerlist->len();
+  in->facetmarkerlist = new int[in->numberoffacets];
+  for (i = 0; i < in->numberoffacets; i++) {
+    marker = * (int *) (* markerlist)[i];
+    in->facetmarkerlist[i] = marker;
+  }
+  // Initialize the 'facetabovepointlist'.
+  facetabovepointarray = new point[in->numberoffacets + 1];
+  for (i = 0; i < in->numberoffacets + 1; i++) {
+    facetabovepointarray[i] = (point) NULL;
+  }
 
   // The mesh contains boundary now.
   checksubfaces = 1;
+  // The mesh is nonconvex now.
+  nonconvex = 1;
 
   // Is there periodic boundary confitions?
   if (checkpbcs) {
-    if (in->pbcgrouplist != (tetgenio::pbcgroup *) NULL) {
-      tetgenio::pbcgroup *pg;
-      pbcdata *pd;
-      // Create 'subpbcgrouptable'.
-      createsubpbcgrouptable();
-      // Loop for each pbcgroup i.
-      for (i = 0; i < in->numberofpbcgroups; i++) {
-        pg = &(in->pbcgrouplist[i]);
-        pd = &(subpbcgrouptable[i]);
-        // Find all subfaces of pd, set each subface's group id be i.
-        for (j = 0; j < 2; j++) {
-          subfaces->traversalinit();
-          subloop.sh = shellfacetraverse(subfaces);
-          while (subloop.sh != (shellface *) NULL) {
-            facetidx = shellmark(subloop);
-            marker = in->facetmarkerlist[facetidx - 1];
-            if (marker == pd->fmark[j]) {
-              setshellpbcgroup(subloop, i);
-              pd->ss[j] = subloop;
-            }
-            subloop.sh = shellfacetraverse(subfaces);
+    tetgenio::pbcgroup *pg;
+    pbcdata *pd;
+    // Initialize the global array 'subpbcgrouptable'.
+    createsubpbcgrouptable();
+    // Loop for each pbcgroup i.
+    for (i = 0; i < in->numberofpbcgroups; i++) {
+      pg = &(in->pbcgrouplist[i]);
+      pd = &(subpbcgrouptable[i]);
+      // Find all subfaces of pd, set each subface's group id be i.
+      for (j = 0; j < 2; j++) {
+        subfaces->traversalinit();
+        subloop.sh = shellfacetraverse(subfaces);
+        while (subloop.sh != (shellface *) NULL) {
+          facetidx = shellmark(subloop);
+          marker = in->facetmarkerlist[facetidx - 1];
+          if (marker == pd->fmark[j]) {
+            setshellpbcgroup(subloop, i);
+            pd->ss[j] = subloop;
           }
+          subloop.sh = shellfacetraverse(subfaces);
         }
-        if (pg->pointpairlist != (int *) NULL) {
-          // Set the connections between pbc point pairs.
-          for (j = 0; j < pg->numberofpointpairs; j++) {
-            iorg = pg->pointpairlist[j * 2] - in->firstnumber;
-            idest = pg->pointpairlist[j * 2 + 1] - in->firstnumber;
-            torg = idx2verlist[iorg];
-            tdest = idx2verlist[idest];
-            setpoint2pbcpt(torg, tdest);
-            setpoint2pbcpt(tdest, torg);
-          }
+      }
+      if (pg->pointpairlist != (int *) NULL) {
+        // Set the connections between pbc point pairs.
+        for (j = 0; j < pg->numberofpointpairs; j++) {
+          iorg = pg->pointpairlist[j * 2] - in->firstnumber;
+          idest = pg->pointpairlist[j * 2 + 1] - in->firstnumber;
+          torg = idx2verlist[iorg];
+          tdest = idx2verlist[idest];
+          setpoint2pbcpt(torg, tdest);
+          setpoint2pbcpt(tdest, torg);
         }
       }
-      // Create 'segpbcgrouptable'.
-      createsegpbcgrouptable();
     }
+    // Create the global array 'segpbcgrouptable'.
+    createsegpbcgrouptable();
   }
 
-  if (b->quality && varconstraint) {
-    // Assign constraints on facets, segments, and nodes.
-    assignvarconstraints(idx2verlist);
-  }
+  // 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, false, false, false); 
+      flip(flipqueue, NULL); 
     }
     delete flipqueue;
   }
+  */
 
   delete markerlist;
   delete neighshlist;
@@ -20014,6 +24513,49 @@ long tetgenmesh::reconstructmesh()
   return hullsize;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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'.      //
@@ -20026,11 +24568,10 @@ void tetgenmesh::insertaddpoints()
   triface searchtet;
   face checksh, checkseg;
   point newpoint;
-  point p1, p2, p3, p4;
   enum locateresult loc;
-  REAL ori;
+  REAL *attr;
   int index;
-  int i;
+  int i, j;
   
   if (!b->quiet) {
     printf("Insert additional points into mesh.\n");
@@ -20046,6 +24587,12 @@ void tetgenmesh::insertaddpoints()
     newpoint[0] = in->addpointlist[index++];
     newpoint[1] = in->addpointlist[index++];
     newpoint[2] = in->addpointlist[index++];
+    // Copy new attributes (if available).
+    if(in->addpointattributelist != (REAL *) NULL) {
+      attr = in->addpointattributelist + in->numberofpointattributes * i;
+      for (j = 0; j < in->numberofpointattributes; j++)
+        newpoint[3 + j] = attr[j];
+    }
     // Find the location of the inserted point.
     searchtet = recenttet;
     loc = locate(newpoint, &searchtet);
@@ -20059,25 +24606,10 @@ void tetgenmesh::insertaddpoints()
       tetrahedrons->traversalinit();
       searchtet.tet = tetrahedrontraverse();
       while (searchtet.tet != (tetrahedron *) NULL) {
-        p1 = (point) searchtet.tet[4];
-        p2 = (point) searchtet.tet[5];
-        p3 = (point) searchtet.tet[6];
-        p4 = (point) searchtet.tet[7];
-        ori = orient3d(p2, p1, p3, newpoint);
-        if (ori >= 0) {
-          ori = orient3d(p1, p2, p4, newpoint);
-          if (ori >= 0) {
-            ori = orient3d(p2, p3, p4, newpoint);
-            if (ori >= 0) {
-              ori = orient3d(p3, p1, p4, newpoint);
-              if (ori >= 0) {
-                // 'newpoint' lies inside, or on a face, or on an edge, or
-                //   a vertex of 'searchtet'.
-                loc = adjustlocate(newpoint, &searchtet, OUTSIDE, b->epsilon);
-                if (loc != OUTSIDE) break;
-              }
-            }
-          }
+        if (intettest(newpoint, &searchtet, b->epsilon)) {
+          loc = adjustlocate(newpoint, &searchtet, OUTSIDE, b->epsilon);
+          assert(loc != OUTSIDE);
+          break;
         }
         searchtet.tet = tetrahedrontraverse();
       }
@@ -20085,7 +24617,7 @@ void tetgenmesh::insertaddpoints()
     // Insert the point if it not lies outside or on a vertex.
     switch (loc) {
     case INTETRAHEDRON:
-      setpointtype(newpoint, FREEVOLVERTEX);
+      setpointtype(newpoint, VOLVERTEX);
       splittetrahedron(newpoint, &searchtet, flipqueue);
       break;
     case ONFACE:
@@ -20101,531 +24633,230 @@ void tetgenmesh::insertaddpoints()
       tsspivot(&searchtet, &checkseg);
       if (checkseg.sh != dummysh) {
         setpointtype(newpoint, FREESEGVERTEX);
+        setpoint2sh(newpoint, sencode(checkseg));
       } else {
         tspivot(searchtet, checksh);
         if (checksh.sh != dummysh) {
           setpointtype(newpoint, FREESUBVERTEX);
         } else {
-          setpointtype(newpoint, FREEVOLVERTEX);
+          setpointtype(newpoint, VOLVERTEX);
         }
       }
       splittetedge(newpoint, &searchtet, flipqueue);
       break;
-    case ONVERTEX:
-      if (b->verbose) {
-        printf("Warning: Point (%.17g, %.17g, %.17g) falls on a vertex.\n",
-               newpoint[0], newpoint[1], newpoint[2]);
-      }
-      break;
-    case OUTSIDE:
-      if (b->verbose) {
-        printf("Warning: Point (%.17g, %.17g, %.17g) lies outside the mesh.\n",
-               newpoint[0], newpoint[1], newpoint[2]);
-      }
-      break;
-    }
-    // Remember the tetrahedron for next point searching.
-    recenttet = searchtet;
-    if (loc == ONVERTEX || loc == OUTSIDE) {
-      pointdealloc(newpoint);
-    } else {
-      flip(flipqueue, NULL, false, false, false);
-    }
-  }
-
-  delete flipqueue;
-}
-
-//
-// End of mesh reconstruction routines
-//
-
-//
-// Begin of mesh repair routines
-//
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// checktet4dege()    Check a tetrahedron to see if it is degenerate.        //
-//                                                                           //
-// A tetrahedron is degenerate if (1) it has a zero-volume; or (2) it has 2  //
-// faces on a facet. case (2) is caused by the vertices of a facet are not   //
-// exactly coplanar.                                                         //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-bool tetgenmesh::checktet4dege(triface* testtet, list* degetetlist)
-{
-  badface *degetet;
-  face checksh1, checksh2;
-  face checkseg;
-  point pa, pb, pc, pd;
-  REAL volume;
-  int shmark1, shmark2;
-  int i, j, k, l;
-
-  pa = org(*testtet);
-  pb = dest(*testtet);
-  pc = apex(*testtet);
-  pd = oppo(*testtet);
-  volume = orient3d(pb, pa, pc, pd);
-  // 'volume' should be non negative.
-  assert(volume >= 0.0);
-
-  if (volume != 0.0) {
-    // Check if it spans on one facet. That is, to look if there're two
-    //   subfaces of the tet which belong to the same facet.
-    for (i = 0; (i < 3) && (volume != 0); i++) {
-      sdecode((shellface) testtet->tet[8 + i], checksh1);
-      if (checksh1.sh != dummysh) {
-        shmark1 = shellmark(checksh1);
-        for (j = i + 1; (j < 4) && (volume != 0); j++) {
-          sdecode((shellface) testtet->tet[8 + j], checksh2);
-          if (checksh2.sh != dummysh) {
-            shmark2 = shellmark(checksh2); 
-            if (shmark1 == shmark2) {
-              // The same marker - belong to the same facet.
-              volume = 0.0;
-            } else {
-              // Two different markers. Find the sharing edge.
-              for (k = 0; k < 3; k++) {
-                for (l = 0; l < 3; l++) {
-                  if (sorg(checksh2) == sorg(checksh1)) {
-                    if (sdest(checksh2) == sdest(checksh1)) break;
-                  } else if (sdest(checksh2) == sorg(checksh1)) {
-                    if (sorg(checksh2) == sdest(checksh1)) break;
-                  }
-                  senextself(checksh2);
-                }
-                if (l < 3) break;
-                senextself(checksh1);
-              }
-              assert(k < 3); // The edge must exist.
-              // Is there a segment?
-              sspivot(checksh2, checkseg);
-              if (checkseg.sh == dummysh) {
-                // No segment - two subfaces belong to a unified facet.
-                volume = 0.0;
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  if (volume == 0.0) {
-    if (degetetlist != (list *) NULL) {
-      degetet = (badface *) degetetlist->append(NULL);
-      degetet->tt = *testtet;
-      degetet->forg = pa;
-      degetet->fdest = pb;
-      degetet->fapex = pc;
-      degetet->foppo = pd;
-    }
-    if (b->verbose > 1) {
-      printf("    Find tet (%d, %d, %d, %d).\n", pointmark(pa), pointmark(pb),
-             pointmark(pc), pointmark(pd));
-    }
-  }
-
-  return volume == 0.0;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// finddiagonal()    Find one of the diagonal edges in a kite.               //
-//                                                                           //
-// 'akite' (abcd) is degenerate. This routine sets ab be the diagonal edge.  //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-bool tetgenmesh::finddiagonal(triface* akite)
-{
-  point pa, pb, pc, pd;
-  REAL v1[3], v2[3], v3[3];
-  REAL L12, L22, L32;
-  REAL pref[3], n[3], nlen;
-  REAL sign1, sign2, sign3;
-  int i;
-
-  pa = org(*akite);
-  pb = dest(*akite);
-  pc = apex(*akite);
-  pd = oppo(*akite);
-
-  // Calculate a point which is exactly above the plane having abcd.
-  L12 = L22 = L32 = 0.0;
-  for (i = 0; i < 3; i++) {v1[i] = pb[i] - pa[i]; L12 += (v1[i] * v1[i]);}
-  for (i = 0; i < 3; i++) {v2[i] = pc[i] - pa[i]; L22 += (v2[i] * v2[i]);}
-  for (i = 0; i < 3; i++) {v3[i] = pd[i] - pa[i]; L32 += (v3[i] * v3[i]);}
-  sign1 = v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
-  sign2 = v1[0] * v3[0] + v1[1] * v3[1] + v1[2] * v3[2];
-  sign1 = (sign1 * sign1) / (L12 * L22);
-  sign2 = (sign2 * sign2) / (L12 * L32);
-  if (sign1 < sign2) {
-    // Angle cab is closer to 90 degree.
-    facenormal(pa, pb, pc, n, &nlen);
-  } else {
-    // Angle dab is closer to 90 degree.
-    facenormal(pa, pb, pd, n, &nlen);
-  }
-  assert(nlen > 0.0);
-  for (i = 0; i < 3; i++) n[i] /= nlen;
-  nlen = sqrt(L12);
-  for (i = 0; i < 3; i++) pref[i] = pa[i] + nlen * n[i];
-
-  for (i = 0; i < 3; i++) {
-    pa = org(*akite);
-    pb = dest(*akite);
-    pc = apex(*akite);
-    sign1 = orient3d(pa, pb, pref, pc);
-    sign2 = orient3d(pa, pb, pref, pd);
-    sign3 = sign1 * sign2;
-    assert(sign3 != 0.0);
-    if (sign3 < 0.0) break;
-    enextself(*akite);
-  }
-  if (i == 3) return false;
-  return true;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// removetetbypeeloff()    Remove a boundary tetrahedron by peeling off.     //
-//                                                                           //
-// 'badtet' (abcd) is a boundary tetrahedron and going to be peeled off. abc //
-// and bad are the external boundary faces.                                  //
-//                                                                           //
-// To peel 'abcd' from the mesh is to detach its two interal faces (dca and  //
-// cdb) from their adjoining tetrahedra together with a 2-to-2 flip to trans-//
-// form two subfaces (abc and bad) into another two (dca and cdb).           //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-void tetgenmesh::removetetbypeeloff(triface *badtet, queue* flipqueue)
-{
-  triface abcd, badc;
-  triface dcacasing, cdbcasing;
-  face abc, bad;
-  
-  if (b->verbose > 1) {
-    printf("    by peeling off it from boundary.\n");
-  }
-
-  abcd = *badtet;
-  adjustedgering(abcd, CCW);
-  
-  // Get the external subfaces abc, bad.
-  fnext(abcd, badc);
-  esymself(badc);
-  tspivot(abcd, abc);
-  tspivot(badc, bad);
-  assert((abc.sh != dummysh) && (bad.sh != dummysh));
-  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);
-  assert(cdbcasing.tet != dummytet && dcacasing.tet != dummytet);
-
-  // 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);
-
-  if (flipqueue != (queue *) NULL) {
-    // Edge cd may be non-Delaunay.
-    adjustedgering(cdbcasing, CCW);
-    fnextself(cdbcasing);
-    enqueueflipface(cdbcasing, flipqueue);
-    adjustedgering(dcacasing, CCW);
-    fnextself(dcacasing);
-    enqueueflipface(dcacasing, flipqueue);
-    // Do flipping if cd is non-Delaunay.
-    flip(flipqueue, NULL, false, false, false);
-  }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// removetetbyflip32()    Remove a tetrahedron by a 3-to-2 flip.             //
-//                                                                           //
-// 'badtet' (abcd) is the bad tetrahedron which is going to be removed by a  //
-// 3-to-2 flip.  abc represents one of the internal faces, bad is another.   //
-// If abc and bad are subfaces, a 2-to-2 flip is performed to transform abc, //
-// bad into dca, cdb, before the 3-to-2 flip is applying.                    //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-void tetgenmesh::removetetbyflip32(triface *badtet, queue* flipqueue)
-{
-  triface abcd, badc;
-  triface cdab, dcba;
-  triface baccasing, abdcasing;
-  triface dcacasing, cdbcasing;
-  face abc, bad;
-  REAL attrib, testattr;
-  int i;  
-
-  if (b->verbose > 1) {
-    printf("    by doing a 3-to-2 flip.\n");
-  }
-
-  abcd = *badtet;
-  adjustedgering(abcd, CCW);
-  fnext(abcd, badc);
-  esymself(badc);
-  sym(abcd, baccasing);
-  sym(badc, abdcasing);
-  assert((baccasing.tet != dummytet) && (abdcasing.tet != dummytet));
-  assert(oppo(baccasing) == oppo(abdcasing));
-  
-  // Get subfaces abc, bad.
-  tspivot(abcd, abc);
-  tspivot(badc, bad);
-  if (abc.sh != dummysh) {
-    // Because ab should not be a subsegment.
-    assert(bad.sh != dummysh);
-    // Find abc and bad are internal subfaces. Here 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 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);
-      testattr = elemattribute(abdcasing.tet, i);
-      assert(attrib == testattr);
-      setelemattribute(abcd.tet, i, attrib);
+    case ONVERTEX:
+      if (!b->quiet) {
+        printf("Warning: Point (%.17g, %.17g, %.17g) falls on a vertex.\n",
+               newpoint[0], newpoint[1], newpoint[2]);
+      }
+      break;
+    case OUTSIDE:
+      if (!b->quiet) {
+        printf("Warning: Point (%.17g, %.17g, %.17g) lies outside the mesh.\n",
+               newpoint[0], newpoint[1], newpoint[2]);
+      }
+      break;
+    }
+    // Remember the tetrahedron for next point searching.
+    recenttet = searchtet;
+    if (loc == ONVERTEX || loc == OUTSIDE) {
+      pointdealloc(newpoint);
+    } else {
+      flip(flipqueue, NULL);
     }
-    findedge(&abc, org(abcd), dest(abcd));
-    findedge(&bad, org(badc), dest(badc));
-    // Detach abc, bad from the four tetrahedra at both sides.
-    stdissolve(abc);
-    stdissolve(bad);
-    sesymself(abc);
-    sesymself(bad);
-    stdissolve(abc);
-    stdissolve(bad);
-    sesymself(abc);
-    sesymself(bad);
-    // Detach the four tetrahedra 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 tetrahedra.
-    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);          
-  }
-  // Do a 3-to-2 flip on face abc to remove tetrahedron abcd.
-  flip32(&abcd, flipqueue);
-  // Do flipping if necessary.
-  if (flipqueue != (queue *) NULL) {
-    flip(flipqueue, NULL, false, false, false);
   }
+
+  delete flipqueue;
 }
 
+//
+// End of mesh reconstruction routines
+//
+
+//
+// Begin of background mesh routines
+//
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// removekite()    Remove a degenerate kite from the mesh.                   //
+// interpolatepointsize()    Set a point size by interpolating in bgmesh.    //
 //                                                                           //
-// 'akite' (abcd) is a degenerate kite (i.e., a, b, c, and d are coplanar),  //
-// and ab is the diagonal edge. It is removable if (a) either the face pair  //
-// abc and abd or dca and dcb are hull faces, hence it can be peeled off; or //
-// (b) it is an internal tet and either edge ab or cd can be flipped by a 3- //
-// to-2 flip.  Remove the kite if it is in case (a) or (b) and return TRUE.  //
-// Otherwise it is unremovable, do nothing and return FALSE.                 //
+// This function first finds the tet t in background mesh contains 'pt, then //
+// set the size of 'pt' by interpolating the sizes of the corners of t.      //
+//                                                                           //
+// 'bgmtet' is a suggesting tet in background mesh for locating 'pt' in it.  //
+// It returns the tet containing 'pt'.                                       //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::removekite(triface* akite, queue* flipqueue)
+bool tetgenmesh::interpolatepointsize(point pt, triface* bgmtet, long *scount)
 {
-  triface abcd, badc;  // Tet configuration at edge ab.
-  triface baccasing, abdcasing;
-  triface cdab, dcba;  // Tet configuration at edge cd.
-  triface bcdcasing, cadcasing;
-  face abseg, cdseg;
-
-  abcd = *akite;
-  adjustedgering(abcd, CCW);
-
-  if (b->verbose > 1) {
-    printf("    Removing kite (%d, %d, %d, %d).\n", pointmark(org(abcd)),
-      pointmark(dest(abcd)), pointmark(apex(abcd)), pointmark(oppo(abcd)));
-  }
-
-  // Get the tet configuration at edge ab.
-  fnext(abcd, badc);
-  esymself(badc);
-  sym(abcd, baccasing);
-  sym(badc, abdcasing);
-  tsspivot(&abcd, &abseg);
-  // Is edge ab a subsegment?
-  if (abseg.sh == dummysh) {
-    // Can 'abcd' be peeled off?
-    if ((baccasing.tet == dummytet) && (abdcasing.tet == dummytet)) {
-      removetetbypeeloff(&abcd, flipqueue);
-      return true;
-    } 
-    // Can edge 'ab' be flipped away?
-    if (oppo(baccasing) == oppo(abdcasing)) {
-      removetetbyflip32(&abcd, flipqueue);
-      return true;
-    }
-  }
+  point bgmpt[4];
+  enum locateresult loc;
+  REAL vol, volpt[4], weights[4];
+  int i;
 
-  // Get the tet configuration at edge cd.
-  enextfnext(abcd, dcba); // dcba = bcda
-  esymself(dcba); // dcba = cbda
-  enext2self(dcba);
-  enext2fnext(abcd, cdab); // cdab = cadb
-  esymself(cdab); // cdab = acdb
-  enextself(cdab);
-  sym(dcba, bcdcasing);
-  sym(cdab, cadcasing);
-  tsspivot(&dcba, &cdseg);  
-  // Is edge cd a subsegment?
-  if (cdseg.sh == dummysh) {
-    // Can 'abcd' be peeled off?
-    if ((bcdcasing.tet == dummytet) && (cadcasing.tet == dummytet)) {
-      removetetbypeeloff(&cdab, flipqueue);
-      return true;
-    }
-    // Can edge 'cd' be flipped away?
-    if (oppo(bcdcasing) == oppo(cadcasing)) {
-      removetetbyflip32(&cdab, flipqueue);
-      return true;
+  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;
+      }
+      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.
+    vol = orient3d(bgmpt[0], bgmpt[1], bgmpt[2], bgmpt[3]);
+    volpt[0] = orient3d(pt, bgmpt[1], bgmpt[2], bgmpt[3]);
+    volpt[1] = orient3d(bgmpt[0], pt, bgmpt[2], bgmpt[3]);
+    volpt[2] = orient3d(bgmpt[0], bgmpt[1], pt, bgmpt[3]);
+    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];
     }
+  } else {
+    setpoint2bgmtet(pt, (tetrahedron) NULL);  // in m
   }
-
-  if ((abseg.sh != dummysh) && (cdseg.sh != dummysh)) {
-    // Two crossing segments in one tet.  This may be a error in the PLC.
-    printf("Warning:  Segments (%d, %d) and (%d, %d) are cross each other.\n",
-           pointmark(org(abcd)), pointmark(dest(abcd)), pointmark(apex(abcd)),
-           pointmark(oppo(abcd)));
-  } else if (abseg.sh != dummysh) {
-    // ab is a segment, cd is an internal edge but not flippable.
-  } else if (cdseg.sh != dummysh) {
-    // cd is a segment, ab is an internal edge but not flippable.
-  }
-
-  return false;
+  return loc != OUTSIDE;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// talldegetets()    Queue all the degenerate tetrahedra in the mesh.        //
+// searchpointrecursive()    Search point in background mesh recursively.    //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::talldegetets(list* degetetlist)
+void tetgenmesh::searchpointrecursive(triface *curtet, long *scount)
 {
-  triface tetloop;
+  triface searchtet, bgmtet;
+  point searchpt;
+  int idx, i;
 
-  tetrahedrons->traversalinit();
-  tetloop.tet = tetrahedrontraverse();
-  while (tetloop.tet != (tetrahedron *) NULL) {
-    checktet4dege(&tetloop, degetetlist);
-    tetloop.tet = tetrahedrontraverse();
+  // 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);
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// removedegetets()    Repair mesh by removing degenerate elements.          //
+// interpolatesizemap()    Interpolate the point sizes in the given size map.//
+//                                                                           //
+// The size map is specified on each node of the background mesh. The points //
+// of current mesh get their sizes by interpolating.                         //
+//                                                                           //
+// This function operation on two meshes simultaneously, the current mesh m, //
+// and the background mesh bgm. After this function, each point p in m will  //
+// have a pointer to a tet of bgm.                                           //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::repairdegetets()
+void tetgenmesh::interpolatesizemap()
 {
-  list *degetetlist;
-  queue *flipqueue;
-  badface *degetet;
-  int total, counter, i;
+  triface tetloop, bgmtet;
+  point searchpt;
+  long scount;
+  int idx, i;
 
-  if (!b->quiet) {
-    printf("Removing degenerate tets.\n");
+  if (b->verbose) {
+    printf("  Interpolating size map.\n");
   }
+  scount = 0l;
 
-  // Initialize the pool of bad tetrahedra.
-  degetetlist = new list(sizeof(badface), NULL, 1024);
-  total = 0;
-  
-  // Find all degenerate tetrahedra.
-  talldegetets(degetetlist);
-  do {
-    // Initialize the counter of removed tets.
-    counter = 0;
-    for (i = 0; i < degetetlist->len(); i++) {
-      degetet = (badface *)(* degetetlist)[i];
-      if (!isdead(&degetet->tt) && (org(degetet->tt) == degetet->forg) &&
-          (dest(degetet->tt) == degetet->fdest) &&
-          (apex(degetet->tt) == degetet->fapex) &&
-          (oppo(degetet->tt) == degetet->foppo)) {
-        if (finddiagonal(&(degetet->tt))) {
-          if (removekite(&(degetet->tt), NULL)) counter++;
+  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.
+          bgmtet = bgm->recenttet;
+          if (interpolatepointsize(searchpt, &bgmtet, &scount)) {
+            bgm->recenttet = bgmtet;
+          }
+          // 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);
     }
-    if (counter == 0) {
-      // No degenerate tet is removed.
-      if (b->verbose && (degetetlist->len() > 0)) {
-        printf("Warning:  %d degenerate tets survived.\n", degetetlist->len());
-      }
-      break;
-    }
-    // Accumulate the number of removed elements.
-    total += counter; 
-    // Some degenerate tets are removed. Continue the loop.
-    degetetlist->clear();
-    talldegetets(degetetlist);
-  } while (degetetlist->len() > 0);
+    tetloop.tet = tetrahedrontraverse();
+  }
 
-  if (total > 0) {
-    // Some faces may become non-Delaunay. Check and correct them.
-    flipqueue = new queue(sizeof(badface));
-    checkdelaunay(0.0, flipqueue);
-    if (!flipqueue->empty()) {
-      // Call flip algorithm to recover Delaunayness.
-      flip(flipqueue, NULL, false, false, false); 
-    }
-    delete flipqueue; 
+  // Have searched all points. Unmark tets.
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    assert(infected(tetloop));
+    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
   }
 
+#ifdef SELF_CHECK
   if (b->verbose) {
-    printf("  %ld degeneracies are removed.\n", total);
+    printf("  %ld brute-force searches.\n", scount);
   }
-
-  delete degetetlist;
+#endif
 }
 
 //
-// End of mesh repair routines
+// End of of background mesh routines
 //
 
 //
@@ -20634,231 +24865,230 @@ void tetgenmesh::repairdegetets()
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// initializerpsarray()    Initialize the 'rpsarray'.                        //
+// calclocalfeaturesizes()    Calculate local feature sizes of all points.   //
 //                                                                           //
-// Calculate the initial radii of protecting spheres for all acute vertices. //
-// During Delaunay refinement, each acute vertex v is protected by a sphere  //
-// S(v, r), no point should be added inside S(v).  The radius r is chosen as //
-// follows: Let w be another vertex connecting to v, (a) if w is acute, then //
-// r_w = 1/3 |vw|; (b) is w is not acute, then r_w = 1/2 |vw|. r = min{r_w}. //
+// Given a PLC X, the local feature size, lfs_d(x), of any point x in X is   //
+// defined as the distance from x to two features of X which are of dim no   //
+// large than d. For example, lfs_0(x) is the distance from x to the second  //
+// nearest point of X. Let lfs(x) = lfs_2(x).                                //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::initializerpsarray()
+void tetgenmesh::calclocalfeaturesizes()
 {
-  list *neightetlist;
+  list *tetlist, *verlist;
   tetrahedron tetptr;
-  triface starttet, neightet;
-  point pointloop, workpt[3];
-  REAL rps, len;
-  int i, j;  
+  triface starttet;
+  face checksh, checkseg;
+  point ploop, ver[3];
+  point ptlfslarge, ptlfssmall;
+  enum locateresult loc;
+  REAL prj[3], lfs[3], len;
+  REAL lfslarge, lfssmall;
+  int i, j;
 
-  if (b->verbose) {
-    printf("  Initializing protecting spheres.\n");
+  if (b->verbose > 0) {
+    printf("  Calculating local feature sizes.\n");
   }
 
-  // Initialize the point2tet field of each point.
-  points->traversalinit();
-  pointloop = pointtraverse();
-  while (pointloop != (point) NULL) {
-    setpoint2tet(pointloop, (tetrahedron) NULL);
-    pointloop = pointtraverse();
-  }
   // Construct a map from points to tetrahedra.
   makepoint2tetmap();
-  // Initialize 'neightetlist'.
-  neightetlist = new list(sizeof(triface), NULL, 256);
-  
+  // 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;
+
   points->traversalinit();
-  pointloop = pointtraverse();
-  while (pointloop != (point) NULL) {
-    tetptr = point2tet(pointloop);
-    // Only calculate lfs(p) if it is acute and is not dangling.
-    if ((pointtype(pointloop) == ACUTEVERTEX) &&
-        (tetptr != (tetrahedron) NULL)) {
+  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);
-      assert((starttet.tet != NULL) && (starttet.tet != dummytet));
-      // Find all tetrahedra sharing 'pointloop'.
-      findorg(&starttet, pointloop);
-      infect(starttet);
-      neightetlist->append(&starttet);
-      for (i = 0; i < neightetlist->len(); i++) {
-        starttet = * (triface *)(* neightetlist)[i];
-        assert(infected(starttet));
-        // The origin of 'starttet' should be 'pointloop'.
-        adjustedgering(starttet, CCW);
-        if (org(starttet) != pointloop) {
-          enextself(starttet);
-        }
-        assert(org(starttet) == pointloop);
-        // Let 'starttet' be the opposite face of 'pointloop'.
-        enextfnextself(starttet);
-        assert(oppo(starttet) == pointloop);
-        // Get three neighbors of faces having 'pointloop'.
-        adjustedgering(starttet, CCW);
+      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++) {
-          fnext(starttet, neightet);
-          symself(neightet);
-          // Add it into list if is is not outer space and not infected.
-          if ((neightet.tet != dummytet) && !infected(neightet)) {
-            findorg(&neightet, pointloop);
-            infect(neightet);
-            neightetlist->append(&neightet);
+          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);
         }
       }
-      // 'neightetlist' contains all tetrahedra sharing at 'pointloop'.
-      rps = longest;
-      for (i = 0; i < neightetlist->len(); i++) {
-        starttet = * (triface *)(* neightetlist)[i];
-        assert(org(starttet) == pointloop);
-        workpt[0] = dest(starttet);
-        workpt[1] = apex(starttet);
-        workpt[2] = oppo(starttet);
-        for (j = 0; j < 3; j++) {
-          len = distance(workpt[j], pointloop);
-          if (pointtype(workpt[j]) == ACUTEVERTEX) {
-            len /= 3.0;
-          } else {
-            len /= 2.0;
+      // 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;
           }
-          if (len < rps) rps = len;
         }
       }
-      // Return the local feature size of pointloop.
-      rpsarray[pointmark(pointloop)] = rps;
-      // Uninfect tetrahedra and clear 'neightetlist'.
-      for (i = 0; i < neightetlist->len(); i++) {
-        starttet = * (triface *)(* neightetlist)[i];
-        uninfect(starttet);
+      // 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;
+        }
       }
-      neightetlist->clear();
+      // Clear working lists.
+      tetlist->clear();
+      verlist->clear();
     }
-    pointloop = pointtraverse();
+    ploop = pointtraverse();
   }
 
-  delete neightetlist;
+  if (b->verbose > 1) {
+    printf("  smallest lfs = %g (%d).\n", lfssmall, pointmark(ptlfssmall));
+    printf("  largest  lfs = %g (%d).\n", lfslarge, pointmark(ptlfslarge));
+  }
+
+  delete tetlist;
+  delete verlist;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// marksharpsubfaces()    Mark all sharp subfaces.                           //
-//                                                                           //
-// A subface is sharp if it belongs to a facet which forms an acute dihedral //
-// angle (< 'dihedbound', given in degrees) with other facets. It is marked  //
-// as SHARPSUB. (May be SHARPSKINNYSUB later by markskinnysubfaces().)       //
+// marksharpsubsegs()    Mark all sharp subsegments.                         //
 //                                                                           //
-// This procedure operates in two phases.  The first phase finds some sharp  //
-// subfaces by checking the dihedral angles of facets around segments.  The  //
-// second phase finds all sharp subfaces by a neighbor-first search.         //
+// A segment is sharp if it is between two facets that form a small dihedral //
+// angle (< 'dihedbound', given in degrees). It is marked as SHARP.          //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::marksharpsubfaces(REAL dihedbound)
+void tetgenmesh::marksharpsubsegs(REAL dihedbound)
 {
-  list *incishlist, *sharpshlist;
-  triface adjtet; 
+  list *spinshlist;
+  triface adjtet;
   face startsh, spinsh, neighsh;
-  face segloop, prevseg, checkseg;
-  point eorg, edest; 
-  REAL small, angle;
-  int i, j;
+  face segloop, prevseg, nextseg;
+  point eorg, edest;
+  enum shestype stype;
+  REAL angle, smallang;
+  bool issharp;
+  int scount;
+  int i;
 
-  if (b->verbose) {
-    printf("  Marking sharp subfaces.\n");
+  if (b->verbose > 0) {
+    printf("  Marking sharp subsegments.\n");
   }
 
-  small = dihedbound * PI / 180.;
-  // Initial working lists.
-  incishlist = new list(sizeof(face), NULL, 256);
-  sharpshlist = new list(sizeof(face), NULL, subfaces->items);
+  smallang = dihedbound * PI / 180.;
+  scount = 0;
+  eorg = edest = (point) NULL; // avoid compilation warnings.
+  // Initial working list.
+  spinshlist = new list(sizeof(face), NULL, 256);
 
-  // Loop the set of segments, collect some sharp subfaces.
+  // A segment s may be split into many subsegments. Operate the one which
+  //   contains the origin of s. Then mark the rest of subsegments.
   subsegs->traversalinit();
   segloop.sh = shellfacetraverse(subsegs);
   while (segloop.sh != (shellface *) NULL) {
-    // A segment may be split into many subsegments, Operate the one which
-    //   contains the origin of the segment.
     segloop.shver = 0;
     senext2(segloop, prevseg);
     spivotself(prevseg);
     if (prevseg.sh == dummysh) {
-      // Operate on this subsegment.
+      // Operate on this seg.
+      issharp = false;
       segloop.shver = 0;
       spivot(segloop, startsh);
-      assert(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 'segloop'.
-        spinsh = startsh;
-        do {
-          if (sorg(spinsh) != eorg) {
-            sesymself(spinsh);
-          }
-          incishlist->append(&spinsh);  
-          spivotself(spinsh);
-        } while (spinsh.sh != startsh.sh);
+      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;
+          do {
+            if (sorg(spinsh) != eorg) {
+              sesymself(spinsh);
+            }
+            spinshlist->append(&spinsh);  
+            spivotself(spinsh);
+          } while (spinsh.sh != startsh.sh);
+        }
         // Check the pair of adjacent subfaces for small angle.
-        spinsh = * (face *)(* incishlist)[0];
-        for (i = 1; i <= incishlist->len(); i++) {
-          if (i == incishlist->len()) {
-            neighsh = * (face *)(* incishlist)[0];
+        spinsh = * (face *)(* spinshlist)[0];
+        for (i = 1; i <= spinshlist->len() && !issharp; i++) {
+          if (i == spinshlist->len()) {
+            neighsh = * (face *)(* spinshlist)[0];
           } else {
-            neighsh = * (face *)(* incishlist)[i];
+            neighsh = * (face *)(* spinshlist)[i];
           }
-          // Only do test when the side spinsh is faceing inward.
+          // Only do test when the spinsh is faceing inward.
           stpivot(spinsh, adjtet);
           if (adjtet.tet != dummytet) {
             angle = facedihedral(eorg, edest, sapex(spinsh), sapex(neighsh));
-            // Is angle acute?
-            if (angle < small) {
-              // Has spinsh been marked?
-              if (shelltype(spinsh) != SHARPSUB) {
-                setshelltype(spinsh, SHARPSUB);
-                sharpshlist->append(&spinsh);
-              }
-              // Has neighsh been marked?
-              if (shelltype(neighsh) != SHARPSUB) {
-                setshelltype(neighsh, SHARPSUB);
-                sharpshlist->append(&neighsh);
-              }
-            }
+            issharp = angle < smallang;
           }
           spinsh = neighsh;
         }
-        incishlist->clear();
+        spinshlist->clear();
       }
-    }
-    segloop.sh = shellfacetraverse(subsegs);
-  }
-
-  // Next finds all sharp subfaces.
-  for (i = 0; i < sharpshlist->len(); i++) {
-    startsh = * (face *)(* sharpshlist)[i];
-    assert(shelltype(startsh) == SHARPSUB);
-    for (j = 0; j < 3; j++) {
-      sspivot(startsh, checkseg);
-      if (checkseg.sh == dummysh) {
-        spivot(startsh, neighsh);
-        if (shelltype(neighsh) != SHARPSUB) {
-          setshelltype(neighsh, SHARPSUB);
-          sharpshlist->append(&neighsh);
-        }
+      // 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);
       }
-      senextself(startsh);
     }
+    segloop.sh = shellfacetraverse(subsegs);
   }
 
-  if (b->verbose) {
-    printf("  %d subfaces have been marked.\n", sharpshlist->len());
+  if (b->verbose > 0) {
+    printf("  %d sharp segments.\n", scount);
   }
-
-  delete incishlist;
-  delete sharpshlist;
+  delete spinshlist;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -20867,7 +25097,7 @@ void tetgenmesh::marksharpsubfaces(REAL dihedbound)
 //                                                                           //
 // 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 SKINNYSUB or SHARPSKINNYSUB.        //
+// to refine.  It will be marked as type SKINNY.                             //
 //                                                                           //
 // This procedure operates in two phases.  The first phase finds some skinny //
 // subfaces by checking the angles of subfaces.  The second phase finds all  //
@@ -20883,18 +25113,18 @@ void tetgenmesh::markskinnysubfaces(REAL anglebound)
   face seg1, seg2, checkseg;
   point pa, pb, pc;
   enum shestype shty;
-  REAL small, angle;
+  REAL smallang, angle;
   int i, j;
 
-  if (b->verbose) {
+  if (b->verbose > 0) {
     printf("  Marking skinny subfaces.\n");
   }
 
-  small = anglebound * PI / 180.;
+  smallang = anglebound * PI / 180.;
   // Initial working list.
   skinnyshlist = new list(sizeof(face), NULL, subfaces->items);
 
-  // Loop the set of subfaces, collect some which are skinny.
+  // Loop the set of subfaces, collect some skinny ones.
   subfaces->traversalinit();
   subloop.sh = shellfacetraverse(subfaces);
   while (subloop.sh != (shellface *) NULL) {
@@ -20909,13 +25139,9 @@ void tetgenmesh::markskinnysubfaces(REAL anglebound)
           pb = sdest(subloop);
           pc = sapex(subloop);
           angle = interiorangle(pa, pb, pc, NULL);
-          if (angle < small) {
+          if (angle < smallang) {
             // It is skinny!
-            if (shelltype(subloop) == SHARPSUB) {
-              setshelltype(subloop, SHARPSKINNYSUB);
-            } else {
-              setshelltype(subloop, SKINNYSUB);
-            }
+            setshelltype(subloop, SKINNY);
             skinnyshlist->append(&subloop);
             break;
           }
@@ -20930,7 +25156,6 @@ void tetgenmesh::markskinnysubfaces(REAL anglebound)
   for (i = 0; i < skinnyshlist->len(); i++) {
     startsh = * (face *)(* skinnyshlist)[i];
     shty = shelltype(startsh);
-    assert((shty == SKINNYSUB) || (shty == SHARPSKINNYSUB));
     for (j = 0; j < 3; j++) {
       sspivot(startsh, checkseg);
       if (checkseg.sh == dummysh) {
@@ -20944,13 +25169,98 @@ void tetgenmesh::markskinnysubfaces(REAL anglebound)
     }
   }
 
-  if (b->verbose) {
-    printf("  %d subfaces have been marked.\n", skinnyshlist->len());
+  if (b->verbose > 0) {
+    printf("  %d skinny subfaces.\n", skinnyshlist->len());
   }
-
   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;
+    }
+  } 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);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// enqueueencsub()    Add an encroached subface into the queue.              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::enqueueencsub(face* testsub, point encpt, int quenumber,
+  REAL* cent)
+{
+  badface *encsub;
+  int i;
+
+  encsub = (badface *) badsubfaces->alloc();
+  encsub->ss = *testsub;
+  encsub->forg = sorg(*testsub);
+  encsub->fdest = sdest(*testsub);
+  encsub->fapex = sapex(*testsub);
+  encsub->foppo = (point) encpt;
+  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];
+  }
+  encsub->nextitem = (badface *) NULL;
+  // Set the pointer of 'encsubseg' into 'testsub'.  It has two purposes:
+  //   (1) We can regonize it is encroached; (2) It is uniquely queued.
+  setshell2badface(encsub->ss, encsub);
+  // Add the subface to the end of a queue (quenumber = 2, high priority).
+  *subquetail[quenumber] = encsub;
+  // Maintain a pointer to the NULL pointer at the end of the queue.
+  subquetail[quenumber] = &encsub->nextitem;
+  if (b->verbose > 2) {
+    printf("    Queuing subface (%d, %d, %d) [%d].\n", pointmark(encsub->forg),
+           pointmark(encsub->fdest), pointmark(encsub->fapex), quenumber);
+  }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // dequeuebadtet()    Remove a tetrahedron from the front of the queue.      //
@@ -20978,29 +25288,58 @@ tetgenmesh::badface* tetgenmesh::dequeuebadtet()
   return (badface *) NULL;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dequeueencsub()    Remove an enc-subface from the front of the queue.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+tetgenmesh::badface* tetgenmesh::dequeueencsub(int* pquenumber)
+{
+  badface *result;
+  int quenumber;
+
+  // Look for a nonempty queue.
+  for (quenumber = 2; quenumber >= 0; quenumber--) {
+    result = subquefront[quenumber];
+    if (result != (badface *) NULL) {
+      // Remove the badface from the queue.
+      subquefront[quenumber] = result->nextitem;
+      // Maintain a pointer to the NULL pointer at the end of the queue.
+      if (subquefront[quenumber] == (badface *) NULL) {
+        subquetail[quenumber] = &subquefront[quenumber];
+      }
+      *pquenumber = quenumber;
+      return result;
+    }
+  }
+  return (badface *) NULL;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // checkseg4encroach()    Check a subsegment to see if it is encroached.     //
 //                                                                           //
-// A subsegment is encroached if there is a vertex in its diametral circle   //
-// (that is, the subsegment faces an angle greater than 90 degrees).         //
+// A segment s is encroached if there is a vertex lies inside or on its dia- //
+// metral circumsphere, i.e., s faces an angle theta >= 90 degrees.          //
 //                                                                           //
-// If 'testpt' is not NULL, only check whether 'testseg' is encroached by it //
-// or not. Otherwise, check all apexes of faces in mesh containing 'testseg'.//
-// If 'pencpt' is not NULL, return the encroaching point if it exists.       //
+// If 'testpt' (p) != NULL, only test if 'testseg' (s) is encroached by it,  //
+// else, check all apexes of faces around s. Return TRUE if s is encroached. //
+// If and 'enqflag' is TRUE, add it into 'badsubsegs' if s is encroached.    //
 //                                                                           //
-// If testseg is found be encroached, add it into 'badsubsegs' if 'enqflag'  //
-// is TRUE.  Return TRUE if testseg is encroached, otherwise return FALSE.   //
+// If 'prefpt' != NULL, it returns the reference point (defined in my paper) //
+// if it exists.  This point is will be used to split s.                     //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::
-checkseg4encroach(face* testseg, point testpt, point* pencpt, bool enqflag)
+bool tetgenmesh::checkseg4encroach(face* testseg, point testpt, point* prefpt,
+  bool enqflag)
 {
   badface *encsubseg;
   triface starttet, spintet;
   point eorg, edest, eapex, encpt;
   REAL cent[3], radius, dist, diff;
+  REAL maxradius;
   bool enq;
   int hitbdry;
 
@@ -21012,7 +25351,7 @@ checkseg4encroach(face* testseg, point testpt, point* pencpt, bool enqflag)
   radius = distance(cent, eorg);
 
   enq = false;
-  encpt = (point) NULL;
+  maxradius = 0.0;
   if (testpt == (point) NULL) {
     // Check if it is encroached by traversing all faces containing it.
     sstpivot(testseg, &starttet);
@@ -21023,10 +25362,21 @@ checkseg4encroach(face* testseg, point testpt, point* pencpt, bool enqflag)
       dist = distance(cent, apex(spintet));
       diff = dist - radius;
       if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
-      if (diff < 0.0) {
+      if (diff <= 0.0) {
+        // s is encroached.
         enq = true;
-        encpt = apex(spintet);
-        break;
+        if (prefpt != (point *) NULL) {
+          // Find the reference point.
+          encpt = apex(spintet);
+          circumsphere(eorg, edest, encpt, NULL, NULL, &dist);
+          if (dist > maxradius) {
+            // Rememebr this point.
+            *prefpt = encpt;
+            maxradius = dist;
+          }
+        } else {
+          break;
+        }
       }
       if (!fnextself(spintet)) {
         hitbdry++;
@@ -21043,7 +25393,7 @@ checkseg4encroach(face* testseg, point testpt, point* pencpt, bool enqflag)
     dist = distance(cent, testpt);
     diff = dist - radius;
     if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
-    enq = diff < 0.0;
+    enq = (diff <= 0.0);
   }
 
   if (enq && enqflag) {
@@ -21055,16 +25405,12 @@ checkseg4encroach(face* testseg, point testpt, point* pencpt, bool enqflag)
     encsubseg->ss = *testseg;
     encsubseg->forg = eorg;
     encsubseg->fdest = edest;
-    encsubseg->foppo = encpt;
+    encsubseg->foppo = (point) NULL; // Not used.
     // 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);
   }
   
-  if (pencpt != (point *) NULL) {
-    *pencpt = encpt;
-  }
-
   return enq;
 }
 
@@ -21072,29 +25418,29 @@ checkseg4encroach(face* testseg, point testpt, point* pencpt, bool enqflag)
 //                                                                           //
 // checksub4encroach()    Check a subface to see if it is encroached.        //
 //                                                                           //
-// A subface is encroached if there is a vertex in its diametral sphere. If  //
-// 'testpt != NULL', only test if 'testsub' is encroached by it.  Otherwise, //
-// test the opposites of the adjoining tetrahedra of 'testsub'.              //
+// A subface f is encroached if there is a vertex inside or on its diametral //
+// circumsphere.                                                             //
 //                                                                           //
-// If testsub is found be encroached, add it into 'badsubfacess' if 'enqflag'//
-// is TRUE.  Return TRUE if testsub is encroached, otherwise return FALSE.   //
+// If 'testpt (p) != NULL', test if 'testsub' (f) is encroached by it, else, //
+// test if f is encroached by one of the two opposites of the adjacent tets. //
+// Return TRUE if f is encroached and queue it if 'enqflag' is set.          //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 bool tetgenmesh::checksub4encroach(face* testsub, point testpt, bool enqflag)
 {
-  badface *encsub;
   triface abuttet;
   point forg, fdest, fapex, encpt;
-  REAL cent[3], radius, dist, diff;
+  REAL cent[3];
+  REAL radius, dist, diff;
   bool enq, ncollinear;
-  int i;
+  int quenumber;
   
   forg = sorg(*testsub);
   fdest = sdest(*testsub);
   fapex = sapex(*testsub);
   ncollinear = circumsphere(forg, fdest, fapex, NULL, cent, &radius);
-  assert(ncollinear == true);
+  if (!ncollinear) return false; // Not a valid subface.
   
   enq = false;
   encpt = (point) NULL;  
@@ -21104,7 +25450,7 @@ bool tetgenmesh::checksub4encroach(face* testsub, point testpt, bool enqflag)
       dist = distance(cent, oppo(abuttet));
       diff = dist - radius;
       if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
-      enq = diff < 0.0;
+      enq = (diff <= 0.0);
       if (enq) encpt = oppo(abuttet);
     }
     if (!enq) {
@@ -21114,40 +25460,42 @@ bool tetgenmesh::checksub4encroach(face* testsub, point testpt, bool enqflag)
         dist = distance(cent, oppo(abuttet));
         diff = dist - radius;
         if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
-        enq = diff < 0.0;
+        enq = (diff <= 0.0);
         if (enq) encpt = oppo(abuttet);
       }
     }
   } else {
-    // Only do test when 'testpt' is not one of its corners.
-    if (testpt != forg && testpt != fdest && testpt != fapex) {
-      dist = distance(cent, testpt);
-      diff = dist - radius;
-      if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
-      enq = diff < 0.0;
-    }
+    dist = distance(cent, testpt);
+    diff = dist - radius;
+    if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
+    enq = (diff <= 0.0);
   }
 
-  if (enq && enqflag) {    
-    encsub = (badface *) badsubfaces->alloc();
-    encsub->ss = *testsub;
-    encsub->forg = sorg(*testsub);
-    encsub->fdest = sdest(*testsub);
-    encsub->fapex = sapex(*testsub);
-    encsub->foppo = encpt;
-    for (i = 0; i < 3; i++) encsub->cent[i] = cent[i];
-    encsub->nextitem = (badface *) NULL;
-    // Set the pointer of 'encsubseg' into 'testsub'.  It has two purposes:
-    //   (1) We can regonize it is encroached; (2) It is uniquely queued.
-    setshell2badface(encsub->ss, encsub);
-    // Add the subface to the end of a queue (quenumber = 0, low priority).
-    *subquetail[0] = encsub;
-    // Maintain a pointer to the NULL pointer at the end of the queue.
-    subquetail[0] = &encsub->nextitem;
-    if (b->verbose > 2) {
-      printf("    Queuing encroached subface (%d, %d, %d).\n", 
-             pointmark(forg), pointmark(fdest), pointmark(fapex));
+  if (enq && enqflag) {
+    /* REAL prj[3], ori1, ori2, ori3;
+    bool inflag;
+    // Test if encpt is inside the face.
+    if (encpt) {
+      projpt2face(encpt, forg, fdest, fapex, prj);
+    } else {
+      assert(testpt);
+      projpt2face(testpt, forg, fdest, fapex, prj);
+    }
+    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;
@@ -21202,7 +25550,6 @@ bool tetgenmesh::checkseg4badqual(face* testseg, bool enqflag)
 
 bool tetgenmesh::checksub4badqual(face* testsub, bool enqflag)
 {
-  badface *encsub;
   face sametestsub;
   face subseg1, subseg2;
   point torg, tdest, tapex;
@@ -21216,7 +25563,6 @@ bool tetgenmesh::checksub4badqual(face* testsub, bool enqflag)
   REAL apexlen, orglen, destlen;
   REAL angle, area;
   bool enq;
-  int i;
 
   enq = false;
   torg = sorg(*testsub);
@@ -21275,1780 +25621,2529 @@ bool tetgenmesh::checksub4badqual(face* testsub, bool enqflag)
   }
 
   // Check if both edges that form the angle are segments.
-  if ((subseg1.sh != dummysh) && (subseg2.sh != dummysh)) {
+  // if ((subseg1.sh != dummysh) && (subseg2.sh != dummysh)) {
+  if (shelltype(*testsub) == SKINNY) {
     // The angle is a segment intersection.  Don't add this bad subface to
     //   the list; there's nothing that can be done about a small angle
     //   between two segments.
     angle = 0.0;
-  } 
+  }
+
+  // Check whether the angle is smaller than permitted.
+  if (angle > b->goodangle) {
+    enq = true;
+  }
+
+  if (!enq && varconstraint && areabound(*testsub) > 0.0) {
+    // Check whether the area is larger than desired.  A variation form of
+    //   Heron's formula which only uses the squares of the edge lengthes
+    //   is used to calculated the area of a 3D triangle.
+    area = apexlen + orglen - destlen;
+    area = area * area;
+    area = 4 * apexlen * orglen - area;
+    area = 0.25 * sqrt(fabs(area));
+    enq = area > areabound(*testsub);
+  }
+
+  if (enq && enqflag) {   
+    enqueueencsub(testsub, NULL, 2, NULL);
+  }
+
+  return enq;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checktet4badqual()    Test a tetrahedron for quality measures.            //
+//                                                                           //
+// Tests a tetrahedron to see if it satisfies the minimum ratio condition    //
+// and the maximum volume condition. Tetrahedra that aren't upto spec are    //
+// added to the bad tetrahedron queue.                                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+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 radius2, smlen2, ratio2;
+  REAL dist, sdist, split;
+  bool enq;
+  int indx[4];
+  int queuenumber;
+  int sidx, i, j; 
+
+  pa = (point) testtet->tet[4];
+  pb = (point) testtet->tet[5];
+  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];
+  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];
+  // Get the rest edge vectors
+  for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i];
+  for (i = 0; i < 3; i++) vbc[i] = pc[i] - pb[i];
+  for (i = 0; i < 3; i++) vca[i] = pa[i] - pc[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;
+  if (volume < 0.0) volume = -volume;
+  // Compare the volume to average edge length of abcd.
+  elen[0] = dot(vda, vda);
+  elen[1] = dot(vdb, vdb);
+  elen[2] = dot(vdc, vdc);
+  elen[3] = dot(vab, vab);
+  elen[4] = dot(vbc, vbc);
+  elen[5] = dot(vca, vca);
+  
+  enq = false;
+  if (b->offcenter) {
+    // Check if the tet is very flat.
+    L = 0.0;
+    for (i = 0; i < 6; i++) L += sqrt(elen[i]);
+    L /= 6.0;
+    q = volume / (L * L * L);
+    enq = (q < b->epsilon * 1e+2);
+  }
+  
+  // Is abcd very flat?
+  if (!enq) {
+    rhs[0] = 0.5 * dot(vda, vda);
+    rhs[1] = 0.5 * dot(vdb, vdb);
+    rhs[2] = 0.5 * dot(vdc, vdc);
+    lu_solve(A, 3, indx, rhs, 0);
+    // Get the circumcenter.
+    for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i];
+    // Get the square of the circumradius.
+    radius2 = dot(rhs, rhs);
+    // Find the square of the shortest edge length.
+    smlen2 = elen[0]; sidx = 0;
+    for (i = 1; i < 6; i++) {
+      if (smlen2 > elen[i]) { smlen2 = elen[i]; sidx = i; }
+    }
+    // Calculate the square of radius-edge ratio.
+    ratio2 = radius2 / smlen2;
+    // Check whether the ratio is smaller than permitted.
+    enq = ratio2 > b->goodratio;
+    if (!enq) {
+      // abcd has good ratio.
+      if (b->offcenter) {
+        // Test if it is a sliver.
+        // Compute the 4 face normals (N[0], ..., N[3]).
+        for (j = 0; j < 3; j++) {
+          for (i = 0; i < 3; i++) rhs[i] = 0.0;
+          rhs[j] = 1.0;  // Positive means the inside direction
+          lu_solve(A, 3, indx, rhs, 0);
+          for (i = 0; i < 3; i++) N[j][i] = rhs[i];
+        }
+        // Get the fourth normal by summing up the first three.
+        for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
+        // Normalized the normals.
+        for (i = 0; i < 4; i++) {
+          L = sqrt(dot(N[i], N[i]));
+          if (L > 0.0) {
+            for (j = 0; j < 3; j++) N[i][j] /= L;
+          }
+        }
+        // N[0] is the normal of face bcd. Test the dihedral angles at edge
+        //   cd, bd, and bc to see if they are too small or too big.
+        for (i = 1; i < 4 && !enq; i++) {
+          cosd = -dot(N[0], N[i]); // Edge cd, bd, bc.
+          enq = ((cosd > cosmindihed) || ((cosd < cosmaxdihed)));
+        }
+        if (enq) {
+          // A sliver! Split it at the barycenter.
+          for (i = 0; i < 3; i++) {
+            circumcent[i] = 0.25 * (pa[i] + pb[i] + pc[i] + pd[i]);
+          }
+          ratio2 = 0.0;
+        }
+      }
+    } else if (b->offcenter) {
+      // abcd has bad-quality. Use off-center instead of circumcenter.
+      switch (sidx) {
+      case 0: // edge da.
+        pe1 = pd; pe2 = pa; break;
+      case 1: // edge db.
+        pe1 = pd; pe2 = pb; break;
+      case 2: // edge dc.
+        pe1 = pd; pe2 = pc; break;
+      case 3: // edge ab.
+        pe1 = pa; pe2 = pb; break;
+      case 4: // edge bc.
+        pe1 = pb; pe2 = pc; break;
+      case 5: // edge ca.
+        pe1 = pc; pe2 = pa; break;
+      default: break;
+      }
+      // The shortest edge is e1->e2.
+      for (i = 0; i < 3; i++) bicent[i] = 0.5 * (pe1[i] + pe2[i]);
+      dist = distance(bicent, circumcent);
+      // sdist = sqrt(smlen2) * sin(PI / 3.0); // A icoso-triangle.
+      // The following formulae is from 
+      sdist = b->alpha3 * (b->minratio + sqrt(b->goodratio - 0.25))
+            * sqrt(smlen2);
+      split = sdist / dist;
+      if (split > 1.0) split = 1.0;
+      // Get the off-center.
+      for (i = 0; i < 3; i++) {
+        offcent[i] = bicent[i] + split * (circumcent[i] - bicent[i]);
+      }
+    }
+  } else {
+    // A fat tet. Split it at the centroid.
+    for (i = 0; i < 3; i++) {
+      circumcent[i] = 0.25 * (pa[i] + pb[i] + pc[i] + pd[i]);
+    }
+    ratio2 = 0.0;
+  }
+
+  if (!enq && (b->varvolume || b->fixedvolume)) {
+    // The tet is in good shape.
+    ratio2 = 0.0;
+    enq = b->fixedvolume && (volume > b->maxvolume);
+    if (!enq && b->varvolume) {
+      enq = (volume > volumebound(testtet->tet)) &&
+            (volumebound(testtet->tet) > 0.0);
+    }
+  }
+  if (!enq) {
+    // The tet is in good shape.
+    ratio2 = 0.0;
+    if (b->bgmesh && (b->alpha1 > 0.0)) {
+      sdist = sqrt(radius2) / b->alpha1;
+      // Check if the nodal size map is satisfied. 
+      for (i = 0; i < 4; i++) {
+        pa = (point) testtet->tet[4 + i];
+        // Get the indicated size of p.
+        dist = pa[3]; // dist = b->alpha1 * pa[pointlfsindex];
+        enq = ((dist < sdist) && (dist > 0.0));
+        if (enq) break; // It is bad wrt. a node constraint.
+        // *** Experiment ! Stop test if c is inside H(a).
+        // if ((dist > 0.0) && (dist > sdist)) break;
+      }
+      // *** Experiment !
+      // enq = (i == 4); // Does c lies outside all sparse-ball?
+    }
+  }
+
+  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);
+    }
+  }
+
+  return enq;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// acceptsegpt()    Check if a segment point can be inserted or not.         //
+//                                                                           //
+// Segment(ab) is indicated to be split by a point p (\in ab). This routine  //
+// decides whether p can be inserted or not.                                 //
+//                                                                           //
+// 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.                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+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;
+
+  if (b->nobisect == 1) {
+    // '-Y'. It can not be split if it is on the hull.
+    sstpivot(splitseg, &spintet);
+    assert(spintet.tet != dummytet);
+    pc = apex(spintet);
+    do {
+      if (!fnextself(spintet)) {
+        // Meet a boundary face - s is on the hull.
+        return false;
+      }
+    } while (pc != apex(spintet));
+  } else if (b->nobisect > 1) {
+    // '-YY'. Do not split it.
+    return false;
+  }
+  
+  pa = sorg(*splitseg);
+  pb = sdest(*splitseg);
+  ablen = distance(pa, pb);
+  if (varconstraint) {
+    A = areabound(*splitseg);
+    if ((A > 0.0) && (ablen > A)) {
+      return true; // case (1)
+    }
+  }
+
+  if (varconstraint && in->facetconstraintlist) {
+    A = ablen * ablen / 2.0;
+    spinsh = parentsh;
+    do {
+      if ((A > areabound(spinsh)) && (areabound(spinsh) > 0.0)) {
+        return true; // case (2)
+      }
+      spivotself(spinsh);
+    } while (spinsh.sh != parentsh.sh);
+  }
+
+  if (b->varvolume || b->fixedvolume) {
+    V = ablen * ablen * ablen / 6.0;
+    if (b->fixedvolume && (V > b->maxvolume)) {
+      return true; // case (3)
+    }
+    if (b->varvolume) {
+      spivot(*splitseg, parentsh);
+      if (sorg(parentsh) != pa) sesymself(parentsh);
+      stpivot(parentsh, spintet);
+      if (spintet.tet == dummytet) {
+        sesymself(parentsh);
+        stpivot(parentsh, spintet);
+      }
+      findedge(&spintet, pa, pb);
+      pc = apex(spintet);
+      while (true) {
+        if (!fnextself(spintet)) {
+          // Meet a boundary, walk through it.
+          tspivot(spintet, spinsh);
+          findedge(&spinsh, pa, pb);
+          sfnextself(spinsh);
+          stpivot(spinsh, spintet);
+          findedge(&spintet, pa, pb);
+        }
+        if ((V > volumebound(spintet.tet)) && 
+            (volumebound(spintet.tet) > 0.0)) {
+          return true; // case (3)
+        }
+        if (apex(spintet) == pc) break;
+      }
+    }
+  }
+
+  // If p is outside both protect balls of a and b.
+  palen = distance(segpt, pa);
+  pblen = distance(segpt, pb);
+  if (!b->bgmesh) {
+    if ((palen > (b->alpha2 * pa[pointlfsindex])) &&
+        (pblen > (b->alpha2 * pb[pointlfsindex]))) {
+      return true; // case (4)
+    }
+  } else {
+    if ((palen > b->alpha2 * pa[3]) && (pblen > b->alpha2 * pb[3])) {
+      return true; // case (4)
+    }
+  }
+
+  // If 'refpt' != NULL, force p to be inserted.
+  if (refpt != (point) NULL) {
+    cdtenforcesegpts++;
+    return true;
+  }
+
+  // Do not split it.
+  rejsegpts++;
+  return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// acceptfacpt()    Check if a facet point can be inserted or not.           //
+//                                                                           //
+// 'subceillist' is CBC(p). 'verlist' (V) is empty on input, it returns the  //
+// set of vertices of CBC(p).                                                //
+//                                                                           //
+// 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.    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::acceptfacpt(point facpt, list* subceillist, list* verlist)
+{
+  triface testtet;
+  face *testsh;
+  point p[3];
+  REAL L, L2, L3, lfs;
+  int idx, i, j;
+
+  if (b->nobisect == 1) {
+    // '-Y'. p can not be inserted if CBC(p) is on the hull.
+    testsh = (face *)(* subceillist)[0];
+    stpivot(*testsh, testtet);
+    if (testtet.tet != dummytet) {
+      sesymself(*testsh);
+      stpivot(*testsh, testtet);
+    }
+    if (testtet.tet == dummytet) return false;
+  } else if (b->nobisect > 1) {
+    // '-YY'. Do not split s.
+    return false;
+  }
+
+  // Collect the vertices of CBC(p), save them in V.
+  for (i = 0; i < subceillist->len(); i++) {
+    testsh = (face *)(* subceillist)[i];
+    p[0] = sorg(*testsh);
+    p[1] = sdest(*testsh);
+    for (j = 0; j < 2; j++) {
+      idx = pointmark(p[j]);
+      if (idx >= 0) {
+        setpointmark(p[j], -idx - 1);
+        verlist->append(&(p[j]));
+      }
+    }
+  }
+  // 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.
+  for (i = 0; i < verlist->len(); i++) {
+    p[0] = * (point *)(* verlist)[i];
+    if (!b->bgmesh) {
+      lfs = b->alpha2 * p[0][pointlfsindex];
+    } else {
+      lfs = b->alpha2 * p[0][3];
+    }
+    L = distance(p[0], facpt);
+    if (L < lfs) break; // p is inside ball.
+  }
+  if (i == verlist->len()) return true; // case (3).
+
+  rejsubpts++;
+  return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// acceptvolpt()    Check if a volume point can be inserted or not.          //
+//                                                                           //
+// '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.                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
-  // Check whether the angle is smaller than permitted.
-  if (angle > b->goodangle) {
-    enq = true;
+bool tetgenmesh::acceptvolpt(point volpt, list* ceillist, list* verlist)
+{
+  triface* testtet;
+  point p[4];
+  REAL L, vol, lfs;
+  int idx, i, j;
+
+  // Collect the vertices of CBC(p), save them in V.
+  for (i = 0; i < ceillist->len(); i++) {
+    testtet = (triface *)(* ceillist)[i];
+    p[0] = org(*testtet);
+    p[1] = dest(*testtet);
+    p[2] = apex(*testtet);
+    for (j = 0; j < 3; j++) {
+      idx = pointmark(p[j]);
+      if (idx >= 0) {
+        setpointmark(p[j], -idx - 1);
+        verlist->append(&(p[j]));
+      }
+    }
+  }
+  // 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 (!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 (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)
+        }
+      }
+    }
   }
 
-  if (enq && enqflag) {    
-    encsub = (badface *) badsubfaces->alloc();
-    encsub->ss = *testsub;
-    encsub->forg = sorg(*testsub);
-    encsub->fdest = sdest(*testsub);
-    encsub->fapex = sapex(*testsub);
-    encsub->foppo = (point) NULL;
-    // Circumcent of testsub is not available. Only initialize it.    
-    for (i = 0; i < 3; i++) encsub->cent[i] = 0.0;
-    encsub->nextitem = (badface *) NULL;
-    // Set the pointer of 'encsubseg' into 'testsub'.  It has two purposes:
-    //   (1) We can regonize it is encroached; (2) It is uniquely queued.
-    setshell2badface(encsub->ss, encsub);
-    // Add the subface to the end of a queue (quenumber = 1, high priority).
-    *subquetail[1] = encsub;
-    // Maintain a pointer to the NULL pointer at the end of the queue.
-    subquetail[1] = &encsub->nextitem;
-    if (b->verbose > 2) {
-      printf("    Queuing badqual subface (%d, %d, %d).\n", pointmark(torg),
-             pointmark(tdest), pointmark(tapex));
+  // Check if p is inside the protect balls of vertices of V.
+  for (i = 0; i < verlist->len(); i++) {
+    p[0] = * (point *)(* verlist)[i];
+    if (!b->bgmesh) {
+      lfs = b->alpha2 * p[0][pointlfsindex];
+    } else {
+      lfs = b->alpha2 * p[0][3];
     }
+    L = distance(p[0], volpt);
+    if (L < lfs) break; // p is inside ball.
   }
+  if (i == verlist->len()) return true; // case (2).
 
-  return enq;
+  rejtetpts++;
+  return false;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// checktet4badqual()    Test a tetrahedron for quality measures.            //
-//                                                                           //
-// Tests a tetrahedron to see if it satisfies the minimum ratio condition    //
-// and the maximum volume condition. Tetrahedra that aren't upto spec are    //
-// added to the bad tetrahedron queue.                                       //
+// getsplitpoint()    Get the inserting point in a segment.                  //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::checktet4badqual(triface* testtet, bool enqflag)
+void tetgenmesh::getsplitpoint(point e1, point e2, point refpt, point newpt)
 {
-  badface *newbadtet;
-  point torg, tdest, tapex, toppo;
-  REAL dxod, dyod, dzod, dxda, dyda, dzda, dxao, dyao, dzao;
-  REAL dxop, dyop, dzop, dxdp, dydp, dzdp, dxap, dyap, dzap;
-  REAL dxod2, dyod2, dzod2, dxda2, dyda2, dzda2, dxao2, dyao2, dzao2;
-  REAL dxop2, dyop2, dzop2, dxdp2, dydp2, dzdp2, dxap2, dyap2, dzap2;
-  REAL dxoc, dyoc, dzoc, dxoc2, dyoc2, dzoc2;
-  REAL elen[6], circumcent[3];
-  REAL smlen, volume;
-  REAL radius, ratio2;
-  bool enq;
-  int queuenumber;
+  point ei, ej;
+  REAL split, L, d1, d2, ps, rs;
+  bool acutea, acuteb;
   int i;
 
-  torg = org(*testtet);
-  tdest = dest(*testtet);
-  tapex = apex(*testtet);
-  toppo = oppo(*testtet);
+  if (refpt != (point) NULL) {
+    // Use the CDT rules to split the segment.
+    acutea = (pointtype(e1) == ACUTEVERTEX);
+    acuteb = (pointtype(e2) == ACUTEVERTEX);
+    if (acutea ^ acuteb) {
+      // Only one endpoint is acute. Use rule-2 or rule-3.
+      ei = acutea ? e1 : e2;
+      ej = acutea ? e2 : e1;
+      L = distance(ei, ej);
+      // Apply rule-2.
+      d1 = distance(ei, refpt);
+      split = d1 / L;
+      for (i = 0; i < 3; i++) newpt[i] = ei[i] + split * (ej[i] - ei[i]);
+      // Check if rule-3 is needed.
+      d2 = distance(refpt, newpt);
+      if (d2 > (L - d1)) {
+        // Apply rule-3.
+        if ((d1 - d2) > (0.5 * d1)) {
+          split = (d1 - d2) / L;
+        } else {
+          split = 0.5 * d1 / L;
+        }
+        for (i = 0; i < 3; i++) newpt[i] = ei[i] + split * (ej[i] - ei[i]);
+        if (b->verbose > 1) {
+          printf("    Found by rule-3:");
+        }
+        r3count++;
+      } else {
+        if (b->verbose > 1) {
+          printf("    Found by rule-2:");
+        }
+        r2count++;
+      }
+      if (b->verbose > 1) {
+        printf(" center %d, split = %.12g.\n", pointmark(ei), split);
+      }
+      // Add a random perturbation on newpt.
+      d1 = distance(ei, newpt);
+      d2 = distance(newpt, refpt);
+      ps = randgenerator(d2 * b->epsilon2);
+      rs = ps / d1;
+      // Perturb newpt away from ei.
+      for (i = 0; i < 3; i++) newpt[i] = ei[i] + (1.0+rs) * (newpt[i] - ei[i]);
+    } else {
+      // Both endpoints are acute or not. Split it at the middle.
+      for (i = 0; i < 3; i++) newpt[i] = 0.5 * (e1[i] + e2[i]);
+    }
+  } else {
+    // Split the segment at its midpoint.
+    for (i = 0; i < 3; i++) newpt[i] = 0.5 * (e1[i] + e2[i]);
+  }
+}
 
-  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];
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// shepardinterpolation()    Interpolate the local size of a newpoint.       //
+//                                                                           //
+// The classical Shepard interoplation (inversed weighted distance) is used. //
+// (With the choice p = 2).                                                  //
+//                                                                           //
+// 'verlist' contains a list vertices neighboring to 'newpt'.                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
-  dxop = torg[0] - toppo[0];
-  dyop = torg[1] - toppo[1];
-  dzop = torg[2] - toppo[2];
-  dxdp = tdest[0] - toppo[0];
-  dydp = tdest[1] - toppo[1];
-  dzdp = tdest[2] - toppo[2];
-  dxap = tapex[0] - toppo[0];
-  dyap = tapex[1] - toppo[1];
-  dzap = tapex[2] - toppo[2];
+void tetgenmesh::shepardinterpolate(point newpt, list *verlist)
+{
+  point neipt;
+  REAL *weights, sumweight;
+  REAL vec[3];
+  int i, j;
 
-  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;
+  weights = new REAL[verlist->len()];
+  sumweight = 0.0;
+
+  // Calculate the weight of each point.
+  for (i = 0; i < verlist->len(); i++) {
+    neipt = * (point *)(* verlist)[i];
+    for (j = 0; j < 3; j++) vec[j] = neipt[j] - newpt[j];
+    weights[i] = 1.0 / dot(vec, vec);
+    sumweight += weights[i];
+  }
+  // Interpolate.
+  newpt[pointlfsindex] = 0.0;
+  for (i = 0; i < verlist->len(); i++) {
+    neipt = * (point *)(* verlist)[i];
+    newpt[pointlfsindex] += (weights[i] * neipt[pointlfsindex]) / sumweight;
+  }
+
+  delete [] weights;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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.              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
-  dxop2 = dxop * dxop;
-  dyop2 = dyop * dyop;
-  dzop2 = dzop * dzop;
-  dxdp2 = dxdp * dxdp;
-  dydp2 = dydp * dydp;
-  dzdp2 = dzdp * dzdp;
-  dxap2 = dxap * dxap;
-  dyap2 = dyap * dyap;
-  dzap2 = dzap * dzap;
-
-  // Find the smallest edge length of 'testtet'.
-  elen[0] = dxod2 + dyod2 + dzod2;
-  elen[1] = dxda2 + dyda2 + dzda2;
-  elen[2] = dxao2 + dyao2 + dzao2;
-  elen[3] = dxop2 + dyop2 + dzop2;
-  elen[4] = dxdp2 + dydp2 + dzdp2;
-  elen[5] = dxap2 + dyap2 + dzap2;
-  smlen = elen[0];
-  for (i = 1; i < 6; i++) {
-    if (smlen > elen[i]) {
-      smlen = elen[i];
-    }
-  }
-
-  // Find the circumcenter and circumradius of 'testtet'.
-  circumsphere(torg, tdest, tapex, toppo, circumcent, NULL);
-  dxoc = torg[0] - circumcent[0];
-  dyoc = torg[1] - circumcent[1];
-  dzoc = torg[2] - circumcent[2];
-  dxoc2 = dxoc * dxoc;
-  dyoc2 = dyoc * dyoc;
-  dzoc2 = dzoc * dzoc;
-  radius = dxoc2 + dyoc2 + dzoc2;
+void tetgenmesh::setnewpointsize(point newpt, list* verlist)
+{
+  if (b->bgmesh) {
+    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);
+  } else {
+    // Interpolate a local size for p using Shepard interpolation.
+    shepardinterpolate(newpt, verlist);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// splitencseg()    Split an enc-seg and recover the Delaunayness by flips.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::splitencseg(point newpt, face* splitseg, list* tetlist,
+  list* sublist, list* verlist, queue* flipque, bool chkencsub, bool chkbadtet)
+{
+  triface starttet;
+  face startsh, spinsh, checksh;
+  int i;
+
+  // 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);
   
-  // Calculate the square of radius-edge ratio.
-  ratio2 = radius / smlen;
-  // Check whether the ratio is smaller than permitted.
-  enq = ratio2 > b->goodratio;
-  if (!enq && (b->varvolume || b->fixedvolume)) {
-    // The tet is in good shape.
-    ratio2 = 0.0;
-    // It will get split if it's volume is larger than permitted.
-    volume = orient3d(torg, tdest, tapex, toppo);
-    if (volume < 0) volume = -volume;
-    volume /= 6.0;
-    enq = b->fixedvolume && (volume > b->maxvolume);
-    if (!enq && b->varvolume) {
-      enq = (volume > volumebound(testtet->tet)) &&
-            (volumebound(testtet->tet) > 0.0);
+  // Check the two new subsegs to see if they're encroached (not by p).
+  for (i = 0; i < 2; i++) {
+    if (!shell2badface(*splitseg)) {
+      checkseg4encroach(splitseg, NULL, NULL, true);
+      if (!shell2badface(*splitseg)) {
+        if (varconstraint && (areabound(*splitseg) > 0.0)) {
+          checkseg4badqual(splitseg, true);
+        }
+      }
+    }
+    if (i == 1) break; // Two new segs have been checked.
+    senextself(*splitseg);
+    spivotself(*splitseg);
+#ifdef SELF_CHECK
+    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);
+          if (!shell2badface(checksh)) {
+            if (varconstraint && (areabound(checksh) > 0.0)) {
+              checksub4badqual(&checksh, true);
+            }
+          }
+        }
+      }
+      sublist->clear();
+      verlist->clear();
+      spivotself(spinsh);
+    } while (spinsh.sh != startsh.sh);
+  }
+  
+  // Collect the new tets connecting at p.
+  sstpivot(splitseg, &starttet);
+  tetlist->append(&starttet);
+  formstarpolyhedron(newpt, tetlist, verlist, true);
+
+  // 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();
+}
 
-  if (enq && enqflag) {
-    // Allocate space for the bad tetrahedron.
-    newbadtet = (badface *) badtetrahedrons->alloc();
-    newbadtet->tt = *testtet;
-    newbadtet->key = ratio2;
-    newbadtet->cent[0] = circumcent[0];
-    newbadtet->cent[1] = circumcent[1];
-    newbadtet->cent[2] = circumcent[2];
-    newbadtet->forg = torg;
-    newbadtet->fdest = tdest;
-    newbadtet->fapex = tapex;
-    newbadtet->foppo = toppo;
-    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;
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tallencsegs()    Check for encroached segments and save them in list.     //
+//                                                                           //
+// If 'testpt' (p) != NULL, only check if segments are encroached by p, else,//
+// check all the nearby mesh vertices.                                       //
+//                                                                           //
+// If 'ceillists' (B_i(p)) != NULL, there are 'n' B_i(p)s, only check the    //
+// segments which are on B_i(p)s, else, check the entire list of segments    //
+// (in the pool 'this->subsegs').                                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::tallencsegs(point testpt, int n, list **ceillists)
+{
+  list *ceillist;
+  triface ceiltet;
+  face checkseg;
+  long oldencnum;
+  int i, j, k;
+  
+  // Remember the current number of encroached segments.
+  oldencnum = badsubsegs->items;
+
+  if (ceillists != (list **) NULL) {
+    for (k = 0; k < n; k++) {
+      ceillist = ceillists[k];
+      // Check the segments on B_i(p).
+      for (i = 0; i < ceillist->len(); i++) {
+        ceiltet = * (triface *)(* ceillist)[i];
+        ceiltet.ver = 0;
+        for (j = 0; j < 3; j++) {
+          tsspivot(&ceiltet, &checkseg);
+          if (checkseg.sh != dummysh) {
+            // 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);
+        }
       }
-    } 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(torg), pointmark(tdest), pointmark(tapex),
-             pointmark(toppo), sqrt(ratio2), queuenumber);
+  } else {
+    // Check the entire list of segments.
+    subsegs->traversalinit();
+    checkseg.sh = shellfacetraverse(subsegs);
+    while (checkseg.sh != (shellface *) NULL) {
+      // 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);
     }
   }
 
-  return enq;
+  return (badsubsegs->items > oldencnum);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// checktet4sliver()    Test a tetrahedron to see if it is a sliver.         //
+// tallencsubs()    Find all encroached subfaces and save them in list.      //
+//                                                                           //
+// If 'testpt' (p) != NULL, only check if subfaces are encroached by p, else,//
+// check the adjacent vertices of subfaces.                                  //
 //                                                                           //
-// A tetrahedron is a sliver if it is not in bad quality with respect to the //
-// radius-edge ratio, but contains large dihedral angle (> 175 degree).      //
+// If 'ceillists' (B_i(p)) != NULL, there are 'n' B_i(p)s, only check the    //
+// subfaces which are on B_i(p)s, else, check the entire list of subfaces    //
+// (in the pool 'this->subfaces').                                           //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::checktet4sliver(triface* testtet, bool enqflag)
+bool tetgenmesh::tallencsubs(point testpt, int n, list** ceillists)
 {
-  badface *newbadtet;
-  point pa, pb, pc, pd;
-  REAL da[6], maxdihedral;
-  bool enq;
-  int i;
+  list *ceillist;
+  triface ceiltet;
+  face checksh;
+  long oldencnum;
+  int i, k;
+  
+  // Remember the current number of encroached segments.
+  oldencnum = badsubfaces->items;
 
-  maxdihedral = 170.0 / 180.0 * PI;
-  enq = false;
-  if (!checktet4badqual(testtet, false)) {
-    pa = org(*testtet);
-    pb = dest(*testtet);
-    pc = apex(*testtet);
-    pd = oppo(*testtet);
-    tetalldihedral(pa, pb, pc, pd, da);
-    for (i = 0; i < 6; i++) {
-      enq = da[i] > maxdihedral;
-      if (enq) break;
+  if (ceillists != (list **) NULL) {
+    for (k = 0; k < n; k++) {
+      ceillist = ceillists[k];
+      // Check the subfaces on B_i(p).
+      for (i = 0; i < ceillist->len(); i++) {
+        ceiltet = * (triface *)(* ceillist)[i];
+        tspivot(ceiltet, checksh);
+        if (checksh.sh != dummysh) {
+          // 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);
+              }
+            }
+          }
+        }
+      }
+    }
+  } else {
+    // Check the entire list of subfaces.
+    subfaces->traversalinit();
+    checksh.sh = shellfacetraverse(subfaces);
+    while (checksh.sh != (shellface *) NULL) {
+      // 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);
     }
   }
 
-  if (enq && enqflag) {
-    // Allocate space for the bad tetrahedron.
-    newbadtet = (badface *) badtetrahedrons->alloc();
-    newbadtet->tt = *testtet;
-    newbadtet->key = da[i];
-    newbadtet->cent[0] = 0.0;
-    newbadtet->cent[1] = 0.0;
-    newbadtet->cent[2] = 0.0;
-    newbadtet->forg = pa;
-    newbadtet->fdest = pb;
-    newbadtet->fapex = pc;
-    newbadtet->foppo = pd;
-    newbadtet->nextitem = (badface *) NULL;
-    if (b->verbose > 2) {
-      printf("    Queueing sliver: (%d, %d, %d, %d) %.12g.\n", pointmark(pa),
-             pointmark(pb), pointmark(pc), pointmark(pd), da[i] / PI * 180.0);
-    }
+  return (badsubfaces->items > oldencnum);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tallbadtetrahedrons()    Queue all the bad-quality tetrahedra in the mesh.//
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::tallbadtetrahedrons()
+{
+  triface tetloop;
+
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    checktet4badqual(&tetloop, true);
+    tetloop.tet = tetrahedrontraverse();
   }
-
-  return enq;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// checkseg4splitting()    Check an encroached subsegment to see if it is    //
-//                         suitable to be split.                             //
+// repairencsegs()    Repair (split) all the encroached segments.            //
+//                                                                           //
+// Each encroached segment is repaired by splitting it - inserting a vertex  //
+// at or near its midpoint.  Newly inserted vertices may encroach upon other //
+// subsegments, these are also repaired.                                     //
 //                                                                           //
-// Segment(ab) is encroached by an existing vertex or rejected circumcenter  //
-// of a subface.  It can be split if it satifies the following cases:        //
-//   (1) if ab is encroached by an existing vertex; else                     //
-//   (2) if ab is too long wrt the edge constraint; else                     //
-//   (3) if ab not belongs to a skinny subface, then split it if:            //
-//       (a) both a and b are acute or nonacute; else,                       //
-//       (b) assume a is acute, it can be split if |ab| > rps(a) / 2.0.      //
-//   (4) When the facet constraint is in use. If there is a constrained      //
-//       subface s containing ab, and |ab|^2 > a, a is the area bound of a.  //
-//   (5) When the volume costraint (-a) is in use. If there is a constrained //
-//       tet t containg ab, and |ab|^3 > v, v is the volume bound of t.      //
-// The perpose of using values |ab|^2 and |ab|^3 instead of area and volume  //
-// is to avoid resulting too skinny triangles and tetrahedron.               //
+// 'chkencsub' and 'chkbadtet' are two flags that specify whether one should //
+// take note of new encroaced subfaces and bad quality tets that result from //
+// inserting vertices to repair encroached subsegments.                      //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::checkseg4splitting(face* testseg, point* pencpt)
+void tetgenmesh::repairencsegs(bool chkencsub, bool chkbadtet)
 {
-  triface spintet;
-  face parentsh, spinsh;
-  point eorg, edest, fapex;
-  bool acuteorg, acutedest;
-  REAL rpslimit, L, L2, L3;
-  enum shestype shty;
-  bool skinny;
-  int ptidx;
-
-  *pencpt = (point) NULL;
-  
-  // Is it encroached by an existing vertex?
-  if (checkseg4encroach(testseg, NULL, pencpt, false)) {
-    assert(*pencpt != (point) NULL);
-    return true;
+  list **tetlists, **ceillists;
+  list **sublists, **subceillists;
+  list *tetlist, *sublist, *verlist;
+  queue *flipque;
+  badface *encloop;
+  face splitseg, symsplitseg;
+  point newpt, sympt, refpt;
+  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];
+    sublists = new list*[nmax];
+    subceillists = new list*[nmax];
+  } 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));
   }
 
-  eorg = sorg(*testseg);
-  edest = sdest(*testseg);
-  L = distance(eorg, edest);
-
-  // Is it in badqual?
-  if (varconstraint && (areabound(*testseg) > 0.0)) {
-    return L > areabound(*testseg);
+  // Loop until the pool 'badsubsegs' is empty. Note that steinerleft == -1
+  //   if an unlimited number of Steiner points is allowed.
+  while ((badsubsegs->items > 0) && (steinerleft != 0)) {
+    badsubsegs->traversalinit();
+    encloop = badfacetraverse(badsubsegs);
+    while ((encloop != (badface *) NULL) && (steinerleft != 0)) {
+      // Get an encroached subsegment s.
+      splitseg = encloop->ss;
+      // Clear the in-queue flag in s.
+      setshell2badface(splitseg, NULL);
+      if ((sorg(splitseg) == encloop->forg) && 
+          (sdest(splitseg) == encloop->fdest)) {
+        if (b->verbose > 1) {
+          printf("  Get an enc-seg (%d, %d)\n", pointmark(encloop->forg),
+                 pointmark(encloop->fdest));
+        }
+        refpt = (point) NULL;
+        if (b->conformdel) {
+          // Look for a reference point.
+          checkseg4encroach(&splitseg, NULL, &refpt, false);
+        }
+        // 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));
+        // Decide whether p can be inserted or not.
+        if (acceptsegpt(newpt, refpt, &splitseg)) {
+          // Is there periodic boundary condition?
+          if (checkpbcs) {
+            // Insert points on other segments of incident pbcgroups.
+            i = shellmark(splitseg) - 1;
+            for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++) {
+              makepoint(&sympt);
+              symloc = getsegpbcsympoint(newpt, &splitseg, sympt, &symsplitseg,
+                                         segpglist[j]);
+              if (symloc == ONEDGE) {
+                if (symsplitseg.sh != splitseg.sh) {
+                  // Insert sympt.
+                  setpointtype(sympt, FREESEGVERTEX);
+                  setpoint2sh(sympt, sencode(symsplitseg));
+                  if (!b->fliprepair) {
+                    // Form BC(symp), B(symp), CBC(symp)s, C(symp)s.
+                    formbowatcavity(sympt, &symsplitseg, NULL, &n, &nmax,
+                      sublists, subceillists, tetlists, ceillists);
+                    // Validate BC(symp), B(symp), CBC(symp)s, C(symp)s.
+                    if (trimbowatcavity(sympt, &symsplitseg, n, sublists,
+                          subceillists, tetlists, ceillists, -1.0)) {
+                      bowatinsertsite(sympt, &symsplitseg, n, sublists,
+                        subceillists, tetlists, ceillists, verlist, flipque,
+                        true, chkencsub, chkbadtet);
+                      setnewpointsize(sympt, verlist);
+                      if (steinerleft > 0) steinerleft--;
+                    } else {
+                      // p did not insert for invalid BC(symp).
+                      pointdealloc(sympt);
+                    }
+                    // Free the memory allocated in formbowatcavity().
+                    releasebowatcavity(&symsplitseg, n, sublists, subceillists,
+                                       tetlists, ceillists);
+                  } else {
+                    splitencseg(sympt, &symsplitseg, tetlist, sublist, verlist,
+                                flipque, chkencsub, chkbadtet);
+                    setnewpointsize(sympt, verlist);
+                    if (steinerleft > 0) steinerleft--;
+                  }
+                  verlist->clear();
+                } else {
+                  // The sympt are on the same segment. It is possible when
+                  //   splitseg is the symmetric rotating axes.
+                  pointdealloc(sympt);
+                }
+              } else if (symloc == ONVERTEX) {
+                // The sympt already exists. It is possible when two pbc
+                //   groups are exactly the same. Omit this point.
+                pointdealloc(sympt);
+              } else {
+                // Do not isnert symp for unknown cases: ONFACE, OUTSIDE.
+                // assert(0);
+                pointdealloc(sympt);
+              }
+            } // for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++)
+          } // if (checkpbcs)
+          if (!b->fliprepair) {
+            // Form BC(p), B(p), CBC(p)s, and C(p)s.
+            formbowatcavity(newpt, &splitseg, NULL, &n, &nmax, sublists,
+                            subceillists, tetlists, ceillists);
+            // Validate/update BC(p), B(p), CBC(p)s, and C(p)s.
+            if (trimbowatcavity(newpt, &splitseg, n, sublists, subceillists, 
+                                tetlists, ceillists, -1.0)) {
+              bowatinsertsite(newpt, &splitseg, n, sublists, subceillists,
+                              tetlists, ceillists, verlist, flipque, true,
+                              chkencsub, chkbadtet);
+              setnewpointsize(newpt, verlist);
+              if (steinerleft > 0) steinerleft--;
+            } else {
+              // p did not insert for invalid B(p).
+              pointdealloc(newpt);
+            }
+            // Free the memory allocated in formbowatcavity().
+            releasebowatcavity(&splitseg, n, sublists, subceillists, tetlists,
+                               ceillists);
+          } else {
+            splitencseg(newpt, &splitseg, tetlist, sublist, verlist, flipque,
+                        chkencsub, chkbadtet);
+            setnewpointsize(newpt, verlist);
+            if (steinerleft > 0) steinerleft--;
+          }
+          verlist->clear();
+        } else {
+          // p did not accept for insertion.
+          pointdealloc(newpt);
+        } // if (checkseg4splitting(newpt, &splitseg))
+      } // if ((encloop->forg == pa) && (encloop->fdest == pb))
+      badfacedealloc(badsubsegs, encloop); // Remove this entry from list.
+      encloop = badfacetraverse(badsubsegs); // Get the next enc-segment.
+    } // while ((encloop != (badface *) NULL) && (steinerleft != 0))
+  } // while ((badsubsegs->items > 0) && (steinerleft != 0))
+
+  if (!b->fliprepair) {
+    delete [] tetlists;
+    delete [] ceillists;
+    delete [] sublists;
+    delete [] subceillists;
+  } else {
+    delete tetlist;
+    delete sublist;
+  }
+  delete verlist;
+  if (b->fliprepair) {
+    delete flipque;
   }
+}
 
-  // Check if ab belongs to a skinny subface.
-  skinny = false;
-  spivot(*testseg, parentsh);
-  spinsh = parentsh;
-  do {
-    shty = shelltype(spinsh);
-    if ((shty == SKINNYSUB) || (shty == SHARPSKINNYSUB)) {
-      skinny = true; break;
-    }
-    spivotself(spinsh);
-  } while (spinsh.sh != parentsh.sh);
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// repairencsubs()    Repair (split) all the encroached subfaces.            //
+//                                                                           //
+// Each encroached subface is repaired by splitting it - inserting a vertex  //
+// at or near its circumcenter.  Newly inserted vertices may encroach upon   //
+// other subfaces, these are also repaired.                                  //
+//                                                                           //
+// 'chkbadtet' is a flag that specifies whether one should take note of new  //
+// bad quality tets that result from inserted vertices.                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
-  if (!skinny) {
-    acuteorg = pointtype(eorg) == ACUTEVERTEX;
-    acutedest = pointtype(edest) == ACUTEVERTEX;
-    if ((acuteorg && acutedest) || (!acuteorg && !acutedest)) {
-      // It can be split.
-      return true;
-    }
-    // Now exactly one vertex is acute.
-    assert(acuteorg || acutedest);
-    if (acuteorg) {
-      ptidx = pointmark(eorg);
-    } else {
-      assert(acutedest);
-      ptidx = pointmark(edest);
-    }
-    rpslimit = rpsarray[ptidx] / 2.0;
-    if (L > (rpslimit * 1.1)) {
-      // The edge is not too small, can be split.
-      return true;
-    }
-    // L <= rpslimit.
-  }
+void tetgenmesh::repairencsubs(bool chkbadtet)
+{
+  list *tetlists[2], *ceillists[2];
+  list *sublist, *subceillist;
+  list *verlist;
+  badface *encloop;
+  face splitsub, symsplitsub;
+  point newpt, sympt;
+  enum locateresult loc, symloc;
+  bool reject;
+  long oldptnum;
+  int quenumber, n, i;
 
-  if (varconstraint && in->facetconstraintlist) {
-    // Is there a subface which has too large area?
-    L2 = L * L / 2.0;
-    spinsh = parentsh;
-    do {
-      if ((L2 > areabound(spinsh)) && (areabound(spinsh) > 0.0)) {
-        // This edge is too long wrt the maximum area bound. Split it.
-        return true;
-      }
-      spivotself(spinsh);
-    } while (spinsh.sh != parentsh.sh);
-  }
+  n = 0;
+  sublist = (list *) NULL;
+  subceillist = (list *) NULL;
+  verlist = new list(sizeof(point *), NULL, 256);
 
-  // L <= rpslimit.  We should not split it. However, it may still be
-  //   split if its length is too long wrt. the volume constraints.
-  if (b->varvolume || b->fixedvolume) {
-    L = distance(eorg, edest);
-    L3 = L * L * L / 6.0;
-    if (b->fixedvolume && (L3 > b->maxvolume)) {
-      // This edge is too long wrt. the maximum volume bound. Split it.
-      return true; 
-    } 
-    if (b->varvolume) {
-      spivot(*testseg, parentsh);
-      if (sorg(parentsh) != eorg) sesymself(parentsh);
-      stpivot(parentsh, spintet);
-      if (spintet.tet == dummytet) {
-        sesymself(parentsh);
-        stpivot(parentsh, spintet);
-        assert(spintet.tet != dummytet);
+  // Loop until the pool 'badsubfaces' is empty. Note that steinerleft == -1
+  //   if an unlimited number of Steiner points is allowed.
+  while ((badsubfaces->items > 0) && (steinerleft != 0)) {
+    // Get an encroached subface f.
+    encloop = dequeueencsub(&quenumber);
+    splitsub = encloop->ss;
+    // 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 (b->verbose > 1) {
+        printf("    Dequeuing ensub (%d, %d, %d) [%d].\n",
+               pointmark(encloop->forg), pointmark(encloop->fdest),
+               pointmark(encloop->fapex), quenumber);
       }
-      findedge(&spintet, eorg, edest);
-      fapex = apex(spintet);
-      while (true) {
-        if (!fnextself(spintet)) {
-          // Meet a boundary, walk through it.
-          tspivot(spintet, spinsh);
-          assert(spinsh.sh != dummysh);
-          findedge(&spinsh, eorg, edest);
-          sfnextself(spinsh);
-          stpivot(spinsh, spintet);
-          assert(spintet.tet != dummytet);
-          findedge(&spintet, eorg, edest);
+      // Create a new point p.
+      makepoint(&newpt);
+      // If f was added by checksub4badqual(), calculate its circumcenter.
+      if (quenumber == 2) {
+        circumsphere(encloop->forg, encloop->fdest, encloop->fapex, NULL,
+                     encloop->cent, NULL);
+      }
+      for (i = 0; i < 3; i++) newpt[i] = encloop->cent[i];
+      setpointtype(newpt, FREESUBVERTEX);
+      setpoint2sh(newpt, sencode(splitsub));
+      // Set the abovepoint of f for point location.
+      abovepoint = facetabovepointarray[shellmark(splitsub)];
+      if (abovepoint == (point) NULL) {
+        getfacetabovepoint(&splitsub);
+      }
+      // Locate p, start from f, stop at segment (1), use a tolerance to
+      //   detect ONVERTEX or OUTSIDE case. Update f on return.
+      loc = locatesub(newpt, &splitsub, 1, b->epsilon * 1e+2);
+      if ((loc != ONVERTEX) && (loc != OUTSIDE)) {
+        // 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)).
+        reject = tallencsegs(newpt, 2, ceillists);
+        if (!reject) {
+          // Decide whether f is allowed to be split or not?
+          reject = !acceptfacpt(newpt, subceillist, verlist);
+          verlist->clear();
         }
-        if ((L3 > volumebound(spintet.tet)) && 
-            (volumebound(spintet.tet) > 0.0)) {
-          // This edge is too long wrt the maximum volume bound. Split it.
-          return true; 
+        if (!reject) {
+          // Validate/update cavity.
+          reject = !trimbowatcavity(newpt, NULL, n, &sublist, &subceillist,
+                                    tetlists, ceillists, -1.0);
+        }
+        if (!reject) {
+          // CBC(p) should include s, so that s can be removed after CBC(p)
+          //   is remeshed. However, if there are locally non-Delaunay faces
+          //   and encroached subsegments, s may not be collected in CBC(p).
+          //   p should not be inserted in such case.
+          reject = !sinfected(encloop->ss);
+        }
+        if (!reject) {
+          if (checkpbcs) {
+            if (shellpbcgroup(splitsub) >= 0) {
+              // Check for splitting of the symmetric subface of f.
+              makepoint(&sympt);
+              symloc = getsubpbcsympoint(newpt,&splitsub,sympt,&symsplitsub);
+              if (symloc != ONVERTEX) {
+                // Release CBC(p) and BC(p) and free the memory..
+                releasebowatcavity(NULL, 2, &sublist, &subceillist, tetlists,
+                                   ceillists);
+                // Form CBC(symp), C(symp), BC(sympt) and B(sympt).
+                formbowatcavity(sympt, NULL, &symsplitsub, &n, NULL, &sublist,
+                                &subceillist, tetlists, ceillists);
+                reject = tallencsegs(sympt, 2, ceillists);
+                if (!reject) {
+                  reject = !acceptfacpt(sympt, subceillist, verlist);
+                  verlist->clear();
+                }
+                if (!reject) {
+                  reject = !trimbowatcavity(sympt,NULL,n,&sublist,&subceillist,
+                                            tetlists, ceillists, -1.0);
+                }
+                if (!reject) {
+                  // Insert sympt.
+                  setpoint2pbcpt(newpt, sympt);
+                  setpoint2pbcpt(sympt, newpt);
+                  setpointtype(sympt, FREESUBVERTEX);
+                  setpoint2sh(sympt, sencode(symsplitsub));
+                  bowatinsertsite(sympt, NULL, n, &sublist, &subceillist,
+                     tetlists,ceillists,verlist,NULL,false,true,chkbadtet);
+                  setnewpointsize(sympt, verlist);
+                  verlist->clear();
+                  if (steinerleft > 0) steinerleft--;
+                } 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);
+                }
+                // 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);
+                // p is rejected due to symp.
+                reject = true;
+              }
+            }
+          } // if (checkpbcs)
+        }
+        if (!reject) {
+          // Insert p.
+          if (checkpbcs) {
+            if (shellpbcgroup(splitsub) >= 0) {
+              // Form CBC(p), C(p), BC(p) and B(p).
+              formbowatcavity(newpt, NULL, &splitsub, &n, NULL, &sublist,
+                              &subceillist, tetlists, ceillists);
+              trimbowatcavity(newpt, NULL, n, &sublist, &subceillist, tetlists,
+                              ceillists, -1.0);
+            }
+          }
+          bowatinsertsite(newpt, NULL, n, &sublist, &subceillist, tetlists,
+                          ceillists, verlist, NULL, true, true, chkbadtet);
+          setnewpointsize(newpt, verlist);
+          verlist->clear();
+          if (steinerleft > 0) steinerleft--;
+        } else {
+          // p is rejected for the one of the following reasons:
+          //   (1) BC(p) is not valid.
+          //   (2) s does not in CBC(p).
+          //   (3) p encroaches upon some segments (queued); or
+          //   (4) p is rejected by point accepting rule, or
+          //   (5) due to the rejection of symp (the PBC).
+          pointdealloc(newpt);
+        } // if (!reject)
+        // Release the cavity and free the memory.
+        releasebowatcavity(NULL, n, &sublist, &subceillist, tetlists,
+                           ceillists);
+        if (reject) {
+          // Are there queued encroached subsegments.
+          if (badsubsegs->items > 0) {
+            // Repair enc-subsegments.
+            oldptnum = points->items;
+            repairencsegs(true, chkbadtet);
+            if (points->items > oldptnum) {
+              // Some enc-subsegments got split. Try to repair f later.
+              splitsub = encloop->ss;
+              if (!isdead(&splitsub)) {
+                if (!shell2badface(splitsub)) {
+                  checksub4encroach(&splitsub, NULL, true);
+                  if (!shell2badface(splitsub)) {
+                    if (varconstraint && (areabound(splitsub) > 0.0)) {
+                      checksub4badqual(&splitsub, true);
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      } else {
+        // Don't insert p for one of the following reasons:
+        //   (1) Locate on an existing vertex; or
+        //   (2) locate outside the domain.
+        // Case (1) should not be possible. If such vertex v exists, it is
+        //   the circumcenter of f, ie., f is non-Delaunay. Either f was got
+        //   split before by v, but survived after v was inserted, or the
+        //   same for a f' which is nearly co-circular with f.  Whatsoever,
+        //   there are encroached segs by v, but the routine tallencsegs()
+        //   did not find them out.
+        if (loc == ONVERTEX) {
+          printf("Internal error in repairencsubs():\n");
+          printf("  During repairing encroached subface (%d, %d, %d)\n",
+                 pointmark(encloop->forg), pointmark(encloop->fdest),
+                 pointmark(encloop->fapex));
+          printf("  New point %d is coincident with an existing vertex %d\n",
+                 pointmark(newpt), pointmark(sorg(splitsub)));
+          internalerror();
+        }
+        // Case (2) can happen when thers is a segment s which is close to f
+        //   and is non-conforming Delaunay. The circumcenter of f encroaches
+        //   upon s, but the circumcenter of s is rejected for insertion.
+        pointdealloc(newpt);
+      } // if ((loc != ONVERTEX) && (loc != OUTSIDE))
+    } else {
+      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 (apex(spintet) == fapex) break;
       }
-    }
-  }
+    } // if (!isdead(&splitsub) && (sorg(splitsub) == encloop->forg) &&
+    // Remove this entry from list.
+    badfacedealloc(badsubfaces, encloop);
+  } // while ((badsubfaces->items > 0) && (steinerleft != 0))
 
-  // Not split it.
-  return false;
+  delete verlist;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// checksub4splitting()    Check an encroached subface to see if it is       //
-//                         suitable to be split.                             //
+// repairbadtets()    Repair all bad-quality tetrahedra.                     //
 //                                                                           //
-// Subface(abc) is in bad quality, or is encroached by an existing vertex or //
-// by a rejected circumcenter of a tetrahedron.  It can be split if:         //
-//   (1) it is in bad quality (indicated by 'bqual'); else,                  //
-//   (2) it is not in bad quality and not sharp; else,                       //
-//   (3) When the volume costraint (-a) is in use. If there is a tet t       //
-//       containg abc, and L^3 > vol(t), where L := max{|ab|, |bc|, |ca|}.   //
-// The purpose of using L^3 is to avoid resulting too skinny tetrahedron.    //
+// All bad-quality tets are stored in pool 'badtetrahedrons'.  Each bad tet  //
+// is repaired by inserting a point at or near its circumcenter. However, if //
+// this point encroaches any subsegment or subface, it is not inserted. Ins- //
+// tead the encroached segment and subface are split.  Newly inserted points //
+// may create other bad-quality tets, these are also repaired.               //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::checksub4splitting(face* testsh, bool bqual)
+void tetgenmesh::repairbadtets()
 {
-  triface testtet;
-  point p[3];
-  enum shestype shty;
-  REAL L, L3;
+  list *tetlist, *ceillist;
+  list *verlist;
+  badface *badtet;
+  triface starttet;
+  point newpt;
+  enum locateresult loc;
+  bool reject;
+  long oldptnum;
   int i;
 
-  if (bqual) {
-    return true;
-  } else {
-    shty = shelltype(*testsh);
-    if ((shty != SHARPSUB) && (shty != SHARPSKINNYSUB)) {
-      return true;
-    }
-  }
+  tetlist = new list(sizeof(triface), NULL, 1024);
+  ceillist = new list(sizeof(triface), NULL, 1024);
+  verlist = new list(sizeof(point *), NULL, 256);
 
-  if (b->varvolume || b->fixedvolume) {
-    // Check if it is in case (3).
-    p[0] = sorg(*testsh);
-    p[1] = sdest(*testsh);
-    p[2] = sapex(*testsh);
-    // Get the longest edge length of testsh = L.
-    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; 
-    }
-    if (b->varvolume) {
-      for (i = 0; i < 2; i ++) {
-        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;
+  // Loop until pool 'badtetrahedrons' is empty. Note that steinerleft == -1
+  //   if an unlimited number of Steiner points is allowed.
+  while ((badtetrahedrons->items > 0) && (steinerleft != 0)) {
+    // Get a bad-quality tet t.
+    badtet = dequeuebadtet();
+    // Make sure that the tet is still the same one when it was tested.
+    //   Subsequent transformations may have made it a different tet.
+    if (!isdead(&badtet->tt) && org(badtet->tt) == badtet->forg &&
+        dest(badtet->tt) == badtet->fdest && 
+        apex(badtet->tt) == badtet->fapex &&
+        oppo(badtet->tt) == badtet->foppo) {
+      // Create the new point p.
+      makepoint(&newpt);
+      for (i = 0; i < 3; i++) newpt[i] = badtet->cent[i];
+      setpointtype(newpt, FREEVOLVERTEX);
+      // Locate p.
+      starttet = badtet->tt;
+      loc = preciselocate(newpt, &starttet, tetrahedrons->items);
+      if ((loc != ONVERTEX) && (loc != OUTSIDE)) {
+        // For BC(p) and B(p).
+        infect(starttet);
+        tetlist->append(&starttet);
+        formbowatcavityquad(newpt, tetlist, ceillist);
+        // Check for encroached subsegments.
+        reject = tallencsegs(newpt, 1, &ceillist);
+        if (!reject) {
+          // Check for encroached subfaces.
+          reject = tallencsubs(newpt, 1, &ceillist);
+        }
+        if (!reject) {
+          // Does p allowed to be inseted?
+          reject = !acceptvolpt(newpt, ceillist, verlist);
+        }
+        if (!reject) {
+          reject = !trimbowatcavity(newpt, NULL, 1, NULL, NULL, &tetlist,
+                                    &ceillist, -1.0);
+        }
+        if (!reject) {
+          // BC(p) should include t, so that t can be removed after BC(p) is
+          //   remeshed. However, if there are locally non-Delaunay faces
+          //   and encroached subsegments/subfaces, t may not be collected
+          //   in BC(p). p should not be inserted in such case.
+          reject = !infected(badtet->tt);
+          if (reject) outbowatcircumcount++;
+        }
+        if (!reject) {
+          // Insert p.
+          bowatinsertsite(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist,
+                          NULL, NULL, false, false, true);
+          setnewpointsize(newpt, verlist);
+          if (steinerleft > 0) steinerleft--;
+        } else {
+          // p is rejected for one of the following reasons:
+          //   (1) BC(p) is not valid.
+          //   (2) t does not in BC(p).
+          //   (3) p encroaches upon some segments;
+          //   (4) p encroaches upon some subfaces;
+          //   (5) p is rejected by the point accepting rule.
+          pointdealloc(newpt);
+          // Uninfect tets of BC(p).
+          for (i = 0; i < tetlist->len(); i++) {
+            starttet = * (triface *)(* tetlist)[i];
+            uninfect(starttet);
           }
         }
-        sesymself(*testsh);
-      }
-    }
-  }
+        tetlist->clear();
+        ceillist->clear();
+        verlist->clear();
+        // Split encroached subsegments/subfaces if there are.
+        if (reject) {
+          oldptnum = points->items;
+          if (badsubsegs->items > 0) {
+            repairencsegs(true, true);
+          }
+          if (badsubfaces->items > 0) {
+            repairencsubs(true);
+          }
+          if (points->items > oldptnum) {
+            // Some encroaching subsegments/subfaces have been split.
+            starttet = badtet->tt;
+            if (!isdead(&starttet)) {
+              checktet4badqual(&starttet, true);
+            }
+          }
+        }
+      } else {
+        // Do not insert p. The reason may be one of:
+        //   (1) p is coincident (ONVERTEX) with an existing vertex; or
+        //   (2) p is outside (OUTSIDE) the mesh.
+        // Case (1) should not be possible. If such vertex v exists, it is
+        //   the circumcenter of t, ie., t is non-Delaunay. Either t was got
+        //   split before by v, but survived after v was inserted, or the
+        //   same for a t' which is nearly co-spherical with t.  Whatsoever,
+        //   there are encroached segments or subfaces by v but the routines
+        //   tallencsegs() or tallencsubs() did not find them out.
+        if (loc == ONVERTEX) {
+          printf("Internal error in repairbadtets():\n");
+          printf("  During repairing bad tet (%d, %d, %d, %d)\n",
+                 pointmark(badtet->forg), pointmark(badtet->fdest),
+                 pointmark(badtet->fapex), pointmark(badtet->foppo));
+          printf("  New point %d is coincident with an existing vertex %d\n",
+                 pointmark(newpt), pointmark(org(starttet)));
+          internalerror();
+        }
+        // Case (2) can happen when there is a segment s (or subface f) which
+        //   is close to f and is non-conforming Delaunay.  The circumcenter
+        //   of t encroaches upon s (or f), but the circumcenter of s (or f)
+        //   is rejected for insertion.
+        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);
+  } // while ((badtetrahedrons->items > 0) && (steinerleft != 0))
 
-  return false;
+  delete tetlist;
+  delete ceillist;
+  delete verlist;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// doqualchecktetlist()    Put bad-quality tetrahedra in 'qualchecktetlist'  //
-//                         into queue and clear it.                          //
-//                                                                           //
-// 'qualchecktetlist' stores a list of tetrahedra which are possibly bad-    //
-// quality, furthermore, one tetrahedron may appear many times in it.  For   //
-// testing and queuing each bad-quality tetrahedron only once, infect it     //
-// after testing, later on, only test the one which is not infected.  On     //
-// finish, uninfect them.                                                    //
+// enforcequality()    Refine the mesh.                                      //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::doqualchecktetlist()
+void tetgenmesh::enforcequality()
 {
-  triface testtet;
+  long total, vertcount;
   int i;
+  
+  if (!b->quiet) {
+    printf("Adding Steiner points to enforce quality.\n");
+  } 
 
-  for (i = 0; i < qualchecktetlist->len(); i++) {
-    testtet = * (triface *) (* qualchecktetlist)[i];
-    if (!isdead(&testtet) && !infected(testtet)) {
-      checktet4badqual(&testtet, true);
-      infect(testtet);
-    }
+  total = vertcount = 0l;
+  if (b->conformdel) {
+    r2count = r3count = 0l;
+  }
+
+  if (b->refine) {
+    // Mark segment vertices (acute or not).
+    markacutevertices(89.0);
+  }
+  if (!b->bgmesh) {
+    // Calculate the node local feature sizes.
+    calclocalfeaturesizes();
+  }
+  // Mark sharp subfaces (for termination).
+  marksharpsubsegs(89.0);
+  // Mark skinny subfaces (for reducing Steiner points).
+  markskinnysubfaces(19.0);
+
+  // Initialize the pool of encroached subsegments.
+  badsubsegs = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
+  // Looking for encroached subsegments.
+  tallencsegs(NULL, 0, NULL);
+  if (b->verbose && badsubsegs->items > 0) {
+    printf("  Splitting encroached subsegments.\n");
+  }
+  vertcount = points->items;
+  // Fix encroached segments without noting any enc subfaces.
+  repairencsegs(false, false);
+  if (b->verbose > 0) {
+    printf("  %ld split points.\n", points->items - vertcount);
+  }
+  total += points->items - vertcount;
+
+  // Initialize the pool of encroached subfaces.
+  badsubfaces = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
+  // Initialize the priority queues of badfaces.
+  for (i = 0; i < 3; i++) subquefront[i] = (badface *) NULL;
+  for (i = 0; i < 3; i++) subquetail[i] = &subquefront[i];
+  // Looking for encroached subfaces.
+  tallencsubs(NULL, 0, NULL);
+  if (b->verbose && badsubfaces->items > 0) {
+    printf("  Splitting encroached subfaces.\n");
+  }
+  vertcount = points->items;
+  // Fix encroached subfaces without noting bad tetrahedra.
+  repairencsubs(false);
+  if (b->verbose > 0) {
+    printf("  %ld split points.\n", points->items - vertcount);
   }
-  for (i = 0; i < qualchecktetlist->len(); i++) {
-    testtet = * (triface *) (* qualchecktetlist)[i];
-    if (!isdead(&testtet) && infected(testtet)) {
-      uninfect(testtet);
+  total += points->items - vertcount;
+  // At this point, the mesh should be conforming Delaunay if no input
+  //   angle is smaller than 90 degree.
+
+  // Next, fix bad quality tetrahedra.
+  if ((b->minratio > 0.0) || b->varvolume || b->fixedvolume) {
+    // Initialize the pool of bad tets
+    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];
+    // Looking for bad quality tets.
+    tallbadtetrahedrons();
+    if (b->verbose && badtetrahedrons->items > 0) {
+      printf("  Splitting bad tetrahedra.\n");
+    }
+    vertcount = points->items;
+    repairbadtets();
+    if (b->verbose > 0) {
+      printf("  %ld refinement points.\n", points->items - vertcount);
     }
+    total += points->items - vertcount;
+    delete badtetrahedrons;
+  }
+
+  if (b->verbose > 0) {
+    printf("  Totally added %ld points.\n", total);
   }
-  qualchecktetlist->clear();
+
+  delete badsubfaces;
+  delete badsubsegs;
 }
 
+//
+// End of Delaunay refinement routines
+//
+
+//
+// Begin of mesh smoothing routines
+//
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// tallencsegs()    Check for encroached segments, save them in list.        //
+// checktet4ill()    Check a tet to see if it is illegal.                    //
 //                                                                           //
-// If 'testpt' is not a NULL, only check if segments are encroached by this  //
-// point.  Otherwise, check all the nearby mesh vertices.                    //
+// A tet is "illegal" if it spans on one input facet.  Save the tet in queue //
+// if it is illegal and the flag 'enqflag' is set.                           //
 //                                                                           //
-// If 'cavtetlist' is not a NULL only check the segments in 'cavtetlist' to  //
-// see if they're encroached.  Otherwise, check the entire list of segments. //
+// Note: Such case can happen when the input facet has non-coplanar vertices //
+// and the Delaunay tetrahedralization of the vertices may creat such tets.  //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::tallencsegs(point testpt, list *cavtetlist)
+bool tetgenmesh::checktet4ill(triface* testtet, bool enqflag)
 {
-  triface starttet, neightet;
+  badface *newbadtet;
+  triface checktet;
+  face checksh1, checksh2;
   face checkseg;
-  long oldencnum;
-  int i, j;
-  
-  // Remember the current number of encroached segments.
-  oldencnum = badsubsegs->items;
+  bool illflag;
+  int i;
 
-  if (cavtetlist != (list *) NULL) {
-    // Check segments in the list of tetrahedra.
-    for (i = 0; i < cavtetlist->len(); i++) {
-      starttet = * (triface *)(* cavtetlist)[i];
-      infect(starttet); // Indicate it has been tested.
-      sym(starttet, neightet);
-      if (!infected(neightet)) {
-        // Test all three edges of this face.
-        for (j = 0; j < 3; j++) {
-          tsspivot(&starttet, &checkseg);
-          if (checkseg.sh != dummysh) {
-            if (!shell2badface(checkseg)) {
-              checkseg4encroach(&checkseg, testpt, NULL, true);
-            }
-          }
-          enextself(starttet);
-        }
-      }
-      adjustedgering(starttet, CCW);
-      fnext(starttet, neightet);
-      symself(neightet);
-      if ((neightet.tet == dummytet) || !infected(neightet)) {
-        fnext(starttet, neightet);
-        // Test the tow other edges of this face.
-        for (j = 0; j < 2; j++) {
-          enextself(neightet);
-          tsspivot(&neightet, &checkseg);
-          if (checkseg.sh != dummysh) {
-            if (!shell2badface(checkseg)) {
-              checkseg4encroach(&checkseg, testpt, NULL, true);
-            }
-          }
-        }
-      }
-      enextfnext(starttet, neightet);
-      symself(neightet);
-      if ((neightet.tet == dummytet) || !infected(neightet)) {
-        enextfnext(starttet, neightet);
-        // Only test the next edge of this face.
-        enextself(neightet);
-        tsspivot(&neightet, &checkseg);
-        if (checkseg.sh != dummysh) {
-          if (!shell2badface(checkseg)) {
-            checkseg4encroach(&checkseg, testpt, NULL, true);
+  illflag = false;
+  for (testtet->loc = 0; testtet->loc < 4; testtet->loc++) {
+    tspivot(*testtet, checksh1);
+    if (checksh1.sh != dummysh) {
+      testtet->ver = 0;
+      findedge(&checksh1, org(*testtet), dest(*testtet));
+      for (i = 0; i < 3; i++) {
+        fnext(*testtet, checktet);
+        tspivot(checktet, checksh2);
+        if (checksh2.sh != dummysh) {
+          // Two subfaces share this edge. It should be a segment.
+          sspivot(checksh1, checkseg);
+          if (checkseg.sh == dummysh) {
+            illflag = true; break;
           }
         }
+        enextself(*testtet);
+        senextself(checksh1);
       }
     }
-    // Uninfect all tetrahedra in the list.
-    for (i = 0; i < cavtetlist->len(); i++) {
-      starttet = * (triface *)(* cavtetlist)[i];
-      assert(infected(starttet));
-      uninfect(starttet);
-    }
-  } else {
-    // Check the entire list of segments.
-    subsegs->traversalinit();
-    checkseg.sh = shellfacetraverse(subsegs);
-    while (checkseg.sh != (shellface *) NULL) {
-      if (!shell2badface(checkseg)) {
-        checkseg4encroach(&checkseg, testpt, NULL, true);
-      }
-      checkseg.sh = shellfacetraverse(subsegs);
+    if (illflag) break;
+  }
+
+  if (illflag && enqflag) {
+    // Allocate space for the bad tetrahedron.
+    newbadtet = (badface *) badtetrahedrons->alloc();
+    newbadtet->tt = *testtet;
+    newbadtet->key = 0.0;
+    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 illtet: (%d, %d, %d, %d).\n",
+             pointmark(newbadtet->forg), pointmark(newbadtet->fdest),
+             pointmark(newbadtet->fapex), pointmark(newbadtet->foppo));
     }
   }
 
-  return (badsubsegs->items > oldencnum);
+  return illflag;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// tallencsubs()    Find all encroached subfaces and save them in list.      //
+// checktet4sliver()    Check a tet to see if it is a sliver.                //
+//                                                                           //
+// A sliver is a tet has no small edges, but has a nearly zero volume. When  //
+// the mesh quality is measured by radios-edge ratio, slivers can have rela- //
+// tively small value and are not classified as bad quality.                 //
 //                                                                           //
-// If 'testpt' is not a NULL, only check if subfaces are encroached by this  //
-// point.  Otherwise, check all the nearby mesh vertices.                    //
+// 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 'cavtetlist' is not a NULL only check the subfaces in 'cavtetlist' to  //
-// see if they're encroached.  Otherwise, check the entire list of subfaces. //
+// If the flag 'chkill' is set, only check the volume of tet. It is a sliver //
+// if it has a zero or negative volume.                                      //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-bool tetgenmesh::tallencsubs(point testpt, list* cavtetlist)
+bool tetgenmesh::checktet4sliver(triface* testtet, bool chkill, bool enqflag)
 {
-  triface starttet, neightet;
-  face checksh;
-  long oldencnum;
-  int i, j;
-  
-  // Remember the current number of encroached segments.
-  oldencnum = badsubfaces->items;
+  badface *newbadtet;
+  point pa, pb, pc, pd;
+  REAL N[4][3], volume, len;
+  REAL cosd, smallcosd;
+  bool enq;
+  int edgeno, i, j;
 
-  if (cavtetlist != (list *) NULL) {
-    // Check subfaces in the list of tetrahedra.
-    for (i = 0; i < cavtetlist->len(); i++) {
-      starttet = * (triface *)(* cavtetlist)[i];
-      infect(starttet); // Indicate it has been tested.
-      sym(starttet, neightet);
-      if (!infected(neightet)) {
-        // Test if this face is encroached.
-        tspivot(starttet, checksh);
-        if (checksh.sh != dummysh) {
-          // If it is not encroached, test it.
-          if (shell2badface(checksh) == NULL) {
-            checksub4encroach(&checksh, testpt, true);
-          }
-        }
-      }
-      adjustedgering(starttet, CCW);
-      // Check the other three sides of this tet.
-      for (j = 0; j < 3; j++) {
-        fnext(starttet, neightet);
-        symself(neightet);
-        if ((neightet.tet == dummytet) || !infected(neightet)) {
-          fnext(starttet, neightet);
-          // Test if this face is encroached.
-          tspivot(neightet, checksh);
-          if (checksh.sh != dummysh) {
-            // If it is not encroached, test it.
-            if (shell2badface(checksh) == NULL) {
-              checksub4encroach(&checksh, testpt, true);
-            }
-          }
-        }
-        enextself(starttet);
-      }
+  enq = false;
+
+  pa = (point) testtet->tet[4];
+  pb = (point) testtet->tet[5];
+  pc = (point) testtet->tet[6];
+  pd = (point) testtet->tet[7];
+  // Compute the 4 face normals (N[0], ..., N[3]).
+  tetallnormal(pa, pb, pc, pd, N, &volume);
+  // Normalize the normals.
+  for (i = 0; i < 4; i++) {
+    len = sqrt(dot(N[i], N[i]));
+    if (len != 0.0) {
+      for (j = 0; j < 3; j++) N[i][j] /= len;
+    }
+  }
+  // Find the largest dihedral and the edge.
+  smallcosd = -dot(N[2], N[3]); // Edge ab.
+  edgeno = 0;
+  for (i = 1; i < 4; i++) {
+    cosd = -dot(N[0], N[i]); // Edge cd, bd, bc.
+    if (cosd < smallcosd) {
+      smallcosd = cosd;
+      edgeno = i;
     }
-    // Uninfect all tetrahedra in the list.
-    for (i = 0; i < cavtetlist->len(); i++) {
-      starttet = * (triface *)(* cavtetlist)[i];
-      assert(infected(starttet));
-      uninfect(starttet);
+  }
+  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 {
-    // Check the entire list of subfaces.
-    subfaces->traversalinit();
-    checksh.sh = shellfacetraverse(subfaces);
-    while (checksh.sh != (shellface *) NULL) {
-      // If it is not encroached, test it.
-      if (shell2badface(checksh) == NULL) {
-        checksub4encroach(&checksh, testpt, true);
-      }
-      checksh.sh = shellfacetraverse(subfaces);
+    enq = (volume <= 0.0);
+  }
+
+  if (enq && enqflag) {
+    // Let t represent the edge having the biggest dihedral angle.
+    testtet->loc = 0;
+    testtet->ver = 0;
+    switch (edgeno) {
+    case 0: break; // edge ab
+    case 1: // edge cd 
+      enextfnextself(*testtet);
+      enextself(*testtet);
+      break;
+    case 2: // edge bd
+      enextfnextself(*testtet);
+      enext2self(*testtet);
+      break;
+    case 3: // edge bc
+      enextself(*testtet);
+      break;
+    case 4: // edge ad
+      enext2fnextself(*testtet);
+      enextself(*testtet);
+      break;
+    case 5: // edge ac
+      enext2self(*testtet);
+      break;
+    }
+    // Allocate space for the bad tetrahedron.
+    newbadtet = (badface *) badtetrahedrons->alloc();
+    newbadtet->tt = *testtet;
+    newbadtet->key = smallcosd;
+    for (i = 0; i < 3; i++) newbadtet->cent[i] = 0.0;
+    newbadtet->forg = org(*testtet);
+    newbadtet->fdest = dest(*testtet);
+    newbadtet->fapex = apex(*testtet);
+    newbadtet->foppo = oppo(*testtet);
+    newbadtet->nextitem = (badface *) NULL;
+    if (b->verbose > 2) {
+      printf("    Queueing sliver: (%d, %d, %d, %d), maxdihed %g (degree).\n",
+             pointmark(newbadtet->forg), pointmark(newbadtet->fdest),
+             pointmark(newbadtet->fapex), pointmark(newbadtet->foppo),
+             acos(smallcosd) * 180.0 / PI);
     }
   }
 
-  return (badsubfaces->items > oldencnum);
+  return enq;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// tallencsubsfseg()    Find all bad-qual or enc subfaces at a segment.      //
-//                                                                           //
-// This routine is called in repairencsegs() directly after a seg is split.  //
-// 'testseg' is the one of the two resulting subsegments.                    //
+// removetetbystripoff()    Remove a boundary tet by stripping it off.       //
 //                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-void tetgenmesh::tallencsubsfseg(face* testseg)
-{
-  face startsh, spinsh, checksh;
-  face splitseg, checkseg;
-
-  splitseg = *testseg;
-  // Check the subfaces link of splitseg to see if they're encroached.
-  spivot(splitseg, startsh);
-  spinsh = startsh;
-  do {
-    findedge(&spinsh, sorg(splitseg), sdest(splitseg));
-    // The next two lines are only for checking.
-    sspivot(spinsh, checkseg);
-    assert(checkseg.sh == splitseg.sh);
-    checksh = spinsh;
-    if (!shell2badface(checksh)) {
-      checksub4badqual(&checksh, true);
-    }
-    if (!shell2badface(checksh)) {
-      checksub4encroach(&checksh, NULL, true);
-    }
-    // The above operation may change the edge.
-    findedge(&spinsh, sorg(splitseg), sdest(splitseg));
-    spivotself(spinsh);
-  } while (spinsh.sh != startsh.sh);
-}
-
-///////////////////////////////////////////////////////////////////////////////
+// 'striptet' (abcd) is on boundary and can be removed by stripping it off.  //
+// Let abc and bad are the external boundary faces.                          //
 //                                                                           //
-// tallbadsegs()    Find all bad-quality segments and save them in list.     //
+// 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::tallbadsegs()
+void tetgenmesh::removetetbystripoff(triface *striptet)
 {
-  face checkseg;
-
-  subsegs->traversalinit();
-  checkseg.sh = shellfacetraverse(subsegs);
-  while (checkseg.sh != (shellface *) NULL) {
-    if (varconstraint && (areabound(checkseg) > 0.0)) {
-      checkseg4badqual(&checkseg, true);
-    }
-    checkseg.sh = shellfacetraverse(subsegs);
+  triface abcd, badc;
+  triface dcacasing, cdbcasing;
+  face abc, bad;
+  
+  if (b->verbose > 1) {
+    printf("    by stripping it off.\n");
   }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// tallbadsubs()    Find all bad-quality subfaces and save them in list.     //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-void tetgenmesh::tallbadsubs()
-{
-  face checksh;
 
-  subfaces->traversalinit();
-  checksh.sh = shellfacetraverse(subfaces);
-  while (checksh.sh != (shellface *) NULL) {
-    checksub4badqual(&checksh, true);
-    checksh.sh = shellfacetraverse(subfaces);
-  }
-}
+  striptetcount++;
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// tallbadtetrahedrons()    Queue all the bad-quality tetrahedra in the mesh.//
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
+  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));
 
-void tetgenmesh::tallbadtetrahedrons()
-{
-  triface tetloop;
+  // 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
 
-  tetrahedrons->traversalinit();
-  tetloop.tet = tetrahedrontraverse();
-  while (tetloop.tet != (tetrahedron *) NULL) {
-    checktet4badqual(&tetloop, true);
-    tetloop.tet = tetrahedrontraverse();
-  }
+  // 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);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// tallslivers()    Queue all the slivers in the mesh.                       //
+// removetetbyflip32()    Remove a tet by a 3-to-2 flip.                     //
 //                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-void tetgenmesh::tallslivers()
-{
-  triface tetloop;
-
-  tetrahedrons->traversalinit();
-  tetloop.tet = tetrahedrontraverse();
-  while (tetloop.tet != (tetrahedron *) NULL) {
-    checktet4sliver(&tetloop, true);
-    tetloop.tet = tetrahedrontraverse();
-  }
-}
-
-///////////////////////////////////////////////////////////////////////////////
+// '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.   //
 //                                                                           //
-// getsplitpoint1()    Get a suitable point for splitting a segment.         //
+// 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.                //
 //                                                                           //
-// 'splitseg' is going to be split.  This routine finds a suitable point in  //
-// it.  The rules of finding point are similar to that of getsplitpoint().   //
-// If 'encpt != NULL', it encroaches 'splitseg'.                             //
+// 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.                   //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::getsplitpoint1(face* splitseg, REAL* splitpt, point encpt)
+void tetgenmesh::removetetbyflip32(triface *fliptet, bool enq, bool chkill)
 {
-  point ei, ej, ek;
-  point farorg, fardest;
-  REAL dij, dip, djp;
-  REAL dvj, dvp, div;
-  REAL dki, dkj, dkp;
-  REAL split;
-  bool acuteorg, acutedest;
-  int i;
+  triface abcd, badc;
+  triface cdab, dcba;
+  triface baccasing, abdcasing;
+  triface dcacasing, cdbcasing;
+  face abc, bad;
+  REAL attrib, volume;
+  int i;  
 
-  ei = sorg(*splitseg);
-  ej = sdest(*splitseg);
-  if (encpt == (point) NULL) {
-    // No existing point encroaches the seg. Split it at the middle.
-    for (i = 0; i < 3; i++) splitpt[i] = ei[i] + 0.5 * (ej[i] - ei[i]);
-    return;
+  if (b->verbose > 1) {
+    printf("    by a 3-to-2 flip.\n");
   }
 
-  acuteorg = (pointtype(ei) == ACUTEVERTEX);
-  acutedest = (pointtype(ej) == ACUTEVERTEX);
-  
-  if (acuteorg && acutedest) {
-    // Use rule 1.
-    dij = distance(ei, ej);
-    dip = distance(ei, encpt);
-    djp = distance(ej, encpt);
-    if (dip < 0.5 * dij) {
-      split = dip / dij;
-    } else if (djp < 0.5 * dij) {
-      split = (dij - djp) / dij;
-    } else {
-      split = 0.5;
-    }
-    for (i = 0; i < 3; i++) splitpt[i] = ei[i] + split * (ej[i] - ei[i]);
-    return;
-  }
-  if (acuteorg || acutedest) {
-    if (!acuteorg) {
-      // eorg is not acute, but edest is. Exchange eorg, edest.
-      ei = ej;
-      ej = sorg(*splitseg);
-    }
-    // Now, eorg must be acute.
-    // Try to split it by rule-2.      
-    dij = distance(ei, ej);
-    dip = distance(ei, encpt);
-    split = dip / dij;
-    for (i = 0; i < 3; i++) splitpt[i] = ei[i] + split * (ej[i] - ei[i]);
-    dvj = dij - dip;
-    dvp = distance(splitpt, encpt);
-    if (dvj < dvp) {
-      // v is rejected, use rule-3.
-      split = 0.5 * dip / dij;
-      for (i = 0; i < 3; i++) splitpt[i] = ei[i] + split * (ej[i] - ei[i]);
-    }
-    return;
-  }
+   fliptetcount++;
 
-  // Both ei and ej are nonacute.
-  farorg = getsegmentorigin(splitseg);
-  acuteorg = (pointtype(farorg) == ACUTEVERTEX);
-  sesymself(*splitseg);
-  fardest = getsegmentorigin(splitseg);
-  acutedest = (pointtype(fardest) == ACUTEVERTEX);
-  sesymself(*splitseg);
-  
-  if (acuteorg || acutedest) {
-    if (acuteorg && acutedest) {
-      // Always use the vertex having smaller index.
-      if (pointmark(farorg) < pointmark(fardest)) {
-        acutedest = false;
-      } else {
-        acuteorg = false;
-      }
-    }
-    if (!acuteorg) {
-      // eorg is not acute, but edest is.
-      assert(acutedest);
-      // Exchange eorg, edest.
-      ei = ej;
-      ej = sorg(*splitseg);
-      ek = fardest;
-    } else {
-      ek = farorg;
+  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);
     }
-    // Try use rule-2.
-    dki = distance(ek, ei); 
-    dkj = distance(ek, ej);
-    dkp = distance(ek, encpt);
-    split = dkp / dkj;
-    for (i = 0; i < 3; i++) splitpt[i] = ek[i] + split * (ej[i] - ek[i]);
-    // v may too close to ei or ej. If any of these happens, reject v.
-    dvp = distance(splitpt, encpt);
-    div = distance(ei, splitpt);
-    dvj = distance(splitpt, ej);
-    if ((div < dvp) || (dvj < dvp)) {
-      // Reject v. Use the middle point of ei and ej.
-      for (i = 0; i < 3; i++) splitpt[i] = ei[i] + 0.5 * (ej[i] - ei[i]);
+    if (b->varvolume) {
+      volume = volumebound(baccasing.tet);
+      setvolumebound(abcd.tet, volume);
     }
-  } else {
-    // No far acute points. Use rule 1.
-    dij = distance(ei, ej);
-    dip = distance(ei, encpt);
-    djp = distance(ej, encpt);
-    if (dip < 0.5 * dij) {
-      split = dip / dij;
-    } else if (djp < 0.5 * dij) {
-      split = (dij - djp) / dij;
+    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 {
-      split = 0.5;
+      // Test the two new tets to see if they are sliver.
+      checktet4sliver(&abcd, false, true);
+      checktet4sliver(&badc, false, true);
     }
-    for (i = 0; i < 3; i++) splitpt[i] = ei[i] + split * (ej[i] - ei[i]);
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// repairencsegs()    Repair all the encroached segments.                    //
+// removetetbyrecon()    Remove a tet by local reconnection.                 //
 //                                                                           //
-// Encroached segments are in 'badsubsegs'.  Each queued segment is repaired //
-// by inserting a point somewhere in it.  Newly inserted points may encroach //
-// upon other segments, these are also repaired.                             //
+// '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.           //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::repairencsegs(queue* flipqueue)
+bool tetgenmesh::removetetbyrecon(badface* remtet, bool chkill)
 {
-  badface *encloop;
-  triface starttet;
-  face splitseg, symsplitseg;
-  point eorg, edest, encpt;
-  point newpoint, sympoint;
-  enum locateresult symloc;
-  bool chkencsubs, chkbadqual;
-  int i, j;
-
-  if (b->verbose > 1) {
-    printf("  Splitting encroached subsegments.\n");
-  }
-
-  // Note that steinerleft == -1 if an unlimited number of Steiner points 
-  //   is allowed.  Loop until 'badsubsegs' is empty.
-  while ((badsubsegs->items > 0) && (steinerleft != 0)) {
-    badsubsegs->traversalinit();
-    encloop = badfacetraverse(badsubsegs);
-    while ((encloop != (badface *) NULL) && (steinerleft != 0)) {
-      splitseg = encloop->ss;
-      // Every splitseg has a pointer to encloop, now clear it.
-      assert(shell2badface(splitseg) == encloop);
-      setshell2badface(splitseg, NULL);
-      eorg = sorg(splitseg);
-      edest = sdest(splitseg);
-      if ((eorg == encloop->forg) && (edest == encloop->fdest)) {
-        if (b->verbose > 1) {
-          printf("  Get seg (%d, %d) ", pointmark(eorg), pointmark(edest));
-          printf("enc by %d.\n", encloop->foppo != (point) NULL ? 
-                 pointmark(encloop->foppo) : 0);
-        }
-        // Split the seg if (1) it is encroached by an existing vertex, or
-        //   (2) it is permitted to be split.
-        if (checkseg4splitting(&splitseg, &encpt)) {
-          // Create the new point.
-          makepoint(&newpoint);
-          // Decide the position to split the segment.
-          getsplitpoint1(&splitseg, newpoint, encpt);
-          // Set the parent point into the newpoint.
-          setpoint2ppt(newpoint, encpt);
-          // Set the type of the newpoint.
-          setpointtype(newpoint, FREESEGVERTEX);
-          // Set splitseg into the newpoint.
-          // setpoint2sh(newpoint, sencode(splitseg));
-          // Has subface confoming started?
-          chkencsubs = badsubfaces != (memorypool *) NULL;
-          // Has quality mesh started?
-          chkbadqual = badtetrahedrons != (memorypool *) NULL;
-
-          // Is there periodic boundary condition?
-          if (checkpbcs) {
-            // Yes! Insert points on other segments of incident pbcgroups.
-            i = shellmark(splitseg) - 1;
-            for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++) {
-              makepoint(&sympoint);
-              symloc = getsegpbcsympoint(newpoint, &splitseg, sympoint,
-                                         &symsplitseg, segpglist[j]);
-              assert(symloc != OUTSIDE);
-              if (symloc == ONEDGE) {
-                assert(symsplitseg.sh != dummysh);
-                setpointtype(sympoint, FREESEGVERTEX);
-                // setpoint2sh(sympoint, sencode(symsplitseg));
-                // Insert sympoint into the mesh.
-                symsplitseg.shver = 0;
-                sstpivot(&symsplitseg, &starttet);
-                splittetedge(sympoint, &starttet, flipqueue);
-                if (steinerleft > 0) steinerleft--;
-                // Check the two new subsegs to see if they're encroached.
-                //   Note, symsplitseg may have already been queued.
-                if (!shell2badface(symsplitseg)) {
-                  if (varconstraint && (areabound(symsplitseg) > 0.0)) {
-                    checkseg4badqual(&symsplitseg, true);
-                  }
-                }
-                if (!shell2badface(symsplitseg)) {
-                  checkseg4encroach(&symsplitseg, NULL, NULL, true);
-                }
-                if (chkencsubs) {
-                  // Find encroaching subfaces around s.
-                  tallencsubsfseg(&symsplitseg);
-                }
-                senextself(symsplitseg);
-                spivotself(symsplitseg);
-                assert(symsplitseg.sh != (shellface *) NULL);
-                symsplitseg.shver = 0;
-                // symsplitseg is a new segment and has not been queued.
-                assert(shell2badface(symsplitseg) == (badface *) NULL);
-                if (varconstraint && (areabound(symsplitseg) > 0.0)) {
-                  checkseg4badqual(&symsplitseg, true);
-                }
-                if (!shell2badface(symsplitseg)) {
-                  checkseg4encroach(&symsplitseg, NULL, NULL, true);
-                }
-                if (chkencsubs) {
-                  // Find encroaching subfaces around s.
-                  tallencsubsfseg(&symsplitseg);
-                }
-                // Recover Delaunay property by flipping.
-                flip(flipqueue, NULL, true, chkencsubs, chkbadqual);
-              } else if (symloc == ONVERTEX) {
-                // The sympoint already exists. It is possible when two
-                //   pbc groups are exactly the same. Omit this point.
-                pointdealloc(sympoint);
-              }
-            }
-          }
+  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;
 
-          // Insert new point into the mesh. It should be always success.
-          splitseg.shver = 0;
-          sstpivot(&splitseg, &starttet);
-          splittetedge(newpoint, &starttet, flipqueue);
-          if (steinerleft > 0) steinerleft--;
-          // Check the two new subsegments to see if they're encroached.
-          //   Note, splitseg may have already been queued.
-          if (!shell2badface(splitseg)) {
-            if (varconstraint && (areabound(splitseg) > 0.0)) {
-              checkseg4badqual(&splitseg, true);
+  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.
           }
-          if (!shell2badface(splitseg)) {
-            checkseg4encroach(&splitseg, NULL, NULL, true);
-          }
-          if (chkencsubs) {
-            // Find encroaching subfaces around s.
-            tallencsubsfseg(&splitseg);
-          }
-          senextself(splitseg);
-          spivotself(splitseg);
-          assert(splitseg.sh != (shellface *) NULL);
-          splitseg.shver = 0;
-          // splitseg is a new segment and has not been queued.
-          assert(shell2badface(splitseg) == (badface *) NULL);
-          if (varconstraint && (areabound(splitseg) > 0.0)) {
-            checkseg4badqual(&splitseg, true);
-          }
-          if (!shell2badface(splitseg)) {
-            checkseg4encroach(&splitseg, NULL, NULL, true);
-          }
-          if (chkencsubs) {
-            // Find encroaching subfaces around s.
-            tallencsubsfseg(&splitseg);
-          }
-          // Recover Delaunay property by flipping. Existing segments which
-          //   are encroached by newpoint will be discovered and queued.
-          flip(flipqueue, NULL, true, chkencsubs, chkbadqual);
-          
-          // Queuing bad-quality tetrahedra if need.
-          if (chkbadqual) {
-            doqualchecktetlist();
-          }
-        }
-      } else {
-        // Splitseg has been split. Check it for encroachment.
-        if (varconstraint && (areabound(splitseg) > 0.0)) {
-          checkseg4badqual(&splitseg, true);
-        }
-        if (!shell2badface(splitseg)) {
-          checkseg4encroach(&splitseg, NULL, NULL, true);
         }
       }
+    } // 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++)
 
-      // Remove this entry from list.
-      badfacedealloc(badsubsegs, encloop);  
-      // Get the next encroached segments.
-      encloop = badfacetraverse(badsubsegs);
-    }
-  }
+  return remflag;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// repairencsubs()    Repair all the encroached subfaces.                    //
-//                                                                           //
-// Encroached subfaces are in pool 'badsubfaces'. Each encroached subface is //
-// repaired by inserting a point near its circumcenter. However, If the new  //
-// point encroaches upon one or more segments, it is not inserted.  Instead  //
-// the encroached segments are split. Newly added points may encroach upon   //
-// other subfaces, these are also repaired.                                  //
+// removetetbysplit()    Remove a tet by inserting a point in it.            //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::repairencsubs(list* cavtetlist, queue* flipqueue)
+bool tetgenmesh::removetetbysplit(badface* remtet)
 {
-  badface *encloop;
-  triface starttet, symstarttet;
-  face splitsub, symsplitsub, neisplitsub;
-  face checksh, checkseg;
-  point newpoint, sympoint;
-  point checkpt, pa, pb;
-  enum locateresult loc, symloc;
-  REAL epspp, dist;
-  bool reject, chkbadqual;
-  int quenumber;
-  int epscount;
-  int i;
+  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;
 
-  if (b->verbose > 1) {
-    printf("  Splitting encroached subfaces.\n");
-  }
+  // tet 'abcd' is indicated to remove.
+  abcd = remtet->tt;
+  abseg.sh = dummysh;
+  abcsh.sh = dummysh;
 
-  // Note that steinerleft == -1 if an unlimited number of Steiner points
-  //   is allowed.  Loop until the list 'badsubfaces' is empty.
-  while ((badsubfaces->items > 0) && (steinerleft != 0)) {
-    // Look for a nonempty queue.
-    encloop = (badface *) NULL;
-    for (quenumber = 1; quenumber >= 0; quenumber--) {
-      encloop = subquefront[quenumber];
-      if (encloop != (badface *) NULL) {
-        // Remove the badface from the queue.
-        subquefront[quenumber] = encloop->nextitem;
-        // Maintain a pointer to the NULL pointer at the end of the queue.
-        if (subquefront[quenumber] == (badface *) NULL) {
-          subquetail[quenumber] = &subquefront[quenumber];
+  // 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);
         }
-        break;
       }
     }
-    assert(encloop != (badface *) NULL);
-    // Clear the pointer saved in encloop->ss. 
-    splitsub = encloop->ss;
-    setshell2badface(splitsub, NULL);
-    // The subface may be not the same one when it was determined to be
-    //   encroached.  If its adjacent encroached subface was split, the
-    //   consequent flips may change it into another subface.
-    if ((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);
-      }
-      if (checksub4splitting(&splitsub, (quenumber == 1))) {
-        // We can split this subface.
-        makepoint(&newpoint);
-        // If it is a bad quality face, calculate its circumcenter.
-        if (quenumber == 1) {
-          circumsphere(encloop->forg, encloop->fdest, encloop->fapex, NULL,
-                       encloop->cent, NULL);
-        }
-        // Set the coordinates of newpoint.
-        for (i = 0; i < 3; i++) newpoint[i] = encloop->cent[i];
-        // Set the type of the newpoint.
-        setpointtype(newpoint, FREESUBVERTEX);
-        
-        // Locate the newpoint in facet (resulting in splitsub).
-        loc = locatesub(newpoint, &splitsub, 1);
-        stpivot(splitsub, starttet);
-        if (starttet.tet == dummytet) {
-          sesymself(splitsub);
-          stpivot(splitsub, starttet);
-        }
-        assert(starttet.tet != dummytet);
-        // Look if the newpoint encroaches upon any segment.
-        cavtetlist->append(&starttet);
-        collectcavtets(newpoint, cavtetlist);
-        assert(cavtetlist->len() > 0);
-        reject = tallencsegs(newpoint, cavtetlist);
-        // Clear the list for the next use.
-        cavtetlist->clear();
-        if (!reject) {
-          // Remove the encroached subface by inserting the newpoint.
-          if (loc != ONVERTEX) {
-            // Adjust the location of newpoint wrt. starttet.
-            epspp = b->epsilon;
-            epscount = 0;
-            while (epscount < 32) {
-              loc = adjustlocate(newpoint, &starttet, ONFACE, epspp);
-              if (loc == ONVERTEX) {
-                checkpt = org(starttet);
-                dist = distance(checkpt, newpoint);
-                if ((dist / longest) > b->epsilon) {
-                  epspp *= 1.0e-1;
-                  epscount++;
-                  continue;
-                }
-              }
-              break;
-            }
-          }
-          pa = org(starttet);
-          pb = dest(starttet);
-          findedge(&splitsub, pa, pb);
-
-          // Has quality mesh started?
-          chkbadqual = badtetrahedrons != (memorypool *) NULL;
+  }
 
-          if (checkpbcs) {
-            if (shellpbcgroup(splitsub) >= 0) {
-              makepoint(&sympoint);
-              symloc = getsubpbcsympoint(newpoint, &splitsub, sympoint,
-                                         &symsplitsub);
-              assert(symloc != ONVERTEX);
-              setpoint2pbcpt(newpoint, sympoint);
-              setpoint2pbcpt(sympoint, newpoint);
-              // Set the type of sympoint.
-              setpointtype(sympoint, FREESUBVERTEX);
-              stpivot(symsplitsub, symstarttet);
-              if (symstarttet.tet == dummytet) {
-                sesymself(symsplitsub);
-                stpivot(symsplitsub, symstarttet);
-              }
-              assert(symstarttet.tet != dummytet);
-              // Adjust symstarttet be the same edge as symsplitsub.
-              pa = sorg(symsplitsub);
-              pb = sdest(symsplitsub);
-              findedge(&symstarttet, pa, pb);
-              // 'symsplitsub' is face abc.  ab is the current edge.
-              if (symloc == ONFACE) {
-                // Split the face abc into three faces abv, bcv, cav. 
-                splittetface(sympoint, &symstarttet, flipqueue);
-                // Adjust symsplitsub be abv.
-                findedge(&symsplitsub, pa, pb);
-                assert(sapex(symsplitsub) == sympoint);
-                // Check the three new subfaces to see if they're encroached.
-                //   symsplitsub may be queued (it exists before split).
-                checksh = symsplitsub;
-                if (!shell2badface(checksh)) {
-                  checksub4badqual(&checksh, true); // abv
-                }
-                if (!shell2badface(checksh)) {
-                  checksub4encroach(&checksh, NULL, true); // abv
-                }
-                senext(symsplitsub, checksh);
-                spivotself(checksh);
-                // It is a new created face and should not be infected.
-                assert(checksh.sh != dummysh && !shell2badface(checksh));
-                checksub4badqual(&checksh, true); // bcv
-                if (!shell2badface(checksh)) {
-                  checksub4encroach(&checksh, NULL, true); // bcv
-                }
-                senext2(symsplitsub, checksh);
-                spivotself(checksh);
-                // It is a new created face and should not be infected.
-                assert(checksh.sh != dummysh && !shell2badface(checksh));
-                checksub4badqual(&checksh, true); // cav
-                if (!shell2badface(checksh)) {
-                  checksub4encroach(&checksh, NULL, true); // cav
-                }
-              } else if (symloc == ONEDGE) {
-                // Let the adjacent subface be bad.  ab is the spliting edge.
-                //   Split 2 faces: abc, bad into 4: avc, vbc, avd, vbd.
-                sspivot(symsplitsub, checkseg);
-                assert(checkseg.sh == dummysh);
-                // Remember the neighbor subface abd (going to be split too).
-                spivot(symsplitsub, neisplitsub);
-                findedge(&neisplitsub, pa, pb);
-                // Split 2 faces: abc, abd into 4: avc, vbc, avd, vbd.
-                splittetedge(sympoint, &symstarttet, flipqueue);
-                // Adjust symsplitsub be avc, neisplitsub be avd.
-                findedge(&symsplitsub, pa, sympoint);
-                findedge(&neisplitsub, pa, sympoint);
-                // Check the four new subfaces to see if they're encroached.
-                //   splitsub may be infected (it exists before the split).
-                checksh = symsplitsub;
-                if (!shell2badface(checksh)) {
-                  checksub4badqual(&checksh, true); // avc
-                }
-                if (!shell2badface(checksh)) {
-                  checksub4encroach(&checksh, NULL, true); // avc
-                }
-                //   Get vbc.
-                senext(symsplitsub, checksh);
-                spivotself(checksh);
-                //   vbc is newly created.
-                assert(checksh.sh != dummysh && !shell2badface(checksh));
-                checksub4badqual(&checksh, true); // vbc
-                if (!shell2badface(checksh)) {
-                  checksub4encroach(&checksh, NULL, true); // vbc
-                }
-                //   neisplitsub may be infected (exists before the split).
-                checksh = neisplitsub;
-                if (!shell2badface(checksh)) {
-                  checksub4badqual(&checksh, true); // avd
-                }
-                if (!shell2badface(checksh)) {
-                  checksub4encroach(&checksh, NULL, true); // avd
-                }
-                //   Get vbd.
-                senext(neisplitsub, checksh);
-                spivotself(checksh);
-                //   vbd is newly created.
-                assert(checksh.sh != dummysh && !shell2badface(checksh));
-                checksub4badqual(&checksh, true); // vbd
-                if (!shell2badface(checksh)) {
-                  checksub4encroach(&checksh, NULL, true); // vbd
-                }
-              } else {
-                // Delete the sympoint.
-                pointdealloc(sympoint);
-              }
-              if ((symloc == ONFACE) || (symloc == ONEDGE)) {
-                if (steinerleft > 0) steinerleft--;
-                // Recover Delaunay property by flipping.
-                flip(flipqueue, NULL, false, true, chkbadqual);
-                // There should be no encroached segments.
-                // assert(badsubsegs->items == 0);
-                // Queuing bad-quality tetrahedra if need.
-                if (chkbadqual) {
-                  doqualchecktetlist();
-                }
-              }
-            }
-          }
-          
-          stpivot(splitsub, starttet);
-          if (starttet.tet == dummytet) {
-            sesymself(splitsub);
-            stpivot(splitsub, starttet);
-          }
-          assert(starttet.tet != dummytet);
-          // Adjust starttet be the same edge as splitsub.
-          pa = sorg(splitsub);
-          pb = sdest(splitsub);
-          findedge(&starttet, pa, pb);
-          // 'splitsub' is face abc.  ab is the current edge.
-          if (loc == ONFACE) {
-            // Split the face abc into three faces abv, bcv, cav. 
-            splittetface(newpoint, &starttet, flipqueue);
-            // Adjust splitsub be abv.
-            findedge(&splitsub, pa, pb);
-            assert(sapex(splitsub) == newpoint);
-            // Check the three new subfaces to see if they're encroached.
-            //   splitsub may be queued (it exists before split).
-            checksh = splitsub;
-            if (!shell2badface(checksh)) {
-              checksub4badqual(&checksh, true); // abv
-            }
-            if (!shell2badface(checksh)) {
-              checksub4encroach(&checksh, NULL, true); // abv
-            }
-            senext(splitsub, checksh);
-            spivotself(checksh);
-            // It is a new created face and should not be infected.
-            assert(checksh.sh != dummysh && !shell2badface(checksh));
-            checksub4badqual(&checksh, true); // bcv
-            if (!shell2badface(checksh)) {
-              checksub4encroach(&checksh, NULL, true); // bcv
-            }
-            senext2(splitsub, checksh);
-            spivotself(checksh);
-            // It is a new created face and should not be infected.
-            assert(checksh.sh != dummysh && !shell2badface(checksh));
-            checksub4badqual(&checksh, true); // cav
-            if (!shell2badface(checksh)) {
-              checksub4encroach(&checksh, NULL, true); // cav
-            }
-          } else if (loc == ONEDGE) {
-            // Let the adjacent subface be bad.  ab is the spliting edge.
-            //   Split 2 faces: abc, bad into 4: avc, vbc, avd, vbd.
-            sspivot(splitsub, checkseg);
-            assert(checkseg.sh == dummysh);
-            // Remember the neighbor subface abd (going to be split too).
-            spivot(splitsub, neisplitsub);
-            findedge(&neisplitsub, pa, pb);
-            // Split two faces abc, abd into four faces avc, vbc, avd, vbd.
-            splittetedge(newpoint, &starttet, flipqueue);
-            // Adjust splitsub be avc, neisplitsub be avd.
-            findedge(&splitsub, pa, newpoint);
-            findedge(&neisplitsub, pa, newpoint);
-            // Check the four new subfaces to see if they're encroached.
-            //   splitsub may be infected (it exists before the split).
-            checksh = splitsub;
-            if (!shell2badface(checksh)) {
-              checksub4badqual(&checksh, true); // avc
-            }
-            if (!shell2badface(checksh)) {
-              checksub4encroach(&checksh, NULL, true); // avc
-            }
-            //   Get vbc.
-            senext(splitsub, checksh);
-            spivotself(checksh);
-            //   vbc is newly created.
-            assert(checksh.sh != dummysh && !shell2badface(checksh));
-            checksub4badqual(&checksh, true); // vbc
-            if (!shell2badface(checksh)) {
-              checksub4encroach(&checksh, NULL, true); // vbc
-            }
-            //   neisplitsub may be infected (it exists before the split).
-            checksh = neisplitsub;
-            if (!shell2badface(checksh)) {
-              checksub4badqual(&checksh, true); // avd
-            }
-            if (!shell2badface(checksh)) {
-              checksub4encroach(&checksh, NULL, true); // avd
-            }
-            //   Get vbd.
-            senext(neisplitsub, checksh);
-            spivotself(checksh);
-            //   vbd is newly created.
-            assert(checksh.sh != dummysh && !shell2badface(checksh));
-            checksub4badqual(&checksh, true); // vbd
-            if (!shell2badface(checksh)) {
-              checksub4encroach(&checksh, NULL, true); // vbd
-            }
-          } else {
-            /* It's a BUG.
-            printf("Internal error in splitencsub():  Point %d locates %s.\n",
-              pointmark(newpoint), loc == ONVERTEX ? "on vertex" : "outside");
-            internalerror();
-            */
-            // Delete the newpoint.
-            pointdealloc(newpoint);
-          }
-          if ((loc == ONFACE) || (loc == ONEDGE)) {
-            if (steinerleft > 0) steinerleft--;
-            // Recover Delaunay property by flipping. Subfaces which are
-            //   encroached by the new point will be discovered.
-            flip(flipqueue, NULL, false, true, chkbadqual);
-            // There should be no encroached segments.
-            // assert(badsubsegs->items == 0);
-            // Queuing bad-quality tetrahedra if need.
-            if (chkbadqual) {
-              doqualchecktetlist();
-            }
-          }
-        } else {
-          // newpoint encroaches upon some segments. Rejected.
-          // Delete the newpoint.
-          pointdealloc(newpoint);
-        }
-        // Repair all the encroached segments.
-        if (badsubsegs->items > 0) {
-          repairencsegs(flipqueue);
+  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 {
-      // enq = false!  This subface has been changed, check it again.
-      checksub4badqual(&splitsub, true);
-      if (!shell2badface(splitsub)) {
-        checksub4encroach(&splitsub, NULL, true);
-      }
-    }
-    // Remove this entry from list.
-    badfacedealloc(badsubfaces, encloop);
-  }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// repairbadtets()    Repair all bad-quality tetrahedra.                     //
-//                                                                           //
-// At beginning, all bad-quality tetrahedra are stored in 'badtetrahedrons'. //
-// Each bad tetrahedron is repaired by inserting a point at or near its cir- //
-// cumcenter.  However, if this point encroaches any subsegment or subface,  //
-// it is not inserted. Instead the encroached segment and subface are split. //
-// Newly inserted points may create other bad-quality tetrahedra, these are  //
-// also repaired.                                                            //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-void tetgenmesh::repairbadtets(list* cavtetlist, queue* flipqueue)
-{
-  badface *badtet;
-  triface starttet;
-  point newpoint;
-  enum insertsiteresult success;
-  enum locateresult loc;
-  bool reject;
-  int i;
-
-  // Loop until pool 'badtetrahedrons' is empty. Note that steinerleft == -1
-  //   if an unlimited number of Steiner points is allowed.
-  while ((badtetrahedrons->items > 0) && (steinerleft != 0)) {
-    badtet = dequeuebadtet();
-    assert (badtet != (badface *) NULL);
-    // Make sure that 'badtet->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 a newpoint at the circumcenter of this tetrahedron.
-      makepoint(&newpoint);
-      for (i = 0; i < 3; i++) newpoint[i] = badtet->cent[i];
-      // Set it's type be FREEVOLVERTEX.
-      setpointtype(newpoint, FREEVOLVERTEX);
-  
-      // Locate newpoint in mesh.
-      starttet = badtet->tt;  // Used for the input of preciselocate().
-      loc = preciselocate(newpoint, &starttet);
-      // Look if the newpoint encroaches upon any segment or subface.
-      cavtetlist->append(&starttet);
-      collectcavtets(newpoint, cavtetlist);
-      assert(cavtetlist->len() > 0);
-      reject = tallencsubs(newpoint, cavtetlist);
-      // Clear the list for the next use.
-      cavtetlist->clear();
-
-      if (!reject && (loc != OUTSIDE)) {
-        // Insert the point, it should be always success.
-        starttet = badtet->tt;
-        success = insertsite(newpoint, &starttet, true, flipqueue);
-        if (success != DUPLICATEPOINT) {
-          if (steinerleft > 0) steinerleft--;
-          // Recover Delaunay property by flipping.
-          flip(flipqueue, NULL, false, false, true);
-          // Queuing bad-quality tetrahedra if need.
-          doqualchecktetlist();
-        } else {
-          // !!! It's a bug!!!
-          pointdealloc(newpoint);
-        }
-      } else {
-        // newpoint encroaches upon some subfaces. Rejected.
-        pointdealloc(newpoint);
-        if (badsubfaces->items > 0) {
-          // Repair all the encroached subfaces.
-          repairencsubs(cavtetlist, flipqueue);
+      // 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);
         }
       }
+      smoothsubpt++;
+    } else {
+      // The local quality will not be improved. Do not insert p.
+      pointdealloc(newpt);
+      newpt = (point) NULL;
+      unsmoothsubpt++;
+    }
+    // Free the memory allocated in formbowatcavity().
+    releasebowatcavity(NULL, n, sublists, subceillists, tetlists, ceillists);
+    delete [] tetlists;
+    delete [] ceillists;
+    delete [] sublists;
+    delete [] subceillists;
+    delete verlist;
+  } else {
+    // Insert the midpoint of the edge having largest dihedral angle.
+    abcd = remtet->tt;
+    makepoint(&newpt);
+    getsplitpoint(org(abcd), dest(abcd), NULL, newpt);
+    setpointtype(newpt, FREEVOLVERTEX);
+    // Form BC(p).
+    tetlist = new list(sizeof(triface), NULL, 1024);
+    ceillist = new list(sizeof(triface), NULL, 1024);
+    verlist = new list(sizeof(point *), NULL, 256);
+    starttet = abcd;
+    infect(starttet);
+    tetlist->append(&starttet);
+    formbowatcavityquad(newpt, tetlist, ceillist);
+    // Can local maximal dihedral be reduced by inserting p?
+    if (trimbowatcavity(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist,
+                        remtet->key)) {
+      // Inserting p. Ignore any new enc-seg, enc-sub, and bad tets.
+      bowatinsertsite(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist, verlist,
+                      NULL, false, false, false);
+      setnewpointsize(newpt, verlist);
+      // Check if there are new slivers at p.
+      for (i = 0; i < ceillist->len(); i++) {
+        starttet = * (triface *)(* ceillist)[i];
+        checktet4sliver(&starttet, false, true);
+      }
+      smoothvolpt++;
+    } else {
+      // The local quality will not be improved. Do not insert p.
+      pointdealloc(newpt);
+      newpt = (point) NULL;
+      // Uninfect tets of BC(p).
+      for (i = 0; i < tetlist->len(); i++) {
+        starttet = * (triface *)(* tetlist)[i];
+        uninfect(starttet);
+      }
+      unsmoothvolpt++;
     }
-    // Remove the bad-quality tetrahedron from the pool.
-    badfacedealloc(badtetrahedrons, badtet);
+    delete tetlist;
+    delete ceillist;
+    delete verlist;
   }
+
+  return newpt != (point) NULL;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// repairslivers()    Remove slivers from the mesh.                          //
-//                                                                           //
-// Slivers are found and stored in 'badtetrahedrons'. Each sliver is removed //
-// by either local transformation operator or inserting a point at or near   //
-// its circumcenter.                                                         //
+// tallslivers()    Queue all the slivers in the mesh.                       //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::repairslivers(list* cavtetlist, queue* flipqueue)
+void tetgenmesh::tallslivers(bool chkill)
 {
-  badface *badtet;
-  triface starttet;
-  point newpoint;
-  enum insertsiteresult success;
-  enum locateresult loc;
-  bool reject;
-  int total, counter;
+  triface tetloop;
 
-  total = 0;
-  while (badtetrahedrons->items > 0l) {
-    counter = 0;
-    // Loop in pool 'badtetrahedrons'.
-    badtetrahedrons->traversalinit();
-    badtet = badfacetraverse(badtetrahedrons);
-    while (badtet != (badface *) NULL) {
-      if (!isdead(&badtet->tt) && (org(badtet->tt) == badtet->forg) &&
-          (dest(badtet->tt) == badtet->fdest) &&
-          (apex(badtet->tt) == badtet->fapex) &&
-          (oppo(badtet->tt) == badtet->foppo)) {
-        if (finddiagonal(&(badtet->tt))) {
-          if (removekite(&(badtet->tt), NULL)) {
-            // Remove the sliver from the pool.
-            badfacedealloc(badtetrahedrons, badtet);
-            counter++; 
-          }
-        }
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    if (chkill) {
+      if (!checktet4sliver(&tetloop, true, true)) {
+        checktet4ill(&tetloop, true);
       }
-      badtet = badfacetraverse(badtetrahedrons);
-    }
-    // Are there any sliver be removed?
-    if (counter == 0) break;
-    // Accumulate the number of removed slivers.
-    total += counter;
-    if (badtetrahedrons->items > 0l) {
-      // Some slivers may remain in the mesh.
-      badtetrahedrons->restart();
-      tallslivers();
+    } else {
+      checktet4sliver(&tetloop, false, true);
     }
+    tetloop.tet = tetrahedrontraverse();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// repairmesh()    Remove illegal tets in the mesh.                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::repairmesh()
+{
+  badface *remtet, *lastunrementry;
+
+  if (!b->quiet) {
+    printf("Repairing mesh.\n");
   }
 
-  if (badtetrahedrons->items > 0l) {
-    // Some slivers survived. Try to split them.
-    counter = 0;
+  // Initialize the pool of bad tets
+  badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0);
+  lastunrementry = (badface *) NULL;
+  striptetcount = fliptetcount = unimprovecount = 0l;
+
+  // Looking for illegal tets.
+  tallslivers(true);
+  
+  // Loop until pool 'badtetrahedrons' is empty.
+  while (badtetrahedrons->items > 0) {
     badtetrahedrons->traversalinit();
-    badtet = badfacetraverse(badtetrahedrons);
-    while (badtet != (badface *) NULL) {
-      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 a newpoint at the circumcenter of this sliver.
-        makepoint(&newpoint);
-        circumsphere(badtet->forg, badtet->fdest, badtet->fapex, badtet->foppo,
-                     newpoint, NULL);
-        // Set it's type be FREEVOLVERTEX.
-        setpointtype(newpoint, FREEVOLVERTEX);
-        // Locate newpoint in mesh.
-        starttet = badtet->tt;  // Used for the input of preciselocate().
-        loc = preciselocate(newpoint, &starttet);
-        // Look if the newpoint encroaches upon any segment or subface.
-        cavtetlist->append(&starttet);
-        collectcavtets(newpoint, cavtetlist);
-        assert(cavtetlist->len() > 0);
-        reject = tallencsubs(newpoint, cavtetlist);
-        // Clear the list for the next use.
-        cavtetlist->clear();
-        if (!reject && (loc != OUTSIDE)) {
-          // Insert the point, it should be always success.
-          starttet = badtet->tt;
-          success = insertsite(newpoint, &starttet, true, flipqueue);
-          if (success != DUPLICATEPOINT) {
-            if (steinerleft > 0) steinerleft--;
-            // Recover Delaunay property by flipping.
-            flip(flipqueue, NULL, false, false, false);
-            // Remove the sliver from the pool.
-            badfacedealloc(badtetrahedrons, badtet);
-            counter++; 
+    remtet = badfacetraverse(badtetrahedrons);
+    while (remtet != (badface *) NULL) {
+      // Make sure that the tet is still the same one when it was tested.
+      //   Subsequent transformations may have made it a different tet.
+      if (!isdead(&remtet->tt) && org(remtet->tt) == remtet->forg &&
+          dest(remtet->tt) == remtet->fdest && 
+          apex(remtet->tt) == remtet->fapex &&
+          oppo(remtet->tt) == remtet->foppo) {
+        if (b->verbose > 1) {
+          printf("    Repair tet (%d, %d, %d, %d).\n", pointmark(remtet->forg),
+                 pointmark(remtet->fdest), pointmark(remtet->fapex),
+                 pointmark(remtet->foppo));
+        }
+        if (!removetetbyrecon(remtet, true)) {
+          // An unremoveable tet. Check if it forms a loop.
+          if (lastunrementry != (badface *) NULL) {
+            if (remtet == lastunrementry) break;
           } else {
-            // !!! It's a bug!!!
-            pointdealloc(newpoint);
+            // Remember this tet as a breakpoint.
+            lastunrementry = remtet;
           }
         } else {
-          // Rejected. Do not insert the point.
-          pointdealloc(newpoint);
-          // Clean the pool.
-          badsubfaces->restart();
+          // Clear the breakpoint.
+          lastunrementry = (badface *) NULL;
+          // Remove the entry from the queue.
+          badfacedealloc(badtetrahedrons, remtet);
         }
       } else {
-        // Sliver has been changed.
-        badfacedealloc(badtetrahedrons, badtet);
-        counter++;
+        // Remove the entry from the queue.
+        badfacedealloc(badtetrahedrons, remtet);
       }
-      badtet = badfacetraverse(badtetrahedrons);
+      remtet = badfacetraverse(badtetrahedrons);
     }
-    // Accumulate the number of removed slivers.
-    total += counter;
+    // Stop if the above loop was out by force.
+    if (remtet != (badface *) NULL) break;
   }
 
   if (b->verbose) {
-    printf("  %d slivers are removed.\n", total);
+    if (striptetcount > 0l) {
+      printf("  %ld tets are stripped off.\n", striptetcount);
+    }
+    if (fliptetcount > 0l) {
+      printf("  %ld tets are flipped away.\n", fliptetcount);
+    }
     if (badtetrahedrons->items > 0l) {
-      printf("  %ld sliver(s) survived.\n", badtetrahedrons->items);
+      printf("  %ld tets are unremoveable.\n", badtetrahedrons->items);
     }
   }
+
+  delete badtetrahedrons;
+  badtetrahedrons = (memorypool *) NULL;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// enforcequality()    Remove all the encroached subsegments, subfaces  and  //
-//                     bad tetrahedra from the tetrahedral mesh.             //
+// smoothmesh()    Smooth the mesh.                                          //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::enforcequality()
+void tetgenmesh::smoothmesh()
 {
-  queue *flipqueue;
-  list *cavtetlist;
-  long total, vertcount;
-  int i;
-  
-  if (!b->quiet) {
-    printf("Adding Steiner points to enforce quality.\n");
-  } 
-
-  total = 0l;
-  // Initialize working queues, lists.
-  flipqueue = new queue(sizeof(badface));
-  rpsarray = new REAL[points->items + 1];
-  cavtetlist = new list(sizeof(triface), NULL, 256);
+  badface *remtet, *lastunrementry;
 
-  if (b->refine) {
-    // Mark segment vertices (acute or not).
-    markacutevertices(89.0);
+  if (!b->quiet) {
+    printf("Smoothing mesh.\n");
   }
-  // Mark sharp subfaces (for termination).
-  marksharpsubfaces(89.0);
-  // Mark skinny subfaces (for reducing Steiner points).
-  markskinnysubfaces(19.0);
-  // Calculate the protecting spheres for all acute points.
-  initializerpsarray();
 
-  // Initialize the pool of encroached subsegments.
-  badsubsegs = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
-  if (varconstraint && in->segmentconstraintlist) {
-    // Test all segments to see if they're bad-quality.
-    tallbadsegs();
-  }
-  // Test all segments to see if they're encroached.
-  tallencsegs(NULL, NULL);
-  if (b->verbose && badsubsegs->items > 0) {
-    printf("  Splitting encroached subsegments.\n");
-  }
-  vertcount = points->items;
-  // Fix encroached segments without noting any enc subfaces.
-  repairencsegs(flipqueue);
-  if (b->verbose) {
-    printf("  %ld points are inserted.\n", points->items - vertcount);
-  }
-  total += points->items - vertcount;
+  // 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;
 
-  // Initialize the pool of encroached subfaces.
-  badsubfaces = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
-  // Initialize the queues of badfaces.
-  for (i = 0; i < 2; i++) subquefront[i] = (badface *) NULL;
-  for (i = 0; i < 2; i++) subquetail[i] = &subquefront[i];
-  // Test all subfaces to see if they're bad-quality.
-  tallbadsubs();
-  // Test the rest of subfaces to see if they're encroached.
-  tallencsubs(NULL, NULL);
-  if (b->verbose && badsubfaces->items > 0) {
-    printf("  Splitting encroached subfaces.\n");
-  }
-  vertcount = points->items;
-  // Fix encroached subfaces without noting bad tetrahedra.
-  repairencsubs(cavtetlist, flipqueue);
-  // At this point, the mesh should be (conforming) Delaunay.
-  if (b->verbose) {
-    printf("  %ld points are inserted.\n", points->items - vertcount);
+  // 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 {
+        // 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;
   }
-  total += points->items - vertcount;
 
-  // Next, fix bad quality tetrahedra.
-  if ((b->minratio > 0.0) || b->varvolume || b->fixedvolume) {
-    // Initialize the pool of bad tetrahedra.
-    badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0);
-    // Initialize the list of bad tetrahedra.
-    qualchecktetlist = new list(sizeof(triface), NULL);
-    // Initialize the queues of bad tetrahedra.
-    for (i = 0; i < 64; i++) tetquefront[i] = (badface *) NULL;
-    for (i = 0; i < 64; i++) tetquetail[i] = &tetquefront[i];
-    // Test all tetrahedra to see if they're bad.
-    tallbadtetrahedrons();
-    if (b->verbose && badtetrahedrons->items > 0) {
-      printf("  Splitting bad tetrahedra.\n");
-    }
-    vertcount = points->items;
-    repairbadtets(cavtetlist, flipqueue);
-    // At this point, it should no bad quality tetrahedra.
-    if (b->verbose) {
-      printf("  %ld points are inserted.\n", points->items - vertcount);
+  if (b->verbose) {
+    if (striptetcount > 0l) {
+      printf("  %ld tets are stripped off.\n", striptetcount);
     }
-    total += points->items - vertcount;
-    assert(badtetrahedrons->items == 0l);
-    // Next, remove slivers from the mesh.
-    tallslivers();
-    if (b->verbose && badtetrahedrons->items > 0) {
-      printf("  Removing slivers.\n");
+    if (fliptetcount > 0l) {
+      printf("  %ld tets are flipped away.\n", fliptetcount);
     }
-    vertcount = points->items;
-    repairslivers(cavtetlist, flipqueue);
-    if (b->verbose) {
-      printf("  %ld points are inserted.\n", points->items - vertcount);
+  }
+
+  lastunrementry = (badface *) NULL;
+  // Loop until pool 'badtetrahedrons' is empty.
+  while (badtetrahedrons->items > 0) {
+    badtetrahedrons->traversalinit();
+    remtet = badfacetraverse(badtetrahedrons);
+    while (remtet != (badface *) NULL) {
+      // Make sure that the tet is still the same one when it was tested.
+      //   Subsequent transformations may have made it a different tet.
+      if (!isdead(&remtet->tt) && org(remtet->tt) == remtet->forg &&
+          dest(remtet->tt) == remtet->fdest && 
+          apex(remtet->tt) == remtet->fapex &&
+          oppo(remtet->tt) == remtet->foppo) {
+        if (b->verbose > 1) {
+          printf("    Repair tet (%d, %d, %d, %d).\n", pointmark(remtet->forg),
+                 pointmark(remtet->fdest), pointmark(remtet->fapex),
+                 pointmark(remtet->foppo));
+        }
+        if (!removetetbyrecon(remtet, false)) {
+          // An unremoveable tet. Find if a segment which can be split.
+          if (!removetetbysplit(remtet)) {
+            // An unremoveable tet. Check if it forms a loop.
+            if (lastunrementry != (badface *) NULL) {
+              if (remtet == lastunrementry) break;
+            } else {
+              // Remember this tet as a breakpoint.
+              lastunrementry = remtet;
+            }
+          } else {
+            // Clear the breakpoint.
+            lastunrementry = (badface *) NULL;
+            // Remove the entry from the queue.
+            badfacedealloc(badtetrahedrons, remtet);
+          }
+        } else {
+          // Clear the breakpoint.
+          lastunrementry = (badface *) NULL;
+          // Remove the entry from the queue.
+          badfacedealloc(badtetrahedrons, remtet);
+        }
+      } else {
+        // Remove the entry from the queue.
+        badfacedealloc(badtetrahedrons, remtet);
+      }
+      remtet = badfacetraverse(badtetrahedrons);
     }
-    total += points->items - vertcount;
-    delete qualchecktetlist;
-    delete badtetrahedrons;
+    // Stop if the above loop was out by force.
+    if (remtet != (badface *) NULL) break;
   }
 
   if (b->verbose) {
-    printf("  Total %ld points are inserted.\n", total);
+    if ((smoothcdtsegpt + smoothsegpt + smoothsubpt + smoothvolpt) > 0l) {
+      printf("  %ld smooth points.\n", 
+             smoothcdtsegpt + smoothsegpt + smoothsubpt + smoothvolpt);
+    }
+    if (badtetrahedrons->items > 0l) {
+      printf("  %ld remaining tets.\n", badtetrahedrons->items);
+    }
   }
 
-  delete cavtetlist;
-  delete flipqueue;
-  delete badsubfaces;
-  delete badsubsegs;
-  delete [] rpsarray;
+  delete badtetrahedrons;
+  badtetrahedrons = (memorypool *) NULL;
 }
 
 //
-// End of Delaunay refinement routines
+// End of mesh smoothing routines
 //
 
 //
@@ -23109,8 +28204,9 @@ void tetgenmesh::transfernodes()
   longest = sqrt(x * x + y * y + z * z);
   if (longest == 0.0) {
     printf("Error:  The point set is trivial.\n");
-    exit(1);
+    terminatetetgen(1);
   }
+  lengthlimit = longest * b->epsilon * 1e+2;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -23129,7 +28225,8 @@ void tetgenmesh::jettisonnodes()
 {
   point pointloop;
   bool jetflag;
-  int idx;
+  int oldidx, newidx;
+  int remcount;
 
   if (!b->quiet) {
     printf("Jettisoning redundants points.\n");
@@ -23137,20 +28234,39 @@ void tetgenmesh::jettisonnodes()
 
   points->traversalinit();
   pointloop = pointtraverse();
-  idx = in->firstnumber;
+  oldidx = newidx = 0; // in->firstnumber;
+  remcount = 0;
   while (pointloop != (point) NULL) {
     jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) || 
       (pointtype(pointloop) == UNUSEDVERTEX);
     if (jetflag) {
       // It is a duplicated point, delete it.
       pointdealloc(pointloop);
+      remcount++;
     } else {
-      // Index it.
-      setpointmark(pointloop, idx);
-      idx++;
+      // Re-index it.
+      setpointmark(pointloop, newidx + in->firstnumber);
+      if (in->pointmarkerlist != (int *) NULL) {
+        if (oldidx < in->numberofpoints) {
+          // Re-index the point marker as well.
+          in->pointmarkerlist[newidx] = in->pointmarkerlist[oldidx];
+        }
+      }
+      newidx++;
+    }
+    oldidx++;
+    if (oldidx == in->numberofpoints) {
+      // Update the numbe of input points (Because some were removed).
+      in->numberofpoints -= remcount;
+      // Remember this number for output original input nodes.
+      jettisoninverts = remcount;
     }
     pointloop = pointtraverse();
   }
+  if (b->verbose) {
+    printf("  %d duplicated vertices have been removed.\n", dupverts);
+    printf("  %d unused vertices have been removed.\n", unuverts);
+  }
   dupverts = 0;
   unuverts = 0;
 
@@ -23184,10 +28300,10 @@ void tetgenmesh::highorder()
   //   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};
+  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");
@@ -23197,7 +28313,7 @@ void tetgenmesh::highorder()
   highordertable = new point[tetrahedrons->items * 6];
   if (highordertable == (point *) NULL) {
     printf("Error:  Out of memory.\n");
-    exit(1);
+    terminatetetgen(1);
   }
 
   // The following line ensures that dead items in the pool of nodes cannot
@@ -23266,9 +28382,9 @@ void tetgenmesh::highorder()
         // 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.
@@ -23318,10 +28434,15 @@ void tetgenmesh::outnodes(tetgenio* out)
 {
   FILE *outfile;
   char outnodefilename[FILENAMESIZE];
+  shellface subptr;
+  triface adjtet;
+  face subloop;
   point pointloop;
-  int nextras, bmark, marker;
+  point *extralist, ep[3];
+  int nextras, bmark, shmark, marker;
   int coordindex, attribindex;
-  int pointnumber, index, i;
+  int pointnumber, firstindex;
+  int index, i;
 
   if (out == (tetgenio *) NULL) {
     strcpy(outnodefilename, b->outfilename);
@@ -23336,14 +28457,19 @@ void tetgenmesh::outnodes(tetgenio* out)
     }
   }
 
-  nextras = in->numberofpointattributes;
+  // nextras = in->numberofpointattributes;
+  nextras = 0; // After version 1.4.0, don't output point attributes.
   bmark = !b->nobound && in->pointmarkerlist;
 
+  // Avoid compile warnings.
+  outfile = (FILE *) NULL;
+  marker = coordindex = 0;
+
   if (out == (tetgenio *) NULL) {
     outfile = fopen(outnodefilename, "w");
     if (outfile == (FILE *) NULL) {
       printf("File I/O Error:  Cannot create file %s.\n", outnodefilename);
-      exit(1);
+      terminatetetgen(1);
     }
     // Number of points, number of dimensions, number of point attributes,
     //   and number of boundary markers (zero or one).
@@ -23353,14 +28479,14 @@ void tetgenmesh::outnodes(tetgenio* out)
     out->pointlist = new REAL[points->items * 3];
     if (out->pointlist == (REAL *) NULL) {
       printf("Error:  Out of memory.\n");
-      exit(1);
+      terminatetetgen(1);
     }
     // 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");
-        exit(1);
+        terminatetetgen(1);
       }
     }
     // Allocate space for 'pointmarkerlist' if necessary;
@@ -23368,68 +28494,218 @@ void tetgenmesh::outnodes(tetgenio* out)
       out->pointmarkerlist = new int[points->items];
       if (out->pointmarkerlist == (int *) NULL) {
         printf("Error:  Out of memory.\n");
-        exit(1);
+        terminatetetgen(1);
+      }
+    }
+    out->numberofpoints = points->items;
+    out->numberofpointattributes = nextras;
+    coordindex = 0;
+    attribindex = 0;
+  }
+
+  if (bmark && (b->plc || b->refine)) {
+    // Initialize the point2tet field of each point.
+    points->traversalinit();
+    pointloop = pointtraverse();
+    while (pointloop != (point) NULL) {
+      setpoint2tet(pointloop, (tetrahedron) NULL);
+      pointloop = pointtraverse();
+    }
+    // Make a map point-to-subface. Hence a boundary point will get the
+    //   facet marker from that facet where it lies on.
+    subfaces->traversalinit();
+    subloop.sh = shellfacetraverse(subfaces);
+    while (subloop.sh != (shellface *) NULL) {
+      subloop.shver = 0;
+      // Check all three points of the subface.
+      for (i = 0; i < 3; i++) {
+        pointloop = (point) subloop.sh[3 + i];
+        setpoint2tet(pointloop, (tetrahedron) sencode(subloop));
+      }
+      if (b->order == 2) {
+        // '-o2' switch. Set markers for quadratic nodes of this subface.
+        stpivot(subloop, adjtet);
+        if (adjtet.tet == dummytet) {
+          sesymself(subloop);
+          stpivot(subloop, adjtet);
+        }
+        assert(adjtet.tet != dummytet);
+        extralist = (point *) adjtet.tet[highorderindex];
+        switch (adjtet.loc) {
+        case 0:
+          ep[0] = extralist[0];
+          ep[1] = extralist[1];
+          ep[2] = extralist[2];
+          break;
+        case 1:
+          ep[0] = extralist[0];
+          ep[1] = extralist[4];
+          ep[2] = extralist[3];
+          break;
+        case 2:
+          ep[0] = extralist[1];
+          ep[1] = extralist[5];
+          ep[2] = extralist[4];
+          break;
+        case 3:
+          ep[0] = extralist[2];
+          ep[1] = extralist[3];
+          ep[2] = extralist[5];
+          break;
+        default: break;
+        }
+        for (i = 0; i < 3; i++) {
+          setpoint2tet(ep[i], (tetrahedron) sencode(subloop));
+        }
+      }
+      subloop.sh = shellfacetraverse(subfaces);
+    }
+  }
+
+  // Determine the first index (0 or 1).
+  firstindex = b->zeroindex ? 0 : in->firstnumber; 
+
+  points->traversalinit();
+  pointloop = pointtraverse();
+  pointnumber = firstindex; // in->firstnumber;
+  index = 0;
+  while (pointloop != (point) NULL) {
+    if (bmark) {
+      // Default the vertex has a zero marker.
+      marker = 0;
+      // Is it an input vertex?
+      if (index < in->numberofpoints) {
+        // Input point's marker is directly copied to output.
+        marker = in->pointmarkerlist[index];
+      }
+      // Is it a boundary vertex has marker zero?
+      if ((marker == 0) && (b->plc || b->refine)) {
+        subptr = (shellface) point2tet(pointloop);
+        if (subptr != (shellface) NULL) {
+          // Default a boundary vertex has marker 1.
+          marker = 1;
+          if (in->facetmarkerlist != (int *) NULL) {
+            // The vertex gets the marker from the facet it lies on.
+            sdecode(subptr, subloop);
+            shmark = shellmark(subloop);
+            marker = in->facetmarkerlist[shmark - 1];
+          }
+        }
+      }
+    }
+    if (out == (tetgenio *) NULL) {
+      // Point number, x, y and z coordinates.
+      fprintf(outfile, "%4d    %.17g  %.17g  %.17g", pointnumber,
+              pointloop[0], pointloop[1], pointloop[2]);
+      for (i = 0; i < nextras; i++) {
+        // Write an attribute.
+        fprintf(outfile, "  %.17g", pointloop[3 + i]);
+      }
+      if (bmark) {
+        // Write the boundary marker.
+        fprintf(outfile, "    %d", marker);
+      }
+      fprintf(outfile, "\n");
+    } else {
+      // X, y, and z coordinates.
+      out->pointlist[coordindex++] = pointloop[0];
+      out->pointlist[coordindex++] = pointloop[1];
+      out->pointlist[coordindex++] = pointloop[2];
+      // Point attributes.
+      for (i = 0; i < nextras; i++) {
+        // Output an attribute.
+        out->pointattributelist[attribindex++] = pointloop[3 + i];
+      }
+      if (bmark) {
+        // Output the boundary marker.  
+        out->pointmarkerlist[index] = marker;
+      }
+    }
+    pointloop = pointtraverse();
+    pointnumber++; 
+    index++;
+  }
+
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outmetrics()    Output the metric to a file (*.mtr) or a tetgenio obj.    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outmetrics(tetgenio* out)
+{
+  FILE *outfile;
+  char outmtrfilename[FILENAMESIZE];
+  point pointloop;
+  int nextras, attribindex;
+  int i;  
+
+  if (out == (tetgenio *) NULL) {
+    strcpy(outmtrfilename, b->outfilename);
+    strcat(outmtrfilename, ".mtr");
+  }
+
+  if (!b->quiet) {
+    if (out == (tetgenio *) NULL) {
+      printf("Writing %s.\n", outmtrfilename);
+    } else {
+      printf("Writing metrics.\n");
+    }
+  }
+
+  // Avoid compile warnings.
+  outfile = (FILE *) NULL;
+  attribindex = 0;
+
+  nextras = 0;
+  if (b->bgmesh) {
+    nextras = bgm->in->numberofpointattributes;
+  } else if (b->quality) {
+    nextras = 1;
+  }
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(outmtrfilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", outmtrfilename);
+      terminatetetgen(1);
+    }
+    // Number of points, number of point attributes,
+    fprintf(outfile, "%ld  %d\n", points->items, nextras);
+  } else {
+    // Allocate space for 'pointattributelist' if necessary;
+    if (nextras > 0) {
+      out->pointattributelist = new REAL[points->items * nextras];
+      if (out->pointattributelist == (REAL *) NULL) {
+        printf("Error:  Out of memory.\n");
+        terminatetetgen(1);
       }
     }
-    out->numberofpoints = points->items;
     out->numberofpointattributes = nextras;
-    coordindex = 0;
     attribindex = 0;
   }
-
+  
   points->traversalinit();
   pointloop = pointtraverse();
-  pointnumber = in->firstnumber;
-  index = 0;
   while (pointloop != (point) NULL) {
-    if (bmark) {
-      // Determine the boundary marker.
-      if (index < in->numberofpoints) {
-        // Input point's marker is directly copied to output.
-        marker = in->pointmarkerlist[index];
-        if (marker == 0) {
-          // Change the marker if it is a boundary point.
-          marker = (pointtype(pointloop) != FREEVOLVERTEX) ? 1 : 0;
-        }
-      } else if (pointtype(pointloop) != FREEVOLVERTEX) {
-        // A boundary vertex has marker 1.
-        marker = 1;
-      } else {
-        // Free or internal point has a zero marker.
-        marker = 0;
-      }
-    }
     if (out == (tetgenio *) NULL) {
-      // Point number, x, y and z coordinates.
-      fprintf(outfile, "%4d    %.17g  %.17g  %.17g", pointnumber,
-              pointloop[0], pointloop[1], pointloop[2]);
       for (i = 0; i < nextras; i++) {
         // Write an attribute.
-        fprintf(outfile, "  %.17g", pointloop[3 + i]);
-      }
-      if (bmark) {
-        // Write the boundary marker.
-        fprintf(outfile, "    %d", marker);
+        fprintf(outfile, "%-22.17e ", pointloop[3 + i]);
       }
       fprintf(outfile, "\n");
     } else {
-      // X, y, and z coordinates.
-      out->pointlist[coordindex++] = pointloop[0];
-      out->pointlist[coordindex++] = pointloop[1];
-      out->pointlist[coordindex++] = pointloop[2];
-      // Point attributes.
       for (i = 0; i < nextras; i++) {
         // Output an attribute.
         out->pointattributelist[attribindex++] = pointloop[3 + i];
       }
-      if (bmark) {
-        // Output the boundary marker.  
-        out->pointmarkerlist[index] = marker;
-      }
     }
     pointloop = pointtraverse();
-    pointnumber++; 
-    index++;
   }
 
   if (out == (tetgenio *) NULL) {
@@ -23452,6 +28728,7 @@ void tetgenmesh::outelements(tetgenio* out)
   tetrahedron* tptr;
   int *tlist;
   REAL *talist;
+  int firstindex, shift;
   int pointindex;
   int attribindex;
   point p1, p2, p3, p4;
@@ -23473,12 +28750,18 @@ void tetgenmesh::outelements(tetgenio* out)
     }
   }
 
+  // Avoid compile warnings.
+  outfile = (FILE *) NULL;
+  tlist = (int *) NULL;
+  talist = (double *) NULL;
+  pointindex = attribindex = 0;
+
   eextras = in->numberoftetrahedronattributes;
   if (out == (tetgenio *) NULL) {
     outfile = fopen(outelefilename, "w");
     if (outfile == (FILE *) NULL) {
       printf("File I/O Error:  Cannot create file %s.\n", outelefilename);
-      exit(1);
+      terminatetetgen(1);
     }
     // Number of tetras, points per tetra, attributes per tetra.
     fprintf(outfile, "%ld  %d  %d\n", tetrahedrons->items,
@@ -23489,14 +28772,14 @@ void tetgenmesh::outelements(tetgenio* out)
                                    (b->order == 1 ? 4 : 10)];
     if (out->tetrahedronlist == (int *) NULL) {
       printf("Error:  Out of memory.\n");
-      exit(1);
+      terminatetetgen(1);
     }
     // Allocate memory for output tetrahedron attributes if necessary.
     if (eextras > 0) {
       out->tetrahedronattributelist = new REAL[tetrahedrons->items * eextras];
       if (out->tetrahedronattributelist == (REAL *) NULL) {
         printf("Error:  Out of memory.\n");
-        exit(1);
+        terminatetetgen(1);
       }
     }
     out->numberoftetrahedra = tetrahedrons->items;
@@ -23508,9 +28791,16 @@ void tetgenmesh::outelements(tetgenio* out)
     attribindex = 0;
   }
 
+  // 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 the output indices by 1.
+  }
+
   tetrahedrons->traversalinit();
   tptr = tetrahedrontraverse();
-  elementnumber = in->firstnumber;
+  elementnumber = firstindex; // in->firstnumber;
   while (tptr != (tetrahedron *) NULL) {
     p1 = (point) tptr[4];
     p2 = (point) tptr[5];
@@ -23519,40 +28809,49 @@ void tetgenmesh::outelements(tetgenio* out)
     if (out == (tetgenio *) NULL) {
       // Tetrahedron number, indices for four points.
       fprintf(outfile, "%5d   %5d %5d %5d %5d", elementnumber,
-              pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4));
+              pointmark(p1) - shift, pointmark(p2) - shift,
+              pointmark(p3) - shift, pointmark(p4) - shift);
       if (b->order == 2) {
         extralist = (point *) tptr[highorderindex];
         // Tetrahedron number, indices for four points plus six extra points.
         fprintf(outfile, "  %5d %5d %5d %5d %5d %5d",
-                pointmark(extralist[0]), pointmark(extralist[1]),
-                pointmark(extralist[2]), pointmark(extralist[3]),
-                pointmark(extralist[4]), pointmark(extralist[5]));
+          pointmark(extralist[0]) - shift, pointmark(extralist[1]) - shift,
+          pointmark(extralist[2]) - shift, pointmark(extralist[3]) - shift,
+          pointmark(extralist[4]) - shift, pointmark(extralist[5]) - shift);
       }
       for (i = 0; i < eextras; i++) {
         fprintf(outfile, "    %.17g", elemattribute(tptr, i));
       }
       fprintf(outfile, "\n");
     } else {
-      tlist[pointindex++] = pointmark(p1);
-      tlist[pointindex++] = pointmark(p2);
-      tlist[pointindex++] = pointmark(p3);
-      tlist[pointindex++] = pointmark(p4);
+      tlist[pointindex++] = pointmark(p1) - shift;
+      tlist[pointindex++] = pointmark(p2) - shift;
+      tlist[pointindex++] = pointmark(p3) - shift;
+      tlist[pointindex++] = pointmark(p4) - shift;
       if (b->order == 2) {
         extralist = (point *) tptr[highorderindex];
-        tlist[pointindex++] = pointmark(extralist[0]);
-        tlist[pointindex++] = pointmark(extralist[1]);
-        tlist[pointindex++] = pointmark(extralist[2]);
-        tlist[pointindex++] = pointmark(extralist[3]);
-        tlist[pointindex++] = pointmark(extralist[4]);
-        tlist[pointindex++] = pointmark(extralist[5]);
+        tlist[pointindex++] = pointmark(extralist[0]) - shift;
+        tlist[pointindex++] = pointmark(extralist[1]) - shift;
+        tlist[pointindex++] = pointmark(extralist[2]) - shift;
+        tlist[pointindex++] = pointmark(extralist[3]) - shift;
+        tlist[pointindex++] = pointmark(extralist[4]) - shift;
+        tlist[pointindex++] = pointmark(extralist[5]) - shift;
       }
       for (i = 0; i < eextras; i++) {
         talist[attribindex++] = elemattribute(tptr, i);
       }
     }
+    if (b->neighout) {
+      // Remember the index of this element.
+      * (int *) (tptr + elemmarkerindex) = elementnumber;
+    }
     tptr = tetrahedrontraverse();
     elementnumber++;
   }
+  if (b->neighout) {
+    // Set the outside element marker.
+    * (int *) (dummytet + elemmarkerindex) = -1;
+  }
 
   if (out == (tetgenio *) NULL) {
     fprintf(outfile, "# Generated by %s\n", b->commandline);
@@ -23581,6 +28880,7 @@ void tetgenmesh::outfaces(tetgenio* out)
   point torg, tdest, tapex;
   long faces;
   int bmark, faceid, marker;
+  int firstindex, shift;
   int facenumber;
 
   if (out == (tetgenio *) NULL) {
@@ -23596,6 +28896,12 @@ void tetgenmesh::outfaces(tetgenio* out)
     }
   }
 
+  // Avoid compile warnings.
+  outfile = (FILE *) NULL;
+  elist = (int *) NULL;
+  emlist = (int *) NULL;
+  index =  marker = 0;
+
   faces = (4l * tetrahedrons->items + hullsize) / 2l;
   bmark = !b->nobound && in->facetmarkerlist;
 
@@ -23603,7 +28909,7 @@ void tetgenmesh::outfaces(tetgenio* out)
     outfile = fopen(facefilename, "w");
     if (outfile == (FILE *) NULL) {
       printf("File I/O Error:  Cannot create file %s.\n", facefilename);
-      exit(1);
+      terminatetetgen(1);
     }
     fprintf(outfile, "%ld  %d\n", faces, bmark);
   } else {
@@ -23611,14 +28917,14 @@ void tetgenmesh::outfaces(tetgenio* out)
     out->trifacelist = new int[faces * 3];
     if (out->trifacelist == (int *) NULL) {
       printf("Error:  Out of memory.\n");
-      exit(1);
+      terminatetetgen(1);
     }
     // Allocate memory for 'trifacemarkerlist' if necessary.
     if (bmark) {
       out->trifacemarkerlist = new int[faces];
       if (out->trifacemarkerlist == (int *) NULL) {
         printf("Error:  Out of memory.\n");
-        exit(1);
+        terminatetetgen(1);
       }
     }
     out->numberoftrifaces = faces;
@@ -23627,9 +28933,16 @@ void tetgenmesh::outfaces(tetgenio* out)
     index = 0;
   }
 
+  // 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 the output indices by 1.
+  }
+
   tetrahedrons->traversalinit();
   tface.tet = tetrahedrontraverse();
-  facenumber = in->firstnumber;
+  facenumber = firstindex; // in->firstnumber;
   // To loop over the set of faces, loop over all tetrahedra, and look at
   //   the four faces of each one. If there isn't another tetrahedron
   //   adjacent to this face, operate on the face.  If there is another
@@ -23663,7 +28976,8 @@ void tetgenmesh::outfaces(tetgenio* out)
         if (out == (tetgenio *) NULL) {
           // Face number, indices of three vertices.
           fprintf(outfile, "%5d   %4d  %4d  %4d", facenumber,
-                  pointmark(torg), pointmark(tdest), pointmark(tapex));
+                  pointmark(torg) - shift, pointmark(tdest) - shift,
+                  pointmark(tapex) - shift);
           if (bmark) {
             // Output a boundary marker.
             fprintf(outfile, "  %d", marker);
@@ -23671,9 +28985,9 @@ void tetgenmesh::outfaces(tetgenio* out)
           fprintf(outfile, "\n");
         } else {
           // Output indices of three vertices.
-          elist[index++] = pointmark(torg);
-          elist[index++] = pointmark(tdest);
-          elist[index++] = pointmark(tapex);
+          elist[index++] = pointmark(torg) - shift;
+          elist[index++] = pointmark(tdest) - shift;
+          elist[index++] = pointmark(tapex) - shift;
           if (bmark) {
             emlist[facenumber - in->firstnumber] = marker;
           }
@@ -23710,6 +29024,7 @@ void tetgenmesh::outhullfaces(tetgenio* out)
   triface tface, tsymface;
   face checkmark;
   point torg, tdest, tapex;
+  int firstindex, shift;
   int facenumber;
 
   if (out == (tetgenio *) NULL) {
@@ -23725,11 +29040,16 @@ void tetgenmesh::outhullfaces(tetgenio* out)
     }
   }
 
+  // Avoid compile warnings.
+  outfile = (FILE *) NULL;
+  elist = (int *) NULL;
+  index = 0;
+
   if (out == (tetgenio *) NULL) {
     outfile = fopen(facefilename, "w");
     if (outfile == (FILE *) NULL) {
       printf("File I/O Error:  Cannot create file %s.\n", facefilename);
-      exit(1);
+      terminatetetgen(1);
     }
     fprintf(outfile, "%ld  0\n", hullsize);
   } else {
@@ -23737,16 +29057,23 @@ void tetgenmesh::outhullfaces(tetgenio* out)
     out->trifacelist = new int[hullsize * 3];
     if (out->trifacelist == (int *) NULL) {
       printf("Error:  Out of memory.\n");
-      exit(1);
+      terminatetetgen(1);
     }
     out->numberoftrifaces = hullsize;
     elist = out->trifacelist;
     index = 0;
   }
 
+  // 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 the output indices by 1.
+  }
+
   tetrahedrons->traversalinit();
   tface.tet = tetrahedrontraverse();
-  facenumber = in->firstnumber;
+  facenumber = firstindex; // in->firstnumber;
   // To loop over the set of hull faces, loop over all tetrahedra, and look
   //   at the four faces of each one. If there isn't another tetrahedron
   //   adjacent to this face, operate on the face.
@@ -23760,13 +29087,14 @@ void tetgenmesh::outhullfaces(tetgenio* out)
         if (out == (tetgenio *) NULL) {
           // Face number, indices of three vertices.
           fprintf(outfile, "%5d   %4d  %4d  %4d", facenumber,
-                  pointmark(torg), pointmark(tdest), pointmark(tapex));
+                  pointmark(torg) - shift, pointmark(tdest) - shift,
+                  pointmark(tapex) - shift);
           fprintf(outfile, "\n");
         } else {
           // Output indices of three vertices.
-          elist[index++] = pointmark(torg);
-          elist[index++] = pointmark(tdest);
-          elist[index++] = pointmark(tapex);
+          elist[index++] = pointmark(torg) - shift;
+          elist[index++] = pointmark(tdest) - shift;
+          elist[index++] = pointmark(tapex) - shift;
         }
         facenumber++;
       }
@@ -23802,6 +29130,8 @@ void tetgenmesh::outsubfaces(tetgenio* out)
   face faceloop;
   point torg, tdest, tapex;
   int bmark, faceid, marker;
+  int firstindex, shift;
+  int neigh1, neigh2;
   int facenumber;
 
   if (out == (tetgenio *) NULL) {
@@ -23817,13 +29147,20 @@ void tetgenmesh::outsubfaces(tetgenio* out)
     }
   }
 
+  // Avoid compile warnings.
+  outfile = (FILE *) NULL;
+  elist = (int *) NULL;
+  emlist = (int *) NULL;
+  index = marker = 0;
+  neigh1 = neigh2 = 0;
+
   bmark = !b->nobound && in->facetmarkerlist;
 
   if (out == (tetgenio *) NULL) {
     outfile = fopen(facefilename, "w");
     if (outfile == (FILE *) NULL) {
       printf("File I/O Error:  Cannot create file %s.\n", facefilename);
-      exit(1);
+      terminatetetgen(1);
     }
     // Number of subfaces.
     fprintf(outfile, "%ld  %d\n", subfaces->items, bmark);
@@ -23832,14 +29169,22 @@ void tetgenmesh::outsubfaces(tetgenio* out)
     out->trifacelist = new int[subfaces->items * 3];
     if (out->trifacelist == (int *) NULL) {
       printf("Error:  Out of memory.\n");
-      exit(1);
+      terminatetetgen(1);
     }
-    // Allocate memory for 'trifacemarkerlist', if necessary.
     if (bmark) {
+      // Allocate memory for 'trifacemarkerlist'.
       out->trifacemarkerlist = new int[subfaces->items];
       if (out->trifacemarkerlist == (int *) NULL) {
         printf("Error:  Out of memory.\n");
-        exit(1);
+        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 = subfaces->items;
@@ -23848,15 +29193,21 @@ void tetgenmesh::outsubfaces(tetgenio* out)
     index = 0;
   }
 
+  // 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 the output indices by 1.
+  }
+
   subfaces->traversalinit();
   faceloop.sh = shellfacetraverse(subfaces);
-  facenumber = in->firstnumber;
+  facenumber = firstindex; // in->firstnumber;
   while (faceloop.sh != (shellface *) NULL) {
     stpivot(faceloop, abuttingtet);
     if (abuttingtet.tet == dummytet) {
       sesymself(faceloop);
       stpivot(faceloop, abuttingtet);
-      // assert(abuttingtet.tet != dummytet) {
     }
     if (abuttingtet.tet != dummytet) {
       // If there is a tetrahedron containing this subface, orient it so
@@ -23876,21 +29227,43 @@ void tetgenmesh::outsubfaces(tetgenio* out)
       faceid = shellmark(faceloop) - 1;
       marker = in->facetmarkerlist[faceid];
     }
+    if (b->neighout > 1) {
+      // '-nn' switch. Output adjacent tets indices.
+      neigh1 = -1;
+      stpivot(faceloop, abuttingtet);
+      if (abuttingtet.tet != dummytet) {
+        neigh1 = * (int *)(abuttingtet.tet + elemmarkerindex);
+      }
+      neigh2 = -1;
+      sesymself(faceloop);
+      stpivot(faceloop, abuttingtet);
+      if (abuttingtet.tet != dummytet) {
+        neigh2 = * (int *)(abuttingtet.tet + elemmarkerindex);
+      }
+    }
     if (out == (tetgenio *) NULL) {
       fprintf(outfile, "%5d   %4d  %4d  %4d", facenumber,
-              pointmark(torg), pointmark(tdest), pointmark(tapex));
+              pointmark(torg) - shift, pointmark(tdest) - shift,
+              pointmark(tapex) - shift);
       if (bmark) {
         fprintf(outfile, "    %d", marker);
       }
+      if (b->neighout > 1) {
+        fprintf(outfile, "    %5d  %5d", neigh1, neigh2);
+      }
       fprintf(outfile, "\n");
     } else {
       // Output three vertices of this face;
-      elist[index++] = pointmark(torg);
-      elist[index++] = pointmark(tdest);
-      elist[index++] = pointmark(tapex);
+      elist[index++] = pointmark(torg) - shift;
+      elist[index++] = pointmark(tdest) - shift;
+      elist[index++] = pointmark(tapex) - shift;
       if (bmark) {
         emlist[facenumber - in->firstnumber] = marker;
       }
+      if (b->neighout > 1) {
+        out->adjtetlist[(facenumber - in->firstnumber) * 2]     = neigh1;
+        out->adjtetlist[(facenumber - in->firstnumber) * 2 + 1] = neigh2;
+      }
     }
     facenumber++;
     faceloop.sh = shellfacetraverse(subfaces);
@@ -23904,10 +29277,7 @@ void tetgenmesh::outsubfaces(tetgenio* out)
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// outsubsegments()    Output segments (i.e. boundary edges) to a .edge file //
-//                     or a tetgenio structure.                              //
-//                                                                           //
-// The boundary edges are stored in 'subsegs'.                               //
+// outsubsegments()    Output segments to a .edge file or a structure.       //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -23919,6 +29289,7 @@ void tetgenmesh::outsubsegments(tetgenio* out)
   int index;
   face edgeloop;
   point torg, tdest;
+  int firstindex, shift;
   int edgenumber;
 
   if (out == (tetgenio *) NULL) {
@@ -23934,11 +29305,16 @@ void tetgenmesh::outsubsegments(tetgenio* out)
     }
   }
 
+  // Avoid compile warnings.
+  outfile = (FILE *) NULL;
+  elist = (int *) NULL;
+  index = 0;  
+
   if (out == (tetgenio *) NULL) {
     outfile = fopen(edgefilename, "w");
     if (outfile == (FILE *) NULL) {
       printf("File I/O Error:  Cannot create file %s.\n", edgefilename);
-      exit(1);
+      terminatetetgen(1);
     }
     // Number of subsegments.
     fprintf(outfile, "%ld\n", subsegs->items);
@@ -23947,26 +29323,33 @@ void tetgenmesh::outsubsegments(tetgenio* out)
     out->edgelist = new int[subsegs->items * 2];
     if (out->edgelist == (int *) NULL) {
       printf("Error:  Out of memory.\n");
-      exit(1);
+      terminatetetgen(1);
     }
     out->numberofedges = subsegs->items;
     elist = out->edgelist;
     index = 0;
   }
 
+  // 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 the output indices by 1.
+  }
+
   subsegs->traversalinit();
   edgeloop.sh = shellfacetraverse(subsegs);
-  edgenumber = in->firstnumber;
+  edgenumber = firstindex; // in->firstnumber;
   while (edgeloop.sh != (shellface *) NULL) {
     torg = sorg(edgeloop);
     tdest = sdest(edgeloop);
     if (out == (tetgenio *) NULL) {
-      fprintf(outfile, "%5d   %4d  %4d\n", edgenumber, pointmark(torg),
-              pointmark(tdest));
+      fprintf(outfile, "%5d   %4d  %4d\n", edgenumber,
+              pointmark(torg) - shift, pointmark(tdest) - shift);
     } else {
       // Output three vertices of this face;
-      elist[index++] = pointmark(torg);
-      elist[index++] = pointmark(tdest);
+      elist[index++] = pointmark(torg) - shift;
+      elist[index++] = pointmark(tdest) - shift;
     }
     edgenumber++;
     edgeloop.sh = shellfacetraverse(subsegs);
@@ -23980,8 +29363,7 @@ void tetgenmesh::outsubsegments(tetgenio* out)
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// outneighbors()    Output a list of neighbors to a .neigh file or a        //
-//                   tetgenio structure.                                     //
+// outneighbors()    Output tet neighbors to a .neigh file or a structure.   //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -23991,9 +29373,9 @@ void tetgenmesh::outneighbors(tetgenio* out)
   char neighborfilename[FILENAMESIZE];
   int *nlist;
   int index;
-  tetrahedron *tptr;
   triface tetloop, tetsym;
   int neighbor1, neighbor2, neighbor3, neighbor4;
+  int firstindex;
   int elementnumber;
 
   if (out == (tetgenio *) NULL) {
@@ -24009,11 +29391,16 @@ void tetgenmesh::outneighbors(tetgenio* out)
     }
   }
 
+  // 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);
-      exit(1);
+      terminatetetgen(1);
     }
     // Number of tetrahedra, four faces per tetrahedron.
     fprintf(outfile, "%ld  %d\n", tetrahedrons->items, 4);
@@ -24022,38 +29409,31 @@ void tetgenmesh::outneighbors(tetgenio* out)
     out->neighborlist = new int[tetrahedrons->items * 4];
     if (out->neighborlist == (int *) NULL) {
       printf("Error:  Out of memory.\n");
-      exit(1);
+      terminatetetgen(1);
     }
     nlist = out->neighborlist;
     index = 0;
   }
 
-  tetrahedrons->traversalinit();
-  tptr = tetrahedrontraverse();
-  elementnumber = in->firstnumber;
-  while (tptr != (tetrahedron *) NULL) {
-    * (int *) (tptr + 8) = elementnumber;
-    tptr = tetrahedrontraverse();
-    elementnumber++;
-  }
-  * (int *) (dummytet + 8) = -1;
+  // Determine the first index (0 or 1).
+  firstindex = b->zeroindex ? 0 : in->firstnumber;
 
   tetrahedrons->traversalinit();
   tetloop.tet = tetrahedrontraverse();
-  elementnumber = in->firstnumber;
+  elementnumber = firstindex; // in->firstnumber;
   while (tetloop.tet != (tetrahedron *) NULL) {
     tetloop.loc = 2;
     sym(tetloop, tetsym);
-    neighbor1 = * (int *) (tetsym.tet + 8);
+    neighbor1 = * (int *) (tetsym.tet + elemmarkerindex);
     tetloop.loc = 3;
     sym(tetloop, tetsym);
-    neighbor2 = * (int *) (tetsym.tet + 8);
+    neighbor2 = * (int *) (tetsym.tet + elemmarkerindex);
     tetloop.loc = 1;
     sym(tetloop, tetsym);
-    neighbor3 = * (int *) (tetsym.tet + 8);
+    neighbor3 = * (int *) (tetsym.tet + elemmarkerindex);
     tetloop.loc = 0;
     sym(tetloop, tetsym);
-    neighbor4 = * (int *) (tetsym.tet + 8);
+    neighbor4 = * (int *) (tetsym.tet + elemmarkerindex);
     if (out == (tetgenio *) NULL) {
       // Tetrahedra number, neighboring tetrahedron numbers.
       fprintf(outfile, "%4d    %4d  %4d  %4d  %4d\n", elementnumber,
@@ -24076,8 +29456,7 @@ void tetgenmesh::outneighbors(tetgenio* out)
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// outpbcnodes()    Output a list of node pairs to a .pbc file or a tetgenio //
-//                  structure.                                               //
+// outpbcnodes()    Output pbc node pairs to a .pbc file or a structure.     //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -24091,8 +29470,10 @@ void tetgenmesh::outpbcnodes(tetgenio* out)
   face faceloop;
   face checkseg, symseg;
   point *ptpair, pa, pb;
-  REAL sympt[3];
+  enum locateresult loc;
+  REAL sympt[3], d1, d2;
   int *worklist;
+  int firstindex, shift;
   int index, idx;
   int i, j, k, l;
 
@@ -24109,11 +29490,16 @@ void tetgenmesh::outpbcnodes(tetgenio* out)
     }
   }
 
+  // Avoid compilation warnings.
+  outfile = (FILE *) NULL;
+  pgo = (tetgenio::pbcgroup *) NULL;
+  index = 0;
+
   if (out == (tetgenio *) NULL) {
     outfile = fopen(pbcfilename, "w");
     if (outfile == (FILE *) NULL) {
       printf("File I/O Error:  Cannot create file %s.\n", pbcfilename);
-      exit(1);
+      terminatetetgen(1);
     }
     // Number of pbc groups.
     fprintf(outfile, "# number of PBCs.\n");
@@ -24122,9 +29508,10 @@ void tetgenmesh::outpbcnodes(tetgenio* out)
     out->numberofpbcgroups = in->numberofpbcgroups;
     // Allocate memory for 'out->pbcgrouplist'.
     out->pbcgrouplist = new tetgenio::pbcgroup[in->numberofpbcgroups];
-    if (out->neighborlist == (int *) NULL) {
+    // (Next line was a bug, reported by Murry Nigel). 
+    if (out->pbcgrouplist == (tetgenio::pbcgroup *) NULL) {
       printf("Error:  Out of memory.\n");
-      exit(1);
+      terminatetetgen(1);
     }
   }
 
@@ -24132,6 +29519,13 @@ void tetgenmesh::outpbcnodes(tetgenio* out)
   worklist = new int[points->items + 1];
   for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
 
+  // 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 the output indices by 1.
+  }
+
   for (i = 0; i < in->numberofpbcgroups; i++) {
     // Group i.
     pgi = &(in->pbcgrouplist[i]);
@@ -24185,9 +29579,19 @@ void tetgenmesh::outpbcnodes(tetgenio* out)
                         ((pd->fmark[0] == pgi->fmark2) &&
                          (pd->fmark[1] == pgi->fmark1))) break;
                   }
+#ifdef SELF_CHECK
                   assert(l < idx2segpglist[idx + 1]);
-                  getsegpbcsympoint(pa, &checkseg, sympt, &symseg,
-                                    segpglist[l]);
+#endif
+                  loc = getsegpbcsympoint(pa, &checkseg, sympt, &symseg,
+                                          segpglist[l]);
+                  if (loc != ONVERTEX) {
+                    // Not found a match point! It may be caused by the
+                    //   pair of input vertices don't have enough digits.
+                    //   Choose a near vertex.
+                    d1 = distance(sympt, sorg(symseg));
+                    d2 = distance(sympt, sdest(symseg));
+                    if (d1 > d2) sesymself(symseg);
+                  }
                   pb = sorg(symseg);
                 } else {
                   // Operate on pa if it is inside the facet.
@@ -24226,10 +29630,11 @@ void tetgenmesh::outpbcnodes(tetgenio* out)
       pa = ptpair[0];
       pb = ptpair[1];
       if (out == (tetgenio *) NULL) {
-        fprintf(outfile, "  %4d %4d\n", pointmark(pa), pointmark(pb));
+        fprintf(outfile, "  %4d %4d\n", pointmark(pa) - shift,
+                pointmark(pb) - shift);
       } else {
-        pgo->pointpairlist[index++] = pointmark(pa);
-        pgo->pointpairlist[index++] = pointmark(pb);
+        pgo->pointpairlist[index++] = pointmark(pa) - shift;
+        pgo->pointpairlist[index++] = pointmark(pb) - shift;
       }
       // Unmark pa.
       worklist[pointmark(pa)] = 0;
@@ -24263,13 +29668,14 @@ void tetgenmesh::outpbcnodes(tetgenio* out)
 void tetgenmesh::outsmesh(char* smfilename)
 {
   FILE *outfile;
+  char nodfilename[FILENAMESIZE];
   char smefilename[FILENAMESIZE];
   face faceloop;
-  point pointloop;
   point p1, p2, p3;
-  int pointnumber;
-  int nextras, bmark;
+  int firstindex, shift;
+  int bmark;
   int faceid, marker;
+  int i;
 
   if (smfilename != (char *) NULL && smfilename[0] != '\0') {
     strcpy(smefilename, smfilename);
@@ -24278,7 +29684,9 @@ void tetgenmesh::outsmesh(char* smfilename)
   } else {
     strcpy(smefilename, "unnamed");
   }
+  strcpy(nodfilename, smefilename);
   strcat(smefilename, ".smesh");
+  strcat(nodfilename, ".node");
 
   if (!b->quiet) {
     printf("Writing %s.\n", smefilename);
@@ -24289,33 +29697,18 @@ void tetgenmesh::outsmesh(char* smfilename)
     return;
   }
 
+  // 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 the output indices by 1.
+  }
+
   fprintf(outfile, "# %s.  TetGen's input file.\n", smefilename);
-  
-  nextras = in->numberofpointattributes;
-  bmark = !b->nobound && in->pointmarkerlist;
-  
   fprintf(outfile, "\n# part 1: node list.\n");
-  // Number of points, number of dimensions, number of point attributes,
-  //   and number of boundary markers (zero or one).
-  fprintf(outfile, "%ld  %d  %d  %d\n", points->items, 3, nextras, bmark);
-
-  points->traversalinit();
-  pointloop = pointtraverse();
-  pointnumber = in->firstnumber;
-  while (pointloop != (point) NULL) {
-    // Point coordinates.
-    fprintf(outfile, "%4d  %.17g  %.17g  %.17g",  pointnumber,
-            pointloop[0], pointloop[1], pointloop[2]);
-    if (in->numberofpointattributes > 0) {
-      // Write an attribute, ignore others if more than one.
-      fprintf(outfile, "  %.17g", pointloop[3]);
-    }
-    fprintf(outfile, "\n");
-    setpointmark(pointloop, pointnumber);
-    pointloop = pointtraverse();
-    pointnumber++;
-  }
+  fprintf(outfile, "0  3  0  0  # nodes are found in %s.\n", nodfilename);
 
+  marker = 0; // avoid compile warning.
   bmark = !b->nobound && in->facetmarkerlist;  
 
   fprintf(outfile, "\n# part 2: facet list.\n");
@@ -24330,10 +29723,14 @@ void tetgenmesh::outsmesh(char* smfilename)
     p3 = sapex(faceloop);
     if (bmark) {
       faceid = shellmark(faceloop) - 1;
-      marker = in->facetmarkerlist[faceid];
+      if (faceid >= 0) { 
+        marker = in->facetmarkerlist[faceid];
+      } else {
+        marker = 0; // This subface must be added manually later.
+      }
     }
-    fprintf(outfile, "3    %4d  %4d  %4d", pointmark(p1), pointmark(p2),
-            pointmark(p3));
+    fprintf(outfile, "3    %4d  %4d  %4d", pointmark(p1) - shift,
+            pointmark(p2) - shift, pointmark(p3) - shift);
     if (bmark) {
       fprintf(outfile, "    %d", marker);
     }
@@ -24341,11 +29738,24 @@ void tetgenmesh::outsmesh(char* smfilename)
     faceloop.sh = shellfacetraverse(subfaces);
   }
 
+  // Copy input holelist.
   fprintf(outfile, "\n# part 3: hole list.\n");
-  fprintf(outfile, "0\n");
+  fprintf(outfile, "%d\n", in->numberofholes);
+  for (i = 0; i < in->numberofholes; i++) {
+    fprintf(outfile, "%d  %g  %g  %g\n", i + in->firstnumber,
+            in->holelist[i * 3], in->holelist[i * 3 + 1],
+            in->holelist[i * 3 + 2]);
+  }
 
+  // Copy input regionlist.
   fprintf(outfile, "\n# part 4: region list.\n");
-  fprintf(outfile, "0\n");
+  fprintf(outfile, "%d\n", in->numberofregions);
+  for (i = 0; i < in->numberofregions; i++) {
+    fprintf(outfile, "%d  %g  %g  %g  %d  %g\n", i + in->firstnumber,
+            in->regionlist[i * 5], in->regionlist[i * 5 + 1],
+            in->regionlist[i * 5 + 2], (int) in->regionlist[i * 5 + 3],
+            in->regionlist[i * 5 + 4]);
+  }
 
   fprintf(outfile, "# Generated by %s\n", b->commandline);
   fclose(outfile);
@@ -24757,7 +30167,7 @@ void tetgenmesh::internalerror()
   printf("  Please report this bug to sihang@mail.berlios.de. Include the\n");
   printf("    message above, your input data set, and the exact command\n");
   printf("    line you used to run this program, thank you.\n");
-  exit(1);
+  terminatetetgen(2);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -24771,13 +30181,13 @@ void tetgenmesh::checkmesh()
   triface tetraloop;
   triface oppotet, oppooppotet;
   point tetorg, tetdest, tetapex, tetoppo;
-  point oppodest, oppoapex;
   REAL oritest;
   int horrors;
 
   if (!b->quiet) {
     printf("  Checking consistency of mesh...\n");
   }
+
   horrors = 0;
   // Run through the list of tetrahedra, checking each one.
   tetrahedrons->traversalinit();
@@ -24815,22 +30225,6 @@ void tetgenmesh::checkmesh()
           printtet(&oppotet);
           horrors++;
         }
-        // Check that both tetrahedra agree on the identities
-        //   of their shared vertices.
-        if (findorg(&oppotet, tetorg)) {
-          oppodest = dest(oppotet);
-          oppoapex = apex(oppotet);
-        } else {
-          oppodest = (point) NULL;
-        }
-        if ((tetdest != oppoapex) || (tetapex != oppodest)) {
-          printf("  !! !! Mismatched face coordinates between two tetras:\n");
-          printf("    First mismatched ");
-          printtet(&tetraloop);
-          printf("    Second mismatched ");
-          printtet(&oppotet);
-          horrors++;
-        }
       }
     }
     tetraloop.tet = tetrahedrontraverse();
@@ -25080,6 +30474,7 @@ void tetgenmesh::checkdelaunay(REAL eps, queue* flipqueue)
   face opposhelle;
   point tetorg, tetdest, tetapex, tetoppo;
   point oppooppo;
+  enum fliptype fc;
   REAL sign;
   int shouldbedelaunay;
   int horrors;
@@ -25124,8 +30519,20 @@ void tetgenmesh::checkdelaunay(REAL eps, queue* flipqueue)
           if (flipqueue) {
             enqueueflipface(tetraloop, flipqueue);
           } else {
-            printf("  !! Non-locally Delaunay face (%d, %d, %d).\n",
+            printf("  !! Non-locally Delaunay face (%d, %d, %d) ",
                    pointmark(tetorg), pointmark(tetdest), pointmark(tetapex));
+            fc = categorizeface(tetraloop);
+            switch (fc) {
+            case T23: printf("\"T23\""); break;
+            case T32: printf("\"T32\""); break;
+            case T22: printf("\"T22\""); break;
+            case T44: printf("\"T44\""); break;
+            case UNFLIPABLE: printf("\"UNFLIPABLE\""); break;
+            case FORBIDDENFACE:printf("\"FORBIDDENFACE\""); break;
+            case FORBIDDENEDGE:printf("\"FORBIDDENEDGE\""); break;
+            case NONCONVEX:printf("\"NONCONVEX\""); break;
+            }
+            printf("\n");
           }
           horrors++;
         }
@@ -25228,8 +30635,8 @@ void tetgenmesh::checkconforming()
   segloop.sh = shellfacetraverse(subsegs);
   while (segloop.sh != (shellface *) NULL) {
     if (checkseg4encroach(&segloop, NULL, NULL, false)) {
-      printf("  !! !! Non-conforming subsegment: ");
-      printsh(&segloop);
+      printf("  !! !! Non-conforming subsegment: (%d, %d)\n",
+             pointmark(sorg(segloop)), pointmark(sdest(segloop)));
       encsubsegs++;
     }
     segloop.sh = shellfacetraverse(subsegs);
@@ -25239,8 +30646,9 @@ void tetgenmesh::checkconforming()
   shloop.sh = shellfacetraverse(subfaces);
   while (shloop.sh != (shellface *) NULL) {
     if (checksub4encroach(&shloop, NULL, false)) {
-      printf("  !! !! Non-conforming subface: ");
-      printsh(&shloop);
+      printf("  !! !! Non-conforming subface: (%d, %d, %d)\n",
+             pointmark(sorg(shloop)), pointmark(sdest(shloop)),
+             pointmark(sapex(shloop)));
       encsubfaces++;
     }
     shloop.sh = shellfacetraverse(subfaces);
@@ -25259,6 +30667,56 @@ void tetgenmesh::checkconforming()
   }
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// algorithmicstatistics()    Print statistics about the mesh algorithms.    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::algorithmicstatistics()
+{
+  printf("Algorithmic statistics:\n\n");
+  if (b->plc || b->refine) {
+    printf("  Number of facet above points calculations: %ld\n", abovecount);
+  }
+  if (b->plc) {
+    printf("  Segment split rules: R1 %ld, R2 %ld, R3 %ld\n", r1count, r2count,
+           r3count);
+  }
+  if (b->quality) {
+    printf("  Bowyer-Watson counts (seg, sub, vol)\n");
+    printf("    Insert vertices: %ld, %ld, %ld\n",
+           bowatsegcount, bowatsubcount, bowatvolcount);
+    printf("    Update cavities: %ld, %ld, %ld\n",
+           updsegcount, updsubcount, updvolcount);
+    printf("    Failed cavities: %ld, %ld, %ld\n",
+           failsegcount, failsubcount, failvolcount);
+    printf("  Number of repair flips: %ld.\n", repairflipcount);
+    printf("  Number of circumcenters outside Bowat-cav.: %ld.\n",
+           outbowatcircumcount);
+    if (b->conformdel) {
+      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("\n");
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // qualitystatistics()    Print statistics about the quality of the mesh.    //
@@ -25271,31 +30729,33 @@ void tetgenmesh::qualitystatistics()
   point p[4];
   char sbuf[128];
   REAL radiusratiotable[12];
-  REAL aspectratiotable[16];
-  REAL dx[6], dy[6], dz[6];
-  REAL edgelength[6];
-  REAL alldihed[6];
-  REAL cent[3];
+  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 shortest, longest;
   REAL smallestvolume, biggestvolume;
   REAL smallestdiangle, biggestdiangle;
-  REAL tetvol;
-  REAL tetlongest2;
-  REAL minaltitude;
-  REAL cirradius, insradius;
+  REAL tetvol, minaltitude;
+  REAL cirradius, minheightinv; // insradius;
   REAL shortlen, longlen;
   REAL tetaspect, tetradius;
   REAL smalldiangle, bigdiangle;
   int radiustable[12];
   int aspecttable[16];
   int dihedangletable[18];
+  int indx[4];
   int radiusindex;
   int aspectindex;
   int tendegree;
-  int i, j, k;
+  int i, j;
 
   printf("Mesh quality statistics:\n\n");
 
+  // Avoid compile warnings.
+  shortlen = longlen = 0.0;
+  smalldiangle = bigdiangle = 0.0;
+
   radiusratiotable[0]  =    0.707;    radiusratiotable[1]  =     1.0;
   radiusratiotable[2]  =      1.1;    radiusratiotable[3]  =     1.2;
   radiusratiotable[4]  =      1.4;    radiusratiotable[5]  =     1.6;
@@ -25308,19 +30768,11 @@ void tetgenmesh::qualitystatistics()
   aspectratiotable[4]  =      4.0;    aspectratiotable[5]  =     6.0;
   aspectratiotable[6]  =     10.0;    aspectratiotable[7]  =    15.0;
   aspectratiotable[8]  =     25.0;    aspectratiotable[9]  =    50.0;
-  aspectratiotable[10] =    100.0;    aspectratiotable[11] =   300.0;
-  aspectratiotable[12] =   1000.0;    aspectratiotable[13] = 10000.0;
-  aspectratiotable[14] = 100000.0;    aspectratiotable[15] =     0.0;
+  aspectratiotable[10] =    100.0;    aspectratiotable[11] =     0.0;
   
-  for (i = 0; i < 12; i++) {
-    radiustable[i] = 0;
-  }
-  for (i = 0; i < 16; i++) {
-    aspecttable[i] = 0;
-  }
-  for (i = 0; i < 18; i++) {
-    dihedangletable[i] = 0;
-  }
+  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;
 
   minaltitude = xmax - xmin + ymax - ymin + zmax - zmin;
   minaltitude = minaltitude * minaltitude;
@@ -25335,70 +30787,99 @@ void tetgenmesh::qualitystatistics()
   tetrahedrons->traversalinit();
   tetloop.tet = tetrahedrontraverse();
   while (tetloop.tet != (tetrahedron *) NULL) {
-    p[0] = org(tetloop);
-    p[1] = dest(tetloop);
-    p[2] = apex(tetloop);
-    p[3] = oppo(tetloop);
-    tetlongest2 = 0.0;
+    
+    // Get four vertices: p0, p1, p2, p3.
+    for (i = 0; i < 4; i++) p[i] = (point) tetloop.tet[4 + i];
+    // Set the edge vectors: V[0], ..., V[5]
+    for (i = 0; i < 3; i++) V[0][i] = p[0][i] - p[3][i]; // V[0]: p3->p0.
+    for (i = 0; i < 3; i++) V[1][i] = p[1][i] - p[3][i]; // V[1]: p3->p1.
+    for (i = 0; i < 3; i++) V[2][i] = p[2][i] - p[3][i]; // V[2]: p3->p2.
+    for (i = 0; i < 3; i++) V[3][i] = p[1][i] - p[0][i]; // V[3]: p0->p1.
+    for (i = 0; i < 3; i++) V[4][i] = p[2][i] - p[1][i]; // V[4]: p1->p2.
+    for (i = 0; i < 3; i++) V[5][i] = p[0][i] - p[2][i]; // V[5]: p2->p0.
+    // Set the matrix A = [V[0], V[1], V[2]]^T.
+    for (j = 0; j < 3; j++) {
+      for (i = 0; i < 3; i++) A[j][i] = V[j][i];
+    }
+    // Decompose A just once.
+    lu_decmp(A, 3, indx, &D, 0);   
+    // Get the tet volume.
+    tetvol = fabs(A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
+    // Get the three faces normals.
+    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 face 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];
+    // Get the radius of the circumsphere.
+    for (i = 0; i < 3; i++) rhs[i] = 0.5 * dot(V[i], V[i]);
+    lu_solve(A, 3, indx, rhs, 0);
+    cirradius = sqrt(dot(rhs, rhs));
+    // Normalize the face normals.
+    for (i = 0; i < 4; i++) {
+      // H[i] is the inverse of height of its corresponding face.
+      H[i] = sqrt(dot(N[i], N[i]));
+      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];
+    }
+    // Get the squares of the edge lengthes.
+    for (i = 0; i < 6; i++) edgelength[i] = dot(V[i], V[i]);
+    // Get the dihedrals (in degree) at each edges.
+    j = 0;
+    for (i = 1; i < 4; i++) {
+      alldihed[j] = -dot(N[0], N[i]); // Edge cd, bd, bc.
+      if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
+      else if (alldihed[j] > 1.0) alldihed[j] = 1;
+      alldihed[j] = acos(alldihed[j]) / PI * 180.0;
+      j++;
+    }
+    for (i = 2; i < 4; i++) {
+      alldihed[j] = -dot(N[1], N[i]); // Edge ad, ac.
+      if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
+      else if (alldihed[j] > 1.0) alldihed[j] = 1;
+      alldihed[j] = acos(alldihed[j]) / PI * 180.0;
+      j++;
+    }
+    alldihed[j] = -dot(N[2], N[3]); // Edge ab.
+    if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
+    else if (alldihed[j] > 1.0) alldihed[j] = 1;
+    alldihed[j] = acos(alldihed[j]) / PI * 180.0;
     
     // Calculate the longest and shortest edge length.
-    for (i = 0; i < 3; i++) {
-      j = plus1mod3[i];
-      k = minus1mod3[i];
-      dx[i] = p[j][0] - p[k][0];
-      dy[i] = p[j][1] - p[k][1];
-      dz[i] = p[j][2] - p[k][2];
-      edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i] + dz[i] * dz[i];
+    for (i = 0; i < 6; i++) {
       if (i == 0) {
         shortlen = longlen = edgelength[i];
       } else {
         shortlen = edgelength[i] < shortlen ? edgelength[i] : shortlen;
         longlen  = edgelength[i] > longlen  ? edgelength[i] : longlen;
       }
-      if (edgelength[i] > tetlongest2) {
-        tetlongest2 = edgelength[i];
-      }
-      if (edgelength[i] > longest) {
-        longest = edgelength[i];
-      }
-      if (edgelength[i] < shortest) {
-        shortest = edgelength[i];
-      }
-    }
-    for (i = 3; i < 6; i++) {
-      j = i - 3;
-      k = 3;
-      dx[i] = p[j][0] - p[k][0];
-      dy[i] = p[j][1] - p[k][1];
-      dz[i] = p[j][2] - p[k][2];
-      edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i] + dz[i] * dz[i];
-      shortlen = edgelength[i] < shortlen ? edgelength[i] : shortlen;
-      longlen  = edgelength[i] > longlen  ? edgelength[i] : longlen;
-      if (edgelength[i] > tetlongest2) {
-        tetlongest2 = edgelength[i];
-      }
       if (edgelength[i] > longest) {
         longest = edgelength[i];
-      }
+      } 
       if (edgelength[i] < shortest) {
         shortest = edgelength[i];
       }
     }
     
     // Calculate the largest and smallest volume.
-    tetvol = orient3d(p[0], p[1], p[2], p[3]) / 6.0;
-    if (tetvol < 0) tetvol = -tetvol;
     if (tetvol < smallestvolume) {
       smallestvolume = tetvol;
-    }
+    } 
     if (tetvol > biggestvolume) {
       biggestvolume = tetvol;
     }
     
     // Calculate the largest and smallest dihedral angles.
-    tetalldihedral(p[0], p[1], p[2], p[3], alldihed);
     for (i = 0; i < 6; i++) {
-      alldihed[i] = alldihed[i] * 180.0 / PI;
       if (i == 0) {
         smalldiangle = bigdiangle = alldihed[i];
       } else {
@@ -25407,31 +30888,49 @@ void tetgenmesh::qualitystatistics()
       }
       if (alldihed[i] < smallestdiangle) {
         smallestdiangle = alldihed[i];
-      } else if (alldihed[i] > biggestdiangle) {
+      } 
+      if (alldihed[i] > biggestdiangle) {
         biggestdiangle = alldihed[i];
       }
     }
-    tendegree = (int) (smalldiangle / 10.);
+    // Accumulate the corresponding number in the dihedral angle histogram.
+    if (smalldiangle < 5.0) {
+      tendegree = 0;
+    } else if (smalldiangle >= 5.0 && smalldiangle < 10.0) {
+      tendegree = 1;
+    } else if (smalldiangle >= 80.0 && smalldiangle < 110.0) {
+      tendegree = 9; // Angles between 80 to 110 degree are in one entry.
+    } else {
+      tendegree = (int) (smalldiangle / 10.);
+      if (smalldiangle < 80.0) {
+        tendegree++;  // In the left column.
+      } else {
+        tendegree--;  // In the right column.
+      }
+    }
     dihedangletable[tendegree]++;
-    tendegree = (int) (bigdiangle / 10.);
+    if (bigdiangle >= 80.0 && bigdiangle < 110.0) {
+      tendegree = 9; // Angles between 80 to 110 degree are in one entry.
+    } else if (bigdiangle >= 170.0 && bigdiangle < 175.0) {
+      tendegree = 16;
+    } else if (bigdiangle >= 175.0) {
+      tendegree = 17;
+    } else {
+      tendegree = (int) (bigdiangle / 10.);
+      if (bigdiangle < 80.0) {
+        tendegree++;  // In the left column.
+      } else {
+        tendegree--;  // In the right column.
+      }
+    }
     dihedangletable[tendegree]++;
 
     // Calculate aspect ratio and radius-edge ratio for this element.
-    tetaspect = 0.0;
-    if (!circumsphere(p[0], p[1], p[2], p[3], cent, &cirradius)) {
-      // ! Very bad element.
-      tetaspect = 1.e+8;  
-      tetradius = 100.0;
-    } else { 
-      inscribedsphere(p[0], p[1], p[2], p[3], cent, &insradius);
-    }
-    if (tetaspect == 0.0) {
-      tetradius = cirradius / sqrt(shortlen);
-      tetaspect = sqrt(longlen) / (2.0 * insradius);
-      
-    }
+    tetradius = cirradius / sqrt(shortlen);
+    // tetaspect = sqrt(longlen) / (2.0 * insradius);
+    tetaspect = sqrt(longlen) * minheightinv;
     aspectindex = 0;
-    while ((tetaspect > aspectratiotable[aspectindex]) && (aspectindex < 15)) {
+    while ((tetaspect > aspectratiotable[aspectindex]) && (aspectindex < 11)) {
       aspectindex++;
     }
     aspecttable[aspectindex]++;
@@ -25477,28 +30976,40 @@ void tetgenmesh::qualitystatistics()
   printf("    by its shortest edge length)\n\n");
 
   printf("  Aspect ratio histogram:\n");
-  printf("  1.1547 - %-6.6g    :  %8d      | %6.6g - %-6.6g     :  %8d\n",
-         aspectratiotable[0], aspecttable[0], aspectratiotable[7],
-         aspectratiotable[8], aspecttable[8]);
-  for (i = 1; i < 7; i++) {
+  printf("         < %-6.6g    :  %8d      | %6.6g - %-6.6g     :  %8d\n",
+         aspectratiotable[0], aspecttable[0], aspectratiotable[5],
+         aspectratiotable[6], aspecttable[6]);
+  for (i = 1; i < 5; i++) {
     printf("  %6.6g - %-6.6g    :  %8d      | %6.6g - %-6.6g     :  %8d\n",
            aspectratiotable[i - 1], aspectratiotable[i], aspecttable[i],
-           aspectratiotable[i + 7], aspectratiotable[i + 8],
-           aspecttable[i + 8]);
+           aspectratiotable[i + 5], aspectratiotable[i + 6],
+           aspecttable[i + 6]);
   }
   printf("  %6.6g - %-6.6g    :  %8d      | %6.6g -            :  %8d\n",
-         aspectratiotable[6], aspectratiotable[7], aspecttable[7],
-         aspectratiotable[14], aspecttable[15]);
+         aspectratiotable[4], aspectratiotable[5], aspecttable[5],
+         aspectratiotable[10], aspecttable[11]);
   printf("  (A tetrahedron's aspect ratio is its longest edge length");
-  printf(" divided by the\n");
-  printf("    diameter of its inscribed sphere)\n\n");
-
-  printf("  Dihedral Angle histogram:\n");
-  for (i = 0; i < 9; i++) {
+  printf(" divided by its\n");
+  printf("    smallest side height)\n\n");
+
+  printf("  Dihedral angle histogram:\n");
+  // Print the three two rows:
+  printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
+         0, 5, dihedangletable[0], 80, 110, dihedangletable[9]);
+  printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
+         5, 10, dihedangletable[1], 110, 120, dihedangletable[10]);
+  // Print the third to seventh rows.
+  for (i = 2; i < 7; i++) {
     printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
-           i * 10, i * 10 + 10, dihedangletable[i],
-           i * 10 + 90, i * 10 + 100, dihedangletable[i + 9]);
+           (i - 1) * 10, (i - 1) * 10 + 10, dihedangletable[i],
+           (i - 1) * 10 + 110, (i - 1) * 10 + 120, dihedangletable[i + 9]);
   }
+  // Print the last two rows.
+  printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
+         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]);
+
   printf("\n");
 }
 
@@ -25511,7 +31022,7 @@ void tetgenmesh::qualitystatistics()
 void tetgenmesh::statistics()
 {
   printf("\nStatistics:\n\n");
-  printf("  Input points: %d\n", in->numberofpoints);
+  printf("  Input points: %d\n", in->numberofpoints + jettisoninverts);
   if (b->refine) {
     printf("  Input tetrahedra: %d\n", in->numberoftetrahedra);
   }
@@ -25532,10 +31043,11 @@ void tetgenmesh::statistics()
   } else {
     printf("  Convex hull faces: %ld\n\n", hullsize);
   }
-  if (b->verbose) {
-    // if (b->quality) {
+  if (b->verbose > 0) {
+#ifdef SELF_CHECK
+    // algorithmicstatistics();
+#endif
     qualitystatistics();
-    // }
     printf("\n");
   }
 }
@@ -25556,6 +31068,7 @@ void tetgenmesh::statistics()
 
 tetgenmesh::~tetgenmesh()
 {
+  bgm = (tetgenmesh *) NULL;
   in = (tetgenio *) NULL;
   b = (tetgenbehavior *) NULL;
 
@@ -25577,8 +31090,8 @@ tetgenmesh::~tetgenmesh()
   if (dummyshbase != (shellface *) NULL) {
     delete [] dummyshbase;
   }
-  if (liftpointarray != (REAL *) NULL) {
-    delete [] liftpointarray;
+  if (facetabovepointarray != (point *) NULL) {
+    delete [] facetabovepointarray;
   }
   if (highordertable != (point *) NULL) {
     delete [] highordertable;
@@ -25601,6 +31114,7 @@ tetgenmesh::~tetgenmesh()
 
 tetgenmesh::tetgenmesh()
 {
+  bgm = (tetgenmesh *) NULL;
   in = (tetgenio *) NULL;
   b = (tetgenbehavior *) NULL;
 
@@ -25618,7 +31132,8 @@ tetgenmesh::tetgenmesh()
   dummysh = (shellface *) NULL;
   dummyshbase = (shellface *) NULL;
 
-  liftpointarray = (REAL *) NULL;
+  facetabovepointarray = (point *) NULL;
+  abovepoint = (point) NULL;
   highordertable = (point *) NULL;
   subpbcgrouptable = (pbcdata *) NULL;
   segpbcgrouptable = (list *) NULL;
@@ -25628,8 +31143,8 @@ tetgenmesh::tetgenmesh()
   xmax = xmin = ymax = ymin = zmax = zmin = 0.0; 
   longest = 0.0;
   hullsize = 0l;
-  insegment = 0l;
-  edgeboundindex = 0;
+  insegments = 0l;
+  pointlfsindex = 0;
   pointmarkindex = 0;
   point2simindex = 0;
   point2pbcptindex = 0;
@@ -25644,11 +31159,26 @@ tetgenmesh::tetgenmesh()
   nonconvex = 0;
   dupverts = 0;
   unuverts = 0;
+  relverts = 0;
+  suprelverts = 0;
+  collapverts = 0;
+  unsupverts = 0;
+  jettisoninverts = 0;
+  symbolic = 0;
   samples = 0l;
   randomseed = 0l;
   macheps = 0.0;
   maxcavfaces = maxcavverts = 0;
-  enlcavtimes = 0;
+  expcavcount = 0;
+  abovecount = 0l;
+  bowatvolcount = bowatsubcount = bowatsegcount = 0l;
+  updvolcount = updsubcount = updsegcount = 0l;
+  repairflipcount = 0l;
+  outbowatcircumcount = 0l;
+  failvolcount = failsubcount = failsegcount = 0l;
+  r1count = r2count = r3count = r4count = 0l;
+  cdtenforcesegpts = 0l;
+  rejsegpts = rejsubpts = rejtetpts = 0l;
   flip23s = flip32s = flip22s = flip44s = 0l;
 }
 
@@ -25686,93 +31216,104 @@ tetgenmesh::tetgenmesh()
 
 #include <time.h>           // Defined type clock_t, constant CLOCKS_PER_SEC.
 
-void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out)
+void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
+  tetgenio *bgmesh)
 {
   tetgenmesh m;
-  clock_t tv0, tv1, tv2, tv3, tv4, tv5, tv6, tv7, tv8;
+  clock_t tv0, tv1, tv2, tv3, tv4, tv5, tv6, tv7, tv8, tv9, tv10, tv11;
 
-  if (!b->quiet) {
-    tv0 = clock();
-  }
+  tv0 = clock();
  
   m.b = b;
   m.in = in;
-
   m.macheps = exactinit();
-  m.initializepools();
   m.steinerleft = b->steiner;
-
-  if (!b->quiet) {
-    tv1 = clock();
+  if (b->bgmesh) {
+    // '-m' switch
+    m.bgm = new tetgenmesh();
+    m.bgm->b = b;
+    m.bgm->in = bgmesh;
+    m.bgm->macheps = exactinit();
   }
-
+  m.initializepools();
   m.transfernodes();
+
+  tv1 = clock();
+
   if (b->refine) {
     m.reconstructmesh();
   } else {
-    m.incrflipdelaunay();
+    m.delaunizevertices();
   }
 
+  tv2 = clock();
   if (!b->quiet) {
-    tv2 = clock();
     if (b->refine) {
       printf("Mesh reconstruction seconds:  %g\n",
              (tv2 - tv1) / (REAL) CLOCKS_PER_SEC);
-    } else if (!b->detectinter) {
+    } else {
       printf("Delaunay seconds:  %g\n", (tv2 - tv1) / (REAL) CLOCKS_PER_SEC);
     }
   }
 
   if (b->useshelles && !b->refine) {
-    m.insegment = m.meshsurface();
-    if (b->detectinter) {
-      m.detectinterfaces();
+    m.insegments = m.meshsurface();
+    if (b->diagnose != 1) {
+      m.incrperturbvertices(b->epsilon); // '-p' switch.
+      m.delaunizesegments();
+      m.constrainedfacets();
     } else {
-      if (!b->nobisect) {
-        m.incrperturbvertices(0.0);
-        m.delaunizesegments();
-        m.constrainedfacets();
-      }
+      m.detectinterfaces(); // '-d' switch.
     }
   }
 
+  tv3 = clock();
   if (!b->quiet) {
-    tv3 = clock();
     if (b->useshelles && !b->refine) {
-      if (b->detectinter) {
+      if (b->diagnose != 1) {
+        printf("Segment and facet seconds:  %g\n",
+               (tv3 - tv2) / (REAL) CLOCKS_PER_SEC);
+      } else {
         printf("Intersection seconds:  %g\n", 
                (tv3 - tv2) / (REAL) CLOCKS_PER_SEC);  
-      } else {
-        if (!b->nobisect) {
-          printf("Segment and facet seconds:  %g\n",
-                 (tv3 - tv2) / (REAL) CLOCKS_PER_SEC);
-        }
       }
     } 
   }
 
-  if (b->plc && !b->refine && !b->detectinter) {
+  if (b->plc && !(b->diagnose == 1)) {
     m.carveholes();
   }
 
+  tv4 = clock();
   if (!b->quiet) {
-    tv4 = clock();
-    if (b->plc && !b->refine && !b->detectinter) {
+    if (b->plc && !(b->diagnose == 1)) {
       printf("Hole seconds:  %g\n", (tv4 - tv3) / (REAL) CLOCKS_PER_SEC);
     }
   }
 
-  if ((b->plc || b->refine) && !b->detectinter) {
-    m.repairdegetets(); 
+  if ((b->plc || b->refine) && !(b->diagnose == 1)) {
+    m.repairmesh(); 
   }
 
+  tv5 = clock();
   if (!b->quiet) {
-    tv5 = clock();
-    if ((b->plc || b->refine) && !b->detectinter) {
+    if ((b->plc || b->refine) && !(b->diagnose == 1)) {
       printf("Repair seconds:  %g\n", (tv5 - tv4) / (REAL) CLOCKS_PER_SEC);
     }
   }
 
+  if ((b->plc && b->nobisect) && !(b->diagnose == 1)) {
+    m.removesteiners();
+  }
+
+  tv6 = clock();
+  if (!b->quiet) {
+    if ((b->plc && b->nobisect) && !(b->diagnose == 1)) {
+      printf("Steiner removal seconds:  %g\n",
+             (tv6 - tv5) / (REAL) CLOCKS_PER_SEC);
+    }
+  }
+
   if (b->insertaddpoints) {
     if (in->numberofaddpoints == 0) {
       in->load_addnodes(b->infilename);
@@ -25782,25 +31323,53 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out)
     }
   }
 
+  tv7 = clock();
   if (!b->quiet) {
-    tv6 = clock();
     if ((b->plc || b->refine) && (in->numberofaddpoints > 0)) {
-      printf("Add points seconds:  %g\n", (tv6 - tv5) / (REAL) CLOCKS_PER_SEC);
+      printf("Add points seconds:  %g\n", (tv7 - tv6) / (REAL) CLOCKS_PER_SEC);
+    }
+  }
+
+  if (b->bgmesh) {
+    // '-b' switch
+    m.bgm->initializepools();
+    m.bgm->transfernodes();
+    m.bgm->reconstructmesh();
+    m.interpolatesizemap();
+  }
+
+  tv8 = clock();
+  if (!b->quiet) {
+    if (b->bgmesh) {
+      printf("Background mesh reconstruct seconds:  %g\n",
+             (tv8 - tv7) / (REAL) CLOCKS_PER_SEC);
     }
   }
 
-  if (b->quality && (m.tetrahedrons->items > 0)) {
+  if (b->quality) {
     m.enforcequality();
   }
 
+  tv9 = clock();
+  if (!b->quiet) {
+    if (b->quality) {
+      printf("Quality seconds:  %g\n", (tv9 - tv8) / (REAL) CLOCKS_PER_SEC);
+    }
+  }
+
+  if (b->quality && b->smooth) {
+    m.smoothmesh();
+  }
+
+  tv10 = clock();
   if (!b->quiet) {
-    tv7 = clock();
-    if (b->quality && (m.tetrahedrons->items > 0)) {
-      printf("Quality seconds:  %g\n", (tv7 - tv6) / (REAL) CLOCKS_PER_SEC);
+    if (b->quality && b->smooth) {
+      printf("Smooth seconds:  %g\n", (tv10 - tv9) / (REAL) CLOCKS_PER_SEC);
     }
   }
 
-  if ((m.dupverts > 0) || (m.unuverts > 0)) {
+  if (!b->nojettison && ((m.dupverts > 0) || (m.unuverts > 0)
+      || (b->refine && (in->numberofcorners == 10)))) {
     m.jettisonnodes();
   }
 
@@ -25822,13 +31391,16 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out)
       printf("NOT writing a .node file.\n");
     }
   } else {
-    if (b->detectinter) {
+    if (b->diagnose == 1) {
       if (m.subfaces->items > 0l) {
         // Only output when there are intersecting faces.
         m.outnodes(out);
       }
     } else {
       m.outnodes(out);
+      if (b->metric) {
+        m.outmetrics(out);
+      }
     }
   }
 
@@ -25837,7 +31409,7 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out)
       printf("NOT writing an .ele file.\n");
     }
   } else {
-    if (!b->detectinter) {
+    if (!(b->diagnose == 1)) {
       if (m.tetrahedrons->items > 0l) {
         m.outelements(out);
       }
@@ -25855,13 +31427,13 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out)
         m.outfaces(out);
       }
     } else {
-      if (b->detectinter) {
+      if (b->diagnose == 1) {
         if (m.subfaces->items > 0l) {
           // Only output when there are intersecting faces.
           m.outsubfaces(out);
         }
       } else if (b->plc || b->refine) {
-        if (m.tetrahedrons->items > 0l) {
+        if (m.subfaces->items > 0l) {
           // Output boundary faces.
           m.outsubfaces(out); 
         }
@@ -25879,12 +31451,15 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out)
   }
 
   if (b->edgesout && b->plc) {
-    m.outsubsegments(out); 
+    if (m.subsegs->items > 0l) {
+      m.outsubsegments(out); 
+    }
   }
 
-  if (!out && b->plc && ((b->object == tetgenbehavior::OFF) ||
-                         (b->object == tetgenbehavior::PLY) ||
-                         (b->object == tetgenbehavior::STL))) {
+  if (!out && b->plc && 
+      ((b->object == tetgenbehavior::OFF) ||
+       (b->object == tetgenbehavior::PLY) ||
+       (b->object == tetgenbehavior::STL))) {
     m.outsmesh(b->outfilename);
   }
 
@@ -25904,11 +31479,11 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out)
     m.outneighbors(out);
   }
 
+  tv11 = clock();
   if (!b->quiet) {
-    tv8 = clock();
-    printf("\nOutput seconds:  %g\n", (tv8 - tv7) / (REAL) CLOCKS_PER_SEC);
+    printf("\nOutput seconds:  %g\n", (tv11 - tv10) / (REAL) CLOCKS_PER_SEC);
     printf("Total running seconds:  %g\n",
-           (tv8 - tv0) / (REAL) CLOCKS_PER_SEC);
+           (tv11 - tv0) / (REAL) CLOCKS_PER_SEC);
   }
 
   if (b->docheck) {
@@ -25917,7 +31492,7 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out)
       m.checkshells();
     }
     if (b->docheck > 1) {
-      m.checkdelaunay(b->epsilon, NULL);
+      m.checkdelaunay(0.0, NULL);
       if (b->docheck > 2) {
         if (b->quality || b->refine) {
           m.checkconforming();
@@ -25929,6 +31504,10 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out)
   if (!b->quiet) {
     m.statistics();
   }
+
+  if (bgmesh) {
+    delete m.bgm;
+  }
 }
 
 #ifndef TETLIBRARY
@@ -25949,7 +31528,8 @@ int main(int argc, char *argv[])
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetrahedralize(char *switches, tetgenio *in, tetgenio *out)
+void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
+  tetgenio *bgmesh)
 
 #endif // not TETLIBRARY
 
@@ -25958,30 +31538,40 @@ void tetrahedralize(char *switches, tetgenio *in, tetgenio *out)
 
 #ifndef TETLIBRARY
 
-  tetgenio in;
+  tetgenio in, bgmesh;
   
   if (!b.parse_commandline(argc, argv)) {
-    exit(1);
+    terminatetetgen(1);
   }
   if (b.refine) {
     if (!in.load_tetmesh(b.infilename)) {
-      exit(1);
+      terminatetetgen(1);
     }
   } else {
     if (!in.load_plc(b.infilename, (int) b.object)) {
-      exit(1);
+      terminatetetgen(1);
+    }
+  }
+  if (b.bgmesh) {
+    if (!bgmesh.load_tetmesh(b.bgmeshfilename)) {
+      bgmesh.numberoftetrahedra = 0l;
     }
   }
-  tetrahedralize(&b, &in, NULL);
+
+  if (bgmesh.numberoftetrahedra > 0l) {
+    tetrahedralize(&b, &in, NULL, &bgmesh);
+  } else {
+    tetrahedralize(&b, &in, NULL, NULL);
+  }
 
   return 0;
 
 #else // with TETLIBRARY
 
   if (!b.parse_commandline(switches)) {
-    exit(1);
+    terminatetetgen(1);
   }
-  tetrahedralize(&b, in, out);
+  tetrahedralize(&b, in, out, bgmesh);
 
 #endif // not TETLIBRARY
 }
diff --git a/contrib/Tetgen/tetgen.h b/contrib/Tetgen/tetgen.h
index 896c3f2279614d83acf0ac35c4d489734ed599ad..55b8f3a6041aadef49e4737fca5fe9371d0bb85e 100644
--- a/contrib/Tetgen/tetgen.h
+++ b/contrib/Tetgen/tetgen.h
@@ -4,10 +4,10 @@
 //                                                                           //
 // A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator         //
 //                                                                           //
-// Version 1.3.4                                                             //
-// June 13, 2005                                                             //
+// Version 1.4                                                               //
+// January 14, 2006                                                          //
 //                                                                           //
-// Copyright 2002, 2004, 2005                                                //
+// Copyright 2002, 2004, 2005, 2006                                          //
 // Hang Si                                                                   //
 // Rathausstr. 9, 10178 Berlin, Germany                                      //
 // si@wias-berlin.de                                                         //
@@ -31,22 +31,20 @@
 //   Triangulations". Algorithmica 15: 223-241, 1996.                        //
 //                                                                           //
 //   The constrained Delaunay tetrahedralization algorithm is described in:  //
-//   H. Si and K. Gaertner, "Meshing Piecewise Linear Complexs by Constrain- //
-//   ed Delaunay Tetrahedralizations". To appear in Proceedings of the 14th  //
-//   International Mesh Roundtable. September 2005.                          //
+//   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: J. R. Shewchuk, "Tetrahedral //
-//   Mesh Generation by Delaunay Refinement". Proceedings of the 14th Annual //
-//   Symposium on Computational Geometry, pages 86-95, 1998.                 //
+//   The Delaunay refinement algorithm is from:  Hang Si, "On Refinement of  //
+//   Constrained Delaunay Tetrahedralizations". In Proceeding of the 15th    //
+//   International Meshing Roundtable. September 2006.                       //
 //                                                                           //
 // The mesh data structure of TetGen is a combination of two types of mesh   //
 //   data structures.  The tetrahedron-based mesh data structure introduced  //
-//   by Shewchuk is eligible to implement algorithms of generating Delaunay  //
-//   tetrahedralizations. However, constrained Delaunay tetrahedralization   //
-//   and quality mesh generation algorithms require other mesh elements      //
-//   (subfaces, subsegments) be handled at the same time.  The triangle-edge //
-//   data structure from Muecke is used for this purpose. These data types   //
-//   are handled through a set of fast mesh manipulation primitives.         //
+//   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.                             //
 //                                                                           //
 //   J. R. Shewchuk, "Delaunay Refinement Mesh Generation". PhD thesis,      //
 //   Carnegie Mellon University, 1997.                                       //
@@ -54,18 +52,17 @@
 //   E. P. Muecke, "Shapes and Implementations in Three-Dimensional          //
 //   Geometry". PhD thesis, Univ. of Illinois, Urbana, Illinois, 1993.       //
 //                                                                           //
-// The research of mesh generation is definitly on the move. A lot of state- //
-//   of-the-art algorithms need to be implemented and evaluated.  I heartily //
-//   welcome new algorithms especially for quality conforming Delaunay mesh  //
-//   generation and anisotropic conforming Delaunay mesh generation. If you  //
-//   have any idea on new approaches, please please kindly let me know.      //
+// The research of mesh generation is definitly on the move. Many State-of-  //
+//   the-art algorithms need implementing and evaluating. I heartily welcome //
+//   any new algorithm especially for generating quality conforming Delaunay //
+//   meshes and anisotropic conforming Delaunay meshes.                      //
 //                                                                           //
 // TetGen is supported by the "pdelib" project of Weierstrass Institute for  //
 //   Applied Analysis and Stochastics (WIAS) in Berlin.  It is a collection  //
 //   of software components for solving non-linear partial differential      //
 //   equations including 2D and 3D mesh generators, sparse matrix solvers,   //
 //   and scientific visualization tools, etc.  For more information please   //
-//   see:   http://www.wias-berlin.de/software/pdelib.                       //
+//   visit: http://www.wias-berlin.de/software/pdelib.                       //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -83,35 +80,31 @@
 //                                                                           //
 // TetGen library is comprised by several data types and global functions.   //
 //                                                                           //
-// If you quickly go through this file, you will find there are only three   //
-// main data types defined,  which are "tetgenio", "tetgenbehavior", and     //
-// "tetgenmesh". Tetgenio is used to pass data into and out of mesh routines //
-// of the library;  tetgenbehavior sets the command line options selected by //
-// user and thus controls the behaviors of TetGen;  tetgenmesh, the biggest  //
-// data type I've ever defined,  contains everything for creating Delaunay   //
-// tetrahedralizations and tetrahedral meshes. These data types are defined  //
-// as C++ classes.                                                           //
+// There are three main data types: tetgenio, tetgenbehavior, and tetgenmesh.//
+// Tetgenio is used to pass data into and out of TetGen library; tetgenbeha- //
+// vior keeps the runtime options and thus controls the behaviors of TetGen; //
+// tetgenmesh, the biggest data type I've ever defined, contains mesh data   //
+// structures and mesh traversing and transformation operators.  The meshing //
+// algorithms are implemented on top of it.  These data types are defined as //
+// C++ classes.                                                              //
 //                                                                           //
-// There are few global functions as well.  "tetrahedralize()" is the (only) //
-// user interface for calling TetGen from other programs.  Two functions     //
-// "orient3d()" and "insphere()" for performing exact geometrical tests are  //
-// incorporated from a public C code provided by J. R. Shewchuk.             //
+// There are few global functions. tetrahedralize() is provided for calling  //
+// TetGen from another program. Two functions: orient3d() and insphere() are //
+// incorporated from a public C code provided by Shewchuk.  They performing  //
+// exact geometrical tests.                                                  //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 #ifndef tetgenH
 #define tetgenH
 
-// To compile TetGen as a library (e.g. libtet.a) but not as an executable
-//   program, define the TETLIBRARY symbol.  The library of TetGen can be
-//   linked with programs which want to call TetGen as a function.
+// To compile TetGen as a library instead of an executable program, define
+//   the TETLIBRARY symbol.
 
 // #define TETLIBRARY
 
 // Uncomment the following line to disable assert macros. These macros are
-//   inserted in places where I hope to catch bugs. Somewhat, they slow down
-//   the speed of TetGen.  They can be ignored by adding the -DNDEBUG
-//   compiler switch or uncomment the following line 
+//   inserted in places where I hope to catch bugs.
 
 // #define NDEBUG
 
@@ -135,7 +128,7 @@
   #define REAL double
 #endif 	// not defined SINGLE
 
-// Here is the most general used head files for all C/C++ codes
+// 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(), ...
@@ -152,22 +145,21 @@
 // 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 below, that basically tetgenio is nothing more than a collection //
-// of arrays. These arrays are used to store points, tetrahedra, (triangular)//
-// faces, boundary markers, and so forth.  They are used to describe data in //
-// input & output files of TetGen.  If you understand TetGen's file formats, //
-// then it is straighforward to understand these arrays. The file formats of //
-// TetGen are described in the third section of the user's manual.           //
-//                                                                           //
-// Once you create an object of tetgenio, all arrays are initialized to NULL.//
-// This is done by routine "initialize()", it is automatically called by the //
-// constructor. Before you can set data into these arrays, you have to first //
-// allocate enough memory for them.  And you need to clear the memory after  //
-// the use of them.  "deinitialize()" is automatically called on deletion of //
-// the object. It will deallocate the memory in a array if it is not a NULL. //
-// However, it assumes that the memory is allocated by C++ operator 'new'.   //
-// If you use malloc(), you should free() them and set the pointers to NULLs //
-// before the code reaches deinitialize().                                   //
+// 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].//
 // However, that item is item number `firstnumber' which may be '0' or '1'.  //
@@ -255,10 +247,12 @@ class tetgenio {
     // `pointattributelist':  An array of point attributes.  Each point's
     //   attributes occupy `numberofpointattributes' REALs. 
     // 'addpointlist':  An array of additional point coordinates.
+    // 'addpointattributelist':  An array of attributes for addition points.
     // `pointmarkerlist':  An array of point markers; one int per point.
     REAL *pointlist;
     REAL *pointattributelist;
     REAL *addpointlist;
+    REAL *addpointattributelist;
     int *pointmarkerlist;
     int numberofpoints;
     int numberofpointattributes;
@@ -305,14 +299,14 @@ class tetgenio {
     REAL *regionlist;
     int numberofregions;
 
-    // `facetconstraintlist': An array of facet maximum area constraints.
+    // `facetconstraintlist': An array of facet maximal area constraints.
     //   Two REALs per constraint. The first one is the facet marker (cast
     //   it to int), the second is its maximum area bound.
     // Note the 'facetconstraintlist' is used only for the 'q' switch. 
     REAL *facetconstraintlist;
     int numberoffacetconstraints;
 
-    // `segmentconstraintlist': An array of seg maximum length constraints.
+    // `segmentconstraintlist': An array of segment max. length constraints.
     //   Three REALs per constraint. The first two are the indices (pointing
     //   into 'pointlist') of the endpoints of the segment, the third is its
     //   maximum length bound.
@@ -334,8 +328,14 @@ class tetgenio {
     // `trifacelist':  An array of triangular face endpoints.  The first
     //   face's endpoints are at indices [0], [1] and [2], followed by the
     //   remaining faces.  Three ints per face.
+    // `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'
+    //   switch is used.
     // `trifacemarkerlist':  An array of face markers; one int per face.
     int *trifacelist;
+    int *adjtetlist;
     int *trifacemarkerlist;
     int numberoftrifaces;
 
@@ -359,6 +359,7 @@ class tetgenio {
     bool load_addnodes(char* filename);
     bool load_pbc(char* filename);
     bool load_var(char* filename);
+    bool load_mtr(char* filename);
     bool load_poly(char* filename);
     bool load_off(char* filename);
     bool load_ply(char* filename);
@@ -394,10 +395,10 @@ class tetgenio {
 // for control the behavior of TetGen.  These varibales are all initialized  //
 // to their default values.                                                  //
 //                                                                           //
-// Routine "parse_commandline()" defined in this data type is used to change //
-// the vaules of the variables. This routine accepts the standard parameters //
-// ('argc' and 'argv') that pass to C/C++ main() function. It also accepts a //
-// string which contains the command line options.                           //
+// parse_commandline() provides an simple interface to set the vaules of the //
+// variables.  It accepts the standard parameters (e.g., 'argc' and 'argv')  //
+// that pass to C/C++ main() function. Alternatively a string which contains //
+// the command line options can be used as its parameter.                    //
 //                                                                           //
 // You don't need to understand this data type. It can be implicitly called  //
 // by the global function "tetrahedralize()" defined below.  The necessary   //
@@ -411,7 +412,7 @@ class tetgenbehavior {
   public:
 
     // Labels define the objects which are acceptable by TetGen. They are 
-    //   recognized by TetGen from the file extensions.
+    //   recognized by the file extensions.
     //   - NODES, a list of nodes (.node); 
     //   - POLY, a piecewise linear complex (.poly or .smesh); 
     //   - OFF, a polyhedron (.off, Geomview's file format); 
@@ -431,11 +432,16 @@ class tetgenbehavior {
     int plc;                                              // '-p' switch, 0.
     int refine;                                           // '-r' switch, 0.
     int quality;                                          // '-q' switch, 0.
+    int smooth;                                           // '-s' switch, 0.
+    int metric;                                           // '-m' switch, 0.
+    int bgmesh;                                           // '-b' switch, 0.
     int varvolume;                         // '-a' switch without number, 0.
     int fixedvolume;                          // '-a' switch with number, 0.
     int insertaddpoints;                                  // '-i' switch, 0.
     int regionattrib;                                     // '-A' switch, 0.
-    int detectinter;                                      // '-d' switch, 0.
+    int offcenter;                                        // '-R' switch, 0.
+    int conformdel;                                       // '-D' switch, 0.
+    int diagnose;                                         // '-d' switch, 0.
     int zeroindex;                                        // '-z' switch, 0.
     int order;             // element order, specified after '-o' switch, 1.
     int facesout;                                         // '-f' switch, 0.
@@ -449,29 +455,35 @@ class tetgenbehavior {
     int noelewritten;                                     // '-E' switch, 0.
     int nofacewritten;                                    // '-F' switch, 0.
     int noiterationnum;                                   // '-I' switch, 0.
-    int nomerge;           // not merge two coplanar facets, '-M' switch, 0.
+    int nomerge;           // count of how often '-M' switch is selected, 0.
     int nobisect;          // count of how often '-Y' switch is selected, 0.
     int noflip;                     // do not perform flips. '-Y' switch. 0.
+    int nojettison;     // do not jettison redundants nodes. '-J' switch. 0.
     int steiner;                             // number after '-S' switch. 0.
-    int dofullperturb;               // do full permutation. '-P' switch, 0.
-    int dopermute;                        // do permutation. '-P' switch, 0.
-    int srandseed;          // number of a random seed after '-P' switch, 1.
+    int fliprepair;                                       // '-X' switch, 1.
     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.
     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 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.
 
     // Variables used to save command line switches and in/out file names.
     char commandline[1024];
     char infilename[1024];
     char outfilename[1024];
+    char bgmeshfilename[1024];
 
     tetgenbehavior();
     ~tetgenbehavior() {}
@@ -520,9 +532,7 @@ class tetgenbehavior {
 ///////////////////////////////////////////////////////////////////////////////
 
 REAL exactinit();
-REAL incircle(REAL *pa, REAL *pb, REAL *pc, REAL *pd);
 REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd);
-REAL orient2d(REAL *pa, REAL *pb, REAL *pc);
 REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe);
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -580,14 +590,14 @@ 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, FREEVOLVERTEX,
-                   DEADVERTEX = -32768};
+                   FREESEGVERTEX, FACETVERTEX, FREESUBVERTEX, VOLVERTEX,
+                   FREEVOLVERTEX, DEADVERTEX = -32768};
  
-    // Labels that signify the type of a subface.  A subface is SHARPSUB if
-    //   it is in a facet which forms an acute dihedral angle (less than 90
-    //   degree with other facets). It is SKINNYSUB if it has two segments
-    //   form a small angle (less than 10 degree).
-    enum shestype {NSHARPNSKINNY, SHARPSUB, SKINNYSUB, SHARPSKINNYSUB};
+    // Labels that signify the type of a subface/subsegment.  A subface is
+    //   SKINNY if it has two edges which are subsegments and form a small
+    //   angle (e.g., 10 degree); a subsegment is a SHARP if it is between
+    //   two facets which form an acute dihedral angle.
+    enum shestype {NSHARPNSKINNY, SHARP, SKINNY};
 
     // Labels that signify the type of flips can be applied on a face.
     //   A flipable face has the one of the types T23, T32, T22, and T44.
@@ -634,7 +644,7 @@ class tetgenmesh {
 // tetrahedral mesh of a 3D domain.  However, TetGen uses three data types:  //
 // 'tetrahedron', 'shellface', and 'point'. A 'tetrahedron' is a tetrahedron;//
 // while a 'shellface' can be either a subface or a subsegment; and a 'point'//
-// is a point.  Theese three data types, linked by pointers comprise a mesh. //
+// is a point.  These three data types, linked by pointers comprise a mesh.  //
 //                                                                           //
 // A tetrahedron primarily consists of a list of 4 pointers to its corners,  //
 // a list of 4 pointers to its adjoining tetrahedra, a list of 4 pointers to //
@@ -696,7 +706,7 @@ class tetgenmesh {
 // The subface-subface and subface-subsegment connections                    //
 //                                                                           //
 // Adjoining subfaces sharing a common edge are connected in such a way that //
-// they form a face ring around the edge. It is in deed a single linked list //
+// they form a face ring around the edge. It is indeed a single linked list  //
 // which is cyclic, e.g., one can start from any subface in it and traverse  //
 // back. When the edge is not a subsegment, the ring only has two coplanar   //
 // subfaces which are pointing to each other. Otherwise, the face ring may   //
@@ -723,9 +733,9 @@ class tetgenmesh {
 // direction of your fingers.                                                //
 //                                                                           //
 // The subface and subsegment are also connected through pointers stored in  //
-// their own data fields.  Every subface has a pointer ti its adjoining sub- //
+// their own data fields.  Every subface has a pointer to its adjoining sub- //
 // segment. However, a subsegment only has one pointer to a subface which is //
-// containing it. Such subface can be choosn arbitrarily, other subfaces are //
+// containing it. Such subface can be chosen arbitrarily, other subfaces are //
 // found through the face ring.                                              //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
@@ -736,6 +746,7 @@ class tetgenmesh {
     //   - a list of four subfaces (optional, used for -p switch);
     //   - a list of user-defined floating-point attributes (optional);
     //   - a volume constraint (optional, used for -a switch);
+    //   - an integer of element marker (optional, used for -n switch);
     //   - a pointer to a list of high-ordered nodes (optional, -o2 switch);
 
     typedef REAL **tetrahedron;
@@ -756,9 +767,10 @@ 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);
-    //   - an edge length constraint (optional, used for -q);
+    //   - a REAL of local feature sizes (optional -p switch);
     //   - a pointer to a simplex (tet, tri, edge, or vertex);
-    //   - a pointer to a parent point (optional, used for -q);
+    //   - a pointer to a parent (or duplicate) point;
+    //   - a pointer to a tet in background mesh (optional);
     //   - a pointer to another pbc point (optional);
     //   - an integer for boundary marker;
     //   - an integer for verttype: INPUTVERTEX, FREEVERTEX, ...;
@@ -901,6 +913,61 @@ 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                                  //
@@ -964,7 +1031,7 @@ class tetgenmesh {
 //                                                                           //
 // The index of list always starts from zero, i.e., for a list L contains    //
 //   n elements, the first element is L[0], and the last element is L[n-1].  //
-//   This feature lets lists likes C/C++ arrays.                             //
+//   This feature lets lists like C/C++ arrays.                              //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -996,9 +1063,8 @@ class tetgenmesh {
         int  len() { return items; }
         void *append(void* appitem);
         void *insert(int pos, void* insitem);
-        void del(int pos);
+        void del(int pos, int order);
         int  hasitem(void* checkitem);
-        int  remove(void* remitem);
         void sort();
     }; 
 
@@ -1165,16 +1231,16 @@ class tetgenmesh {
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// Following are variables used in 'tetgenmesh' for miscellaneous purposes.  //
+// Global variables used for miscellaneous purposes.                         //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-    // Pointer to an object of 'tetgenio', which contains input data.
+    // Pointer to the input data (a set of nodes, a PLC, or a mesh).
     tetgenio *in;
-
-    // Pointer to an object of 'tetgenbehavor', which contains the user-
-    //   defined command line swithes and filenames.
+    // Pointer to the options (and filenames).
     tetgenbehavior *b;
+    // Pointer to a background mesh (contains size specification map).
+    tetgenmesh *bgm;
 
     // Variables used to allocate and access memory for tetrahedra, subfaces
     //   subsegments, points, encroached subfaces, encroached subsegments,
@@ -1182,7 +1248,7 @@ class tetgenmesh {
     memorypool *tetrahedrons;
     memorypool *subfaces;
     memorypool *subsegs;
-    memorypool *points;   
+    memorypool *points;
     memorypool *badsubsegs;
     memorypool *badsubfaces;
     memorypool *badtetrahedrons;
@@ -1197,37 +1263,30 @@ class tetgenmesh {
     shellface *dummysh;
     shellface *dummyshbase;    // Keep base address so we can free it later.
 
-    // List of lifting points of facets used for surface triangulation.
-    REAL *liftpointarray;
+    // A point above the plane in which the facet currently being used lies.
+    //   It is used as a reference point for orient3d().
+    point *facetabovepointarray, abovepoint;
 
     // Array (size = numberoftetrahedra * 6) for storing high-order nodes of
     //   tetrahedra (only used when -o2 switch is selected).
     point *highordertable;
 
-    // Two tables for storing pbc datas. 'subpbcgrouptable' is an array(size
-    //   = numberofpbcgroups) for pbcgroup of subfaces.'segpbcgrouptable' is
+    // Arrays for storing and searching pbc data. 'subpbcgrouptable', (size
+    //   is numberofpbcgroups) for pbcgroup of subfaces. 'segpbcgrouptable',
     //   a list for pbcgroup of segments. Because a segment can have several
-    //   pbcgroup incident on it, the size of 'segpbcgrouptable' is unknown
-    //   on input, will be found after createsegpbcgrouptable().  Two lists
-    //   form a map for quick searching the pbcgroups of a given segment.
-    //   'idx2segpglist' (size = number of input segments + 1), 'segpglist'.  
+    //   pbcgroup incident on it, its size is unknown on input, it will be
+    //   found in 'createsegpbcgrouptable()'.
     pbcdata *subpbcgrouptable;
     list *segpbcgrouptable;
+    // A map for searching the pbcgroups of a given segment. 'idx2segpglist'
+    //   (size = number of input segments + 1), and 'segpglist'.  
     int *idx2segpglist, *segpglist;
 
-    // List used in Delaunay refinement for keeping a list of tetrahedra
-    //   which need to be classified in terms of the quality measure.
-    list *qualchecktetlist;
-
-    // Array used in Delaunay refinement for keeping the protecting sphere
-    //   radii of the input vertices.
-    REAL *rpsarray;
-
     // Queues that maintain the bad (badly-shaped or too large) tetrahedra.
     //   The tails are pointers to the pointers that have to be filled in to
     //   enqueue an item.  The queues are ordered from 63 (highest priority)
     //   to 0 (lowest priority).
-    badface *subquefront[2], **subquetail[2];
+    badface *subquefront[3], **subquetail[3];
     badface *tetquefront[64], **tetquetail[64];
 
     // Pointer to a recently visited tetrahedron. Improves point location
@@ -1236,16 +1295,18 @@ class tetgenmesh {
 
     REAL xmax, xmin, ymax, ymin, zmax, zmin;      // Bounding box of points.
     REAL longest;                       // The longest possible edge length.
+    REAL lengthlimit;                  // The limiting length of a new edge.
     long hullsize;                        // Number of faces of convex hull.
-    long insegment;                             // Number of input segments.
+    long insegments;                            // Number of input segments.
     int steinerleft;               // Number of Steiner points not yet used.
-    int edgeboundindex;              // Index to find edge bound of a point.
-    int pointmarkindex;         // Index to find boundary marker of a point.
+    int pointlfsindex;   // Index to find the local feature size of a point.
     int point2simindex;      // Index to find a simplex adjacent to a point.
+    int pointmarkindex;         // Index to find boundary marker of a point.
     int point2pbcptindex;           // Index to find a pbc point to a point.
     int highorderindex; // Index to find extra nodes for highorder elements.
     int elemattribindex;       // Index to find attributes of a tetrahedron.
     int volumeboundindex;    // Index to find volume bound of a tetrahedron.
+    int elemmarkerindex;           // Index to find marker of a tetrahedron.
     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?
@@ -1254,11 +1315,30 @@ class tetgenmesh {
     int nonconvex;                            // Is current mesh non-convex?
     int dupverts;                          // Are there duplicated vertices?
     int unuverts;                              // Are there unused vertices?
+    int relverts;                       // The number of relocated vertices.
+    int suprelverts;         // The number of suppressed relocated vertices.
+    int collapverts;          // The number of collapsed relocated vertices.
+    int unsupverts;                  // The number of unsuppressed 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.
     int maxcavfaces, maxcavverts;         // The size of the largest cavity.
-    int enlcavtimes;                      // The times of enlarging cavitys.
+    int expcavcount;                      // The times of expanding cavitys.
+    long abovecount;                   // Number of abovepoints calculation.
+    long bowatvolcount, bowatsubcount, bowatsegcount;     // Bowyer-Watsons.
+    long updvolcount, updsubcount, updsegcount; // Bow-Wat cavities updates.
+    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 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 flip23s, flip32s, flip22s, flip44s;   // Number of flips performed.
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1321,7 +1401,7 @@ class tetgenmesh {
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-    // Primitives for tetrahedra.
+        // Primitives for tetrahedra.
     inline void decode(tetrahedron ptr, triface& t);
     inline tetrahedron encode(triface& t);
     inline void sym(triface& t1, triface& t2);
@@ -1413,21 +1493,19 @@ class tetgenmesh {
     inline void setpoint2tet(point pt, tetrahedron value);
     inline shellface point2sh(point pt);
     inline void setpoint2sh(point pt, shellface value);
-    inline point point2pt(point pt);
-    inline void setpoint2pt(point pt, point value);
     inline point point2ppt(point pt);
     inline void setpoint2ppt(point pt, point value);
+    inline tetrahedron point2bgmtet(point pt);
+    inline void setpoint2bgmtet(point pt, tetrahedron value);
     inline point point2pbcpt(point pt);
     inline void setpoint2pbcpt(point pt, point value);
-    inline REAL edgebound(point pt);
-    inline void setedgebound(point pt, REAL value);
-    inline point getliftpoint(int facetmark);
 
     // Advanced primitives.
     inline void adjustedgering(triface& t, int direction);
     inline void adjustedgering(face& s, int direction);
     inline bool isdead(triface* t);
     inline bool isdead(face* s);
+    inline bool isfacehaspoint(triface* t, point testpoint);
     inline bool isfacehaspoint(face* t, point testpoint);
     inline bool isfacehasedge(face* s, point tend1, point tend2);
     inline bool issymexist(triface* t);
@@ -1445,7 +1523,7 @@ class tetgenmesh {
     point getsubsegfarorg(face* sseg);
     point getsubsegfardest(face* sseg);
     void printtet(triface*);
-    void printsh(face*);    
+    void printsh(face*);
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
@@ -1473,7 +1551,9 @@ class tetgenmesh {
     enum interresult tri_edge_inter(REAL*, REAL*, REAL*, REAL*, REAL*);
     enum interresult tri_tri_inter(REAL*, REAL*, REAL*, REAL*, REAL*, REAL*);
 
-    // Degenerate cases tests
+    // Geometric predicates
+    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);
@@ -1481,30 +1561,27 @@ class tetgenmesh {
     // Linear algebra functions
     inline REAL dot(REAL* v1, REAL* v2);
     inline void cross(REAL* v1, REAL* v2, REAL* n);
-    void initm44(REAL a00, REAL a01, REAL a02, REAL a03,
-                 REAL a10, REAL a11, REAL a12, REAL a13,
-                 REAL a20, REAL a21, REAL a22, REAL a23,
-                 REAL a30, REAL a31, REAL a32, REAL a33, REAL M[4][4]);
-    void m4xm4(REAL m1[4][4], REAL m2[4][4]);
-    void m4xv4(REAL v2[4], REAL m[4][4], REAL v1[4]);
     bool lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N);
     void lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N);
 
     // Geometric quantities calculators.
     inline REAL distance(REAL* p1, REAL* p2);
     REAL shortdistance(REAL* p, REAL* e1, REAL* e2);
+    REAL shortdistance(REAL* p, REAL* e1, REAL* e2, REAL* e3);
     REAL interiorangle(REAL* o, REAL* p1, REAL* p2, REAL* n);
     void projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj);
     void projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj);
     void facenormal(REAL* pa, REAL* pb, REAL* pc, REAL* n, REAL* nlen);
     void edgeorthonormal(REAL* e1, REAL* e2, REAL* op, REAL* n);
     REAL facedihedral(REAL* pa, REAL* pb, REAL* pc1, REAL* pc2);
-    void tetalldihedral(point, point, point, point, REAL dihed[6]);
+    void tetalldihedral(point, point, point, point, REAL*, REAL*, REAL*);
+    void tetallnormal(point, point, point, point, REAL N[4][3], REAL* volume);
     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);
     void spherelineint(REAL* p1, REAL* p2, REAL* C, REAL R, REAL p[7]);
     void linelineint(REAL *p1,REAL *p2, REAL *p3, REAL *p4, REAL p[7]);
+    void planelineint(REAL*, REAL*, REAL*, REAL*, REAL*, REAL*, REAL*);
 
     // Memory managment routines.
     void dummyinit(int, int);
@@ -1531,10 +1608,13 @@ class tetgenmesh {
     // Point location routines.
     unsigned long randomnation(unsigned int choices);
     REAL distance2(tetrahedron* tetptr, point p);
-    enum locateresult preciselocate(point searchpt, triface* searchtet);
+    enum locateresult preciselocate(point searchpt, triface* searchtet, long);
     enum locateresult locate(point searchpt, triface* searchtet);
-    enum locateresult adjustlocate(point searchpt, triface* searchtet,
-                                   enum locateresult precise, REAL epspp);    
+    enum locateresult adjustlocate(point, triface*, enum locateresult, REAL);
+    enum locateresult locatesub(point searchpt, face* searchsh, int, REAL);
+    enum locateresult adjustlocatesub(point, face*, enum locateresult, REAL);
+    enum locateresult locateseg(point searchpt, face* searchseg);
+    enum locateresult adjustlocateseg(point, face*, enum locateresult, REAL);
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
@@ -1544,35 +1624,6 @@ class tetgenmesh {
 // used to transform (or replace) a set of mesh elements into another set of //
 // mesh elements.                                                            //
 //                                                                           //
-// Flip Types                                                                //
-//                                                                           //
-// If abc is a hull face, it is unflipable, and is locally Delaunay.  In the //
-// following, we assume abc is an interior face, and the other tetrahedron   //
-// adjoining at abc is bace.                                                 //
-//                                                                           //
-// If the convex hull CH of the set {a, b, c, d, e} only has four vertices,  //
-// i.e., one vertex lies inside CH, then abc is unflipable, and is locally   //
-// Delaunay. If CH is the vertex set itself, we have the following cases to  //
-// determine whether abc is flipable or not.                                 //
-//                                                                           //
-// If no four points of {a, b, c, d, e} are coplanar, a 2-to-3 flip can be   //
-// applied to abc if the edge de crosses the triangle abc; a 3-to-2 flip can //
-// be applied to abc if ab crosses cde, and abde exists, otherwise, face abc //
-// is unflipable, i.e., the tetrahedron abde is not present.                 //
-//                                                                           //
-// If four points of {a, b, c, d, e} are coplanar (two faces are coplanar).  //
-// Assume faces abd and abe are coplanar (it is impossible be abc). If a, b, //
-// d, e form a non-convex quadrilateral, then abc is unflipable, furthermore,//
-// it is locally Delaunay.  Assume they are convex quadrilateral, if abd and //
-// abe are hull faces, a 2-to-2 flip can be applied to abc;  if abd and abe  //
-// are interior faces,  assume two tetrahedra adjoining abd and abe at the   //
-// opposite sides are abdg and abef, respectively.  If g = f, a 4-to-4 flip  //
-// can be applied to abc, otherwise, abc is unflipable.                      //
-//                                                                           //
-// There are other cases which can cause abc unflipable. If abc is a subface,//
-// a 2-to-3 flip is forbidden;  if ab is a subsegment, flips 3-to-2, 2-to-2, //
-// and 4-to-4 are forbidden.                                                 //
-//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
     // Mesh transformation routines.
@@ -1583,8 +1634,9 @@ class tetgenmesh {
     void flip32(triface* flipface, queue* flipqueue);
     void flip22(triface* flipface, queue* flipqueue);
     void flip22sub(face* flipedge, queue* flipqueue);
-    long flip(queue* flipqueue, badface **plastflip, bool, bool, bool);
+    long flip(queue* flipqueue, badface **plastflip);
     void undoflip(badface *lastflip);
+    long flipsub(queue* flipqueue);
 
     void splittetrahedron(point newpoint, triface* splittet, queue* flipqueue);
     void unsplittetrahedron(triface* splittet);
@@ -1600,40 +1652,53 @@ class tetgenmesh {
                                      bool approx, queue* flipqueue);
     void undosite(enum insertsiteresult insresult, triface* splittet, 
                   point torg, point tdest, point tapex, point toppo);
-    void inserthullsite(point inspoint, triface* horiz, queue* flipqueue,
-                        link* hulllink, int* worklist);
-    void collectcavtets(point newpoint, list* cavtetlist);
-    void collectcavsubs(point newpoint, list* cavsublist);
 
-    // Incremental flip Delaunay triangulation routines.
-    void incrflipinit(queue* insertqueue);
-    void mergepoints(point testpt, triface* starttet, link*, int*);
-    long incrflipdelaunay();
+    void formbowatcavitysub(point, face*, list*, list*);
+    void formbowatcavityquad(point, list*, list*);
+    void formbowatcavitysegquad(point, list*, list*);
+    void formbowatcavity(point bp, face* bpseg, face* bpsh, int* n, int* nmax,
+                         list** sublists, list** subceillists, list** tetlists,
+                         list** ceillists);
+    void releasebowatcavity(face*, int, list**, list**, list**, list**);
+    bool validatebowatcavityquad(point bp, list* ceillist, REAL maxcosd);
+    void updatebowatcavityquad(list* tetlist, list* ceillist);
+    void updatebowatcavitysub(list* sublist, list* subceillist, int* cutcount);
+    bool trimbowatcavity(point bp, face* bpseg, int n, list** sublists,
+                         list** subceillists, list** tetlists,list** ceillists,
+                         REAL maxcosd);
+    void bowatinsertsite(point bp, face* splitseg, int n, list** sublists,
+                         list** subceillists, list** tetlists,
+                         list** ceillists, list* verlist, queue* flipque,
+                         bool chkencseg, bool chkencsub, bool chkbadtet);
+
+    // 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();
 
     // Surface triangulation routines.
-    enum locateresult locatesub(point searchpt, face* searchsh, int stopatseg);
-    enum locateresult adjustlocatesub(point searchpt, face* searchsh,
-                                      enum locateresult precise, REAL epspp);
-    long flipsub(queue* flipqueue);
-    bool incrflipinitsub(int facetidx, list* ptlist, point* idx2verlist);
-    void collectvisiblesubs(int facetidx, point inspoint, face* horiz,
-                            queue* flipqueue);
-    void incrflipdelaunaysub(int facetidx, list* ptlist, point* idx2verlist,
-                             queue* flipqueue);
+    void formstarpolygon(point pt, list* trilist, list* verlist);
+    void getfacetabovepoint(face* facetsh);
+    void collectcavsubs(point newpoint, list* cavsublist);
+    void collectvisiblesubs(int shmark, point inspoint, face* horiz, queue*);
+    void incrflipdelaunaysub(int shmark, REAL eps, list*, int, REAL*, queue*);
     enum finddirectionresult finddirectionsub(face* searchsh, point tend);
     void insertsubseg(face* tri);
     bool scoutsegmentsub(face* searchsh, point tend);
-    void delaunayfixup(face* fixupsh, int leftside);
-    void constrainededge(face* startsh, point tend);
-    void insertsegmentsub(point tstart, point tend);
+    void flipedgerecursive(face* flipedge, queue* flipqueue);
+    void constrainededge(face* startsh, point tend, queue* flipqueue);
+    void recoversegment(point tstart, point tend, queue* flipqueue);
     void infecthullsub(memorypool* viri);
     void plaguesub(memorypool* viri);
-    void carveholessub(int holes, REAL* holelist);
-    void triangulatefacet(int facetidx, list* ptlist, list* conlist,
-                          point* idx2verlist, queue* flipqueue);
+    void carveholessub(int holes, REAL* holelist, memorypool* viri);
+    void triangulate(int shmark, REAL eps, list* ptlist, list* conlist,
+                     int holes, REAL* holelist, memorypool* viri, queue*);
+    void retrievenewsubs(list* newshlist, bool removeseg);
     void unifysegments();
-    void mergefacets(queue* flipqueue);
-    void assignvarconstraints(point *idx2verlist);
+    void mergefacets(queue* flipqueue);    
     long meshsurface();
 
     // Detect intersecting facets of PLC.
@@ -1645,34 +1710,23 @@ class tetgenmesh {
     // Periodic boundary condition supporting routines.
     void createsubpbcgrouptable();
     void getsubpbcgroup(face* pbcsub, pbcdata** pd, int *f1, int *f2);
-    enum locateresult getsubpbcsympoint(point newpoint, face* splitsub,
-                                        point sympoint, face* symsplitsub);
+    enum locateresult getsubpbcsympoint(point, face*, point, face*);
     void createsegpbcgrouptable();
-    enum locateresult locateseg(point searchpt, face* searchseg);
-    enum locateresult adjustlocateseg(point searchpt, face* searchseg,
-                                      enum locateresult precise, REAL epspp);
-    enum locateresult getsegpbcsympoint(point newpoint, face* splitseg,
-                                        point sympoint, face* symsplitseg,
-                                        int groupid);
+    enum locateresult getsegpbcsympoint(point, face*, point, face*, int);
 
     // Vertex perturbation routines.
     REAL randgenerator(REAL range);
     bool checksub4cocir(face* testsub, REAL eps, bool once, bool enqflag);
-    bool checktet4cosph(triface* testtet, REAL eps, bool once, bool enqflag);
     void tallcocirsubs(REAL eps, bool enqflag);
-    void tallcosphtets(list* testtetlist, REAL eps, bool enqflag);
     bool tallencsegsfsubs(point testpt, list* cavsublist);
-    bool tallencsubsfsubs(point testpt, list* cavtetlist);
     void collectflipedges(point inspoint, face* splitseg, queue* flipqueue);
     void perturbrepairencsegs(queue* flipqueue);
-    void perturbrepairencsubs(REAL eps, list* cavsublist, queue* flipqueue);
-    void perturbrepairbadtets(REAL eps, list* cavsublist, list* cavtetlist,
-                              queue* flipqueue);
+    void perturbrepairencsubs(list* cavsublist, queue* flipqueue);
     void incrperturbvertices(REAL eps);
 
     // Segment recovery routines.
     void markacutevertices(REAL acuteangle);
-    enum finddirectionresult finddirection(triface* searchtet, point tend);
+    enum finddirectionresult finddirection(triface* searchtet, point, long);
     void getsearchtet(point p1, point p2, triface* searchtet, point* tend);
     bool isedgeencroached(point p1, point p2, point testpt, bool degflag);
     point scoutrefpoint(triface* searchtet, point tend);
@@ -1683,31 +1737,31 @@ class tetgenmesh {
     // Facets recovery routines.
     bool insertsubface(face* insertsh, triface* searchtet);
     bool tritritest(triface* checktet, point p1, point p2, point p3);
-    void initializecavity(list* floorlist, list* ceillist, link* frontlink);
-    void delaunizevertices(list* floorptlist, list* ceilptlist,
-                           link* newtetlink, int* worklist);
-    void identifyfronts(link* frontlink, link* newtetlink, link* newfrontlink,
-                        list* missceillist);
-    void classifynewtets(link* frontlink, link* newtetlink,
-                         link* newfrontlink);
-    void carvecavity(link* newtetlink, list* newtetlist);
-    void delaunizecavity(list* floorlist, list* ceillist, list* floorptlist,
-                         list* ceilptlist, list* newtetlist,
-                         list* missceillist, int* worklist);
+    void initializecavity(list* floorlist, list* ceillist, list* frontlist);
+    void delaunizecavvertices(triface*, list*, list*, list*, queue*);
+    void retrievenewtets(list* newtetlist);
+    void insertauxsubface(triface* front, triface* idfront);
+    bool scoutfront(triface* front, triface* idfront, list* newtetlist);
+    void gluefronts(triface* front, triface* front1);
+    bool identifyfronts(list* frontlist, list* misfrontlist, list* newtetlist);
+    void detachauxsubfaces(list* newtetlist);
+    void expandcavity(list* frontlist, list* misfrontlist, list* newtetlist,
+                      list* crosstetlist, queue* missingshqueue, queue*);
+    void carvecavity(list* newtetlist, list* outtetlist, queue* flipque);
+    void delaunizecavity(list* floorlist, list* ceillist, list* ceilptlist,
+                         list* floorptlist, list* frontlist,list* misfrontlist,
+                         list* newtetlist, list* crosstetlist, queue*, queue*);
     void formmissingregion(face* missingsh, list* missingshlist,
                            list* equatptlist, int* worklist);
-    bool scoutcrossingedge(list* missingshlist, list* boundedgelist,
-                           list* crossedgelist, int* worklist);
-    void rearrangesubfaces(list* missingshlist, list* boundedgelist,
-                           list* equatptlist, int* worklist);
     void formcavity(list* missingshlist, list* crossedgelist, 
                     list* equatptlist, list* crossshlist, list* crosstetlist,
                     list* belowfacelist, list* abovefacelist,
                     list* horizptlist, list* belowptlist, list* aboveptlist,
                     queue* missingshqueue, int* worklist);
-    void enlargecavity(list* missceillist, list* ceillist, list* ceilptlist,
-                       list* floorptlist, list* crosstetlist,
-                       queue* missingshqueue, int* worklist);
+    bool scoutcrossingedge(list* missingshlist, list* boundedgelist,
+                           list* crossedgelist, int* worklist);
+    void rearrangesubfaces(list* missingshlist, list* boundedgelist,
+                           list* equatptlist, int* worklist);
     void insertallsubfaces(queue* missingshqueue);
     void constrainedfacets();
 
@@ -1716,54 +1770,92 @@ class tetgenmesh {
     void plague(memorypool *viri);
     void regionplague(memorypool *viri, REAL attribute, REAL volume);
     void removeholetets(memorypool *viri);
+    void assignregionattribs();
     void carveholes();
 
+    // Steiner points removing routines.
+    void replacepolygonsubs(list* oldshlist, list* newshlist);
+    void orientnewsubs(list* newshlist, face* orientsh, REAL* norm);
+    bool constrainedflip(triface* flipface, triface* front, queue* flipque);
+    bool recoverfront(triface* front, list* newtetlist, queue* flipque);
+    void repairflips(queue* flipque);
+    bool constrainedcavity(triface* oldtet, list* floorlist, list* ceillist,
+                           list* ptlist, list* frontlist, list* misfrontlist,
+                           list* newtetlist, queue* flipque);
+    void expandsteinercavity(point steinpt, REAL eps, list* frontlist, list*);
+    bool findrelocatepoint(point sp, point np, REAL* n, list*, list*);
+    void relocatepoint(point steinpt, triface* oldtet, list*, list*, queue*);
+    bool findcollapseedge(point suppt, point* conpt, list* oldtetlist, list*);
+    void collapseedge(point suppt, point conpt, list* oldtetlist, list*);
+    void deallocfaketets(list* frontlist);
+    void restorepolyhedron(list* oldtetlist);
+    bool suppressfacetpoint(face* supsh, list* frontlist, list* misfrontlist,
+                            list* ptlist, list* conlist, memorypool* viri,
+                            queue* flipque);
+    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.
     long reconstructmesh();
+    bool intettest(point testpt, triface* testtet, REAL eps);
     void insertaddpoints();
 
-    // Mesh repair routines.
-    bool checktet4dege(triface* testtet, list* degetetlist);
-    bool finddiagonal(triface* akite);
-    void removetetbypeeloff(triface *badtet, queue* flipqueue);
-    void removetetbyflip32(triface *badtet, queue* flipqueue);
-    bool removekite(triface* akite, queue* flipqueue);
-    void talldegetets(list* degetetlist);
-    void repairdegetets();
+    // Background mesh operations.
+    bool interpolatepointsize(point pt, triface* bgmtet, long *scount);
+    void searchpointrecursive(triface *curtet, long *scount);
+    void interpolatesizemap();
 
     // Delaunay refinement routines.
-    void initializerpsarray();
-    void marksharpsubfaces(REAL dihedbound);
+    void calclocalfeaturesizes();
+    void marksharpsubsegs(REAL dihedbound);
     void markskinnysubfaces(REAL anglebound);
+    void enqueuebadtet(triface* tt, REAL key, REAL* cent);
+    void enqueueencsub(face* ss, point encpt, int quenumber, REAL* cent);
     badface* dequeuebadtet();
+    badface* dequeueencsub(int* quenumber);
     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 checktet4sliver(triface* testtet, bool enqflag);
-    bool checkseg4splitting(face* testseg, point* pencpt);
-    bool checksub4splitting(face* testsub, bool bqual);
-    bool tallencsegs(point testpt, list *cavtetlist);
-    bool tallencsubs(point testpt, list *cavtetlist);
-    void tallencsubsfseg(face* testseg);
-    void tallbadsegs();
-    void tallbadsubs();
+    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);
+    bool tallencsegs(point testpt, int n, list** ceillists);
+    bool tallencsubs(point testpt, int n, list** ceillists);
     void tallbadtetrahedrons();
-    void tallslivers();
-    void doqualchecktetlist();
-    void getsplitpoint1(face* splitseg, REAL* splitpt, point encpt);
-    void repairencsegs(queue* flipqueue);
-    void repairencsubs(list* cavtetlist, queue* flipqueue);
-    void repairbadtets(list* cavtetlist, queue* flipqueue);
-    void repairslivers(list* cavtetlist, queue* flipqueue);
+    void repairencsegs(bool chkencsub, bool chkbadtet);
+    void repairencsubs(bool chkbadtet);
+    void repairbadtets();
     void enforcequality();
 
+    // Mesh Smoothing routines.
+    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();
+
     // I/O routines
     void transfernodes();
     void jettisonnodes();
     void highorder();
     void outnodes(tetgenio* out);
+    void outmetrics(tetgenio* out);
     void outelements(tetgenio* out);
     void outfaces(tetgenio* out);
     void outhullfaces(tetgenio* out);
@@ -1783,6 +1875,7 @@ class tetgenmesh {
     void checkdelaunay(REAL eps, queue* flipqueue);
     void checkdegeneracy(REAL eps);
     void checkconforming();
+    void algorithmicstatistics();
     void qualitystatistics();
     void statistics();
 
@@ -1814,7 +1907,9 @@ class tetgenmesh {
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out);
-void tetrahedralize(char *switches, tetgenio *in, tetgenio *out);
+void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, 
+                    tetgenio *bgmesh = NULL);
+void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
+                    tetgenio *bgmesh = NULL);
 
 #endif // #ifndef tetgenH