From 245c8c979130cd8948328579fccab5e50bca3a1e Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Thu, 6 Dec 2001 13:15:54 +0000
Subject: [PATCH] incorporate the Tetgen tetrahedral mesh generator

---
 Tetgen/Makefile      |    68 +
 Tetgen/constrain.cpp |  3479 +++++++++++++
 Tetgen/defines.h     |   175 +
 Tetgen/linklist.cpp  |  1149 +++++
 Tetgen/linklist.h    |   470 ++
 Tetgen/predicate.cpp |  2945 +++++++++++
 Tetgen/quality.cpp   |  1723 +++++++
 Tetgen/tetlib.cpp    | 10847 +++++++++++++++++++++++++++++++++++++++++
 Tetgen/tetlib.h      |  1301 +++++
 Tetgen/tetmain.cpp   |    11 +
 Tetgen/trilib.cpp    |  5602 +++++++++++++++++++++
 Tetgen/trilib.h      |   515 ++
 12 files changed, 28285 insertions(+)
 create mode 100644 Tetgen/Makefile
 create mode 100644 Tetgen/constrain.cpp
 create mode 100644 Tetgen/defines.h
 create mode 100644 Tetgen/linklist.cpp
 create mode 100644 Tetgen/linklist.h
 create mode 100644 Tetgen/predicate.cpp
 create mode 100644 Tetgen/quality.cpp
 create mode 100644 Tetgen/tetlib.cpp
 create mode 100644 Tetgen/tetlib.h
 create mode 100644 Tetgen/tetmain.cpp
 create mode 100644 Tetgen/trilib.cpp
 create mode 100644 Tetgen/trilib.h

diff --git a/Tetgen/Makefile b/Tetgen/Makefile
new file mode 100644
index 0000000000..adff2be3b3
--- /dev/null
+++ b/Tetgen/Makefile
@@ -0,0 +1,68 @@
+# makefile for Tetgen
+#
+# Type "make" to compile tetgen.
+#
+# After compiling, type "tetgen -h" to read instructions
+#   for using this programs.
+#
+# Type "make clean" to delete all object(*.o) files.
+
+# BIN is the directory where you want to put the executable programs.
+# SRC is the directory in which the *.cpp source files are. 
+
+BIN = ../bin/
+SRC = ./
+
+# CC should be set to the name of your favorite C++ compiler.
+
+CC = g++
+
+# CSWITCHES is a list of all switches passed to the C++ compiler.  
+#   You'd best using the best level of optimization.  
+#
+# By default, Tetgen use double precision floating point numbers.  
+#   If you prefer single precision, use the -DSINGLE switch.
+#   Double precision uses more memory, but improves the resolution of
+#   the meshes you can generate with Tetgen.  It also reduces the
+#   likelihood of a floating exception due to overflow.
+#
+# If yours is not a Unix system, use the -DNO_TIMER switch to eliminate 
+#   the Unix-specific timer code.
+#
+# If you are modifying Tetgen, I recommend using the -DSELF_CHECK switch
+#   while you are debugging.  Defining the SELF_CHECK symbol causes
+#   Tetgen to include self-checking code.  Tetgen will execute more
+#   slowly, however, so be sure to remove this switch before compiling a
+#   production version.
+#
+
+CSWITCHES = -O
+
+# Objects in lexicographic order.
+
+OBJS = constrain.o \
+       linklist.o \
+       predicate.o \
+       quality.o \
+       tetlib.o \
+       trilib.o 
+
+# RM should be set to the name of your favorite rm (file deletion program).
+
+RM = /bin/rm
+
+# The action starts here.
+
+all: tetlib tetgen
+
+.cpp.o:
+	$(CC) $(CSWITCHES) -c $<
+
+tetlib: $(OBJS)
+	ar r ../lib/Tetgen.a $(OBJS)
+
+tetgen: tetmain.o $(OBJS)
+	$(CC) $(CSWITCHES) -o $(BIN)tetgen tetmain.o $(OBJS) -lm
+
+clean:
+	$(RM) $(SRC)*.o
diff --git a/Tetgen/constrain.cpp b/Tetgen/constrain.cpp
new file mode 100644
index 0000000000..fc9c96fed0
--- /dev/null
+++ b/Tetgen/constrain.cpp
@@ -0,0 +1,3479 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// constrain.cpp    Implement the boundary-constranied Delaunay mesh         //
+//                  generation routines.                                     //
+//                                                                           //
+// Tetgen Version 1.0 beta                                                   //
+// November, 2001                                                            //
+//                                                                           //
+// Si hang                                                                   //
+// Email: sihang@weboo.com                                                   //
+// http://www.weboo.com/sh/tetgen.htm                                        //
+//                                                                           //
+// You are free to use, copy and modify the sources under certain            //
+// circumstances, provided this copyright notice remains intact.             //
+// See the file LICENSE for details.                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Unlike the two-dimension case that is guaranteed to recover the segment,  //
+// the three-dimension case has no such guarantee to recover the segment and //
+// facet. The Schonart polyhedron[1] is an example of polyhedron which can   //
+// not be triangulated without adding internal point. So in three-dimension, //
+// boundary-constrained mesh generation is a complex problem which can be    //
+// defined in many ways and several solutions can be proposed.               //
+//                                                                           //
+// Currently, there exist several methods to solve this problem. Weatherill  //
+// [2] and Borouchaki[3] retriangulated the elements intersected by a        //
+// constrained face so as to create a triangulation of the face. In this     //
+// case, the Steiner points are created on the boundary. George et al. [4]   //
+// and Owen[5] regenerated the missing edges and faces in boundary by means  //
+// of local transformations and the possible Steiner points insertion inside //
+// the domain. Shewchuk[6] thought of the constrained boundary triangulation //
+// problem as a subproblem of mesh improvement in his Delaunay refinement    //
+// algorithm and proposed a method to recover boundary only need inserting   //
+// points on segments.                                                       //
+//                                                                           //
+// The method I used to recover segments and facets is relatively derived    //
+// from above methods. It has two stages: Segment recover and Facet recover. //
+// It can be simply described below, the detail please refer to my thesis:   //
+//                                                                           //
+// We use the 'edge flip' + 'stitching' method to recover missing segments.  //
+// For each missing segment, try edge flip operations(flip23, flip22 and     //
+// flip44) first. Under most cases, after one or a series of flip operations,//
+// the missing segment can be recovered. If edge flips failed, inserting a   //
+// vertex into the mesh at the midpoint of the segment (more accurately, at  //
+// the midpoint of the place where the segment should be). After the mesh is //
+// adjusted to maintain the Delaunay property, the two resulting subsegments //
+// may appear in the mesh. If not, the whole procedure is repeated           //
+// recursively for each missing subsegment until the original segment is     //
+// represented by a contiguous linear sequence of edges of the mesh. We are  //
+// assure of eventual success because the Delaunay triangulation always      //
+// connects a vertex to its nearest neighbour; once the spacing of vertices  //
+// along a segment is sufficiently small, its entire length will be          //
+// represented.                                                              //
+//                                                                           //
+// When all missing subsegments are recovered missing facets are recovered   //
+// in an analogous manner. For each facet, it is necessary maintain a        //
+// two-dimensional Delaunay triangulation of its vertices, independent from  //
+// the tetrahedralization in which we hope its subfaces will eventually      //
+// appear. For each triangular subface in a facet triangulation, look for    //
+// a matching face in the tetrahedralization. If there could't find a match  //
+// subface, we can sure this subface is missing from current mesh. When we   //
+// find a subface is missing from the mesh, a local re-meshing method is     //
+// used to recovery all missing subfaces (start from this subface). Please   //
+// refer to Usermanual chapter 4.4.2 for detail description of this methhod. //
+//                                                                           //
+// However, There is no guarantee to recover facets in all condition of my   //
+// implementation now. Acctually, It's a KNOWN BUG now there are still valid //
+// input files for which Tetgen program can not produce a valid mesh. If     //
+// you come across one of these, please send it to sihang@weboo.com so that  //
+// I can continue to make the code more robust, thank you.                   //
+//                                                                           //
+// Refernces:                                                                //
+//                                                                           //
+// [1] E. Schonardt, Uber die Zerlegung von Dreieckspolyedern inTetraeder,   //
+//     Mathematische Annalen, vol 98, pp. 309-312, 1928.                     //
+// [2] N.P. Weatherill and O. Hassan, Efficient three-dimensional Delaunay   //
+//     triangulation with automatic point creation and imposed boundary con- //
+//     straints, Int. J. Numer. Meth. in Eng., vol 37, pp. 2005-2039, 1994.  //
+// [3] H. Borouchaki, Triangulation sous contraintes en dimension quelconque,//
+//     Rapport de Recherche INRIA, RR-2373, 1994.                            //
+// [4] P.L. George, F. Hecht and E. Saltel, Automatic mesh generator with    //
+//     specified boundary, Comp. Meth. in Appl. Mech. and Eng., vol 13,      //
+//     pp. 269-288, 1991.                                                    //
+// [5] Steven J. Owen, Constrained Triangulation: Application to Hex-Domaint //
+//     Mesh Generation. Proceedings, 8th International Meshing Roundtable,   //
+//     South Lake Tahoe, CA, U.S.A., pp.31-41, October 1999                  //
+// [6] Jonathan Richard Shewchuk, Tetrahedral Mesh Generation by Delaunay    //
+//     Refinement. Proceedings of the Fourteenth Annual Symopsium on Comput- //
+//     ional Geometry (Minneapolis, Minnesota), pages 86-95, Association for //
+//     Computing Machinery, June, 1998.                                      //
+// [7] Jonathan Richard Shewchuk, A Condition Guaranteeing the Existence of  //
+//     Higher-Dimensional Constrained Delaunay Triangulations. Proceedings   //
+//     of the Fourteenth Annual Symopsium on Computional Geometry (Minneapo- //
+//     lis, Minnesota), pages 76-85, Association for Computing Machinery,    //
+//     June, 1998.                                                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tetlib.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// Segment/Facet (Boundary) Constrained Routines.                            //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// finddirection()    Find the first tetrahedron on the path from one point  //
+//                    to another.                                            //
+//                                                                           //
+// Finds the tetrahedron that intersects a line segment drawn from the       //
+// origin of 'searchtet' to the point 'endpoint', 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 whether the destination, apex or oppo of the found //
+// tetrahedron is collinear with the two points in question.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum mesh3d::finddirectionresult
+mesh3d::finddirection(triface *searchtet, point3d tend)
+{
+  triface checktet;
+  point3d tstart, tright, tleft, toppo;
+  int baseorient, rightorient, leftorient, forwardorient;
+  int rightflag, leftflag, forwardflag;
+  int basezeroflag, rightzeroflag, leftzeroflag, forwardzeroflag;
+
+  tstart = org(*searchtet);
+  adjustedgering(*searchtet, CCW);
+  if (tstart != org(*searchtet)) {
+    enextself(*searchtet);
+  }
+  tright = dest(*searchtet);
+  if (tright == tend) {
+    return RIGHTCOLLINEAR;
+  }
+  tleft = apex(*searchtet);
+  if (tleft == tend) {
+    return LEFTCOLLINEAR;
+  }
+
+  // Base plane is the plane include face(tstart, tright, tleft), the normal
+  //   is direct to toppo(toppo is above the base plane).
+  basezeroflag = 0;
+  // Is 'tend' below the base plane?
+  baseorient = iorient3d(tstart, tright, tleft, tend);
+  if (baseorient > 0) {
+    // Get another side's tetrahdera of base face, so 'tend' is above the
+    //   base plane, need reset tright and tleft.
+    symself(*searchtet);
+    assert(searchtet->tet != dummytet);
+    findversion(searchtet, tstart, tleft, 0);
+    tright = tleft;
+    tleft = apex(*searchtet);
+  } else if (baseorient == 0) {
+    basezeroflag = 1;
+  }
+
+  if (verbose > 2) {
+    printf("    Find direction to point %d, from tet(%d, %d, %d, %d).\n",
+           pointmark(tend), pointmark(tstart), pointmark(tright),
+           pointmark(tleft), pointmark(oppo(*searchtet)));
+  }
+
+  // Repeat turn right and turn left until find a satisfied tetrahedron.
+  while (true) {
+    toppo = oppo(*searchtet);
+    if (toppo == tend) {
+      return TOPCOLLINEAR;
+    }
+    // Must reset 'rightflag' and 'leftflag' at each start time. Because
+    //   we not always turn the same side in three-dimensional case.
+    rightflag = leftflag = forwardflag = 0;
+    rightzeroflag = leftzeroflag = 0; forwardzeroflag = 0;
+
+    // Is 'endpoint' to the right?
+    rightorient = iorient3d(tend, tstart, tright, toppo);
+    if (rightorient == 0) {
+      rightzeroflag = 1;
+    } else {
+      rightflag = rightorient > 0;
+    }
+    // Is 'endpoint' to the left?
+    leftorient = iorient3d(tstart, tend, tleft, toppo);
+    if (leftorient == 0) {
+      leftzeroflag = 1;
+    } else {
+      leftflag = leftorient > 0;
+    }
+    // Is 'endpoint' forward to the opposite?
+    forwardorient = iorient3d(tright, toppo, tleft, tend);
+    if (forwardorient == 0) {
+      forwardzeroflag = 1;
+    } else {
+      forwardflag = forwardorient > 0;
+    }
+
+    // Check zero flag first.
+    if (basezeroflag) {
+      if (rightzeroflag && forwardflag) {
+        return RIGHTCOLLINEAR;
+      } else if (leftzeroflag && forwardflag) {
+        return LEFTCOLLINEAR;
+      } else if (forwardflag) {
+        if ((rightflag == 0) && (leftflag == 0)) {
+          return WITHIN;
+        }
+      }
+    }
+
+    if (rightzeroflag) {
+      if (leftzeroflag && forwardflag) {
+        return TOPCOLLINEAR;
+      }
+      if (!leftflag && forwardflag) {
+        // This condition is tend coplanar with the right side(may be WITHIN
+        //   ) of this tet, and we can't turn left side(because the leftflag
+        //   is 0). The only choice is try to turn right. Check if there has
+        //   a boundary on the right.
+        fnext(*searchtet, checktet);
+        if (issymexist(&checktet)) {
+          rightflag = 1; // Here leftflag = 0;
+        } else {
+          // Hit a boundary when try turn right, take the right side as
+          //   base plane, then continue...
+          fnextself(*searchtet);
+          esymself(*searchtet);  // Don't miss the tstart.
+          enextself(*searchtet);
+          tleft = tright;
+          tright = toppo;
+          basezeroflag = 1;
+          if (verbose > 2) {
+            printf("    Take right as base palne. Get tet(%d, %d, %d, %d).\n",
+                   pointmark(tstart), pointmark(tright),
+                   pointmark(tleft), pointmark(oppo(*searchtet)));
+          }
+          continue;
+        }
+      }
+    } else if (leftzeroflag) {
+      if (rightzeroflag && forwardflag) {
+        return TOPCOLLINEAR;
+      }
+      if (!rightflag && forwardflag) {
+        // This condition is tend coplanar with the left side(may be WITHIN
+        //   ) of this tet, and we can't turn right side(because the right-
+        //   flag is 0). The only choice is try to turn left. Check if there
+        //   has a boundary on the left.
+        checktet = *searchtet;
+        enext2fnextself(checktet);
+        if (issymexist(&checktet)) {
+          leftflag = 1; // Here rightflag = 0;
+        } else {
+          // Hit a boundary when try turn left, take the left side as
+          //   base plane, then continue...
+          enext2fnextself(*searchtet);
+          esymself(*searchtet); // Don't miss the tstart.
+          tright = tleft;
+          tleft = toppo;
+          basezeroflag = 1;
+          if (verbose > 2) {
+            printf("    Take left as base palne. Get tet(%d, %d, %d, %d).\n",
+                   pointmark(tstart), pointmark(tright),
+                   pointmark(tleft), pointmark(oppo(*searchtet)));
+          }
+          continue;
+        }
+      }
+    } else {
+      // None zero flag(!rightzeroflag && !leftzeroflag) cases.
+      if (!rightflag && !leftflag) {
+        // Both rightflag = 0 and leftflag = 0. This mean tend is both below
+        //   the right side and left side. There have two conditions, decide
+        //   by current forwardflag.
+        if (forwardflag) {
+          return ACROSS;
+        } else {
+          // 'searchtet' faces directly away from `tend'.  We could go left
+          //   or right. Ask whether it's a tetrahedron or a boundary on the
+          //   right.
+          fnext(*searchtet, checktet);
+          if (issymexist(&checktet)) {
+            rightflag = 1; // leftflag = 0;
+          } else {
+            leftflag = 1;  // rightflag = 0;
+          }
+        }
+      } else if (rightflag && leftflag) {
+        // 'searchtet' faces directly away from `tend'.  We could go left
+        //   or right. Ask whether it's a tetrahedron or a boundary on the
+        //   right.
+        fnext(*searchtet, checktet);
+        if (issymexist(&checktet)) {
+          leftflag = 0;  // rightflag = 1;
+        } else {
+          rightflag = 0; // leftflag = 1;
+        }
+      }
+    }
+
+    if (rightflag) {
+      // Turn right once.
+      fnextself(*searchtet);
+      symself(*searchtet);
+      assert(searchtet->tet != dummytet);
+      findversion(searchtet, tstart, tright, 0);
+      tleft = toppo;
+      basezeroflag = rightzeroflag;
+      if (verbose > 2) {
+        printf("    Turn right side.");
+      }
+    } else {
+      assert(leftflag);
+      // Turn left once.
+      enext2fnextself(*searchtet);
+      symself(*searchtet);
+      assert(searchtet->tet != dummytet);
+      findversion(searchtet, tstart, toppo, 0);
+      tright = toppo;
+      basezeroflag = leftzeroflag;
+      if (verbose > 2) {
+        printf("    Turn left side.");
+      }
+    }
+    if (verbose > 2) {
+      printf(" Get tet(%d, %d, %d, %d).\n",
+           pointmark(tstart), pointmark(tright),
+           pointmark(tleft), pointmark(oppo(*searchtet)));
+    }
+#ifdef SELF_CHECK
+    baseorient = iorient3d(tstart, tright, tleft, tend);
+    if (baseorient > 0) {
+      printf("Internal error in finddirection():\n");
+      printf("  'baseorient' shouldn't below the base plane.\n");
+      internalerror();
+    }
+#endif // defined SELF_CHECK
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// segmentintersection()    Find the intersection of an existing segment and //
+//                          a segment that is being inserted. Insert a point //
+//                          at the intersection, splitting an existing shell //
+//                          edge(subsegment).                                //
+//                                                                           //
+// The segment being inserted connects the apex of splittet to endpoint2.    //
+// splitsubseg is the subsegment being split, the edge being split connects  //
+// the origin and destination of splittet.                                   //
+//                                                                           //
+// On completion, splittet is a handle having the newly inserted             //
+// intersection point as its origin, and endpoint1 as its destination.       //
+//                                                                           //
+// Use line and plane intersection algorithm to calculate the intersection   //
+// point of two segment in 3-space:                                          //
+//   If the plane is defined as:                                             //
+//     a*x + b*y + c*z + d = 0           (1)                                 //
+//   and the line is defined as:                                             //
+//     x = x1 + (x2 - x1)*t = x1 + e*t                                       //
+//     y = y1 + (y2 - y1)*t = y1 + f*t   (2)                                 //
+//     z = z1 + (z2 - z1)*t = z1 + g*t                                       //
+//   Then just substitute (2) into the plane equation (1). You end up with:  //
+//     t = - (a*x1 + b*y1 + c*z1 + d)/(a*e + b*f + c*g)                      //
+//   When the denominator is zero, the line is contained in the plane if the //
+//   numerator is also zero (the point at t=0 satisfies the plane equation), //
+//   otherwise the line is parallel to the plane.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::segmentintersection(triface *splittet, face *splitshseg,
+                                 point3d endpoint2)
+{
+  point3d endpoint1, torg, tdest;
+  point3d leftpoint, rightpoint, oppopoint;
+  point3d newpoint;
+  enum insertsiteresult success;
+  enum finddirectionresult collinear;
+  enum locateresult locval;
+  REAL a, b, c, d, e, f, g, t;
+  REAL v12[3], v34[3], norm0[3], norm1[3];
+  int i;
+
+  segmentintersectioncount++;
+
+  // Find the other three segment endpoints.
+  endpoint1 = apex(*splittet);
+  torg = org(*splittet);
+  tdest = dest(*splittet);
+
+  // Segment intersection formulae; see the graphic algorithm faq.
+  Sub3D(tdest, torg, v12);
+  Sub3D(endpoint2, endpoint1, v34);
+  Cross3D(v12, v34, norm0);
+  Cross3D(v34, norm0, norm1);
+
+  a = norm1[0];
+  b = norm1[1];
+  c = norm1[2];
+  d = -(a * endpoint1[0] + b * endpoint1[1] + c * endpoint1[2]);
+  e = v12[0];
+  f = v12[1];
+  g = v12[2];
+  t = -(a * torg[0] + b * torg[1] + c * torg[2] + d) / (a * e + b * f + c * g);
+
+  // Create the new point.
+  newpoint = (point3d) points.alloc();
+  // Interpolate its coordinate and attributes.
+  for (i = 0; i < 3 + nextras; i++) {
+    newpoint[i] = torg[i] + t * v12[i];
+  }
+  setpointmark(newpoint, mark(*splitshseg));
+  if (verbose > 1) {
+    // For debug, need use the pointmark to keep point's index.
+    setpointmark(newpoint, points.items);
+  }
+  if (verbose > 1) {
+    printf("  Splitting edge (%.12g, %.12g, %.12g) (%.12g, %.12g, %.12g)\n",
+           torg[0], torg[1], torg[2], tdest[0], tdest[1], tdest[2]);
+    printf("    at (%.12g, %.12g, %.12g).\n", newpoint[0], newpoint[1],
+           newpoint[2]);
+  }
+  // Insert the intersection point.  This should always succeed.
+  success = insertsite(newpoint, splittet, (face*) NULL, splitshseg);
+  if (success != SUCCESSFUL) {
+    printf("Internal error in segmentintersection():");
+    printf("  Fail to split a segment.\n");
+    internalerror();
+  }
+  if (steinerleft > 0) {
+    steinerleft--;
+  }
+  // Find newpoint in splittet, set it as origin of splittet,
+  if (!findorg(splittet, newpoint)) {
+    splittet->ver = 0;
+    for (splittet->loc = 0; splittet->loc < 4; splittet->loc++) {
+      if (isaboveplane(splittet, newpoint)) break;
+    }
+    assert(splittet->loc < 4);
+    locval = preciselocate(newpoint, splittet);
+    assert(locval == ONVERTEX);
+  }
+  setpoint2tet(newpoint, encode(*splittet));
+
+  // Inserting the point may have caused edge flips.  We wish to rediscover
+  //   the edge connecting endpoint1 to the new intersection point.
+  collinear = finddirection(splittet, endpoint1);
+  rightpoint = dest(*splittet);
+  leftpoint = apex(*splittet);
+  oppopoint = oppo(*splittet);
+  if (leftpoint == endpoint1) {
+    enext2self(*splittet);
+    esymself(*splittet);
+  } else if (oppopoint == endpoint1) {
+    fnextself(*splittet);
+    enext2self(*splittet);
+    esymself(*splittet);
+  } else if (rightpoint != endpoint1) {
+    printf("Internal error in segmentintersection():\n");
+    printf("  Topological inconsistency after splitting a segment.\n");
+    internalerror();
+  }
+  // 'splittet' should have destination endpoint1.
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// scoutsegment()    Scout the first tetrahedron on the path from one        //
+//                   endpoint to another, and check for completion(reaching  //
+//                   the second endpoint), a collinear point, and the        //
+//                   intersection of two segments or the intersection of a   //
+//                   segment and a facet.                                    //
+//                                                                           //
+// Returns one if the entire segment is successfully  inserted,  and zero if //
+// the job must be finished by conformingedge() or constrainededge().        //
+//                                                                           //
+// If the first tetrahedron on the path has the second endpoint as its       //
+// destination, apex or opposite, a subsegment is inserted and the job is    //
+// done.                                                                     //
+//                                                                           //
+// If the first tetrahedron  on the path has a  destination or apex that     //
+// lies on the segment, a subsegment is inserted connecting the first        //
+// endpoint to the collinear point, and the search is continued from the     //
+// collinear point.                                                          //
+//                                                                           //
+// If the first tetrahedron on the path has a subsegment opposite its origin,//
+// then there is a segment that intersects the segment being inserted. Their //
+// intersection point is inserted, splitting the subsegment.                 //
+//                                                                           //
+// If the first tetrahedron on the path has a subface opposite its origin,   //
+// then there is a facet that intersects the segment being inserted. Their   //
+// intersection point is inserted, splitting the subface.                    //
+//                                                                           //
+// Otherwise, return zero.                                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::scoutsegment(triface *searchtet, point3d endpoint2, int newmark)
+{
+  triface crosstet;
+  face crossface, crossedge;
+  point3d leftpoint, rightpoint, oppopoint;
+  point3d endpoint1;
+  enum finddirectionresult collinear;
+
+  endpoint1 = org(*searchtet);
+  if (verbose > 2) {
+    printf("    Scout segment from %d to %d.\n",
+           pointmark(endpoint1), pointmark(endpoint2));
+  }
+  collinear = finddirection(searchtet, endpoint2);
+  rightpoint = dest(*searchtet);
+  leftpoint = apex(*searchtet);
+  oppopoint = oppo(*searchtet);
+  if ((oppopoint == endpoint2) || (leftpoint == endpoint2) ||
+      (rightpoint == endpoint2)) {
+    if (oppopoint == endpoint2) {
+      fnextself(*searchtet);
+      enext2self(*searchtet);
+    } else if (leftpoint == endpoint2) {
+      enext2self(*searchtet);
+    }
+    // Insert a subsegment, if there isn't already one there.
+    insertsubsegment(searchtet, newmark);
+    return 1;
+  } else if (collinear == LEFTCOLLINEAR) {
+    // We've collided with a point between the segment's endpoints.
+    // Make the collinear point be the tetrahedron's origin.
+    enext2self(*searchtet);
+    insertsubsegment(searchtet, newmark);
+    // Insert the remainder of the segment.
+    return scoutsegment(searchtet, endpoint2, newmark);
+  } else if (collinear == RIGHTCOLLINEAR) {
+    // We've collided with a point between the segment's endpoints.
+    insertsubsegment(searchtet, newmark);
+    // Make the collinear point be the tetrahedron's origin.
+    enextself(*searchtet);
+    // Insert the remainder of the segment.
+    return scoutsegment(searchtet, endpoint2, newmark);
+  } else if (collinear == TOPCOLLINEAR) {
+    // We've collided with a point between the segment's endpoints.
+    // Make the collinear point be the tetrahedron's origin.
+    fnextself(*searchtet);
+    enext2self(*searchtet);
+    insertsubsegment(searchtet, newmark);
+    // Insert the remainder of the segment.
+    return scoutsegment(searchtet, endpoint2, newmark);
+  } else if (collinear == ACROSS) {
+    // Check for a crossing subface.
+    enextfnext(*searchtet, crosstet);
+    tspivot(crosstet, crossface);
+    if ((crossface.sh != dummysh) && !isnonsolid(crossface)) {
+      /*// Insert a point at the intersection.
+      segmentfacetintersection(&crosstet, &crossface, endpoint2);
+      *searchtet = crosstet;
+      insertsubsegment(searchtet, newmark);
+      // Insert the remainder of the segment.
+      return scoutsegment(searchtet, endpoint2, newmark); */
+      printf("Segment-Facet intersection has not implemented now.\n");
+      exit(1);
+    } else {
+      // Try to do flip23 on the acrossing face.
+      if (categorizeface(crosstet) == T23) {
+        if (verbose > 1) {
+          printf("  Do face-edge swap (T23).\n");
+        }
+        usefliplist = 1;
+        flip23(crosstet);
+        usefliplist = 0;
+        findorg(searchtet, endpoint1);
+        assert(org(*searchtet) == endpoint1);
+        return scoutsegment(searchtet, endpoint2, newmark);
+      }
+    }
+  } else {
+    assert(collinear == WITHIN);
+    // Check for a crossing segment.
+    enextfnext(*searchtet, crosstet);
+    tsspivot(&crosstet, &crossedge);
+    if (crossedge.sh != dummysh) {
+      // Insert a point at the intersection.
+      segmentintersection(&crosstet, &crossedge, endpoint2);
+      *searchtet = crosstet;
+      insertsubsegment(searchtet, newmark);
+      // Insert the remainder of the segment.
+      return scoutsegment(searchtet, endpoint2, newmark);
+    } else {
+      // Try to do flip22 or flip44 on the acrossing edge.
+      point3d fliporg, flipdest;
+      enum facecategory fc;
+
+      fliporg = org(crosstet);
+      flipdest = dest(crosstet);
+      fc = categorizeface(crosstet);
+      if ((fc == T22) || (fc == T44)) {
+        // Check the flipface does not changed by categorizeface().
+        if (((org(crosstet) == fliporg) && (dest(crosstet) == flipdest))
+            || ((org(crosstet) == flipdest) && (dest(crosstet) == fliporg))) {
+          if (verbose > 1) {
+            printf("  Do face-edge swap (%s).\n", fc == T22 ? "T22" : "T44");
+          }
+          usefliplist = 1;
+          if (fc == T22) {
+            flip22(crosstet);
+          } else {
+            flip44(crosstet);
+          }
+          usefliplist = 0;
+          findorg(searchtet, endpoint1);
+          assert(org(*searchtet) == endpoint1);
+          return scoutsegment(searchtet, endpoint2, newmark);
+        }
+      }
+    }
+  }
+  // Can't find such segment, job must be completed by insert points.
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// conformingedge()    Force a segment into a conforming Delaunay            //
+//                     triangulation by inserting a point at its midpoint,   //
+//                     and recursively forcing in the two half-segments if   //
+//                     necessary.                                            //
+//                                                                           //
+// Generates a sequence of edges connecting `endpoint1' to `endpoint2'.      //
+// `newmark' is the boundary marker of the segment, assigned to each new     //
+// splitting point and shell edge.                                           //
+//                                                                           //
+// Note that conformingedge() does not always maintain the conforming        //
+// Delaunay property.  Once inserted, segments are locked into place; points //
+// inserted later (to force other segments in) may render these fixed        //
+// segments non-Delaunay.  The conforming Delaunay property will be restored //
+// by enforcequality() by splitting encroached segments.                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::conformingedge(point3d endpoint1, point3d endpoint2, int newmark)
+{
+  triface searchtet1, searchtet2;
+  face brokenshseg, brokenshface;
+  point3d newpoint;
+  point3d midpoint1, midpoint2;
+  enum insertsiteresult success;
+  enum locateresult locval;
+  int result1, result2;
+  int i;
+
+  if (verbose > 2) {
+    printf("    Forcing segment into triangulation by recursive splitting:");
+    printf(" %d, %d\n", pointmark(endpoint1), pointmark(endpoint2));
+  }
+  // Create a new point to insert in the middle of the segment.
+  newpoint = (point3d) points.alloc();
+  // Interpolate coordinates and attributes.
+  for (i = 0; i < 3 + nextras; i++) {
+    newpoint[i] = 0.5 * (endpoint1[i] + endpoint2[i]);
+  }
+  setpointmark(newpoint, newmark);
+  if (verbose > 1) {
+    // For debug, need use the pointmark to keep point's index.
+    setpointmark(newpoint, points.items);
+  }
+  // Find a boundary tetrahedron to search from.
+  searchtet1.tet = (tetrahedron *) NULL;
+  // Attempt to insert the new point.
+  success = insertsite(newpoint, &searchtet1, (face *) NULL, (face *) NULL);
+  if (success == DUPLICATE) {
+    if (verbose > 2) {
+      printf("    Segment intersects existing point (%.12g, %.12g, %.12g).\n",
+             newpoint[0], newpoint[1], newpoint[2]);
+    }
+    // Use the point that's already there.
+    points.dealloc(newpoint);
+    newpoint = org(searchtet1);
+  } else {
+    if (success == VIOLATINGEDGE) {
+      if (verbose > 2) {
+        printf("    Two segments intersect at (%.12g, %.12g, %.12g).\n",
+               newpoint[0], newpoint[1], newpoint[2]);
+      }
+      // By fluke, we've landed right on another segment.  Split it.
+      tsspivot(&searchtet1, &brokenshseg);
+      success = insertsite(newpoint, &searchtet1, (face*) NULL, &brokenshseg);
+      if (success != SUCCESSFUL) {
+        printf("Internal error in conformingedge():");
+        printf("  Failure to split a segment.\n");
+        internalerror();
+      }
+    } else if (success == VIOLATINGFACE) {
+      if (verbose > 2) {
+        printf("    Segments intersect a subface at (%.12g, %.12g, %.12g).\n",
+               newpoint[0], newpoint[1], newpoint[2]);
+      }
+      // By fluke, we've landed right on a subface.  Split it.
+      tspivot(searchtet1, brokenshface);
+      success = insertsite(newpoint, &searchtet1, &brokenshface, (face*) NULL);
+      if (success != SUCCESSFUL) {
+        printf("Internal error in conformingedge():");
+        printf("  Failure to split a subface.\n");
+        internalerror();
+      }
+    }
+    // The point has been inserted successfully.
+    if (steinerleft > 0) {
+      steinerleft--;
+    }
+    // Find newpoint in searchtet1, set it as origin of splittet,
+    if (!findorg(&searchtet1, newpoint)) {
+      searchtet1.ver = 0;
+      for (searchtet1.loc = 0; searchtet1.loc < 4; searchtet1.loc++) {
+        if (isaboveplane(&searchtet1, newpoint)) break;
+      }
+      assert(searchtet1.loc < 4);
+      locval = preciselocate(newpoint, &searchtet1);
+      assert(locval == ONVERTEX);
+    }
+    setpoint2tet(newpoint, encode(searchtet1));
+  }
+
+  searchtet2 = searchtet1;
+  result1 = scoutsegment(&searchtet1, endpoint1, newmark);
+  result2 = scoutsegment(&searchtet2, endpoint2, newmark);
+  if (!result1) {
+    // The origin of searchtet1 may have changed if a collision with an
+    //   intervening vertex on the segment occurred.
+    midpoint1 = org(searchtet1);
+    conformingedge(midpoint1, endpoint1, newmark);
+  }
+  if (!result2) {
+    // The origin of searchtet2 may have changed if a collision with an
+    //   intervening vertex on the segment occurred.
+    midpoint2 = org(searchtet2);
+    conformingedge(midpoint2, endpoint2, newmark);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertsegment()    Insert a PLC segment into a triangulation.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::insertsegment(point3d endpoint1, point3d endpoint2, int newmark)
+{
+  triface searchtet1, searchtet2;
+  tetrahedron encodedtet;
+  point3d checkpoint;
+
+  if (verbose > 1) {
+    printf("  Connecting %d to %d.\n", pointmark(endpoint1),
+           pointmark(endpoint2));
+  }
+
+  // Find a tetrahedron whose origin is the segment's first endpoint.
+  checkpoint = (point3d) NULL;
+  encodedtet = point2tet(endpoint1);
+  if (encodedtet != (tetrahedron) NULL) {
+    decode(encodedtet, searchtet1);
+    if (findorg(&searchtet1, endpoint1)) {
+      checkpoint = org(searchtet1);
+    }
+  }
+  if (checkpoint != endpoint1) {
+    // Find a boundary tetrahedron to search from.
+    searchtet1.tet = dummytet;
+    searchtet1.loc = 0;
+    symself(searchtet1);
+    // Search for the segment's first endpoint by point location.
+    if (locate(endpoint1, &searchtet1) != ONVERTEX) {
+      printf("Internal error in insertsegment():  Unable to locate point\n");
+      printf("  (%.12g, %.12g, %.12g) in triangulation.\n",
+             endpoint1[0], endpoint1[1], endpoint1[2]);
+      internalerror();
+    }
+  }
+  // Remember this tetrahedron to improve subsequent point location.
+  recenttet = searchtet1;
+  // Scout the beginnings of a path from the first endpoint
+  //   toward the second.
+  if (scoutsegment(&searchtet1, endpoint2, newmark)) {
+    // The segment was easily inserted.
+    if (!fliplist->empty()) {
+      // Restore Delaunayness if necessary.
+      dofliplist();
+    }
+    return;
+  }
+  // The first endpoint may have changed if a collision with an intervening
+  //   vertex on the segment occurred.
+  endpoint1 = org(searchtet1);
+
+  // Find a tetrahedron whose origin is the segment's second endpoint.
+  checkpoint = (point3d) NULL;
+  encodedtet = point2tet(endpoint2);
+  if (encodedtet != (tetrahedron) NULL) {
+    decode(encodedtet, searchtet2);
+    if (findorg(&searchtet2, endpoint2)) {
+      checkpoint = org(searchtet2);
+    }
+  }
+  if (checkpoint != endpoint2) {
+    // Find a boundary tetrahedron to search from.
+    searchtet2.tet = dummytet;
+    searchtet2.loc = 0;
+    symself(searchtet2);
+    // Search for the segment's second endpoint by point location.
+    if (locate(endpoint2, &searchtet2) != ONVERTEX) {
+      printf("Internal error in insertsegment():  Unable to locate point\n");
+      printf("  (%.12g, %.12g, %.12g) in triangulation.\n",
+             endpoint2[0], endpoint2[1], endpoint2[2]);
+      internalerror();
+    }
+  }
+  // Remember this tetrahedron to improve subsequent point location.
+  recenttet = searchtet2;
+  // Scout the beginnings of a path from the second endpoint
+  //   toward the first.
+  if (scoutsegment(&searchtet2, endpoint1, newmark)) {
+    // The segment was easily inserted.
+    if (!fliplist->empty()) {
+      // Restore Delaunayness if necessary.
+      dofliplist();
+    }
+    return;
+  }
+  // The second endpoint may have changed if a collision with an intervening
+  //   vertex on the segment occurred.
+  endpoint2 = org(searchtet2);
+
+  // Insert vertices to force the segment into the triangulation.
+  conformingedge(endpoint1, endpoint2, newmark);
+  if (!fliplist->empty()) {
+    // Restore Delaunayness if necessary.
+    dofliplist();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// getsteinersinseg()    Find all steiner points in a given segment. Return  //
+//                       in a List.                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::getsteinersinseg(point3d endpoint1, point3d endpoint2,
+                              list* steinerpoints)
+{
+  triface searchtet;
+  tetrahedron encodedtet;
+  point3d checkpoint;
+  point3d leftpoint, rightpoint, oppopoint;
+  enum finddirectionresult collinear;
+
+  if (verbose > 2) {
+    printf("    Get steiner points in segment from %d to %d.\n",
+           pointmark(endpoint1), pointmark(endpoint2));
+  }
+
+  // Find a tetrahedron whose origin is the endpoint1.
+  checkpoint = (point3d) NULL;
+  encodedtet = point2tet(endpoint1);
+  if (encodedtet != (tetrahedron) NULL) {
+    decode(encodedtet, searchtet);
+    if (findorg(&searchtet, endpoint1)) {
+      checkpoint = org(searchtet);
+    }
+  }
+  if (checkpoint != endpoint1) {
+    // Find a boundary tetrahedron to search from.
+    searchtet.tet = dummytet;
+    searchtet.loc = 0;
+    symself(searchtet);
+    // Search for the segment's first endpoint by point location.
+    if (locate(endpoint1, &searchtet) != ONVERTEX) {
+      printf("Internal error in insertsegment():  Unable to locate point\n");
+      printf("  (%.12g, %.12g, %.12g) in triangulation.\n",
+             endpoint1[0], endpoint1[1], endpoint1[2]);
+      internalerror();
+    }
+  }
+  // Remember this tetrahedron to improve subsequent point location.
+  recenttet = searchtet;
+
+  while (true) {
+    collinear = finddirection(&searchtet, endpoint2);
+    rightpoint = dest(searchtet);
+    leftpoint = apex(searchtet);
+    oppopoint = oppo(searchtet);
+    if ((oppopoint == endpoint2) || (leftpoint == endpoint2) ||
+        (rightpoint == endpoint2)) {
+      // We are reach the endpoint2, end of searching.
+      return;
+    } else if (collinear == LEFTCOLLINEAR) {
+      // We've collided with a point between the segment's endpoints.
+      steinerpoints->append(&leftpoint);
+      // Make the collinear point be the tetrahedron's origin.
+      enext2self(searchtet);
+    } else if (collinear == RIGHTCOLLINEAR) {
+      // We've collided with a point between the segment's endpoints.
+      steinerpoints->append(&rightpoint);
+      // Make the collinear point be the tetrahedron's origin.
+      enextself(searchtet);
+    } else if (collinear == TOPCOLLINEAR) {
+      // We've collided with a point between the segment's endpoints.
+      steinerpoints->append(&oppopoint);
+      // Make the collinear point be the tetrahedron's origin.
+      fnextself(searchtet);
+      enext2self(searchtet);
+    } else {  // collinear == ACROSS or collinear == WITHIN
+      printf("Internal error in getsteinersinseg(): Segment is missing.\n");
+      internalerror();
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// getdiagonalapexindex()    Get the diagonal point index of the specified   //
+//                           triangle edge(that is, get the neighbour tri    //
+//                           at this edge, then get this edge's apex in it)  //
+//                           in the input triangulateio structure.           //
+//                                                                           //
+// It required that the input triangulateio structure must be created by     //
+// triangle with a switch -n, so triangle will generates a list of triangle  //
+// neighbors in the 'neighborlist' field of triangulateio structure.         //
+//                                                                           //
+// If the diagonal point exist, return the index in pointlist (>= 0), other- //
+// wise, return -1.                                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::
+getdiagonalapexindex(triangulateio* out, int triindex, int edgeorient)
+{
+  int tribase, ntribase;
+  int ntriindex;
+  int iorg, idest;
+  int nidiag;
+
+  tribase = triindex * 3;
+  ntriindex = out->neighborlist[tribase + minus1mod3[edgeorient]];
+  if (ntriindex == -1) {
+    return -1;
+  }
+  ntribase = ntriindex * 3;
+
+  iorg = out->trianglelist[tribase + edgeorient];
+  idest = out->trianglelist[tribase + plus1mod3[edgeorient]];
+
+  nidiag = out->trianglelist[ntribase];
+  if ((nidiag != iorg) && (nidiag != idest)) {
+    return nidiag;
+  }
+  nidiag = out->trianglelist[ntribase + 1];
+  if ((nidiag != iorg) && (nidiag != idest)) {
+    return nidiag;
+  }
+  nidiag = out->trianglelist[ntribase + 2];
+  if ((nidiag != iorg) && (nidiag != idest)) {
+    return nidiag;
+  }
+  return -1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// getneighbourtriedge()    Get the neighbour triangle's index and edge of   //
+//                          the specified triangle edge(that is, get the     //
+//                          neighbour tri at this edge, then get this edge's //
+//                          orient) from the input triangulateio structure.  //
+//                                                                           //
+// It required that the input triangulateio structure must be created by     //
+// triangle with a switch -n, so triangle will generates a list of triangle  //
+// neighbors in the 'neighborlist' field of triangulateio structure.         //
+//                                                                           //
+// If the neighbour tri exist and the edge orient is found, return 1, other- //
+// wise, return -1.                                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::
+getneighbourtriedge(struct triangulateio* out, int triindex, int edgeorient,
+                    int* ntriindex, int* nedgeorient)
+{
+  int tribase, ntribase;
+  int iorg, idest;
+  int niorg, nidest;
+  int i;
+
+  tribase = triindex * 3;
+  *ntriindex = out->neighborlist[tribase + minus1mod3[edgeorient]];
+  if (*ntriindex == -1) {
+    return -1;
+  }
+  ntribase = *ntriindex * 3;
+
+  iorg = out->trianglelist[tribase + edgeorient];
+  idest = out->trianglelist[tribase + plus1mod3[edgeorient]];
+
+  *nedgeorient = -1;
+  for (i = 0; i < 3; i++) {
+    niorg = out->trianglelist[ntribase + i];
+    nidest = out->trianglelist[ntribase + plus1mod3[i]];
+    if ((niorg == idest) && (nidest == iorg)) {
+      *nedgeorient = i;
+      return 1;
+    }
+  }
+
+  return -1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// swapdiagonal()   To do an edge flip in the input triangulateio structure. //
+//                                                                           //
+// It required that the input triangulateio structure must be created by     //
+// triangle with a switch -n, so triangle will generates a list of triangle  //
+// neighbors in the 'neighborlist' field of triangulateio structure.         //
+//                                                                           //
+//              nleftcasing                                                  //
+//                                                                           //
+//          dest  norg__ napex             dest ______   napex               //
+//              |\ \     |                     |     / /|                    //
+//              | \ \<----- nswapedge          |    / / |                    //
+// rightcasing  |  \ \   |                     |   / /  |                    //
+//              |   \ \  | nrightcasing        |  / /   |                    //
+//    swapedge ----->\ \ |                     | / /    |                    //
+//              |_____\ \|                     |/ /_____|                    //
+//          apex    org  ndest             apex          ndest               //
+//                                                                           //
+//             leftcasing                                                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::
+swapdiagonal(struct triangulateio* out, int triindex, int fixedge, int swapedge)
+{
+  int tribase, ntribase;
+  int ntriindex;
+  int nswapedge;
+  int org, dest, apex;
+  int norg, ndest, napex;
+  int rightcasing, leftcasing;
+  int nrightcasing, nleftcasing;
+
+  tribase = triindex * 3;
+  ntriindex = out->neighborlist[tribase + minus1mod3[swapedge]];
+  if (ntriindex == -1) {
+    return 0; // ntriindex does not exist.
+  }
+  ntribase = ntriindex * 3;
+
+  org = out->trianglelist[tribase + swapedge];
+  dest = out->trianglelist[tribase + plus1mod3[swapedge]];
+  apex = out->trianglelist[tribase + minus1mod3[swapedge]];
+  // Find edge(sorg, sdest)'s orient in ntriindex.
+  napex = -1;
+  for (nswapedge = 0; nswapedge < 3; nswapedge++) {
+    norg = out->trianglelist[ntribase + nswapedge];
+    ndest = out->trianglelist[ntribase + plus1mod3[nswapedge]];
+    if ((norg == dest) && (ndest == org)) {
+      napex = out->trianglelist[ntribase + minus1mod3[nswapedge]];
+      break;
+    }
+  }
+  if (napex == -1) {
+    return 0; // ntriindex does not contain the swap edge.
+  }
+  rightcasing = out->neighborlist[tribase + swapedge];
+  leftcasing = out->neighborlist[tribase + plus1mod3[swapedge]];
+  nrightcasing = out->neighborlist[ntribase + nswapedge];
+  nleftcasing = out->neighborlist[ntribase + plus1mod3[nswapedge]];
+
+  if (fixedge == plus1mod3[swapedge]) {
+    // Right edge (dest, apex) of swap edge is fixed (not change).
+    //   org <-- napex
+    out->trianglelist[tribase + swapedge] = napex;
+    //   leftcasing <-- ntriindex
+    out->neighborlist[tribase + plus1mod3[swapedge]] = ntriindex;
+    //   ntriindex <-- nleftcasing
+    out->neighborlist[tribase + minus1mod3[swapedge]] = nleftcasing;
+    //   norg <-- apex
+    out->trianglelist[ntribase + nswapedge] = apex;
+    //   nleftcasing <-- triindex
+    out->neighborlist[ntribase + plus1mod3[nswapedge]] = triindex;
+    //   triindex <-- leftcasing
+    out->neighborlist[ntribase + minus1mod3[nswapedge]] = leftcasing;
+  } else if (fixedge == minus1mod3[swapedge]) {
+    // Left edge (apex, org) of swap edge is fixed (not change).
+    //   dest <--> napex
+    out->trianglelist[tribase + plus1mod3[swapedge]] = napex;
+    //   rightcasing <-- ntriindex
+    out->neighborlist[tribase + swapedge] = ntriindex;
+    //   ntriindex <-- nrightcasing
+    out->neighborlist[tribase + minus1mod3[swapedge]] = nrightcasing;
+    //   ndest <--> apex
+    out->trianglelist[ntribase + plus1mod3[nswapedge]] = apex;
+    //   nrightcasing <-- triindex
+    out->neighborlist[ntribase + nswapedge] = triindex;
+    //   triindex <-- rightcasing
+    out->neighborlist[ntribase + minus1mod3[nswapedge]] = rightcasing;
+  } else {
+    return 0;  // Wrong fixedge number.
+  }
+  return 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// matchface()     Matching the subface of a tetrahedron that has the same   //
+//                 vertexs as inputs. If such face be found, a subface is    //
+//                 inserted and the job is done.                             //
+//                                                                           //
+// If searchtet->tet == dummytet, the subface is defined by 'torg', 'tdest'  //
+// and 'tapex'. If searchtet->tet != dummytet, the subface is defined by     //
+// 'searchtet->org()', 'searchtet->dest()' and 'tapex'.                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum mesh3d::matchfaceresult
+mesh3d::matchface(point3d torg, point3d tdest, point3d tapex,
+                  triface* searchtet, int newmark)
+{
+  triface spintet;
+  tetrahedron encodedtet;
+  point3d checkpoint;
+  point3d leftpoint, rightpoint, oppopoint;
+  enum finddirectionresult collinear;
+  int hitbdry;
+
+  if (searchtet->tet == dummytet) {
+    // Find a tetrahedron whose origin is the face's org.
+    checkpoint = (point3d) NULL;
+    encodedtet = point2tet(torg);
+    if (encodedtet != (tetrahedron) NULL) {
+      decode(encodedtet, *searchtet);
+      if (findorg(searchtet, torg)) {
+        checkpoint = org(*searchtet);
+      }
+    }
+    if (checkpoint != torg) {
+      // Find a boundary tetrahedron to search from.
+      searchtet->tet = dummytet;
+      searchtet->loc = 0;
+      symself(*searchtet);
+      // Search for the segment's first endpoint by point location.
+      if (locate(torg, searchtet) != ONVERTEX) {
+        printf("Internal error in insertsegment():  Unable to locate point\n");
+        printf("  (%.12g, %.12g, %.12g) in triangulation.\n",
+               torg[0], tdest[1], tapex[2]);
+        internalerror();
+      }
+    }
+    // Remember this tetrahedron to improve subsequent point location.
+    recenttet = *searchtet;
+    collinear = finddirection(searchtet, tdest);
+    rightpoint = dest(*searchtet);
+    leftpoint = apex(*searchtet);
+    oppopoint = oppo(*searchtet);
+    if ((oppopoint == tdest) || (leftpoint == tdest) ||
+        (rightpoint == tdest)) {
+      if (oppopoint == tdest) {
+        fnextself(*searchtet);
+        enext2self(*searchtet);
+        esymself(*searchtet);
+      } else if (leftpoint == tdest) {
+        enext2self(*searchtet);
+        esymself(*searchtet);
+      }
+    } else {
+      return EDGEMISSING;
+    }
+    // Here the origin of 'searchtet' must be is torg.
+    assert(org(*searchtet) == torg);
+  }
+
+  if (apex(*searchtet) != tapex) {
+    // Spin around edge torg and tdest, to find a face that contain tapex.
+    spintet = *searchtet;
+    hitbdry = 0;
+    while (true) {
+      if (fnextself(spintet)) {
+        if (apex(spintet) == apex(*searchtet)) {
+          break; // Rewind, can leave now.
+        }
+        if (apex(spintet) == tapex) {
+          // This is the face we looking for.
+          *searchtet = spintet;
+          break;
+        }
+      } else {
+        hitbdry ++;
+        if(hitbdry >= 2) {
+          break;
+        } else {
+          esym(*searchtet, spintet);
+        }
+      }
+    }
+  }
+  if (apex(*searchtet) == tapex) {
+    // Insert a subface, if there isn't already one there.
+    insertsubface(searchtet, newmark, 1);
+    return FACEMATCHING;
+  } else {
+    return APEXMISSING;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertfieldpoint()    Generate and insert a field(steiner) point into     //
+//                       current mesh to form a triangulation for the input  //
+//                       triangular faces.                                   //
+//                                                                           //
+// This routine is called when gift-wrapping failed. The recover facet job   //
+// will be done(not neccessary) by insert field point to mesh.               //
+//                                                                           //
+// An important thing is the new field point must lies 'below' all the faces //
+// (giftfaces) (that is visivle from all faces) and lies 'in' the hole.      //
+//                                                                           //
+// The 'crosstetlist' is a list which keeps all crossing tets, that can help //
+// us to determine if the new field point is located in the hole.            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::insertfieldpoint(int numberofgiftfaces, triface* giftfaces,
+                             int numberofgiftpoints, point3d* giftpoints,
+                             list* crosstetlist)
+{
+  link *unfinfacelist;
+  triface newtet, otherface, *checktetptr;
+  face checksh;
+  point3d newpoint;
+  enum locateresult loc;
+  int findex;
+  int i, j;
+
+  if (verbose > 1) {
+    printf("  Generate field point to complete recover face.\n");
+  }
+  // Create the new point.
+  newpoint = (point3d) points.alloc();
+  // It's a inner point.
+  setpointmark(newpoint, 0);
+  if (verbose > 1) {
+    // For debug, need use the pointmark to keep point's index.
+    setpointmark(newpoint, points.items);
+  }
+  newpoint[0] = newpoint[1] = newpoint[2] = 0.0;
+  for (i = 0; i < numberofgiftpoints; i++) {
+    newpoint[0] += giftpoints[i][0];
+    newpoint[1] += giftpoints[i][1];
+    newpoint[2] += giftpoints[i][2];
+    // Interpolate its coordinate and attributes.
+    for (j = 3; j < 3 + nextras; j++) {
+      newpoint[j] += giftpoints[i][j];
+    }
+  }
+  newpoint[0] /= numberofgiftpoints;
+  newpoint[1] /= numberofgiftpoints;
+  newpoint[2] /= numberofgiftpoints;
+  // Interpolate its coordinate and attributes.
+  for (j = 3; j < 3 + nextras; j++) {
+    newpoint[j] /= numberofgiftpoints;
+  }
+
+  // Check if newpoint lies in the hole.
+  for (i = 0; i < crosstetlist->len(); i++) {
+    checktetptr = (triface*) (*crosstetlist)[i];
+    loc = isintet(org(*checktetptr), dest(*checktetptr), apex(*checktetptr),
+                  oppo(*checktetptr), newpoint);
+    if (loc != OUTSIDE) {
+      break;
+    }
+  }
+  if (i >= crosstetlist->len()) {
+    // This new point is outside the hole.
+    if (!quiet) {
+      printf("Internal error in insertfieldpoint(): \n");
+      printf("  The barycenter of each corner points locates outside the\n");
+      printf("    polyhedra of this corner point and their bounding faces.\n");
+      internalerror();
+    }
+    pointdealloc(newpoint);
+    return 0;
+  }
+  // Check if newpoint lies below(is visible from) the all giftface.
+  for (i = 0; i < numberofgiftfaces; i++) {
+    if (!isbelowplane(&(giftfaces[i]), newpoint)) {
+      break;
+    }
+  }
+  if (i < numberofgiftfaces) {
+    if (!quiet) {
+      printf("Internal error in insertfieldpoint(): \n");
+      printf("  The barycenter of each corner points does not visible from\n");
+      printf("    all bounding faces of the polyhedra.\n");
+      internalerror();
+    }
+    pointdealloc(newpoint);
+    return 0;
+  }
+
+  if (verbose > 1) {
+    printf("  Create new point (%.12g, %.12g, %.12g) %d.\n",
+           newpoint[0], newpoint[1], newpoint[2], pointmark(newpoint));
+  }
+
+  // Setup a list for keeping all unfinished faces.
+  unfinfacelist = new link(sizeof(triface));
+  // Set user-defined compare function for comparing faces.
+  unfinfacelist->setcomp((compfunc) &issameface);
+
+  // Create a initial tet use giftfaces[0] and newpoint.
+  maketetrahedron(&newtet);
+  setorg(newtet, dest(giftfaces[0]));
+  setdest(newtet, org(giftfaces[0]));
+  setapex(newtet, apex(giftfaces[0]));
+  setoppo(newtet, newpoint);
+  // Make the connection between giftfaces[i] and newtet.
+  bond(newtet, giftfaces[0]);
+  tspivot(giftfaces[0], checksh);
+  if (checksh.sh != dummysh) {
+    sesymself(checksh);
+    tsbond(newtet, checksh);
+  }
+  // Add the new tetrahedron's three faces to unfinished faces list.
+  //   Keep 'newpoint' be apex of each faces.
+  otherface = newtet;
+  fnextself(otherface);
+  unfinfacelist->add(&otherface);
+  otherface = newtet;
+  enextfnextself(otherface);
+  unfinfacelist->add(&otherface);
+  otherface = newtet;
+  enext2fnextself(otherface);
+  unfinfacelist->add(&otherface);
+  if (verbose > 2) {
+    printf("    Creating newtet ");
+    dump(&newtet);
+  }
+  for (i = 1; i < numberofgiftfaces; i++) {
+    maketetrahedron(&newtet);
+    setorg(newtet, dest(giftfaces[i]));
+    setdest(newtet, org(giftfaces[i]));
+    setapex(newtet, apex(giftfaces[i]));
+    setoppo(newtet, newpoint);
+    // Make the connection between giftfaces[i] and newtet.
+    bond(newtet, giftfaces[i]);
+    tspivot(giftfaces[i], checksh);
+    if (checksh.sh != dummysh) {
+      sesymself(checksh);
+      tsbond(newtet, checksh);
+    }
+    // Check and bond three inner faces of newtet.
+    otherface = newtet;
+    fnextself(otherface);
+    findex = unfinfacelist->hasitem(&otherface);
+    if ((findex > 0) && (findex <= unfinfacelist->len())) {
+      checktetptr = (triface *) unfinfacelist->getnitem(findex);
+      bond(otherface, *checktetptr);
+      unfinfacelist->del(findex);  // Remove it.
+    } else {
+      unfinfacelist->add(&otherface);
+    }
+    otherface = newtet;
+    enextfnextself(otherface);
+    findex = unfinfacelist->hasitem(&otherface);
+    if ((findex > 0) && (findex <= unfinfacelist->len())) {
+      checktetptr = (triface *) unfinfacelist->getnitem(findex);
+      bond(otherface, *checktetptr);
+      unfinfacelist->del(findex);  // Remove it.
+    } else {
+      unfinfacelist->add(&otherface);
+    }
+    otherface = newtet;
+    enext2fnextself(otherface);
+    findex = unfinfacelist->hasitem(&otherface);
+    if ((findex > 0) && (findex <= unfinfacelist->len())) {
+      checktetptr = (triface *) unfinfacelist->getnitem(findex);
+      bond(otherface, *checktetptr);
+      unfinfacelist->del(findex);  // Remove it.
+    } else {
+      unfinfacelist->add(&otherface);
+    }
+    if (verbose > 2) {
+      printf("    Creating newtet ");
+      dump(&newtet);
+    }
+  }
+  assert(unfinfacelist->len() == 0);
+
+  delete unfinfacelist;
+  return 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// recoverface()    Recover a subface that is missing from the volume mesh.  //
+//                                                                           //
+// This is done by local re-triangulate the missing faces area. Use gift-    //
+// wrapping algorithm do local triangulation.                                //
+//                                                                           //
+// This function follow these steps:                                         //
+//                                                                           //
+// (1) Identify all missing faces from 2D surface mesh, and all vertexs of   //
+//     these missing faces. The missing face will be found one by one start  //
+//     from the input triedge(triindex and edgeorient, this edge must exist  //
+//     in current tetrahedralization). Check other 2 edges are existed. If   //
+//     find oneof edges is missing, this edge's neighbour face is a missing  //
+//     face, take the neighbour triedge and keep it. Then loop untill all    //
+//     missing faces be found. We use a list(missingfacelist) to keep all    //
+//     missingface's index in 2D mesh(out), use a list(equatorpointlist) to  //
+//     keep all the vertexs of missing faces.                                //
+//                                                                           //
+// (2) Identify all the cross edges. These edges penerate all the missing    //
+//     faces and cause they cannot present in current tetrahedralization.    //
+//     The cross edges will be found one by one. A loop is used untill all   //
+//     cross edges are found. We use a list(crossedgelist) to keep all the   //
+//     cross edges.                                                          //
+//                                                                           //
+// (3) Identify all the cross tetrahedra and classify north and sourth       //
+//     points of endpoints of cross edges. We can identify the cross tets    //
+//     from cross edges. Each cross edge has a set of tetrahedra surrounding //
+//     it in the mesh. The identify all cross tets procedure proceeds by     //
+//     interrogating the tetrahedra around each cross edge. At the same time,//
+//     we can identify the endpoint of a cross edge's location (north or     //
+//     sourth). We use a list(crosstetlist) to keep all cross tetrahedra,    //
+//     two list(northpointlist and sourthpointlist) to keep the endpoints of //
+//     cross edges respectly.                                                //
+//                                                                           //
+// (4) Identify and classify all the casing tets(tet which adjoining the     //
+//     cross tets but not a cross tet). Casing tets will be used to generate //
+//     giftfaces. Pay special attention to protect subsegments for all cross //
+//     tets. Because they will be deleted before do gift-wrapping. There has //
+//     a special codes to protect subsegments from cross tets to casing tets //
+//     and dellocate inner nonsolid subfaces (Here we can't use preservesub- //
+//     segment() routine directly). If a casing tet doesnot exist, this will //
+//     happened when a cross tet lies on boundary.  We create a fake tet for //
+//     holding the casing tet's face temporarily. After gift-wrapping, do a  //
+//     remove fake tets job. At last,  We can delete all crosstets. So the   //
+//     memory can be re-used for later re-generation. We use two list(north- //
+//     cassinglist and sourthcassinglist) to keep all the casing tets.       //
+//                                                                           //
+// (5) Create all the equatorcasing tets. At first, there not exist equator- //
+//     casing tet. So like above, temporarily create a fake tetrahedron(oppo //
+//     = null) for holding this equator face. After re-triangulation, they   //
+//     will be removed. First, all casing tets are faceing toward 'tsourth', //
+//     because we triangulating the 'tnorth' side first. We use a list(equa- //
+//     tcasinglist) to keep all equator casing tets.                         //
+//                                                                           //
+// (6) Do local re-meshing at both north and sourth side of this facet. The  //
+//     well-known Gift-wrapping algorithm is used at here.                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::recoverface(list* pointlist, triangulateio* out, int triindex,
+                        int edgeorient)
+{
+  list *missingfacelist;
+  list *crossedgelist, *crosstetlist;
+  list *equatorpointlist, *northpointlist, *sourthpointlist;
+  list *equatorcasinglist, *northcasinglist, *sourthcasinglist;
+  list *backtracelist;
+  triface *giftfaces;
+  triface crossedge, crosstet;
+  triface starttet, spintet;
+  triface checkface, *checkfaceptr;
+  face checksh, checkshseg;
+  point3d torg, tdest, tapex;
+  point3d tnorth, tsourth, tother;
+  point3d *giftpoints;
+  enum matchfaceresult match;
+  int numberofgiftfaces, numberofgiftpoints;
+  int *iptr, iorg, idest, iapex;
+  int hitbdry, orient1, orient2;
+  int edgecount, successbonded;
+  int i, j, index, errorflag;
+
+  if (verbose > 1) {
+    printf("  Recover missing subfaces by local re-triangulation.\n");
+  }
+
+  // Step (1):
+  if (verbose > 2) {
+    printf("    Identify all missing subfaces.\n");
+  }
+  equatorpointlist = new list("point");
+  missingfacelist = new list(sizeof(int) * 2);
+
+  iptr = (int*) missingfacelist->alloc();
+  iptr[0] = triindex;
+  iptr[1] = edgeorient;
+  for (i = 0; i < missingfacelist->len(); i++) {
+    iptr = (int*) (*missingfacelist)[i];
+    triindex = iptr[0];
+    edgeorient = iptr[1];
+    index = triindex * 3;
+    iorg = out->trianglelist[index + edgeorient];
+    idest = out->trianglelist[index + plus1mod3[edgeorient]];
+    iapex = out->trianglelist[index + minus1mod3[edgeorient]];
+    torg = *(point3d*)(*pointlist)[iorg];
+    tdest = *(point3d*)(*pointlist)[idest];
+    tapex = *(point3d*)(*pointlist)[iapex];
+    if (verbose > 2) {
+      printf("    Subface (%d, %d, %d) is missing.\n",
+             pointmark(torg), pointmark(tdest), pointmark(tapex));
+    }
+    if (equatorpointlist->hasitem(&torg) == -1) {
+      equatorpointlist->append(&torg);
+    }
+    if (equatorpointlist->hasitem(&tdest) == -1) {
+      equatorpointlist->append(&tdest);
+    }
+    if (equatorpointlist->hasitem(&tapex) == -1) {
+      equatorpointlist->append(&tapex);
+    }
+    // Skip the current edge; Check other edges are existing.
+    starttet.tet = dummytet;
+    match = matchface(tdest, tapex, torg, &starttet, 0);
+    assert(match != FACEMATCHING);
+    if (match == EDGEMISSING) {
+      // There must exist another missing face.
+      iptr = (int*) missingfacelist->alloc();
+      // Get neighbour triangle's index and edgeorient.
+      getneighbourtriedge(out, triindex, plus1mod3[edgeorient],
+                          &iptr[0], &iptr[1]);
+      assert((iptr[0] != -1) && (iptr[1] != -1));
+    }
+    starttet.tet = dummytet;
+    match = matchface(tapex, torg, tdest, &starttet, 0);
+    assert(match != FACEMATCHING);
+    if (match == EDGEMISSING) {
+      // There must exist another missing face.
+      iptr = (int*) missingfacelist->alloc();
+      // Get neighbour triangle's index and edgeorient.
+      getneighbourtriedge(out, triindex, minus1mod3[edgeorient],
+                          &iptr[0], &iptr[1]);
+      assert((iptr[0] != -1) && (iptr[1] != -1));
+    }
+  }
+
+  // Step (2):
+  if (verbose > 2) {
+    printf("    Identify all the cross edges.\n");
+  }
+  crossedgelist = new list(sizeof(triface));
+  crossedgelist->setcomp((compfunc) &issameedge);
+
+  // Find one cross edge which cause this subface missing. Here we can
+  //   search from starttet. (starttet hold one of existing edges of the
+  //   last found missing face: torg, tdest, tapex.)
+
+  // First find one of points in 'torg', 'tdest' and 'tapex', which does
+  //   not belong to 'starttet'.
+  if (isfacehaspoint(&starttet, torg)) {
+    if (isfacehaspoint(&starttet, tdest)) {
+      tnorth = tapex;
+    } else {
+      tnorth = tdest;
+    }
+  } else {
+    tnorth = torg;
+  }
+  // Find which (fnext) direction we should go.
+  if (!isaboveplane(&starttet, tnorth)) {
+    esymself(starttet);
+  }
+  spintet = starttet;
+  hitbdry = 0;
+  orient1 = iorient3d(torg, tdest, tapex, apex(spintet));
+  errorflag = 0;
+  while (true) {
+    if (fnextself(spintet)) {
+      if (apex(spintet) == apex(starttet)) {
+        errorflag = 1;
+        break;
+      }
+      orient2 = iorient3d(torg, tdest, tapex, apex(spintet));
+      if (orient1 == 0) {
+        if (orient2 != 0) orient1 = orient2;
+      } else {
+        if ((orient2 != 0) && (orient1 != orient2)) {
+          crossedge = spintet;
+          adjustedgering(crossedge, CCW);
+          enextfnextself(crossedge);
+          enextself(crossedge);
+          break;
+        }
+      }
+    } else {
+      hitbdry ++;
+      if (hitbdry >= 2) {
+        errorflag = 1;
+        break;
+      } else {
+        esym(starttet, spintet);
+      }
+    }
+  }
+  if (errorflag) {
+    // No cross edge be found. It may cause by co-circular points of this
+    //   facet(The Delaunay triangulation is not unique).
+    if (verbose > 1) {
+      printf("  No cross edge be found, return anyway.\n");
+    }
+    delete equatorpointlist;
+    delete missingfacelist;
+    delete crossedgelist;
+    return 0;
+  }
+  // Get all other cross edges.
+  if (verbose > 2) {
+    printf("    Queueing cross edge (%d, %d).\n",
+           pointmark(org(crossedge)), pointmark(dest(crossedge)));
+  }
+  crossedgelist->append(&crossedge);
+  // Walk around this edge, identifying all other incident cross edges.
+  //   Note: Here we should not hit boundry.
+  for (i = 0; i < crossedgelist->len(); i++) {
+    spintet = starttet = *(triface*)(*crossedgelist)[i];
+    while (fnextself(spintet)) {
+      if (apex(spintet) == apex(starttet)) {
+        break; // Rewind, can leave now.
+      }
+      // Grab other vertex of this face.
+      tother = apex(spintet);
+      // If vertex is not one of equators(and should not coplanar with
+      //   them), there's another bad edge here. Identify it and store it.
+      if (equatorpointlist->hasitem(&tother) == -1) {
+        // Find which edge is across the plane in spintet.
+        orient1 = iorient3d(torg, tdest, tapex, org(spintet));
+        orient2 = iorient3d(torg, tdest, tapex, tother);
+        crossedge = spintet;
+        if (orient1 != orient2) {
+          // edge tother and 'org' is the cross edge.
+          enext2self(crossedge);
+          esymself(crossedge);
+        } else {
+          // egde 'dest' and tother is the cross edge.
+          enextself(crossedge);
+          esymself(crossedge);
+        }
+        if (crossedgelist->hasitem(&crossedge) == -1) {
+          if (verbose > 2) {
+            printf("    Queueing cross edge (%d, %d).\n",
+                   pointmark(org(crossedge)), pointmark(dest(crossedge)));
+          }
+          crossedgelist->append(&crossedge);
+        }
+      }
+    }
+  }
+
+  // Step (3):
+  if (verbose > 2) {
+    printf("    Classify all the north and sourth points and\n");
+    printf("      identify all the cross(to be dead) tetrahedra.\n");
+  }
+  crosstetlist = new list(sizeof(triface));
+  crosstetlist->setcomp((compfunc) &compare2tets);
+  northpointlist = new list("point");
+  sourthpointlist = new list("point");
+
+  for (i = 0; i < crossedgelist->len(); i++) {
+    spintet = starttet = *(triface*)(*crossedgelist)[i];
+    orient1 = iorient3d(torg, tdest, tapex, org(spintet));
+    assert(orient1 != 0);
+    if (orient1 < 0) {
+      tnorth = org(spintet);
+      tsourth = dest(spintet);
+    } else { // orient1 > 0
+      tnorth = dest(spintet);
+      tsourth = org(spintet);
+    }
+    if (northpointlist->hasitem(&tnorth) == -1) {
+      if (verbose > 2) {
+        printf("    Queueing north point %d.\n", pointmark(tnorth));
+      }
+      northpointlist->append(&tnorth);
+    }
+    if (sourthpointlist->hasitem(&tsourth) == -1) {
+      if (verbose > 2) {
+        printf("    Queueing sourth point %d.\n", pointmark(tsourth));
+      }
+      sourthpointlist->append(&tsourth);
+    }
+    if (crosstetlist->hasitem(&spintet) == -1) {
+      if (verbose > 2) {
+        printf("    Queueing cross tet (%d, %d, %d, %d).\n",
+               pointmark(org(spintet)), pointmark(dest(spintet)),
+               pointmark(apex(spintet)), pointmark(oppo(spintet)));
+      }
+      crosstetlist->append(&spintet);
+    }
+    while (fnextself(spintet)) {
+      if (apex(spintet) == apex(starttet)) {
+        break; // Rewind, can leave now.
+      }
+      if (crosstetlist->hasitem(&spintet) == -1) {
+        if (verbose > 2) {
+          printf("    Queueing cross tet (%d, %d, %d, %d).\n",
+                 pointmark(org(spintet)), pointmark(dest(spintet)),
+                 pointmark(apex(spintet)), pointmark(oppo(spintet)));
+        }
+        crosstetlist->append(&spintet);
+      }
+    }
+  }
+
+  // Step (4):
+  if (verbose > 2) {
+    printf("    Identifying and classifying north and sourth casing faces.\n");
+  }
+  northcasinglist = new list(sizeof(triface));
+  sourthcasinglist = new list(sizeof(triface));
+
+  for (i = 0; i < crosstetlist->len(); i++) {
+    crosstet = *(triface*) (*crosstetlist)[i];
+    if (verbose > 2) {
+      printf("    Get cross tet (%d, %d, %d, %d).\n",
+             pointmark(org(crosstet)), pointmark(dest(crosstet)),
+             pointmark(apex(crosstet)), pointmark(oppo(crosstet)));
+    }
+    // Check each face of this crosstet to see if there exist casing face.
+    //   If a face's neighbour tet not in crosstetlist, then it's a casing
+    //   face. At the same time, find the inner subface if exist and delete
+    //   it, don't forget to protect subsegment before delete subface.
+    for (j = 0; j < 4; j++) {
+      crosstet.loc = j;
+      sym(crosstet, checkface);
+      tspivot(crosstet, checksh);
+      // Here checkface maybe hold 'dummytet'.
+      if (crosstetlist->hasitem(&checkface) == -1) {
+        // It's a casing face of the cavity.
+        adjustedgering(crosstet, CCW);
+        torg = org(crosstet);
+        tdest = dest(crosstet);
+        tapex = apex(crosstet);
+        if (checkface.tet == dummytet) {
+          // This side of crosstet is a boundary face, we need it.
+          //   Temporarily create a fake tetrahedron(oppo = null) for
+          //   holding the face. After re-generation, it will be removed.
+          maketetrahedron(&checkface);
+          checkface.loc = 0; // For sure.
+          setorg(checkface, tdest);
+          setdest(checkface, torg);
+          setapex(checkface, tapex);
+          // setoppo(checkface, NULL);
+          if (verbose > 2) {
+            printf("    Creating a fake tet for holding face(%d, %d, %d).\n",
+                   pointmark(tdest), pointmark(torg), pointmark(tapex));
+          }
+          // Temporarily bond them for later protect segments.
+          bond(checkface, crosstet);
+          if (checksh.sh != dummysh) {
+            sesymself(checksh);
+            tsbond(checkface, checksh);
+          }
+        }
+        adjustedgering(checkface, CCW);
+        if ((northpointlist->hasitem(&torg) >= 0) ||
+            (northpointlist->hasitem(&tdest) >= 0) ||
+            (northpointlist->hasitem(&tapex) >= 0)) {
+          if (verbose > 2) {
+            printf("    Queuing northcasing face (%d, %d, %d).\n",
+                   pointmark(org(checkface)), pointmark(dest(checkface)),
+                   pointmark(apex(checkface)));
+          }
+          northcasinglist->append(&checkface);
+        } else {
+          if (verbose > 2) {
+            printf("    Queuing sourthcasing face (%d, %d, %d).\n",
+                   pointmark(org(checkface)), pointmark(dest(checkface)),
+                   pointmark(apex(checkface)));
+          }
+          sourthcasinglist->append(&checkface);
+        }
+      } else {
+        // Its a inner face. Check if there exist(to be dead) subface.
+        if (checksh.sh != dummysh) {
+          assert(isnonsolid(checksh));
+          // Protect subsegment if there need.
+          findversion(&crosstet, &checksh, 0); // For same enext() direction.
+          edgecount = 0;
+          while (edgecount < 3) {
+            sspivot(checksh, checkshseg);
+            if (checkshseg.sh != dummysh) {
+              face tmpchecksh;
+              spivot(checkshseg, tmpchecksh);
+              if (tmpchecksh.sh == checksh.sh) {
+                // We must protect this subsegment, otherwise the pointer
+                //   in checkshseg will be invalid after deallocate checksh.
+                spintet = crosstet;
+                hitbdry = 0;
+                successbonded = 0;
+                while (true) {
+                  if (fnextself(spintet)) {
+                    if (apex(spintet) == apex(crosstet)) {
+                      break;
+                    }
+                    tspivot(spintet, tmpchecksh);
+                    if (tmpchecksh.sh != dummysh) {
+                      findversion(&tmpchecksh, &spintet);
+                      ssbond(tmpchecksh, checkshseg);
+                      successbonded = 1;
+                      break;
+                    }
+                  } else {
+                    hitbdry ++;
+                    if (hitbdry >= 2) {
+                      break;
+                    } else {
+                      esym(crosstet, spintet);
+                    }
+                  }
+                }
+                if (!successbonded) {
+                  // Can't find a exist subface to hold this subsegment.
+                  //   We must insert a new (nonsolid) subface which must
+                  //   be inserted at a face which its tet is not in
+                  //   crosstetlist.
+                  // Note:
+                  //   (1) If we find such face, still need check if it's
+                  //   a face of fake tet(oppo() = NULL), if so, we need
+                  //   insert the new subface at its real face side, so
+                  //   during the gift-wrapping stage, it will be bonded
+                  //   automatically and we can safely remove the fake tet.
+                  //   (2) If we can't find such face,
+                  spintet = crosstet;
+                  hitbdry = 0;
+                  while (true) {
+                    if (fnextself(spintet)) {
+                      if (apex(spintet) == apex(crosstet)) {
+                        break;
+                      }
+                      if (crosstetlist->hasitem(&spintet) == -1) {
+                        if (spintet.tet[7] == NULL) {
+                          // It's a fake tet. the subface should insert at
+                          //   its real face(that is, loc = 0).
+                          spintet.loc = 0;
+                          if (verbose > 2) {
+                            printf("    Creating a nonsolid subface at fake");
+                            printf(" tet (%d, %d %d)\n",
+                                   pointmark(org(spintet)),
+                                   pointmark(dest(spintet)),
+                                   pointmark(apex(spintet)));
+                          }
+                        } else {
+                          if (verbose > 2) {
+                            printf("    Creating a nonsolid subface at");
+                            printf(" casing tet (%d, %d, %d, %d)\n",
+                                   pointmark(org(spintet)),
+                                   pointmark(dest(spintet)),
+                                   pointmark(apex(spintet)),
+                                   pointmark(oppo(spintet)));
+                          }
+                        }
+                        if (verbose > 2) {
+                           printf("      for holding subsegment (%d, %d).\n",
+                                  pointmark(sorg(checkshseg)),
+                                  pointmark(sdest(checkshseg)));
+                        }
+                        insertsubface(&spintet, NONSOLIDFLAG, 1);
+                        successbonded = 1;
+                        break;
+                      }
+                    } else {
+                      hitbdry ++;
+                      if (hitbdry >= 2) {
+                        break;
+                      } else {
+                        esym(crosstet, spintet);
+                      }
+                    }
+                  }
+                  if (!successbonded) {
+                    // We can't find a face suitable for holding subsegment.
+                    //   Find a boundary face around this subsegment(spintet
+                    //   ) and create a fake tet at this face, then insert
+                    //   a new subface at this fake tet. We can sure, this
+                    //   fake tet will be added to casing face list later.
+                    triface tmpfaketet;
+                    int count = 1000;
+                    while (fnextself(spintet) && count) count--;
+                    if (count <= 0) {
+                      if (verbose) {
+                        printf("Warnning in recoverface():\n");
+                        printf("  We can't find a face suitable for holding");
+                        printf(" subsegment, skip anyway.\n");
+                      }
+                    } else {
+                      adjustedgering(spintet, CCW);
+                      torg = org(spintet);
+                      tdest = dest(spintet);
+                      tapex = apex(spintet);
+                      maketetrahedron(&tmpfaketet);
+                      tmpfaketet.loc = 0; // For sure.
+                      setorg(tmpfaketet, tdest);
+                      setdest(tmpfaketet, torg);
+                      setapex(tmpfaketet, tapex);
+                      // setoppo(tmpfaketet, NULL);
+                      if (verbose > 2) {
+                        printf("    Creating a fake tet for holding");
+                        printf(" subface (%d, %d, %d).\n", pointmark(tdest),
+                               pointmark(torg), pointmark(tapex));
+                      }
+                      bond(tmpfaketet, spintet);
+                      if (verbose > 2) {
+                        printf("    Creating a nonsolid subface (%d, %d, %d)\n",
+                               pointmark(torg), pointmark(tdest),
+                               pointmark(tapex));
+                        printf("      for holding subsegment (%d, %d).\n",
+                               pointmark(sorg(checkshseg)),
+                               pointmark(sdest(checkshseg)));
+                      }
+                      // Insert a new subface, and it will automatically bond
+                      //   the subsegment(set autobond flag be '1').
+                      insertsubface(&spintet, NONSOLIDFLAG, 1);
+                      successbonded = 1;
+                    }
+                  }
+                  // assert(successbonded);
+                }
+              }
+            }
+            senextself(checksh);
+            enextself(crosstet);
+            edgecount++;
+          }
+          // This subface can be dealloced now. Before dealloc, we must
+          //   dissolve it from two side tetrahedra.
+          tsdissolve(crosstet);
+          tsdissolve(checkface);
+          if (verbose > 2) {
+            printf("    Deleting subface (%d, %d, %d) (nonsolid).\n",
+                   pointmark(sorg(checksh)), pointmark(sdest(checksh)),
+                   pointmark(sapex(checksh)));
+          }
+          shellfacedealloc(&subfaces, checksh.sh);
+        }
+      }
+    }
+  }
+  assert(northcasinglist->len());
+  assert(sourthcasinglist->len());
+
+  // Step (5):
+  if (verbose > 2) {
+    printf("    Creating casing faces for missing faces(at equator).\n");
+  }
+  equatorcasinglist = new list(sizeof(triface));
+
+  for (i = 0; i < missingfacelist->len(); i++) {
+    iptr = (int*) (*missingfacelist)[i];
+    index = iptr[0] * 3;
+    iorg = out->trianglelist[index + edgeorient];
+    idest = out->trianglelist[index + plus1mod3[edgeorient]];
+    iapex = out->trianglelist[index + minus1mod3[edgeorient]];
+    torg = *(point3d*)(*pointlist)[iorg];
+    tdest = *(point3d*)(*pointlist)[idest];
+    tapex = *(point3d*)(*pointlist)[iapex];
+    maketetrahedron(&checkface);
+    orient1 = iorient3d(torg, tdest, tapex, tsourth);
+    assert(orient1 != 0);
+    if (orient1 < 0) {
+      setorg(checkface, torg);
+      setdest(checkface, tdest);
+    } else {
+      setorg(checkface, tdest);
+      setdest(checkface, torg);
+    }
+    setapex(checkface, tapex);
+    if (verbose > 2) {
+      printf("    Creating and queuing equatorcasing face (%d, %d, %d).\n",
+             pointmark(org(checkface)), pointmark(dest(checkface)),
+             pointmark(apex(checkface)));
+    }
+    equatorcasinglist->append(&checkface);
+  }
+  assert(equatorcasinglist->len());
+
+  // Step (6):
+  //   Generate giftfaces, giftpoints and giftpointdegrees at north side.
+  numberofgiftfaces = equatorcasinglist->len() + northcasinglist->len();
+  numberofgiftpoints = equatorpointlist->len() + northpointlist->len();
+  giftfaces = new triface[numberofgiftfaces];
+  giftpoints = new point3d[numberofgiftpoints];
+  // Create a backtrace list to keep all new tets be created during
+  //   gift-wrapping stage, so we can delete them if gift-wrapping failed.
+  backtracelist = new list(sizeof(triface));
+
+  //   Generate giftfaces.
+  for (i = 0; i < equatorcasinglist->len(); i++) {
+    giftfaces[i] = *(triface*)(*equatorcasinglist)[i];
+  }
+  for (j = i; j < numberofgiftfaces; j++) {
+    giftfaces[j] = *(triface*)(*northcasinglist)[j - i];
+    dissolve(giftfaces[j]);
+  }
+  //   Generate giftpoints.
+  for (i = 0; i < equatorpointlist->len(); i++) {
+    giftpoints[i] = *(point3d*)(*equatorpointlist)[i];
+  }
+  for (j = i; j < numberofgiftpoints; j++) {
+    giftpoints[j] = *(point3d*)(*northpointlist)[j - i];
+  }
+
+  errorflag = giftwrapping(numberofgiftfaces, giftfaces, numberofgiftpoints,
+                           giftpoints, NULL, 0, backtracelist);
+  if (errorflag == 0) {
+    if (verbose > 2) {
+      printf("    Badly, gift-wrapping failed, clear all new tets that");
+      printf(" created during gift-wrapping.\n");
+    }
+    for (i = 0; i < backtracelist->len(); i++) {
+      checkfaceptr = (triface*)(*backtracelist)[i];
+      if (verbose > 2) {
+        printf("    Deleting new tet (%d, %d, %d, %d).\n",
+               pointmark(org(*checkfaceptr)), pointmark(dest(*checkfaceptr)),
+               pointmark(apex(*checkfaceptr)), pointmark(oppo(*checkfaceptr)));
+      }
+      tetrahedrondealloc(checkfaceptr->tet);
+    }
+    if (!insertfieldpoint(numberofgiftfaces, giftfaces, numberofgiftpoints,
+                          giftpoints, crosstetlist)) {
+      printf("Internalerror in recoverface(): Insert field point failed.\n");
+      internalerror();
+    }
+  }
+
+  if (verbose > 2) {
+    printf("    Removing and replacing fake tets at equator with real tets.\n");
+  }
+  for (i = 0; i < equatorcasinglist->len(); i++) {
+    checkfaceptr = (triface*)(*equatorcasinglist)[i];
+    assert(oppo(*checkfaceptr) == (point3d) NULL);
+    sym(*checkfaceptr, starttet);
+    dissolve(starttet);
+    // Remove fake tet.
+    tetrahedrondealloc(checkfaceptr->tet);
+    // Replace fake tet with a real tet.
+    adjustedgering(starttet, CCW);
+    *checkfaceptr = starttet;
+    // Set a hit pointer in vertexs of face.
+    torg = org(starttet);
+    tdest = dest(starttet);
+    tapex = apex(starttet);
+    setpoint2tet(torg, encode(starttet));
+    setpoint2tet(tdest, encode(starttet));
+    setpoint2tet(tapex, encode(starttet));
+    if (verbose > 2) {
+      printf("    Changing (%d, %d, %d).\n",
+             pointmark(torg), pointmark(tdest), pointmark(tapex));
+    }
+  }
+  delete [] giftfaces;
+  delete [] giftpoints;
+  backtracelist->clear();
+
+  //   Generate giftfaces, giftpoints and giftpointdegrees at sourth side.
+  numberofgiftfaces = equatorcasinglist->len() + sourthcasinglist->len();
+  numberofgiftpoints = equatorpointlist->len() + sourthpointlist->len();
+  giftfaces = new triface[numberofgiftfaces];
+  giftpoints = new point3d[numberofgiftpoints];
+
+  //   Generate giftfaces.
+  for (i = 0; i < equatorcasinglist->len(); i++) {
+    giftfaces[i] = *(triface*)(*equatorcasinglist)[i];
+  }
+  for (j = i; j < numberofgiftfaces; j++) {
+    giftfaces[j] = *(triface*)(*sourthcasinglist)[j - i];
+    dissolve(giftfaces[j]);
+  }
+  //   Generate giftpoints.
+  for (i = 0; i < equatorpointlist->len(); i++) {
+    giftpoints[i] = *(point3d*)(*equatorpointlist)[i];
+  }
+  for (j = i; j < numberofgiftpoints; j++) {
+    giftpoints[j] = *(point3d*)(*sourthpointlist)[j - i];
+  }
+
+  errorflag = giftwrapping(numberofgiftfaces, giftfaces, numberofgiftpoints,
+                           giftpoints, NULL, 0, backtracelist);
+  if (errorflag == 0) {
+    if (verbose > 2) {
+      printf("    Badly, gift-wrapping failed, clear all new tets that");
+      printf(" created during gift-wrapping.\n");
+    }
+    for (i = 0; i < backtracelist->len(); i++) {
+      checkfaceptr = (triface*)(*backtracelist)[i];
+      if (verbose > 2) {
+        printf("    Deleting new tet (%d, %d, %d, %d).\n",
+               pointmark(org(*checkfaceptr)), pointmark(dest(*checkfaceptr)),
+               pointmark(apex(*checkfaceptr)), pointmark(oppo(*checkfaceptr)));
+      }
+      tetrahedrondealloc(checkfaceptr->tet);
+    }
+    if (!insertfieldpoint(numberofgiftfaces, giftfaces, numberofgiftpoints,
+                          giftpoints, crosstetlist)) {
+      printf("Internalerror in recoverface(): Generate field point failed.\n");
+      internalerror();
+    }
+  }
+
+  if (verbose > 2) {
+    printf("    Removing and replacing fake tets in north with dummytet.\n");
+  }
+  for (i = 0; i < northcasinglist->len(); i++) {
+    checkface = *(triface*)(*northcasinglist)[i];
+    if (oppo(checkface) == (point3d) NULL) {
+      if (verbose > 2) {
+        printf("    Changing (%d, %d, %d).\n",
+               pointmark(org(checkface)), pointmark(dest(checkface)),
+               pointmark(apex(checkface)));
+      }
+      sym(checkface, starttet);
+      dissolve(starttet);
+      tspivot(checkface, checksh);
+      if (checksh.sh != dummysh) {
+        stdissolve(checksh);
+      }
+      tetrahedrondealloc(checkface.tet);
+      checkface = starttet;
+    }
+    // Set a hit pointer in vertexs of face.
+    torg = org(checkface);
+    tdest = dest(checkface);
+    tapex = apex(checkface);
+    setpoint2tet(torg, encode(checkface));
+    setpoint2tet(tdest, encode(checkface));
+    setpoint2tet(tapex, encode(checkface));
+  }
+
+  if (verbose > 2) {
+    printf("    Removing and replacing fake tets in sourth with dummytet.\n");
+  }
+  for (i = 0; i < sourthcasinglist->len(); i++) {
+    checkface = *(triface*)(*sourthcasinglist)[i];
+    if (oppo(checkface) == (point3d) NULL) {
+      if (verbose > 2) {
+        printf("    Changing (%d, %d, %d).\n",
+               pointmark(org(checkface)), pointmark(dest(checkface)),
+               pointmark(apex(checkface)));
+      }
+      sym(checkface, starttet);
+      dissolve(starttet);
+      tspivot(checkface, checksh);
+      if (checksh.sh != dummysh) {
+        stdissolve(checksh);
+      }
+      tetrahedrondealloc(checkface.tet);
+      checkface = starttet;
+    }
+    // Set a hit pointer in vertexs of face.
+    torg = org(checkface);
+    tdest = dest(checkface);
+    tapex = apex(checkface);
+    setpoint2tet(torg, encode(checkface));
+    setpoint2tet(tdest, encode(checkface));
+    setpoint2tet(tapex, encode(checkface));
+  }
+
+  // We can delete all crosstets in crosstetlist.
+  for (i = 0; i < crosstetlist->len(); i++) {
+    crosstet = *(triface*)(*crosstetlist)[i];
+    if (verbose > 2) {
+      printf("    Deleting tet (%d, %d, %d, %d).\n",
+             pointmark(org(crosstet)), pointmark(dest(crosstet)),
+             pointmark(apex(crosstet)), pointmark(oppo(crosstet)));
+    }
+    tetrahedrondealloc(crosstet.tet);
+  }
+
+  delete [] giftfaces;
+  delete [] giftpoints;
+  delete missingfacelist;
+  delete crossedgelist;
+  delete crosstetlist;
+  delete equatorpointlist;
+  delete northpointlist;
+  delete sourthpointlist;
+  delete equatorcasinglist;
+  delete northcasinglist;
+  delete sourthcasinglist;
+  delete backtracelist;
+  return 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertfacet()     Force the facet of PLC existing in tetrahedralization.  //
+//                                                                           //
+// First, we need form a triangulation of the PSLG facet. Obviously, we can  //
+// not only consider the verteices of a facet given in the .poly or .smesh   //
+// file. Which vertices of the tetrahedralization need to be considered in a //
+// facet triangulation?  The answer can be found from Shewchuk's paper [6]:  //
+//   ...                                                                     //
+//   It is a fact, albeit somewhat nonintuitive, that if a facet appears in  //
+// a Delaunay tetrahedralization as a union of faces, then the triangulation //
+// of the facet is determined solely by the vertices of the tetrahedralizat- //
+// ion that lies in the plane of the facet.  If a vertex lies close to a     //
+// facet, but not in the same plane, it may cause a subfacet to be missing,  //
+// but it can not affect the shape of the triangulation if all subfacets are //
+// present. The detail please see Jonathan's Ph.D. thesis page 92.           //
+//   Hence the facet triangulation need only consider vertices lying in the  //
+// plane of the facet. Furthermore, because each facet is segment-bounded,   //
+// and segment are recovered (in the tetrahedralization) before facets, each //
+// facet triangulation can saftly ignore vertices that lie outside the facet //
+// (even in the same plane). The only addtional vertices to be considered    //
+// are those that were inserted on segments to force segments and other      //
+// facets into the mesh.                                                     //
+//   Unfortunately, if a facet triangulation is not unique because of        //
+// cocircularity degeneracies, then foregoing statement about extraplanar    //
+// vertices having no effect on the triangulation does not apply. To be      //
+// specific, suppose a facet triangulation has four or more cocircular       //
+// vertices, which are triangulate one way, whereas the tetrahedralization   //
+// contains a set of faces that triangulate the same vertices with a         //
+// diffrent (but also Delaunay) set of triangles. An aggressive implementat- //
+// ion might identify these cases and correct the facet triangulation so     //
+// that it matches the tetrahedralization (it is not always possible to      //
+// force the tetrahedralization to match the triangulation). However,        //
+// inserting a new vertex at the center of the collective circumcircle is    //
+// always available as a lazy alternative. Here I use the first method.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::insertfacet(list* facetseglist, list* holelist, int boundmark,
+                         int facenumber)
+{
+  list *pointlist, *conlist;
+  list *indexlist, *steinerlist;
+  queue *matchlist;
+  triface searchtet;
+  point3d torg, tdest, tapex, tfarapex;
+  point3d *segendpoints;
+  enum matchfaceresult match;
+  struct triangulateio in, out;
+  REAL norm[3], xaxi[3], yaxi[3];
+  REAL v0[3], v1[3], dsin;
+  REAL *holecoords;
+  int *indexofsegendpoints, *indexofconpoints;
+  int iorg, idest, iapex, ifarapex;
+  int edgeorient, isswapable, maxlooptimes;
+  int i, j, index;
+
+  // Set a pointlist and conlist for PSLG facet. 'pointlist' keep all the
+  //   pointers of points. 'conlist' keep each segment's endpoint index in
+  //   'pointlist'.
+  pointlist = new list("point");
+  conlist = new list(sizeof(int) * 2);
+
+  // First form a PSLG from the input 'facetseglist'.  Remeber, at this
+  //   time, every segment is existed in the domain and is represented by
+  //   a contiguous linear sequence of edges of the tetrahedralization. We
+  //   must get all the steiner vertexs in the segment not merely get the
+  //   segment's endpoints.
+  indexlist = new list(sizeof(int) * 2);
+  for (i = 0; i < facetseglist->len(); i++) {
+    segendpoints = (point3d*) (*facetseglist)[i];
+    indexofsegendpoints = (int*) indexlist->alloc();
+    if (segendpoints[1] == (point3d) NULL) {
+      // It's a isolate point in PSLG.
+      pointlist->append(&segendpoints[0]);
+      // We don't need this point's index.
+      indexofsegendpoints[0] = indexofsegendpoints[1] = -1;
+    } else {
+      indexofsegendpoints[0] = pointlist->hasitem(&segendpoints[0]);
+      if (indexofsegendpoints[0] == -1) {
+        pointlist->append(&segendpoints[0]);
+        indexofsegendpoints[0] = pointlist->len() - 1;
+      }
+      indexofsegendpoints[1] = pointlist->hasitem(&segendpoints[1]);
+      if (indexofsegendpoints[1] == -1) {
+        pointlist->append(&segendpoints[1]);
+        indexofsegendpoints[1] = pointlist->len() - 1;
+      }
+    }
+  }
+  // Get all steiner points in segments and make connection infomation.
+  steinerlist = new list("point", 10, 5);
+  for (i = 0; i < facetseglist->len(); i++) {
+    segendpoints = (point3d*) (*facetseglist)[i];
+    if (segendpoints[1] != (point3d) NULL) {
+      getsteinersinseg(segendpoints[0], segendpoints[1], steinerlist);
+      indexofsegendpoints = (int*) (*indexlist)[i];
+      indexofconpoints = (int*) conlist->alloc();
+      indexofconpoints[0] = indexofsegendpoints[0];
+      for (j = 0; j < steinerlist->len(); j++) {
+        pointlist->append((*steinerlist)[j]);
+        indexofconpoints[1] = pointlist->len() - 1;
+        indexofconpoints = (int*) conlist->alloc();
+        indexofconpoints[0] = pointlist->len() - 1;
+      }
+      indexofconpoints[1] = indexofsegendpoints[1];
+      steinerlist->clear();
+    }
+  }
+  delete steinerlist;
+  delete indexlist;
+
+  // Create the 2D mesh that will know what the correct subfaces are.
+  if (verbose > 1) {
+    printf("  Generate %d surface mesh: %d points, %d segments",
+           facenumber, pointlist->len(), conlist->len());
+    if (holelist) {
+      printf(", %d holes.", holelist->len());
+    }
+    printf("\n");
+  }
+  triangulateioinit(&in);
+  triangulateioinit(&out);
+  if ((pointlist->len() == 3) && (conlist->len() == 3)) {
+    // The facet is a triangle, this case we need not do surface mesh and
+    //   set the output mesh directly.
+    out.numberoftriangles = 1;
+    out.trianglelist = new int[3];
+    out.trianglelist[0] = 0;
+    out.trianglelist[1] = 1;
+    out.trianglelist[2] = 2;
+    out.neighborlist = new int[3];
+    out.neighborlist[0] = -1;
+    out.neighborlist[1] = -1;
+    out.neighborlist[2] = -1;
+  } else {
+    in.numberofpoints = pointlist->len();
+    in.pointlist = new REAL[in.numberofpoints * 2];
+    in.numberofsegments = conlist->len();
+    in.segmentlist = new int[in.numberofsegments * 2];
+    index = 0;
+    for (i = 0; i < in.numberofsegments; i ++) {
+      indexofconpoints = (int*) (*conlist)[i];
+      in.segmentlist[index++] = indexofconpoints[0];
+      in.segmentlist[index++] = indexofconpoints[1];
+    }
+    // Determine normal, we need find two not coliner vectors from
+    //   input points.
+    torg = *(point3d*)(*pointlist)[in.segmentlist[0]];
+    tdest = *(point3d*)(*pointlist)[in.segmentlist[1]];
+    Sub3D(tdest, torg, v0);
+    Normalize3D(v0);
+    index = 2;
+    dsin = 0;
+    for (i = 1; fabs(dsin) <= usertolerance; i++) {
+      torg = *(point3d*)(*pointlist)[in.segmentlist[index++]];
+      tdest = *(point3d*)(*pointlist)[in.segmentlist[index++]];
+      Sub3D(tdest, torg, v1);
+      Normalize3D(v1);
+      Cross3D(v0, v1, norm);
+      dsin = Mag3D(norm);
+      if (!(fabs(dsin) <= usertolerance)) Scale3D(norm, 1./dsin);
+      if (i >= in.numberofsegments) {
+        printf("Recover Error: Can't find normal for %d facet.\n", facenumber);
+        recovererror();
+      }
+    }
+    // Project onto a plane
+    Assign3D(v1, xaxi);
+    Cross3D(norm, xaxi, yaxi);
+    index = 0;
+    for (i = 0; i < in.numberofpoints; i ++) {
+      torg = *(point*)(*pointlist)[i];
+      in.pointlist[index++] = Dot3D(torg, xaxi);
+      in.pointlist[index++] = Dot3D(torg, yaxi);
+    }
+    if (holelist) {
+      if (holelist->len() > 0) {
+        in.numberofholes = holelist->len();
+        in.holelist = new REAL[in.numberofholes * 2];
+        index = 0;
+        for (i = 0; i < in.numberofholes; i++) {
+          holecoords = (REAL *) (*holelist)[i];
+          in.holelist[index++] = Dot3D(holecoords, xaxi);
+          in.holelist[index++] = Dot3D(holecoords, yaxi);
+        }
+      }
+    }
+    index = 0;
+    // Now create the 2D mesh.
+    surfmesh->triangulate(&in, &out, NULL);
+    if (surfmesh->triangles.items <= 0) {
+      printf("Recover error: Can't form a surface mesh for facet %d.\n",
+             facenumber);
+      recovererror();
+    }
+    if (verbose > 1) {
+      printf("  Surface mesh result: %d triangles.\n",
+             surfmesh->triangles.items);
+    }
+    surfmesh->trianglerestart();
+  }
+
+  // Set up a list to keep all the subface's index.
+  matchlist = new queue("int");
+  for (i = 0; i < out.numberoftriangles; i++) {
+    matchlist->push(&i);
+  }
+  // To recover each of faces by swapping.  In this case, though,
+  //   no point insertion is ever needed.
+  maxlooptimes = out.numberoftriangles * 4; // Set a emergency break times.
+  if (maxlooptimes <= 0) {
+    // int type Overflow, set it be the largest int number.
+    maxlooptimes = 0x7fffffff;
+  }
+  while (matchlist->get(&i) && maxlooptimes) {
+    maxlooptimes--;
+    index = i * 3;
+    iorg = out.trianglelist[index++];
+    idest = out.trianglelist[index++];
+    iapex = out.trianglelist[index++];
+    torg = *(point3d*)(*pointlist)[iorg];
+    tdest = *(point3d*)(*pointlist)[idest];
+    tapex = *(point3d*)(*pointlist)[iapex];
+    if (verbose > 1) {
+      printf("  Matching subface (%d, %d, %d).\n",
+             pointmark(torg), pointmark(tdest), pointmark(tapex));
+    }
+    edgeorient = 0;
+    searchtet.tet = dummytet;
+    match = matchface(torg, tdest, tapex, &searchtet, boundmark);
+    if (match == EDGEMISSING) {
+      // edge (torg, tdest) is missing. Check if other edges are missing.
+      searchtet.tet = dummytet;
+      match = matchface(tdest, tapex, torg, &searchtet, boundmark);
+      if (match == EDGEMISSING) {
+        searchtet.tet = dummytet;
+        match = matchface(tapex, torg, tdest, &searchtet, boundmark);
+        if (match == EDGEMISSING) {
+          // All edges of subface are missing. Push back to list to
+          //   handle it later.
+          matchlist->push(&i);
+          continue;
+        } else {
+          // edge (tapex, torg) exist, both other 2 edges are missing.
+          assert(match == APEXMISSING);
+          edgeorient = 2;
+        }
+      } else {
+        // edge (tdest, tapex) exist.
+        assert(match == APEXMISSING);
+        edgeorient = 1;
+      }
+    }
+    if (match == APEXMISSING) {
+      // Two edges are missing. Check if there exist degenerate case.
+      //   'searchtet' must be a handle of the exist edge.
+      ifarapex = getdiagonalapexindex(&out, i, plus1mod3[edgeorient]);
+      if (ifarapex != -1) {
+        // Before repair the degenerate case, we should ensure that the
+        //   new triangle is valid (it's three corners appear in counter-
+        //   clockwise direction). Sep. 5, 2001.
+        // Thanks Prof. Renato Cardoso Mesquita (renato@cpdee.ufmg.br).
+        isswapable = 1;
+        if (edgeorient == 0) {
+          if (orient2d(&(in.pointlist[iorg * 2]), &(in.pointlist[idest * 2]),
+                       &(in.pointlist[ifarapex * 2])) <= 0) {
+            isswapable = 0;
+          }
+        } else if (edgeorient == 1) {
+          if (orient2d(&(in.pointlist[idest * 2]), &(in.pointlist[iapex * 2]),
+                       &(in.pointlist[ifarapex * 2])) <= 0) {
+            isswapable = 0;
+          }
+        } else { // edgeorient == 2
+          if (orient2d(&(in.pointlist[iapex * 2]), &(in.pointlist[iorg * 2]),
+                       &(in.pointlist[ifarapex * 2])) <= 0) {
+            isswapable = 0;
+          }
+        }
+        if (isswapable) {
+          tfarapex = *(point3d*)(*pointlist)[ifarapex];
+          match = matchface(NULL, NULL, tfarapex, &searchtet, boundmark);
+          if (match == FACEMATCHING) {
+            swapdiagonal(&out, i, edgeorient, plus1mod3[edgeorient]);
+            continue;
+          }
+        }
+      }
+      ifarapex = getdiagonalapexindex(&out, i, minus1mod3[edgeorient]);
+      if (ifarapex != -1) {
+        // Before repair the degenerate case, we should ensure that the
+        //   new triangle is valid (it's three corners appear in counter-
+        //   clockwise direction). Sep. 5, 2001.
+        // Thanks Prof. Renato Cardoso Mesquita (renato@cpdee.ufmg.br).
+        isswapable = 1;
+        if (edgeorient == 0) {
+          if (orient2d(&(in.pointlist[iorg * 2]), &(in.pointlist[idest * 2]),
+                       &(in.pointlist[ifarapex * 2])) <= 0) {
+            isswapable = 0;
+          }
+        } else if (edgeorient == 1) {
+          if (orient2d(&(in.pointlist[idest * 2]), &(in.pointlist[iapex * 2]),
+                       &(in.pointlist[ifarapex * 2])) <= 0) {
+            isswapable = 0;
+          }
+        } else { // edgeorient == 2
+          if (orient2d(&(in.pointlist[iapex * 2]), &(in.pointlist[iorg * 2]),
+                       &(in.pointlist[ifarapex * 2])) <= 0) {
+            isswapable = 0;
+          }
+        }
+        if (isswapable) {
+          tfarapex = *(point3d*)(*pointlist)[ifarapex];
+          match = matchface(NULL, NULL, tfarapex, &searchtet, boundmark);
+          if (match == FACEMATCHING) {
+            swapdiagonal(&out, i, edgeorient, minus1mod3[edgeorient]);
+            continue;
+          }
+        }
+      }
+      // Subface is missing.
+      matchlist->push(&i);
+      // Recover the missing face.
+      recoverface(pointlist, &out, i, edgeorient);
+    }
+  }
+
+  if (maxlooptimes == 0) {
+    printf("Recover error in insertfacet():\n");
+    printf("  Failed to recover facet %d.\n", facenumber);
+    recovererror();
+  }
+  triangulateiodeinit(&in);
+  triangulateiodeinit(&out);
+  delete matchlist;
+  delete pointlist;
+  delete conlist;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// formskeleton()    Create the shell segments and subfaces of a triangula-  //
+//                   tion, including PLC edges, facets and facets on the     //
+//                   convex hull.                                            //
+//                                                                           //
+// The PLC edges and facets are read from a .poly or .smesh file. The return //
+// value is the number of facets in the file.                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::formskeleton(FILE *polyfile)
+{
+  list **seglist, **holelist;
+  point3d *segendpoints;
+  REAL *holecoords;
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  int *boundmarkers;
+  int facets, polygons, segments, inholes;
+  int facetmarkers;
+  int head, end1, end2, end3;
+  int i, j, k;
+
+  if (poly || smesh) {
+    // Read number of facets and number of boundary markers from a .poly or
+    //   .smesh file.
+    stringptr = readline(inputline, polyfile, inpolyfilename);
+    facets = (int) strtol (stringptr, &stringptr, 0);
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      facetmarkers = 0;
+    } else {
+      facetmarkers = (int) strtol (stringptr, &stringptr, 0);
+    }
+  } else {
+    facets = 0;
+  }
+
+  if (facets > 0) {
+    if (!quiet) {
+      printf("Inserting segments into Delaunay triangulation.\n");
+    }
+    // Compute a mapping from points to tetrahedra.
+    makepointmap();
+    // For each facet, create a list for keeping the endpoints of
+    //   segments of each facet, and create a list for keeping the
+    //   holes point (coordinates) of each facet.
+    boundmarkers = new int[facets];
+    seglist = new list*[facets];
+    holelist = new list*[facets];
+    for (i = 0; i < facets; i++) {
+      boundmarkers[i] = 0;
+      seglist[i] = NULL;
+      holelist[i] = NULL;
+    }
+
+    if (poly) {
+      // For each facet, read and insert all segments.
+      for (i = 1; i <= facets; i++) {
+        seglist[i - 1] = new list(sizeof(point3d) * 2);
+        // Read number of polygons, number of holes and boundary marker of
+        //   this facets.
+        // Note: I assume each polygon in facet at least has two endpoints.
+        stringptr = readline(inputline, polyfile, inpolyfilename);
+        polygons = (int) strtol (stringptr, &stringptr, 0);
+        stringptr = findfield(stringptr);
+        if (*stringptr == '\0') {
+          inholes = 0;
+          boundmarkers[i - 1] = 0;  // no boundary marker for this facet.
+        } else {
+          inholes = (int) strtol (stringptr, &stringptr, 0);
+          if (facetmarkers == 1) {
+            stringptr = findfield(stringptr);
+            if (*stringptr == '\0') {
+              boundmarkers[i - 1] = 0;  // no boundary marker for this facet.
+            } else {
+              boundmarkers[i - 1] = (int) strtol (stringptr, &stringptr, 0);
+            }
+          }
+        }
+
+        // For each polygon in this facet, raed and insert all segments.
+        for (j = 1; j <= polygons; j++) {
+          // Read number of segments of a polygon.
+          stringptr = readline(inputline, polyfile, inpolyfilename);
+          segments = (int) strtol (stringptr, &stringptr, 0);
+          if (segments <= 1) {
+            printf("File I/O Error:  Wrong vertex number of polygon %d", j);
+            printf(" in facet %d in %s.\n", i, inpolyfilename);
+            if (segments == 1) {
+              printf("  If you want define a isolate point in facet, you can\n");
+              printf("  define a degenrate segment(with two same endpoints)\n ");
+              printf("  in stead of.\n");
+            }
+            exit(1);
+          }
+          // Read and insert the segments.
+          stringptr = findfield(stringptr);
+          if (*stringptr == '\0') {
+            // Try load another non-empty line to continue
+            stringptr = readline(inputline, polyfile, inpolyfilename);
+            if (*stringptr == '\0') {
+              printf("File I/O Error:  No endpoints for polygon %d", j);
+              printf(" in facet %d in %s.\n", i, inpolyfilename);
+              exit(1);
+            } else {
+              head = end1 = (int) strtol (stringptr, &stringptr, 0);
+            }
+          } else {
+            head = end1 = (int) strtol (stringptr, &stringptr, 0);
+          }
+          for (k = 1; k < segments; k++) {
+            stringptr = findfield(stringptr);
+            if (*stringptr == '\0') {
+              // Try load another non-empty line to continue
+              stringptr = readline(inputline, polyfile, inpolyfilename);
+              if (*stringptr == '\0') {
+                printf("File I/O Error:  Missing %d endpoints for", segments - k);
+                printf(" polygon %d in facet %d in %s.\n", j, i, inpolyfilename);
+                exit(1);
+              } else {
+                end2 = (int) strtol (stringptr, &stringptr, 0);
+              }
+            } else {
+              end2 = (int) strtol (stringptr, &stringptr, 0);
+            }
+            if ((end1 < firstnumber) || (end1 >= firstnumber + inpoints)) {
+              if (!quiet) {
+                printf("Warning:  Invalid endpoint %d of polygon %d", k, j);
+                printf(" in facet %d in %s.\n", i, inpolyfilename);
+              }
+            } else if ((end2 < firstnumber) || (end2 >= firstnumber + inpoints)) {
+              if (!quiet) {
+                printf("Warning:  Invalid endpoint %d of polygon %d", k + 1, j);
+                printf(" in facet %d in %s.\n", i, inpolyfilename);
+              }
+            } else {
+              segendpoints = (point3d *) seglist[i - 1]->alloc();
+              segendpoints[0] = getpoint(end1);
+              segendpoints[1] = getpoint(end2);
+              if (segendpoints[0] == segendpoints[1]) {
+                if (segments == 2) {
+                  // A degenrate edge, it represent an isolate point in facet.
+                  segendpoints[1] = (point3d) NULL;
+                } else {
+                  printf("Warning:  Polygon %d has two identical endpoints", j);
+                  printf(" in facet %d in %s.\n", i, inpolyfilename);
+                }
+              } else {
+                insertsegment(segendpoints[0], segendpoints[1], boundmarkers[i-1]);
+              }
+            }
+            end1 = end2;
+          }
+          if (segments > 2) {
+            if (((end2 >= firstnumber) && (end2 < firstnumber + inpoints))
+                  && ((head >= firstnumber) && (head < firstnumber + inpoints))) {
+              segendpoints = (point3d *) seglist[i - 1]->alloc();
+              segendpoints[0] = getpoint(end2);
+              segendpoints[1] = getpoint(head);
+              if (segendpoints[0] == segendpoints[1]) {
+                if (segments == 2) {
+                  // A degenrate edge, it represent an isolate point in the facet.
+                  segendpoints[1] = (point3d) NULL;
+                } else {
+                  printf("Warning:  Polygon %d has two identical endpoints", j);
+                  printf(" in facet %d in %s.\n", i, inpolyfilename);
+                }
+              } else {
+                insertsegment(segendpoints[0], segendpoints[1], boundmarkers[i-1]);
+              }
+            }
+          }
+        }
+
+        // Read the holes' coordinates.
+        if (inholes > 0) {
+          holelist[i - 1] = new list(sizeof(REAL) * 3);
+          for (j = 1; j <= inholes; j++) {
+            holecoords = (REAL *) holelist[i - 1]->alloc();
+            stringptr = readline(inputline, polyfile, inpolyfilename);
+            stringptr = findfield(stringptr);
+            if (*stringptr == '\0') {
+              printf("File I/O Error:  Hole %d in facet %d", j, i);
+              printf(" has no coordinates in %s.\n", inpolyfilename);
+              exit(1);
+            } else {
+              holecoords[0] = (REAL) strtod (stringptr, &stringptr);
+            }
+            stringptr = findfield(stringptr);
+            if (*stringptr == '\0') {
+              printf("File I/O Error:  Hole %d in facet %d", j, i);
+              printf(" is missing its y-coordinate in %s.\n", inpolyfilename);
+              exit(1);
+            } else {
+              holecoords[1] = (REAL) strtod (stringptr, &stringptr);
+            }
+            stringptr = findfield(stringptr);
+            if (*stringptr == '\0') {
+              printf("File I/O Error:  Hole %d in facet %d", j, i);
+              printf(" is missing its z-coordinate in %s.\n", inpolyfilename);
+              exit(1);
+            } else {
+              holecoords[2] = (REAL) strtod (stringptr, &stringptr);
+            }
+          }
+        }
+      } // end inserting all segments loop.
+    } else if (smesh) {
+      // Read all input triangular facets and its boundary markers.
+      for (i = 1; i <= facets; i++) {
+        // Read three endpoints of this facet.
+        stringptr = readline(inputline, polyfile, insmeshfilename);
+        segments = (int) strtol (stringptr, &stringptr, 0);
+        if (segments <= 1) {
+          printf("File I/O Error:  Wrong vertex number of facet %d", i);
+          printf(" in %s.\n", insmeshfilename);
+          if (segments == 1) {
+            printf("  If you want define a isolate point in facet, you can\n");
+            printf("  define a degenrate segment(with two same endpoints)\n ");
+            printf("  in stead of.\n");
+          }
+          exit(1);
+        }
+        seglist[i - 1] = new list(sizeof(point3d) * 2, segments);
+        // In smesh files, we obtain facet's boundary mark at last.
+        boundmarkers[i-1] = 0;
+        // Read and insert the segments.
+        stringptr = findfield(stringptr);
+        if (*stringptr == '\0') {
+          // Try load another non-empty line to continue
+          stringptr = readline(inputline, polyfile, insmeshfilename);
+          if (*stringptr == '\0') {
+            printf("File I/O Error:  No endpoints for facet %d", i);
+            printf(" in %s.\n", insmeshfilename);
+            exit(1);
+          } else {
+            head = end1 = (int) strtol (stringptr, &stringptr, 0);
+          }
+        } else {
+          head = end1 = (int) strtol (stringptr, &stringptr, 0);
+        }
+        for (k = 1; k < segments; k++) {
+          stringptr = findfield(stringptr);
+          if (*stringptr == '\0') {
+            // Try load another non-empty line to continue
+            stringptr = readline(inputline, polyfile, inpolyfilename);
+            if (*stringptr == '\0') {
+              printf("File I/O Error:  Missing %d endpoints for", segments - k);
+              printf(" facet %d in %s.\n", i, insmeshfilename);
+              exit(1);
+            } else {
+              end2 = (int) strtol (stringptr, &stringptr, 0);
+            }
+          } else {
+            end2 = (int) strtol (stringptr, &stringptr, 0);
+          }
+          if ((end1 < firstnumber) || (end1 >= firstnumber + inpoints)) {
+            if (!quiet) {
+              printf("Warning:  Invalid endpoint %d of facet %d", k, i);
+              printf(" in %s.\n", insmeshfilename);
+            }
+          } else if ((end2 < firstnumber) || (end2 >= firstnumber + inpoints)) {
+            if (!quiet) {
+              printf("Warning:  Invalid endpoint %d of facet %d", k + 1, i);
+              printf(" in %s.\n", insmeshfilename);
+            }
+          } else {
+            segendpoints = (point3d *) seglist[i - 1]->alloc();
+            segendpoints[0] = getpoint(end1);
+            segendpoints[1] = getpoint(end2);
+            if (segendpoints[0] == segendpoints[1]) {
+              if (segments == 2) {
+                // A degenrate edge, it represent an isolate point in facet.
+                segendpoints[1] = (point3d) NULL;
+              } else {
+                printf("Warning:  Facet %d has two identical endpoints", i);
+                printf(" in %s.\n", insmeshfilename);
+              }
+            } else {
+              insertsegment(segendpoints[0], segendpoints[1], boundmarkers[i-1]);
+            }
+          }
+          end1 = end2;
+        }
+        if (segments > 2) {
+          if (((end2 >= firstnumber) && (end2 < firstnumber + inpoints))
+                && ((head >= firstnumber) && (head < firstnumber + inpoints))) {
+            segendpoints = (point3d *) seglist[i - 1]->alloc();
+            segendpoints[0] = getpoint(end2);
+            segendpoints[1] = getpoint(head);
+            if (segendpoints[0] == segendpoints[1]) {
+              if (segments == 2) {
+                // A degenrate edge, it represent an isolate point in the facet.
+                segendpoints[1] = (point3d) NULL;
+              } else {
+                printf("Warning:  Facet %d has two identical endpoints", i);
+                printf(" in %s.\n", insmeshfilename);
+              }
+            } else {
+              insertsegment(segendpoints[0], segendpoints[1], boundmarkers[i-1]);
+            }
+          }
+        }
+        // Read facet's boundary marker at last.
+        if (facetmarkers == 1) {
+          stringptr = findfield(stringptr);
+          if (*stringptr == '\0') {
+            boundmarkers[i - 1] = 0;  // no boundary marker for this facet.
+          } else {
+            boundmarkers[i - 1] = (int) strtol (stringptr, &stringptr, 0);
+          }
+        }
+      }
+    }
+
+    // At this point, we can sure there are no missing segments in the
+    //   tetrahedralization(that is: every segment is existed in the domain
+    //   and is represented by a contiguous linear sequence of edges of the
+    //   tetrahedralization).
+    if (!quiet) {
+      printf("Inserting facets into Delaunay triangulation.\n");
+    }
+    // Re-compute a mapping from points to tetrahedra.
+    makepointmap();
+    // Set up a 2D mesh object. Switches are chosen to read a PSLG (p),
+    //   numbers all items starting from zero (rather than one) (z),
+    //   generates a list of triangle neighbors (n), no terminal output
+    //   except errors (Q). suppresses use of exact arithmetic (X),
+    //   suppresses output of segments (P), suppresses node output (N).
+    // surfmesh = new mesh2d("pznQXPN");
+    surfmesh = new mesh2d("pznQPN");
+
+    for (i = 0; i < facets; i++) {
+      if (seglist[i]->len() > 2) {
+        insertfacet(seglist[i], holelist[i], boundmarkers[i], i + 1);
+      }
+      delete seglist[i];
+      if (holelist[i]) {
+        delete holelist[i];
+      }
+    }
+    delete [] boundmarkers;
+    delete [] seglist;
+    delete [] holelist;
+  }
+
+  return facets;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// Segment/Facet (Boundary) Constrained Routines.                            //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// Carving out Holes and Concavities Routines.                               //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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.            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::infecthull()
+{
+  triface tetloop, tsymtet;
+  tetrahedron **deadtet;
+  face hullface;
+  point3d horg, hdest, hapex;
+
+  if (verbose) {
+    printf("  Marking concavities (external tetrahedra) 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) || (isnonsolid(hullface))) {
+          // 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 (mark(hullface) == 0) {
+            setmark(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();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// plague()    Spread the virus from all infected tetrahedra to any          //
+//             neighbors not protected by subfaces.  Delete all infected     //
+//             tetrahedra.                                                   //
+//                                                                           //
+// This is the procedure that actually creates holes and concavities.        //
+//                                                                           //
+// This procedure operates in two phases.  The first phase 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.                                    //
+//                                                                           //
+// The second phase actually eliminates the infected tetrahedra.  It also    //
+// eliminates orphaned segments and points(not done now).                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::plague()
+{
+  triface testtet;
+  triface neighbor;
+  triface spintet, swaptet, livetet;
+  tetrahedron **virusloop;
+  tetrahedron **deadtet;
+  face neighborshell;
+  face testseg, testface;
+  point3d testpoint;
+  point3d norg, ndest, napex;
+  point3d deadorg, deaddest, deadapex, deadoppo;
+  int killseg, killorg;
+  int edgecount, successbonded, hitbdry;
+
+  if (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;
+    // A tetrahedron is marked as infected by messing with one of its
+    //   vertices(opposite), setting it to an illegal value.  Hence, we
+    //   have to temporarily uninfect this tetrahedron so that we can get
+    //   the proper vertex of this tetrahedron.
+    uninfect(testtet);
+    if (verbose > 2) {
+      // Assign the tetrahedron an orientation for convenience in
+      //   checking its points.
+      testtet.loc = 0;
+      deadorg = org(testtet);
+      deaddest = dest(testtet);
+      deadapex = apex(testtet);
+      deadoppo = oppo(testtet);
+      printf("    Checking (%d, %d, %d, %d)\n", pointmark(deadorg),
+             pointmark(deaddest), pointmark(deadapex), pointmark(deadoppo));
+    }
+    // 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, neighborshell);
+      // Check if the neighbor is nonexistent or already infected.
+      if ((neighbor.tet == dummytet) || infected(neighbor)) {
+        if (neighborshell.sh != dummysh) {
+          // There is a subface separating the tetrahedron from its neighbor,
+          //   but both tetrahedra are dying, so the subface dies too.
+          //   Before deallocte the subface, check each of the three sides
+          //   of the subface for preserving subsegments if there need. This
+          //   is done by spinning around each edge, checking if it is still
+          //   connected to at least one live tetrahedron.
+          neighborshell.shver = 0;
+          // For keep the same enext() direction.
+          findversion(&testtet, &neighborshell, 0);
+          for (edgecount = 0; edgecount < 3; edgecount++) {
+            sspivot(neighborshell, testseg);
+            if (testseg.sh != dummysh) {
+              spivot(testseg, testface);
+              if (testface.sh == neighborshell.sh) {
+                killseg = 1;
+                spintet = testtet;
+                successbonded = hitbdry = 0;
+                while (true) {
+                  if (fnextself(spintet)) {
+                    if (apex(spintet) == apex(testtet)) {
+                      break; // Rewind, can leave now.
+                    }
+                    if (spintet.tet == testtet.tet) {
+                      continue;
+                    }
+                    if (!infected(spintet)) {
+                      // A live tetrahedron.  The segment survives.
+                      killseg = 0;
+                      tspivot(spintet, testface);
+                      if (testface.sh == dummysh) {
+                        livetet = spintet;
+                        adjustedgering(livetet, CCW);
+                        fnextself(livetet);
+                        tspivot(livetet, testface);
+                      }
+                      if (testface.sh != dummysh) {
+                        findversion(&testface, &spintet);
+                        ssbond(testface, testseg);
+                        successbonded = 1;
+                        break;
+                      }
+                    }
+                  } else {
+                    hitbdry ++;
+                    if(hitbdry >= 2) {
+                      break;
+                    } else {
+                      esym(testtet, spintet);
+                    }
+                  }
+                }
+                if (killseg) {
+                  if (verbose > 1) {
+                    printf("  Deleting subsegment (%d, %d)\n",
+                           pointmark(sorg(testseg)),
+                           pointmark(sdest(testseg)));
+                  }
+                  shellfacedealloc(&subsegs, testseg.sh);
+                } else {
+                  if (!successbonded) {
+                    // Badly, We must insert a nonsolid subface for holding
+                    //   this subsegment; otherwise, it will missing after
+                    //   removing all infected tetrahedra.
+                    insertsubface(&livetet, NONSOLIDFLAG, 1);
+                    tspivot(livetet, testface);
+                    findversion(&testface, &testtet);
+                    ssbond(testface, testseg);
+                  }
+                }
+              }
+            }
+            senextself(neighborshell);
+            enextself(testtet);
+          }
+          shellfacedealloc(&subfaces, neighborshell.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 ((neighborshell.sh == dummysh) || (isnonsolid(neighborshell))) {
+          // There is no subface protecting the neighbor, so
+          //   the neighbor becomes infected.
+          if (verbose > 2) {
+            deadorg = org(neighbor);
+            deaddest = dest(neighbor);
+            deadapex = apex(neighbor);
+            deadoppo = oppo(neighbor);
+            printf("    Marking (%d, %d, %d, %d)\n", pointmark(deadorg),
+             pointmark(deaddest), pointmark(deadapex), pointmark(deadoppo));
+          }
+          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(neighborshell);
+          // The subface becomes a boundary.  Set markers accordingly.
+          if (mark(neighborshell) == 0) {
+            setmark(neighborshell, 1);
+          }
+          norg = org(neighbor);
+          ndest = dest(neighbor);
+          napex = apex(neighbor);
+          if (pointmark(norg) == 0) {
+            setpointmark(norg, 1);
+          }
+          if (pointmark(ndest) == 0) {
+            setpointmark(ndest, 1);
+          }
+          if (pointmark(napex) == 0) {
+            setpointmark(napex, 1);
+          }
+        }
+      }
+    }
+    // Remark the tetrahedron as infected, so it doesn't get added to the
+    //   virus pool again.
+    infect(testtet);
+    virusloop = (tetrahedron **) viri.traverse();
+  }
+
+  if (verbose) {
+    printf("  Deleting marked tetrahedra.\n");
+  }
+  viri.traversalinit();
+  virusloop = (tetrahedron **) viri.traverse();
+  while (virusloop != (tetrahedron **) NULL) {
+    testtet.tet = *virusloop;
+
+    // Check each of the four corners of the tetrahedron for elimination.
+    // To be finished...
+
+    // 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++;
+      }
+    }
+    // Return the dead tetrahedron to the pool of tetrahedra.
+    tetrahedrondealloc(testtet.tet);
+    virusloop = (tetrahedron **) viri.traverse();
+  }
+  // Empty the virus pool.
+  viri.restart();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// regionplague()    Spread regional attributes and/or volume constraints    //
+//                   (from a .poly file) throughout the mesh.                //
+//                                                                           //
+// This procedure operates in two phases.  The first phase spreads an        //
+// attribute and/or an volume constraint through a (segment-bounded) region. //
+// The tetrahedra are marked to ensure that each tetrahedra is added to the  //
+// virus pool only once, so the procedure will terminate.                    //
+//                                                                           //
+// The second phase uninfects all infected tetrahedra, returning them to     //
+// normal.                                                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::regionplague(REAL attribute, REAL volume)
+{
+  triface testtet;
+  triface neighbor;
+  tetrahedron **virusloop;
+  tetrahedron **regiontet;
+  face neighborshell;
+  point3d regionorg, regiondest, regionapex, regionoppo;
+
+  if (verbose > 1) {
+    printf("  Marking neighbors of marked tetrahedra.\n");
+  }
+  // Loop through all the infected tetrahedra, spreading the attribute
+  //   and/or volume constraint to their neighbors, then to their neighbors'
+  //   neighbors.
+  viri.traversalinit();
+  virusloop = (tetrahedron **) viri.traverse();
+  while (virusloop != (tetrahedron **) NULL) {
+    testtet.tet = *virusloop;
+    // A tetrahedron is marked as infected by messing with one of its
+    //   vertices(opposite), setting it to an illegal value.  Hence, we
+    //   have to temporarily uninfect this tetrahedron so that we can get
+    //   the proper vertex of this tetrahedron.
+    uninfect(testtet);
+    if (regionattrib) {
+      // Set an attribute.
+      setelemattribute(testtet.tet, eextras, attribute);
+    }
+    if (varvolume) {
+      // Set an volume constraint.
+      setvolumebound(testtet.tet, volume);
+    }
+    if (verbose > 2) {
+      // Assign the tetrahedron an orientation for convenience in
+      //   checking its points.
+      testtet.loc = 0;
+      regionorg = org(testtet);
+      regiondest = dest(testtet);
+      regionapex = apex(testtet);
+      regionoppo = oppo(testtet);
+      printf("    Checking (%d, %d, %d, %d)\n", pointmark(regionorg),
+        pointmark(regiondest), pointmark(regionapex), pointmark(regionoppo));
+    }
+    // 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, neighborshell);
+      // 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)
+          && ((neighborshell.sh == dummysh) || (isnonsolid(neighborshell)))) {
+        if (verbose > 2) {
+          regionorg = org(neighbor);
+          regiondest = dest(neighbor);
+          regionapex = apex(neighbor);
+          regionoppo = oppo(neighbor);
+          printf("    Marking (%d, %d, %d, %d)\n", pointmark(regionorg),
+            pointmark(regiondest), pointmark(regionapex), pointmark(regionoppo));
+        }
+        // Infect the neighbor.
+        infect(neighbor);
+        // Ensure that the neighbor's neighbors will be infected.
+        regiontet = (tetrahedron **) viri.alloc();
+        *regiontet = neighbor.tet;
+      }
+    }
+    // Remark the tetrahedron as infected, so it doesn't get added to the
+    //   virus pool again.
+    infect(testtet);
+    virusloop = (tetrahedron **) viri.traverse();
+  }
+
+  // Uninfect all tetrahedra.
+  if (verbose > 1) {
+    printf("  Unmarking marked tetrahedra.\n");
+  }
+  viri.traversalinit();
+  virusloop = (tetrahedron **) viri.traverse();
+  while (virusloop != (tetrahedron **) NULL) {
+    testtet.tet = *virusloop;
+    uninfect(testtet);
+    virusloop = (tetrahedron **) viri.traverse();
+  }
+  // Empty the virus pool.
+  viri.restart();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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 mesh3d::carveholes(REAL *holelist, int holes, REAL *regionlist,
+                        int regions)
+{
+  triface searchtet;
+  tetrahedron *tptr;
+  triface *holetets;
+  triface *regiontets;
+  tetrahedron **holetet;
+  tetrahedron **regiontet;
+  enum locateresult intersect;
+  int i;
+
+  if (!(quiet || (noholes && convex))) {
+    printf("Removing unwanted tetrahedra.\n");
+    if (verbose && (holes > 0)) {
+      printf("  Marking holes for elimination.\n");
+    }
+  }
+
+  if ((holes > 0) && !noholes) {
+    // Allocate storage for the tetrahedra in which hole points fall.
+    holetets = (triface *) new triface[holes];
+  }
+
+  if (regions > 0) {
+    // Allocate storage for the tetrahedra in which region points fall.
+    regiontets = (triface *) new triface[regions];
+  }
+
+  // Now, we have to find all the holes and regions BEFORE we infect hull
+  //   and carve the holes, because locate() won't work when there exist
+  //   infect tetrahedra and the tetrahedronlization is no longer convex.
+
+  if ((holes > 0) && !noholes) {
+    // Infect each tetrahedron 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 tetrahedron on the outer boundary.
+        searchtet.tet = dummytet;
+        searchtet.loc = 0;
+        symself(searchtet);
+        // Ensure that the hole is above the boundary face; otherwise,
+        //   locate() will falsely report that the hole falls within the
+        //   starting tetrahedron.
+        adjustedgering(searchtet, CCW);
+        if (isaboveplane(&searchtet, &holelist[i])) {
+          // Find a tetrahedron that contains the hole.
+          intersect = locate(&holelist[i], &searchtet);
+          if ((intersect != OUTSIDE) && (!infected(searchtet))) {
+            // Record the tetrahedron for processing carve hole.
+            holetets[i / 3] = searchtet;
+          }
+        }
+      }
+    }
+  }
+
+  if (regions > 0) {
+    // Find the starting tetrahedron for each region.
+    for (i = 0; i < regions; i++) {
+      regiontets[i].tet = dummytet;
+      // Ignore region points that aren't within the bounds of the mesh.
+      if ((regionlist[5 * i] >= xmin) && (regionlist[5 * i] <= xmax) &&
+          (regionlist[5 * i + 1] >= ymin) && (regionlist[5 * i + 1] <= ymax) &&
+          (regionlist[5 * i + 2] >= zmin) && (regionlist[5 * i + 2] <= zmax)) {
+        // Start searching from some tetrahedron on the outer boundary.
+        searchtet.tet = dummytet;
+        searchtet.loc = 0;
+        symself(searchtet);
+        // Ensure that the region point above the boundary  face; otherwise,
+        //   locate() will falsely report that the region point falls within
+        //   the starting tetrahedron.
+        adjustedgering(searchtet, CCW);
+        if (isaboveplane(&searchtet, &regionlist[5 * i])) {
+          // Find a tetrahedron that contains the region point.
+          intersect = locate(&regionlist[5 * i], &searchtet);
+          if ((intersect != OUTSIDE) && (!infected(searchtet))) {
+            // Record the tetrahedron for processing after the
+            //   holes have been carved.
+            regiontets[i] = searchtet;
+          }
+        }
+      }
+    }
+  }
+
+  if (((holes > 0) && !noholes) || !convex || (regions > 0)) {
+    // Initialize a pool of viri to be used for holes, concavities,
+    //   regional attributes, and/or regional volume constraints.
+    viri.init(sizeof(tetrahedron *), VIRUSPERBLOCK, POINTER, 0);
+  }
+
+  if (!convex) {
+    // Mark as infected any unprotected tetrahedra on the boundary.
+    //   This is one way by which concavities are created.
+    infecthull();
+  }
+
+  if ((holes > 0) && !noholes) {
+    // Infect the hole tetrahedron.  This is done by marking the
+    //  tetrahedron as infect and including the tetrahedron in
+    //  the virus pool.
+    for (i = 0; i < holes; i++) {
+      infect(holetets[i]);
+      holetet = (tetrahedron **) viri.alloc();
+      *holetet = holetets[i].tet;
+    }
+  }
+
+  if (viri.items > 0) {
+    // Carve the holes and concavities.
+    plague();
+  }
+  // The virus pool should be empty now.
+
+  if (regions > 0) {
+    if (!quiet) {
+      if (regionattrib) {
+        if (varvolume) {
+          printf("Spreading regional attributes and volume constraints.\n");
+        } else {
+          printf("Spreading regional attributes.\n");
+        }
+      } else {
+        printf("Spreading regional volume constraints.\n");
+      }
+    }
+    if (regionattrib && !refine) {
+      // Assign every tetrahedron a regional attribute of zero.
+      tetrahedrons.traversalinit();
+      tptr = tetrahedrontraverse();
+      while (tptr != (tetrahedron *) NULL) {
+        setelemattribute(tptr, eextras, 0.0);
+        tptr = tetrahedrontraverse();
+      }
+    }
+    for (i = 0; i < regions; 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 **) viri.alloc();
+          *regiontet = regiontets[i].tet;
+          // Apply one region's attribute and/or volume constraint.
+          regionplague(regionlist[5 * i + 3], regionlist[5 * i + 4]);
+          // The virus pool should be empty now.
+        }
+      }
+    }
+    if (regionattrib && !refine) {
+      // Note the fact that each tetrahedron has an additional attribute.
+      eextras++;
+    }
+  }
+
+  // Free up memory.
+  if (((holes > 0) && !noholes) || !convex || (regions > 0)) {
+    viri.deinit();
+  }
+  if ((holes > 0) && !noholes) {
+    delete [] holetets;
+  }
+  if (regions > 0) {
+    delete [] regiontets;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// Carving out Holes and Concavities Routines.                               //
+///////////////////////////////////////////////////////////////////////////////
diff --git a/Tetgen/defines.h b/Tetgen/defines.h
new file mode 100644
index 0000000000..289dec79ae
--- /dev/null
+++ b/Tetgen/defines.h
@@ -0,0 +1,175 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// defines.h    Header file for all the Tetgen source files needed.          //
+//              Defines switches (Optional) used at compilation time.        //
+//              Includes the most general used head files for all C/C++      //
+//              program code needed. Defines marcos used throughout all      //
+//              the source files.                                            //
+//                                                                           //
+// Tetgen Version 1.0 beta                                                   //
+// July, 2001                                                                //
+//                                                                           //
+// Si hang                                                                   //
+// Email: sihang@weboo.com                                                   //
+// http://www.weboo.com/sh/tetgen.htm                                        //
+//                                                                           //
+// You are free to use, copy and modify the sources under certain            //
+// circumstances, provided this copyright notice remains intact.             //
+// See the file LICENSE for details.                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef definesH
+#define definesH
+
+// If yours is not a Unix system,  define the  NO_TIMER  compiler  switch to
+//   remove the Unix-specific timing code.
+
+// #define NO_TIMER
+
+// Define to disable assertions. Generally the assert() operater only be
+//   used in developping stage, to catch the casual mistakes in programming.
+
+// #define NDEBUG
+
+// To insert lots of self-checks for internal errors, define the SELF_CHECK
+//   symbol.  This will slow down the program significantly.  It is best to
+//   define the symbol using the -DSELF_CHECK compiler switch, but you could
+//   write "#define SELF_CHECK" below.  If you are modifying this code, I
+//   recommend you turn self-checks on.
+
+// #define SELF_CHECK
+
+// For single precision ( which will save some  memory and  reduce paging ),
+//   define the symbol  SINGLE  by using the  -DSINGLE compiler switch or by
+//   writing "#define SINGLE" below.
+//
+// For double precision ( which will allow you to refine meshes to a smaller
+//   edge length), leave SINGLE undefined.
+//
+// Double precision  uses  more  memory,  but improves the resolution of the
+//   meshes you can  generate with Triangle.  It also reduces the likelihood
+//   of a  floating  exception due to overflow.   Finally, it is much faster
+//   than  single precision on  64-bit  architectures like the DEC Alpha.  I
+//   recommend double precision unless you want to generate a mesh for which
+//   you do not have enough memory.
+
+// #define SINGLE
+
+#ifdef SINGLE
+  #define REAL float
+#else
+  #define REAL double
+#endif 	// not defined SINGLE
+
+// numbers that speaks for theirself.
+
+#define PI 3.141592653589793238462643383279502884197169399375105820974944592308
+
+#define SQUAREROOTTWO 1.4142135623730950488016887242096980785696718753769480732
+
+#define ONETHIRD 0.333333333333333333333333333333333333333333333333333333333333
+
+// For efficiency, a variety of data structures are allocated in bulk.  The
+//   following constants determine how many of each structure is allocated
+//   at once.
+
+#define TRIPERBLOCK 4092           // Number of triangles allocated at once.
+#define SHELLEPERBLOCK 508       // Number of shell edges allocated at once.
+#define POINTPERBLOCK 4092            // Number of points allocated at once.
+#define VIRUSPERBLOCK 1020   // Number of virus triangles allocated at once.
+#define TETPERBLOCK 8188        // Number of tetrahedrons allocated at once.
+#define SUBFACEPERBLOCK 1020        // Number of subfaces allocated at once.
+#define SUBSEGPERBLOCK 1020      // Number of subsegments allocated at once.
+#define POINTPERBLOCK 4092            // Number of points allocated at once.
+// Number of encroached segments allocated at once.
+#define BADSEGMENTPERBLOCK 252
+// Number of encroached segments allocated at once.
+#define BADSHELLFACEPERBLOCK 508
+// Number of skinny triangles allocated at once.
+#define BADTRIPERBLOCK 4092
+// Number of skinny tetrahedras allocated at once.
+#define BADTETPERBLOCK 8188
+
+// The point marker DEADPOINT  is an arbitrary number chosen large enough to
+//   (hopefully) not conflict with user boundary markers.  Make sure that it
+//   is small enough to fit into your machine's integer size.
+
+#define DEADPOINT -1073741824
+
+// The nonsolid flag  NONSOLIDFLAG is an arbitrary number chosen large enou-
+//   gh to (hopefully)not conflict with user boundary markers.Make sure that
+//   it is small enough to fit into your machine's integer size.
+
+#define NONSOLIDFLAG  -1342177279
+
+// Maximum number of characters in a file name (including the null).
+
+#ifndef FILENAMESIZE
+  #define FILENAMESIZE 512
+#endif
+
+// Maximum number of characters in a line  read  from a file ( including the
+//   null).
+
+#ifndef INPUTLINESIZE
+  #define INPUTLINESIZE 512
+#endif
+
+// Constant for algorithms based on random sampling.  This constant
+//   have been chosen empirically to optimize its respective algorithms.
+
+// Used for the point location scheme of Mucke, Saias, and Zhu, to decide
+//   how large a random sample of triangles to inspect.
+#define SAMPLEFACTOR 11
+
+// Here is the most general used head files for all C/C++ program code
+//   needed.
+
+#include <stdio.h>                  // standard IO: FILE, NULL (*), EOF, ...
+#include <stdlib.h>        // standard lib: abort(), system(), getenv(), ...
+#include <string.h>        // declarations for string manipulation functions.
+#include <math.h>                     // math lib: sin(), sqrt(), pow(), ...
+#include <assert.h>
+#ifndef NO_TIMER
+  #include <sys/time.h>
+#else
+  #include <time.h>            // definitions/declarations for time routines.
+#endif // defined NO_TIMER
+#ifdef INTEL_MSC_TURBOC
+  #include <float.h>                 // some compilers will not need float.h.
+#endif // defined INTEL_MSC_TURBOC
+
+// If you will compile and run this code on Intel CPUs, Maybe there is some
+//   choices must be made by user to correctly execute Jonathan Schewck's
+//   code for arbitrary floating-point precision arithmetic and robust geom-
+//   etric predicates.  For more detail please see:
+//
+//            http://www.cs.cmu.edu/~quake/robust.pc.html.
+
+// If you use Microsoft C/C++ or TOURB C/C++ or BORLAND C/C++, define the
+//   symbol INTEL_MSC_TURBOC  by using -DINTEL_MSC_TURBOC compiler switch
+//   or by writing #define INTEL_MSC_TURBOC as follows.
+
+// #define INTEL_MSC_TURBOC
+
+// If you use gcc running under Linux, define the symbol INTEL_GCC_LINUX. Be
+//   sure to undefine the symbol INTEL_MSC_TURBOC.
+
+// #define INTEL_GCC_LINUX
+
+// If you use gcc but not running under linux, use the following symbol. Be
+//   sure to undefine the symbol INTEL_MSC_TURBOC and INTEL_GCC_LINUX.
+
+// #define INTEL_GCC
+
+// Routines for Arbitrary Precision Floating-point Arithmetic and Fast
+//   Robust Geometric Predicates.
+
+void exactinit();
+REAL orient2d(REAL* pa, REAL* pb, REAL* pc);
+REAL incircle(REAL* pa, REAL* pb, REAL* pc, REAL* pd);
+REAL orient3d(REAL* pa, REAL* pb, REAL* pc, REAL* pd);
+REAL insphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe);
+
+#endif // #ifndef definesH
diff --git a/Tetgen/linklist.cpp b/Tetgen/linklist.cpp
new file mode 100644
index 0000000000..24d9aa23cc
--- /dev/null
+++ b/Tetgen/linklist.cpp
@@ -0,0 +1,1149 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// linklist.cpp    Implement link, list, queue, stack, memorypool data types //
+//                 which declared in linklist.h.                             //
+//                                                                           //
+// Si hang                                                                   //
+// Email: sihang@weboo.com                                                   //
+// http://www.weboo.com/sh/tetgen.htm                                        //
+//                                                                           //
+// Please see linklist.h for a detail description.                           //
+//                                                                           //
+// You are free to use, copy and modify the sources under certain            //
+// circumstances, provided this copyright notice remains intact.             //
+// See the file LICENSE for details.                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>                             // Defined function printf().
+#include <stdlib.h>                             // Defined function qsort().
+#include <string.h>                 // Defined function strncmp(), strcmp().
+#include "linklist.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Predefined linar order functions for most primitive data types.           //                                                               //
+//                                                                           //
+// Return -1 if x < y; Return +1 if x > y; Return Zero if x == y.            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int compare2ints(const void* pi1, const void* pi2)
+{
+  if(*(int*)pi1 < *(int*)pi2) {
+    return -1;
+  } else if(*(int*)pi1 > *(int*)pi2) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+int compare2unsignedlongs(const void* pl1, const void* pl2)
+{
+  if(*(unsigned long*)pl1 < *(unsigned long*)pl2) {
+    return -1;
+  } else if(*(unsigned long*)pl1 > *(unsigned long*)pl2) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+int compare2chars(const void* pc1, const void* pc2)
+{
+  if(*(char*)pc1 < *(char*)pc2) {
+    return -1;
+  } else if(*(char*)pc1 > *(char*)pc2) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+int compare2strings(const void* pstr1, const void* pstr2)
+{
+  return strcmp(*(char**)pstr1, *(char**)pstr2);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// setpredefineddatatype()                                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void setpredefineddatatype(char* strdatatype, int *itembytes, compfunc *comp)
+{
+  if (strncmp(strdatatype, "int", 3) == 0) {
+    *itembytes = sizeof(int);
+    *comp = compare2ints;
+  } else if (strncmp(strdatatype, "unsigned long", 13) == 0) {
+    *itembytes = sizeof(unsigned long);
+    *comp = compare2unsignedlongs;
+  } else if (strncmp(strdatatype, "char", 4) == 0) {
+    *itembytes = sizeof(char);
+    *comp = compare2chars;
+  } else if (strncmp(strdatatype, "string", 6) == 0) {
+    *itembytes = sizeof(char*);
+    *comp = compare2strings;
+  } else if (strncmp(strdatatype, "point", 5) == 0) {
+    // This type is for my tetrahedra program used, actually type is REAL*.
+    *itembytes = sizeof(unsigned long);
+    *comp = compare2unsignedlongs;
+  } else {
+    printf("Sorry, this data type %s is unknown by list now.\n", strdatatype);
+    assert(0);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// class list implementation                                                 //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+list::list(char* strdatatype, int _maxitems, int _expandsize)
+{
+  int bytesofint = sizeof(int);
+
+  assert(strdatatype && (_maxitems > 0) && (_expandsize > 0));
+
+  comp = (compfunc) NULL;
+  setpredefineddatatype(strdatatype, &itembytes, &comp);
+  assert(comp && (itembytes > 0));
+
+  if(itembytes % bytesofint) {
+    itemints  = itembytes / bytesofint + 1;
+  } else {
+    itemints  = itembytes / bytesofint;
+  }
+
+  maxitems = _maxitems;
+  expandsize = _expandsize;
+  base = new void*[maxitems * itemints];
+  items = 0;
+}
+
+list::list(int _itembytes, int _maxitems, int _expandsize)
+{
+  assert((_itembytes > 0) && (_maxitems > 0) && (_expandsize > 0));
+
+  int bytesofint = sizeof(int);
+  itembytes = _itembytes;
+  if(itembytes % bytesofint) {
+    itemints  = itembytes / bytesofint + 1;
+  } else {
+    itemints  = itembytes / bytesofint;
+  }
+  comp = NULL;
+
+  maxitems = _maxitems;
+  expandsize = _expandsize;
+  base = new void*[maxitems * itemints];
+  items = 0;
+}
+
+list::~list()
+{
+  delete [] base;
+}
+
+list::list(list& src)
+{
+  assert(src.items > 0);
+  itembytes = src.itembytes;
+  itemints = src.itemints;
+  maxitems = src.maxitems;
+  expandsize = src.expandsize;
+  items = src.items;
+  base = new void*[maxitems * itemints];
+  memcpy(base, src.base, items * itemints * sizeof(int));
+}
+
+void* list::operator[](int index)
+{
+  assert(index >= 0 && index < items);
+  return (void*) (base + index * itemints);
+}
+
+void* list::getitem(int index)
+{
+  assert(index >= 0 && index < items);
+  return (void*) (base + index * itemints);
+}
+
+void* list::alloc()
+{
+  if (items == maxitems) {
+    // No space available, need re-allocate.
+    void **newbase = new void*[(maxitems + expandsize) * itemints];
+    memcpy(newbase, base, maxitems * itemints * sizeof(int));
+    delete [] base;
+    base = newbase;
+    maxitems += expandsize;
+  }
+  items++;
+  return (base + (items - 1) * itemints);
+}
+
+void list::append(void* newitem)
+{
+  if (items == maxitems) {
+    // No space available, need re-allocate.
+    void **newbase = new void*[(maxitems + expandsize) * itemints];
+    memcpy(newbase, base, maxitems * itemints * sizeof(int));
+    delete [] base;
+    base = newbase;
+    maxitems += expandsize;
+  }
+  memcpy((void*) (base + items * itemints), newitem, itembytes);
+  items++;
+}
+
+// Insert an item before index 'befireindex'. 'beforeindex' should be a
+//   value from 1 to listlength. If 'beforeindex' == listlength, insert
+//   operation is equal to append operation.
+
+void list::insert(int beforeindex, void* insertitem)
+{
+  assert(beforeindex > 0 && beforeindex <= items);
+  if (beforeindex == items) {
+    append(insertitem);
+    return;
+  }
+  if (items == maxitems) {
+    // No space available, need re-allocate.
+    void **newbase = new void*[(maxitems + expandsize) * itemints];
+    memcpy(newbase, base, maxitems * itemints * sizeof(int));
+    delete [] base;
+    base = newbase;
+    maxitems += expandsize;
+  }
+  // Do block move.
+  memmove((void*) (base + (beforeindex + 1) * itemints),   // dest
+          (void*) (base + beforeindex * itemints),         // src
+          (items - beforeindex) * itemints * sizeof(int)); // size in bytes
+  // Insert the insertitem.
+  memcpy((void*) (base + beforeindex * itemints), insertitem, itembytes);
+  items++;
+}
+
+// Delete an item from the list. 'deleteindex' should be a value from
+//   0 to listlength-1.
+
+void list::del(int deleteindex)
+{
+  assert(deleteindex >= 0 && deleteindex < items);
+  if (deleteindex != (items - 1)) {
+    // Do block move.
+    memmove((void*) (base + deleteindex * itemints),       // dest
+            (void*) (base + (deleteindex + 1) * itemints), // src
+            (items - deleteindex - 1) * itemints * sizeof(int));
+  }
+  items--;
+}
+
+// To remove a specific item from the list when its index is unknown. The
+//   value returned is the index of the item in the Items array before it
+//   was removed. After an item is removed, all the items that follow it
+//   are moved up in index position and the Count(items) is reduced by one.
+// If the Items array contains more than one copy of the pointer, only the
+//   first copy is deleted.
+
+int list::remove(void *removeitem)
+{
+  int index = hasitem(removeitem);
+  if (index != -1) {
+    del(index);
+  }
+  return index;
+}
+
+// Return 0 to listlength - 1 if 'checkitem' existed in list,
+// Return -1 if 'checkitem' not exist.
+
+int list::hasitem(void* checkitem)
+{
+  int i;
+
+  for (i = 0; i < items; i ++) {
+    if (comp) {
+      if ((*comp)((void*)(base + i * itemints), checkitem) == 0) return i;
+    } else {
+      if (compare2ints((void*)(base + i * itemints), checkitem) == 0) return i;
+    }
+  }
+  return -1;
+}
+
+// Return 0 to listlength - 1 if 'finditem' existed in list,
+// Return -1 if 'finditem' not exist.
+
+int list::indexof(void* finditem)
+{
+  return hasitem(finditem);
+}
+
+// Performs a QuickSort on the list based on the comparison function.
+
+void list::sort()
+{
+  qsort((void*)base, (size_t)items, (size_t)(itemints * sizeof(int)), comp);
+}
+
+void list::simplify()
+{
+  compfunc compare;
+  void *pathitem, *checkitem;
+  int i, j;
+
+  if(comp) {
+    compare = (compfunc) comp;
+  } else {
+    compare = (compfunc) compare2ints;  // Use default compare function.
+  }
+
+  for (i = 0; i < items; i++) {
+    pathitem = (*this)[i];
+    for (j = i + 1; j < items; j++) {
+      checkitem = (*this)[j];
+      if ((*compare)(pathitem, checkitem) == 0) {
+        del(j);
+        j--;
+      }
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// class list implementation                                                 //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// class link implementation                                                 //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                     Constructor, Destructor                               //
+///////////////////////////////////////////////////////////////////////////////
+
+link::link(char* strdatatype, int itemcount)
+{
+  int _itembytes;
+
+  assert(strdatatype && (itemcount > 0));
+
+  _itembytes = 0;
+  comp = (compfunc) NULL;
+  setpredefineddatatype(strdatatype, &_itembytes, &comp);
+  assert(comp && (_itembytes > 0));
+
+  poolinit(_itembytes, itemcount);
+  init();
+}
+
+link::link(int _itembytes, int itemcount)
+{
+  assert((_itembytes > 0) && (itemcount > 0));
+
+  poolinit(_itembytes, itemcount);
+  init();
+  comp = NULL;
+}
+
+link::~link()
+{
+  while (firstblock != (void**)NULL) {
+    nowblock = (void **) *firstblock;
+    delete [] firstblock;
+    firstblock = nowblock;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                        Member Functions                                   //
+///////////////////////////////////////////////////////////////////////////////
+
+void link::poolinit(int bytes, int itemcount)
+{
+  itembytes = bytes;
+  itemsperblock = itemcount;
+
+  int bytesofint = sizeof(int);
+  if(itembytes % bytesofint)
+    itemints  = itembytes / bytesofint + 1;
+  else
+    itemints  = itembytes / bytesofint;
+  // In double link, each items need 2 pointer spaces. So actually one
+  //   item's total space is: itemints + 2 (ints).
+  firstblock = new void*[1 + (itemints + 2) * itemsperblock];
+  *firstblock = (void*) NULL;
+  maxitems = itemsperblock;
+  poolrestart();
+}
+
+void link::poolrestart()
+{
+  // Set the currently active block.
+  nowblock = firstblock;
+  // Find the first item in the pool.  Increment by the size of (void *).
+  nextitem = (void*) (nowblock + 1);
+  // There are lots of unallocated items left in this block.
+  unallocateditems = itemsperblock;
+  // The stack of deallocated items is empty.
+  deaditemstack = (void*) NULL;
+}
+
+void* link::alloc()
+{
+  void *newitem;
+  void **newblock;
+
+  // First check the linked list of dead items.  If the list is not
+  //   empty, allocate an item from the list rather than a fresh one.
+  if (deaditemstack != (void *) NULL) {
+    newitem = deaditemstack;               // Take first item in list.
+    deaditemstack = * (void **) deaditemstack;
+  } else {
+    // Check if there are any free items left in the current block.
+    if (unallocateditems == 0) {
+      // Check if another block must be allocated.
+      if (*nowblock == (void *) NULL) {
+        // Allocate a new block of items, pointed to by the previous block.
+        newblock = new void*[1 + (itemints + 2) * itemsperblock];
+        *nowblock = (void *) newblock;
+        // The next block pointer is NULL.
+        *newblock = (void *) NULL;
+        maxitems += itemsperblock;
+      }
+      // Move to the new block.
+      nowblock = (void **) *nowblock;
+      // Find the first item in the block.
+      //   Increment by the size of (VOID *).
+      nextitem = (void *)(nowblock + 1);
+      // There are lots of unallocated items left in this block.
+      unallocateditems = itemsperblock;
+    }
+    // Allocate a new item.
+    newitem = nextitem;
+    // Advance `nextitem' pointer to next free item in block.
+    nextitem = (void *) ((void **) nextitem + itemints + 2);
+    unallocateditems--;
+  }
+
+  return newitem;
+}
+
+void link::dealloc(void* dyingitem)
+{
+  // Push freshly killed item onto stack.
+  *((void **) dyingitem) = deaditemstack;
+  deaditemstack = dyingitem;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                          Member Functions                                 //
+///////////////////////////////////////////////////////////////////////////////
+
+void link::init()
+{
+  head = (void**) alloc();
+  tail = (void**) alloc();
+  *head = (void*) tail;
+  *(head + 1) = NULL;
+  *tail = NULL;
+  *(tail + 1) = (void*) head;
+  nextlinkitem = *head;
+  curpos = 1;
+  items = 0;
+}
+
+int link::move(int i)
+{ // i > 0 move forward, i < 0 move backward.
+  void** nownode = (void**)nextlinkitem;
+  if(i > 0) {
+    int j = 0;
+    while((j < i) && *nownode) {
+      nownode = (void**)*nownode;
+      j++;
+    }
+    if((j > i) || !(*nownode)) return 0;
+    nextlinkitem = (void*)nownode;
+    curpos += i;
+  } else if(i < 0) {
+    int j = 0;
+    i = -i;
+    while((j < i) && *(nownode+1)) {
+      nownode = (void**)*(nownode+1);
+      j++;
+    }
+    if((j > i) || !(*(nownode+1))) return 0;
+    nextlinkitem = (void*)nownode;
+    curpos -= i;
+  }
+  return 1;
+}
+
+int link::locate(int i)
+{
+  if((i == 0) || (i > items)) return 0;
+
+  int headdist = i - 1, taildist = items - i, curdist = i - curpos;
+  int abscurdist = curdist >= 0 ? curdist : -curdist;
+
+  int mindist;
+  if(headdist > taildist) { // 1000
+    if(taildist > abscurdist) {
+      mindist = curdist;
+    } else {
+      // taildist <= abs(curdist)
+      mindist = -taildist;
+      goend();
+    }
+  } else { // 1000 else
+    // headdist <= taildist
+    if(headdist > abscurdist) {
+      mindist = curdist;
+    } else {
+      // headdist <= abs(curdist)
+      mindist = headdist;
+      rewind();
+    }
+  } // 1000
+
+  return move(mindist);
+}
+
+void link::add(void* elem)
+{
+  void **newnode = tail;
+  memcpy((void*)(newnode + 2), elem, itembytes);
+  tail = (void**) alloc();
+  // To do init jobs after 'new' operater
+  for(int i = 0; i < itemints + 2; i ++) {
+    *((int *) (tail + i))  = 0;
+  }
+  *tail = NULL;
+  *newnode = (void*) tail;
+  *(tail + 1) = (void*) newnode;
+  items++;
+}
+
+void link::insert(int index, void* elem)
+{
+  if(!locate(index)) assert(0);
+  void **nownode = (void**) nextlinkitem;
+
+  // Insert a node before 'nownode'.
+  void **newnode = (void**) alloc();
+  // To do init jobs after 'new' operater
+  for(int i = 0; i < itemints + 2; i ++) {
+    *((int *) (newnode + i))  = 0;
+  }
+  memcpy((void*)(newnode + 2), elem, itembytes);
+
+  *(void**)(*(nownode + 1)) = (void*)newnode;
+  *newnode = (void*) nownode;
+  *(newnode + 1) = *(nownode+1);
+  *(nownode + 1) = (void*)newnode;
+  items++;
+
+  nextlinkitem = (void*) newnode;
+}
+
+void link::del(int index)
+{
+  if(!locate(index)) assert(0);
+  void **deadnode = (void**)nextlinkitem;
+
+  // now delete the nownode
+  void **nextnode = (void**)*deadnode;
+  void **prevnode = (void**)*(deadnode + 1);
+  *prevnode = (void*)nextnode;
+  *(nextnode + 1) = (void*)prevnode;
+
+  dealloc((void*) deadnode);
+  items--;
+
+  nextlinkitem = (void*) nextnode;
+}
+
+void* link::getitem()
+{
+  if (nextlinkitem == (void*)tail) return NULL;
+  void **nownode = (void**)nextlinkitem;
+  nextlinkitem = *nownode;
+  curpos += 1;
+  return (void*)(nownode + 2);
+}
+
+void* link::getnitem(int n)
+{
+  if(!locate(n)) return NULL;
+  return (void*)((void**)nextlinkitem + 2);
+}
+
+void link::setnitem(int n, void* elem)
+{
+  assert(locate(n));
+  void **nownode = (void**) nextlinkitem;
+  // now set the nownode's data field with the new data
+  memcpy((void*)(nownode + 2), elem, itembytes);
+}
+
+int link::hasitem(void* testitem)
+{
+  void *pathitem;
+  int count;
+
+  rewind();
+  pathitem = getitem();
+  count = 0;
+  while (pathitem) {
+    count ++;
+    if (comp) {
+      if ((*comp)(pathitem, testitem) == 0) return count;
+    } else {
+      if (compare2ints(pathitem, testitem) == 0) return count;
+    }
+    pathitem = getitem();
+  }
+  return -1;
+}
+
+void link::sort()
+{
+  compfunc compare;
+  if(comp) {
+    compare = (compfunc) comp;
+  } else {
+    compare = (compfunc) compare2ints;  // Use default compare function.
+  }
+
+  unsigned char *table;
+  table = new unsigned char[items * itembytes];
+  rewind();
+  void *pathitem = getitem();
+  int count = 0;
+  while(pathitem) {
+    memcpy(&table[count * itembytes], pathitem, itembytes);
+    pathitem = getitem();
+    count ++;
+  }
+  if(count != items) assert(0);
+
+  qsort (table, (size_t) items, (size_t) itembytes, compare);
+
+  clear();
+  for(int i = 0; i < count; i ++) {
+    add(&table[i * itembytes]);
+  }
+  delete [] table;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// class link implementation                                                 //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// class queue implementation                                                //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+int queue::get(void* retitem)
+{
+  void* tmpitem = link::getnitem(1);
+  if(tmpitem == NULL) return 0;
+  memcpy(retitem, tmpitem, itembytes);
+  link::del(1);
+  return 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// class queue implementation                                                //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// class stack implementation                                                //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                     Constructor, Destructor                               //
+///////////////////////////////////////////////////////////////////////////////
+
+stack::stack(char* strdatatype, int _itemsperblock)
+{
+  int _itembytes;
+
+  assert(strdatatype && _itemsperblock > 0);
+
+  _itembytes = 0;
+  comp = (compfunc) NULL;
+  setpredefineddatatype(strdatatype, &_itembytes, &comp);
+  assert(comp && (_itembytes > 0));
+
+  init(_itembytes, _itemsperblock);
+}
+
+stack::stack(int _itembytes, int _itemsperblock)
+{
+  assert(_itembytes > 0 && _itemsperblock > 0);
+  init(_itembytes, _itemsperblock);
+  comp = NULL;
+}
+
+stack::~stack()
+{
+  while (firstblock != (void**)NULL) {
+    nowblock = (void **) *firstblock;
+    delete [] firstblock;
+    firstblock = nowblock;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                        Member Functions                                   //
+///////////////////////////////////////////////////////////////////////////////
+
+void stack::init(int bytes, int _itemsperblock)
+{
+  int bytesofint = sizeof(int);
+  itembytes = bytes;
+  if(itembytes % bytesofint)
+    itemints  = itembytes / bytesofint + 1;
+  else
+    itemints  = itembytes / bytesofint;
+  itemsperblock = _itemsperblock;
+  firstblock = new void*[2 + itemints*itemsperblock];
+  *firstblock = (void*) NULL;
+  *(firstblock + 1) = (void*) NULL;
+  restart();
+}
+
+void stack::restart()
+{
+  // clear items count
+  items = 0;
+  // find the maxitem's count we can save now.
+  maxitems = itemsperblock;
+  nowblock = firstblock;
+  while(*nowblock != (void*) NULL) {
+    maxitems += itemsperblock;
+    nowblock = (void**) *nowblock;
+  }
+  // Set the currently active block.
+  nowblock = firstblock;
+  // Find the first item in the pool.  Increment by the size of (void *).
+  top = (void*)(nowblock + 2);
+  // There are lots of unused items left in this block.
+  unuseditems = itemsperblock;
+}
+
+void stack::push(void* newitem)
+{
+  if( unuseditems == 0 ) {
+    // nowblock is out of space
+    if( items < maxitems ) {
+      // next block is available, just move to it
+      nowblock = (void**)*nowblock;
+    } else {
+      // we need allocte an new block for extend allocating space
+      void **newblock = new void*[2 + itemints*itemsperblock];
+      // set pointer to newblock and point back
+      *nowblock = (void*) newblock;
+      *newblock = (void*) NULL;
+      *(newblock + 1) = (void*) nowblock;
+      // move to newblock
+      nowblock = newblock;
+      // don't forget to extend maxitems
+      maxitems += itemsperblock;
+    }
+    top = (void*)(nowblock + 2);
+    // There are lots of unused items left in this block.
+    unuseditems = itemsperblock;
+  }
+  // save newitem
+  memcpy(top, newitem, itembytes);
+  items ++;
+  unuseditems --;
+  // move top to next available item
+  if(unuseditems) top = (void *) ((void **) top + itemints);
+}
+
+void* stack::topitem()
+{
+  if(items == 0) return NULL;
+  void* retitem;
+  if (unuseditems == 0) {
+    // this time need attention, because last Push() operator didn't move
+    // top to next block, so top is still point to the last pushed item
+    retitem = top;
+  } else if (unuseditems == itemsperblock) {
+    // this time need move back a block
+    void** prevblock = (void**)*(nowblock + 1);
+    // top is point to the last item of the block
+    retitem = (void*)(prevblock + 2 + itemints * (itemsperblock - 1));
+  } else {
+    // normal case in a block
+    retitem = (void*) ((void**) top - itemints);
+  }
+  return retitem;
+}
+
+int stack::pop(void* retitem)
+{
+  if(items == 0) return 0;
+  if(unuseditems == 0) {
+    // this time need attention, because last Push() operator didn't move
+    // top to next block, so top is still point to the last pushed item
+  } else if(unuseditems == itemsperblock){
+    // this time need move back a block
+    nowblock = (void**)*(nowblock + 1);
+    // top is point to the last item of the block
+    top = (void*)(nowblock + 2 + itemints * (itemsperblock - 1));
+    unuseditems = 0;
+  } else {
+    // normal case in a block
+    top = (void*) ((void**) top - itemints);
+  }
+  // get wanted item
+  memcpy(retitem, top, itembytes);
+  items --;
+  unuseditems ++;
+  return 1;
+}
+
+int stack::hasitem(void* testitem)
+{
+  void** pathblock = firstblock;
+  void* pathitem = (void*) (pathblock + 2);
+  int pathitemsleft = itemsperblock;
+
+  while(pathitem != top) {
+    // Check whether any untraversed items remain in the current block.
+    if (pathitemsleft == 0) {
+      // Find the next block.
+      pathblock = (void **) *pathblock;
+      // Find the first item in the block.  Increment by the size of (VOID *).
+      pathitem = (void *) (pathblock + 2);
+      // Set the number of items left in the current block.
+      pathitemsleft = itemsperblock;
+    }
+    if (comp) {
+      if ((*comp)(pathitem, testitem) == 0) return 1;
+    } else {
+      if (compare2ints(pathitem, testitem) == 0) return 1;
+    }
+    // Find the next item in the block.
+    pathitem = (void*) ((void**) pathitem + itemints);
+    pathitemsleft--;
+  }
+  return -1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// class stack implementation                                                //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// class memorypool implementation                                           //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+memorypool::memorypool()
+{
+  firstblock = nowblock = (void**) NULL;
+  nextitem = (void*) NULL;
+  deaditemstack = (void*) NULL;
+  pathblock = (void**) NULL;
+  pathitem = (void*) NULL;
+  itemwordtype = POINTER;
+  alignbytes = 0;
+  itembytes = itemwords = 0;
+  itemsperblock = 0;
+  items = maxitems = 0;
+  unallocateditems = 0;
+  pathitemsleft = 0;
+}
+
+memorypool::memorypool(int bytecount, int itemcount, enum wordtype wtype,
+  int alignment)
+{
+  assert(bytecount > 0 && itemcount > 0);
+  init(bytecount, itemcount, wtype, alignment);
+}
+
+memorypool::~memorypool()
+{
+  while (firstblock != (void **) NULL) {
+    nowblock = (void **) *(firstblock);
+    delete [] firstblock;
+    firstblock = nowblock;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// init()   Initialize a pool of memory for allocation of items.             //
+//                                                                           //
+// This routine initializes the machinery for allocating items.  A `pool' is //
+// created whose records have size at least `bytecount'. Items will be allo- //
+// cated in `itemcount'-item blocks. Each item is assumed to be a collection //
+// of words, and either pointers or floating-point values are assumed to be  //
+// the "primary" word type.  (The "primary" word type is used to determine   //
+// alignment of items.)  If `alignment' isn't zero, all items will be `alig- //
+// nment'-byte aligned in memory.  `alignment' must be either a multiple or  //
+// a factor of the primary word size; powers of two are safe. `alignment' is //
+// normally used to create a few unused bits at the bottom  of each item's   //
+// pointer, in which information may be stored.                              //
+//                                                                           //
+//  Don't change this routine unless you understand it.                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void memorypool::init(int bytecount, int itemcount, enum wordtype wtype,
+  int alignment)
+{
+  int wordsize;
+
+  // Initialize values in the pool.
+  itemwordtype = wtype;
+  wordsize = (itemwordtype == POINTER) ? sizeof(void *) : sizeof(REALTYPE);
+  // Find the proper alignment, which must be at least as large as:
+  //   - The parameter `alignment'.
+  //   - The primary word type, to avoid unaligned accesses.
+  //   - sizeof(void *), so the stack of dead items can be maintained
+  //       without unaligned accesses.
+  if (alignment > wordsize) {
+    alignbytes = alignment;
+  } else {
+    alignbytes = wordsize;
+  }
+  if (sizeof(void *) > alignbytes) {
+    alignbytes = sizeof(void *);
+  }
+  itemwords = ((bytecount + alignbytes - 1) / alignbytes)
+              * (alignbytes / wordsize);
+  itembytes = itemwords * wordsize;
+  itemsperblock = itemcount;
+
+  // Allocate a block of items.  Space for `itemsperblock' items and one
+  //   pointer (to point to the next block) are allocated, as well as space
+  //   to ensure alignment of the items.
+  firstblock = (void**)
+    (new BYTE[itemsperblock * itembytes + sizeof(void *) + alignbytes]);
+  // Set the next block pointer to NULL.
+  *firstblock = (void *) NULL;
+  restart();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// restart()   Deallocate all items in a pool.                               //
+//                                                                           //
+// The pool is returned to its starting state, except that no memory is      //
+// freed to the operating system.  Rather, the previously allocated blocks   //
+// are ready to be reused.                                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void memorypool::restart()
+{
+  unsigned long alignptr;
+
+  items = 0;
+  maxitems = 0;
+
+  // Set the currently active block.
+  nowblock = firstblock;
+  // Find the first item in the pool.  Increment by the size of (void *).
+  alignptr = (unsigned long) (nowblock + 1);
+  // Align the item on an `alignbytes'-byte boundary.
+  nextitem = (void *)
+    (alignptr + (unsigned long) alignbytes
+     - (alignptr % (unsigned long) alignbytes));
+  // There are lots of unallocated items left in this block.
+  unallocateditems = itemsperblock;
+  // The stack of deallocated items is empty.
+  deaditemstack = (void *) NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// deinit()   Free to the operating system all memory taken by a pool.       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void memorypool::deinit()
+{
+  while (firstblock != (void **) NULL) {
+    nowblock = (void **) *(firstblock);
+    delete [] firstblock;
+    firstblock = nowblock;
+  }
+
+  firstblock = nowblock = (void**) NULL;
+  nextitem = (void*) NULL;
+  deaditemstack = (void*) NULL;
+  pathblock = (void**) NULL;
+  pathitem = (void*) NULL;
+  itemwordtype = POINTER;
+  alignbytes = 0;
+  itembytes = itemwords = 0;
+  itemsperblock = 0;
+  items = maxitems = 0;
+  unallocateditems = 0;
+  pathitemsleft = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// alloc()   Allocate space for an item.                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void* memorypool::alloc()
+{
+  void *newitem;
+  void **newblock;
+  unsigned long alignptr;
+
+  // First check the linked list of dead items.  If the list is not
+  //   empty, allocate an item from the list rather than a fresh one.
+  if (deaditemstack != (void *) NULL) {
+    newitem = deaditemstack;               // Take first item in list.
+    deaditemstack = * (void **) deaditemstack;
+  } else {
+    // Check if there are any free items left in the current block.
+    if (unallocateditems == 0) {
+      // Check if another block must be allocated.
+      if (*(nowblock) == (void *) NULL) {
+        // Allocate a new block of items, pointed to by the previous block.
+        newblock = (void**)
+          (new BYTE[itemsperblock * itembytes + sizeof(void *) + alignbytes]);
+        *(nowblock) = (void *) newblock;
+        // The next block pointer is NULL.
+        *newblock = (void *) NULL;
+      }
+      // Move to the new block.
+      nowblock = (void **) *(nowblock);
+      // Find the first item in the block.
+      //   Increment by the size of (void *).
+      alignptr = (unsigned long) (nowblock + 1);
+      // Align the item on an `alignbytes'-byte boundary.
+      nextitem = (void *)
+        (alignptr + (unsigned long) alignbytes
+         - (alignptr % (unsigned long) alignbytes));
+      // There are lots of unallocated items left in this block.
+      unallocateditems = itemsperblock;
+    }
+    // Allocate a new item.
+    newitem = nextitem;
+    // Advance `nextitem' pointer to next free item in block.
+    if (itemwordtype == POINTER) {
+      nextitem = (void *) ((void **) nextitem + itemwords);
+    } else {
+      nextitem = (void *) ((REALTYPE *) nextitem + itemwords);
+    }
+    unallocateditems--;
+    maxitems++;
+  }
+  items++;
+  return newitem;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dealloc()     Deallocate space for an item.                               //
+//                                                                           //
+// The deallocated space is stored in a queue for later reuse.               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void memorypool::dealloc(void* dyingitem)
+{
+  // Push freshly killed item onto stack.
+  *((void **) dyingitem) = deaditemstack;
+  deaditemstack = dyingitem;
+  items--;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// traversalinit()    Prepare to traverse the entire list of items.          //
+//                                                                           //
+// This routine is used in conjunction with traverse().                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void memorypool::traversalinit()
+{
+  unsigned long alignptr;
+
+  // Begin the traversal in the first block.
+  pathblock = firstblock;
+  // Find the first item in the block.  Increment by the size of (void *).
+  alignptr = (unsigned long) (pathblock + 1);
+  // Align with item on an `alignbytes'-byte boundary.
+  pathitem = (void *)
+    (alignptr + (unsigned long) alignbytes
+     - (alignptr % (unsigned long) alignbytes));
+  // Set the number of items left in the current block.
+  pathitemsleft = itemsperblock;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// traverse()     Find the next item in the list.                            //
+//                                                                           //
+// This routine is used in conjunction with traversalinit().  Be forewarned  //
+// that this routine successively returns all items in the list, including   //
+// deallocated ones on the deaditemqueue. It's up to you to figure out which //
+// ones are actually dead.  Why?  I don't want to allocate extra space just  //
+// to demarcate dead items. It can usually be done more space-efficiently by //
+// a routine that knows something about the structure of the item.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void* memorypool::traverse()
+{
+  void *newitem;
+  unsigned long alignptr;
+
+  // Stop upon exhausting the list of items.
+  if (pathitem == nextitem) {
+    return (void *) NULL;
+  }
+  // Check whether any untraversed items remain in the current block.
+  if (pathitemsleft == 0) {
+    // Find the next block.
+    pathblock = (void **) *(pathblock);
+    // Find the first item in the block.  Increment by the size of (void *).
+    alignptr = (unsigned long) (pathblock + 1);
+    // Align with item on an `alignbytes'-byte boundary.
+    pathitem = (void *)
+      (alignptr + (unsigned long) alignbytes
+       - (alignptr % (unsigned long) alignbytes));
+    // Set the number of items left in the current block.
+    pathitemsleft = itemsperblock;
+  }
+  newitem = pathitem;
+  // Find the next item in the block.
+  if (itemwordtype == POINTER) {
+    pathitem = (void *) ((void **) pathitem + itemwords);
+  } else {
+    pathitem = (void *) ((REALTYPE *) pathitem + itemwords);
+  }
+  pathitemsleft--;
+  return newitem;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// class memorypool implementation                                           //
+///////////////////////////////////////////////////////////////////////////////
diff --git a/Tetgen/linklist.h b/Tetgen/linklist.h
new file mode 100644
index 0000000000..599b5f2115
--- /dev/null
+++ b/Tetgen/linklist.h
@@ -0,0 +1,470 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// linklist.h    Defines some commonly usefed data types, such as link, list //
+//               queue and stack, etc.                                       //
+//                                                                           //
+// Si hang                                                                   //
+// Email: sihang@weboo.com                                                   //
+// http://www.weboo.com/sh/tetgen.htm                                        //
+//                                                                           //
+// You are free to use, copy and modify the sources under certain            //
+// circumstances, provided this copyright notice remains intact.             //
+// See the file LICENSE for details.                                         //
+//                                                                           //
+//   A given programming language will have a number of data types available //
+// along with some operations on them. C/C++ include int, float/double, char,//
+// etc. We don't normally worry about how these datatypes and operations are //
+// implemented, but just know what we can do with them.  However, most real  //
+// programming tasks require more complex and sophisticated data types. If   //
+// the programming language we used doesn't provide them, we'll have to      //
+// define them ourself. Once we've defined such data types, we again don't   //
+// want to worry about how they're implemented, just know what operations    //
+// are allowed on that data type. There is huge range of reasonable courses, //
+// textbooks and online sources on data structures and algorithms[1][2][3]   //
+// [4][5].                                                                   //
+//                                                                           //
+//   In this file, we defined some basic and most useful data types in our   //
+// common programming task. They are list, (double) link, queue, stack and   //
+// memorypool. where memorypool is a special data type for deal with large   //
+// memory blocks and was frequently used in the Tetgen Mesh program. All the //
+// data types defined here can be used with arbitrary data types, include    //
+// built-in and user defined datatypes.                                      //
+//                                                                           //
+//   I didn't use the Standard Template Library (STL)[2] of C++ language     //
+// provided to implement these data types. Although the STL is powerful and  //
+// elegant. But it need all the data types be known at compilation time, so  //
+// it can not compile each data types to seperate object files (*.o) until   //
+// the real date types are constructed. And it duplicate code which will     //
+// increase the code length and compilation time.                            //
+//                                                                           //
+//   The basic idea for implementing arbitrary datatypes is to use the       //
+// generic pointer type of C++ 'void*'. LEDA[4]'s solution is to consider    //
+// a data structure whose containers have a slot for storing objects of a    //
+// type T, which T are not stored directly in the containers of the data     //
+// structure but on the heap. The data slots of the containers have type     //
+// 'void*', and contain pointers to the objects on the heap. Type casting is //
+// used to bridge the gap between the untyped world of the data slots (all   //
+// data is void*) and the typed world of the heap. So to implement a single  //
+// data types, there need 2 seperate classes in LEDA, one represents the     //
+// abstract data type (data slots) and the other represents the real data    //
+// type (data on the heap), these two classes can be compiled seperately     //
+// into object files (*.o) then link them together when in use.              //
+//                                                                           //
+//   My implementation was diffrent with LEDA's. As a fact, I implemented    //
+// the data slots directly on the heap (dynamic memory). Any data type is    //
+// internally represented by a set of bytes, the size of data type is        //
+// determined at running time. Use a pointer (type of void*) to access each  //
+// data slot. No type casing is needed, it is up to user to determinte which //
+// type is. This scheme simplified the implementation but less convient in   //
+// use than LEDA's. Users have to provide the size of data types to the      //
+// constructor and there still can not deal with some kinds of data types    //
+// (like a structure/class contains pointers as its member variables).       //
+// Anyway, I don't mean to provide more general data types at here, anybody  //
+// is welcome to make any improvement on it. Thank you.                      //
+//                                                                           //
+// References:                                                               //
+//                                                                           //
+// [1] A.V. Aho, J.E. Hopcroft, and J.D. Ullman. Data Structures and         //
+//     Algorithms. Addison-Wesley, 1983.                                     //
+// [2] Joseph Bergin, Joe Bergin, F. B. Schneider, Data Structure Programm-  //
+//     ing : With the Standard Template Library in C++ (Undergraduate Texts  //
+//     in Computer Science). Springer Verlag, June 1998.                     //
+// [3] Bruno R. Preiss, Data Structures and Algorithms with Object-Oriented  //
+//     Design Patterns in C++. John Wiley & Sons; August 31, 1998.           //
+// [4] K. Mehlhorn and S. Naher, The LEDA Platform of Combinatorial and      //
+//     Geometric Computing. Cambridge University Press, 1999.                //
+// [5] Data Structures and Algorithms, Online source,                        //
+//     http://www.cee.hw.ac.uk/~alison/ds.html.                              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef linklistH
+#define linklistH
+
+#ifndef NULL
+  #define NULL 0
+#endif
+
+#ifndef BYTE
+  #define BYTE char
+#endif
+
+#ifdef SINGLE
+  #define REALTYPE float
+#else
+  #define REALTYPE double
+#endif
+
+// Uncomment the following line to disable assertions.
+
+// #define NDEBUG
+
+#include <assert.h>
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Define a line-order function type, used in list, link.                    //
+//                                                                           //
+// A function: int cmp(const T &, const T &),  is said to realize a linear   //
+// order on the type T if there is a linear order <= on T such that for all  //
+// x and y in T satisfy the following relation:                              //
+//                                                                           //
+//                  -1  if x < y.                                            //
+//    comp(x, y) =   0  if x is equivalent to y.                             //
+//                  +1  if x > y.                                            //
+//                                                                           //
+// For many primitive data types (like int, unsigned long, ...) a function   //
+// compare is predefined and defines the so-called default ordering of the   //
+// type. The default ordering is the usual "less than or equal" for the      //
+// numerical types, the lexicographic ordering for strings, and the          //
+// lexicographic ordering of the Cartesian coordinates for points. For all   //
+// other types T there is no default ordering, and the user has to define    //
+// the function compare if a linear order on T is required.                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+typedef int (*compfunc) (const void *, const void *);
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Class list                                                                //
+//                                                                           //
+// Any data type list with dynamic re-allocation.                            //
+//                                                                           //
+// base-->  __________     list, which stores an array of pointers(void*),   //
+//         |_        _|    is ofen used to maintain lists of objects. list   //
+//         |_ data 0 _|    introduces properties and methods to:             //
+//         |__________|      > Add or delete the objects in the list.        //
+//         |_        _|      > Rearrange the objects in the list.            //
+//         |_ data 1 _|      > Locate and access objects in the list.        //
+//         |__________|      > Sort the objects in the list.                 //
+//         |_        _|                                                      //
+//         |_ data 2 _|    Note: The index of list is zero-based. Where 0 is //
+//         |__________|          the index of the first object, 1 is the     //
+//         |_        _|          index of second object, and so on.          //
+//         |_        _|                                                      //
+//         |__________|                                                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+class list {
+
+    void **base;
+    int  itembytes, itemints;
+    long items, maxitems;
+    long expandsize;
+    compfunc comp;
+
+  public:
+
+    list(char*, int _maxitems = 256, int _expandsize = 128);
+    list(int _itembytes, int _maxitems = 256, int _expandsize = 128);
+    list(list&);
+    ~list();
+
+    list& operator=(list&);
+    int  getitembytes() { return itembytes; }
+    int  getitemints() { return itemints; }
+    long getmaxitems() { return maxitems; }
+    long getexpandsize() { return expandsize; }
+    void setexpandsize(int size) { assert(size); expandsize = size; }
+    void setcomp(compfunc compf) { assert(compf); comp = compf; }
+
+    void *operator[](int index);
+    void *getitem(int index);
+    void clear() { items = 0; }
+    int  len() { return items; }
+    void *alloc();
+    void append(void*);
+    void insert(int, void*);
+    void del(int);
+    int  remove(void*);
+    int  hasitem(void*);
+    int  indexof(void*);
+    void sort();
+    void simplify();
+
+    friend void mergelist(list*, list*, list&, compfunc compf = NULL);
+    friend void splitlist(list*, int, list&, list&, compfunc compf = NULL);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Class link                                                                //
+//                                                                           //
+// Any data type double link list build on a memory pool.                    //
+//                                                                           //
+// This class's storage scheme is same with class memorypool. It implement a //
+// double link list on the pool. Item traverse is through pointers stored in //
+// each item's 'next' and 'prev' field.  So do not need traverseinit() and   //
+// traverse().                                                               //
+//                                                                           //
+//   head-> _________      _________      _________      _________<-tail     //
+//         |__next___|--> |__next___|--> |__next___|--> |__NULL___|          //
+//         |__NULL___|<-- |__prev___|<-- |__prev___|<-- |__prev___|          //
+//         |         |    |_       _|    |_       _|    |         |          //
+//         |         |    |_ Data1 _|    |_ Data2 _|    |         |          //
+//         |_________|    |_________|    |_________|    |_________|          //
+//                                                                           //
+//                                                                           //
+// Note: The index of link is one-based. Where 1 is the index of the first   //
+//       object, 2 is the index of second object, and so on. 0 is used to    //
+//       indicate a void link.                                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+class link {
+
+  protected:
+
+    void **firstblock, **nowblock;
+    void *nextitem;
+    void *deaditemstack;
+    int  itemsperblock;
+    int  unallocateditems;
+    long maxitems;
+
+    void **head, **tail;
+    void *nextlinkitem;
+    int  itembytes, itemints;
+    long items;
+    int  curpos;
+    compfunc comp;
+
+  protected:
+
+    void *alloc();
+    void dealloc(void*);
+    void poolinit(int, int);
+    void poolrestart();
+
+  public:
+
+    link(char*, int itemcount = 256);
+    link(int _itembytes, int itemcount = 256);
+    ~link();
+
+    int getitembytes() { return itembytes; }
+    int getitemints() { return itemints; }
+    void setcomp(compfunc compf) { assert(compf); comp = compf; }
+
+    void init();
+    void clear() { poolrestart(); init(); }
+    int  len() { return items; }
+    int  move(int);
+    int  locate(int);
+    void add(void*);
+    void insert(int, void*);
+    void del(int);
+    void rewind() { nextlinkitem = *head; curpos= 1; }
+    void goend() { nextlinkitem = *(tail+1); curpos = items; }
+    void *getitem();
+    void *getnitem(int);
+    void setnitem(int, void*);
+    int  hasitem(void*);
+    void sort();
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Class queue                                                               //
+//                                                                           //
+// Unbounded any data type queue with dynamic re-allocation.                 //
+//                                                                           //
+//                ___________     ___________     ___________                //
+//     Get() <-- |_         _|<--|_         _|<--|_         _| <-- Push()    //
+//               |_  Data0  _|   |_  Data1  _|   |_  Data2  _|               //
+//               |___________|   |___________|   |___________|               //
+//                                                                           //
+//                queue head                       queue tail                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Class queue Member Functions                                              //
+//                                                                           //
+// > Empty()                                                                 //
+//   Tests if queue is empty.                                                //
+// > Push()                                                                  //
+//   Adds a new top element (Stack and queue operation!).                    //
+// > Bot()                                                                   //
+//   Returns the bottom element (queue operation!) but does not remove it.   //
+// > Get()                                                                   //
+//   Returns the bottom element (queue operation!) and removes it.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+class queue : public link {
+
+  public:
+
+    queue(char* str, int itemcount = 256) : link(str, itemcount) {};
+    queue(int _itembytes, int itemcount = 256) : link(_itembytes, itemcount) {};
+
+    int  empty() { return items == 0; }
+    void push(void* newitem) { link::add(newitem); };
+    void *bot() { return link::getnitem(1); };
+    int  get(void*);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Class stack                                                               //
+//                                                                           //
+// Unbounded any data type stack with dynamic re-allocation.                 //
+//                                                                           //
+//           firstblock                         nowblock                     //
+//           __________       __________       __________                    //
+//          |__next____|---> |__next____|---> |__NULL____|                   //
+//          |__NULL____|<--- |__prev____|<--- |__prev____|                   //
+// Base---> |_        _|     |_        _|     |_        _|                   //
+//          |_ data 0 _|     |_ data 3 _|     |_ data 6 _|                   //
+//          |__________|     |__________|     |__________|                   //
+//          |_        _|     |_        _|     |_        _| <--- top          //
+//          |_ data 1 _|     |_ data 4 _|     |_        _|                   //
+//          |__________|     |__________|     |__________|                   //
+//          |_        _|     |_        _|     |_        _|                   //
+//          |_ data 2 _|     |_ data 5 _|     |_        _|                   //
+//          |__________|     |__________|     |__________|                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Class stack Member Functions                                              //
+//                                                                           //
+// > Clear()                                                                 //
+//   Clears the contents of stack.                                           //
+// > Empty()                                                                 //
+//   Tests if stack is empty.                                                //
+// > Top()                                                                   //
+//   Returns the top element (stack operation!) but does not pop it.         //
+// > Pop()                                                                   //
+//   Returns the top element (stack operation!) and pops it.                 //
+// > Push()                                                                  //
+//   Adds a new top element (stack and queue operation!).                    //
+// > Len()                                                                   //
+//   Returns the number of elements in stack.                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+class stack {
+
+    void **firstblock, **nowblock;
+    void *top;
+    int  itembytes, itemints;
+    int  itemsperblock;
+    int  unuseditems;
+    long items, maxitems;
+    compfunc comp;
+
+  public:
+
+    stack(char*, int _itemsperblock = 256);
+    stack(int _itembytes, int _itemsperblock = 256);
+    ~stack();
+
+    void setcomp(compfunc compf) { assert(compf); comp = compf; }
+
+    void init(int, int);
+    void restart();
+    int  len() { return items; }
+    int  empty() { return items == 0; }
+    void push(void*);
+    void *topitem();
+    int  pop(void*);
+    int  hasitem(void*);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Labels that signify whether a record consists primarily of pointers or of //
+//   floating-point words.  Used to make decisions about data alignment.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum wordtype {POINTER, FLOATINGPOINT};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// class memorypool                                                          //
+//                                                                           //
+// A type used to allocate memory.  firstblock is the first block of items.  //
+//   nowblock is the block from which items are currently being allocated.   //
+//   nextitem points to the next slab of free memory for an item.            //
+//   deaditemstack is the head of a linked list (stack) of deallocated items //
+//   that can be recycled.  unallocateditems is the number of items that     //
+//   remain to be allocated from nowblock.                                   //
+//                                                                           //
+// Traversal is the process of walking through the entire list of items, and //
+//   is separate from allocation.  Note that a traversal will visit items on //
+//   the "deaditemstack" stack as well as live items.  pathblock points to   //
+//   the block currently being traversed.  pathitem points to the next item  //
+//   to be traversed.  pathitemsleft is the number of items that remain to   //
+//   be traversed in pathblock.                                              //
+//                                                                           //
+// itemwordtype is set to POINTER or FLOATINGPOINT, and is used to suggest   //
+//   what sort of word the record is primarily made up of.  alignbytes       //
+//   determines how new records should be aligned in memory.  itembytes and  //
+//   itemwords are the length of a record in bytes (after rounding up) and   //
+//   words.  itemsperblock is the number of items allocated at once in a     //
+//   single block.  items is the number of currently allocated items.        //
+//   maxitems is the maximum number of items that have been allocated at     //
+//   once; it is the current number of items plus the number of records kept //
+//   on deaditemstack.                                                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// memorypool member functions:                                              //
+//                                                                           //
+// > init()                                                                  //
+//   Initialize a pool of memory for allocation of items.                    //
+// > restart()                                                               //
+//   Deallocate all items in a pool.                                         //
+// > alloc()                                                                 //
+//   Allocate space for an item.                                             //
+// > dealloc()                                                               //
+//   Deallocate space for an item.                                           //
+// > traversalinit()                                                         //
+//   Prepare to traverse the entire list of items.                           //
+// > traverse()                                                              //
+//   Find the next item in the list.                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+class memorypool {
+
+  public:
+
+    void **firstblock, **nowblock;
+    void *nextitem;
+    void *deaditemstack;
+    void **pathblock;
+    void *pathitem;
+    wordtype itemwordtype;
+    int  alignbytes;
+    int  itembytes, itemwords;
+    int  itemsperblock;
+    long items, maxitems;
+    int  unallocateditems;
+    int  pathitemsleft;
+
+  public:
+
+    memorypool();
+    memorypool(int, int, enum wordtype, int);
+    ~memorypool();
+
+    void init(int, int, enum wordtype, int);
+    void restart();
+    void deinit();
+    void *alloc();
+    void dealloc(void*);
+    void traversalinit();
+    void *traverse();
+};
+
+#endif // #ifndef linklistH
diff --git a/Tetgen/predicate.cpp b/Tetgen/predicate.cpp
new file mode 100644
index 0000000000..1fa2a405c1
--- /dev/null
+++ b/Tetgen/predicate.cpp
@@ -0,0 +1,2945 @@
+/*****************************************************************************/
+/*                                                                           */
+/*  Routines for Arbitrary Precision Floating-point Arithmetic               */
+/*  and Fast Robust Geometric Predicates                                     */
+/*  (predicates.c)                                                           */
+/*                                                                           */
+/*  May 18, 1996                                                             */
+/*                                                                           */
+/*  Placed in the public domain by                                           */
+/*  Jonathan Richard Shewchuk                                                */
+/*  School of Computer Science                                               */
+/*  Carnegie Mellon University                                               */
+/*  5000 Forbes Avenue                                                       */
+/*  Pittsburgh, Pennsylvania  15213-3891                                     */
+/*  jrs@cs.cmu.edu                                                           */
+/*                                                                           */
+/*  This file contains C implementation of algorithms for exact addition     */
+/*    and multiplication of floating-point numbers, and predicates for       */
+/*    robustly performing the orientation and incircle tests used in         */
+/*    computational geometry.  The algorithms and underlying theory are      */
+/*    described in Jonathan Richard Shewchuk.  "Adaptive Precision Floating- */
+/*    Point Arithmetic and Fast Robust Geometric Predicates."  Technical     */
+/*    Report CMU-CS-96-140, School of Computer Science, Carnegie Mellon      */
+/*    University, Pittsburgh, Pennsylvania, May 1996.  (Submitted to         */
+/*    Discrete & Computational Geometry.)                                    */
+/*                                                                           */
+/*  This file, the paper listed above, and other information are available   */
+/*    from the Web page http://www.cs.cmu.edu/~quake/robust.html .           */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  Using this code:                                                         */
+/*                                                                           */
+/*  First, read the short or long version of the paper (from the Web page    */
+/*    above).                                                                */
+/*                                                                           */
+/*  Be sure to call exactinit() once, before calling any of the arithmetic   */
+/*    functions or geometric predicates.  Also be sure to turn on the        */
+/*    optimizer when compiling this file.                                    */
+/*                                                                           */
+/*                                                                           */
+/*  Several geometric predicates are defined.  Their parameters are all      */
+/*    points.  Each point is an array of two or three floating-point         */
+/*    numbers.  The geometric predicates, described in the papers, are       */
+/*                                                                           */
+/*    orient2d(pa, pb, pc)                                                   */
+/*    orient2dfast(pa, pb, pc)                                               */
+/*    orient3d(pa, pb, pc, pd)                                               */
+/*    orient3dfast(pa, pb, pc, pd)                                           */
+/*    incircle(pa, pb, pc, pd)                                               */
+/*    incirclefast(pa, pb, pc, pd)                                           */
+/*    insphere(pa, pb, pc, pd, pe)                                           */
+/*    inspherefast(pa, pb, pc, pd, pe)                                       */
+/*                                                                           */
+/*  Those with suffix "fast" are approximate, non-robust versions.  Those    */
+/*    without the suffix are adaptive precision, robust versions.  There     */
+/*    are also versions with the suffices "exact" and "slow", which are      */
+/*    non-adaptive, exact arithmetic versions, which I use only for timings  */
+/*    in my arithmetic papers.                                               */
+/*                                                                           */
+/*                                                                           */
+/*  An expansion is represented by an array of floating-point numbers,       */
+/*    sorted from smallest to largest magnitude (possibly with interspersed  */
+/*    zeros).  The length of each expansion is stored as a separate integer, */
+/*    and each arithmetic function returns an integer which is the length    */
+/*    of the expansion it created.                                           */
+/*                                                                           */
+/*  Several arithmetic functions are defined.  Their parameters are          */
+/*                                                                           */
+/*    e, f           Input expansions                                        */
+/*    elen, flen     Lengths of input expansions (must be >= 1)              */
+/*    h              Output expansion                                        */
+/*    b              Input scalar                                            */
+/*                                                                           */
+/*  The arithmetic functions are                                             */
+/*                                                                           */
+/*    grow_expansion(elen, e, b, h)                                          */
+/*    grow_expansion_zeroelim(elen, e, b, h)                                 */
+/*    expansion_sum(elen, e, flen, f, h)                                     */
+/*    expansion_sum_zeroelim1(elen, e, flen, f, h)                           */
+/*    expansion_sum_zeroelim2(elen, e, flen, f, h)                           */
+/*    fast_expansion_sum(elen, e, flen, f, h)                                */
+/*    fast_expansion_sum_zeroelim(elen, e, flen, f, h)                       */
+/*    linear_expansion_sum(elen, e, flen, f, h)                              */
+/*    linear_expansion_sum_zeroelim(elen, e, flen, f, h)                     */
+/*    scale_expansion(elen, e, b, h)                                         */
+/*    scale_expansion_zeroelim(elen, e, b, h)                                */
+/*    compress(elen, e, h)                                                   */
+/*                                                                           */
+/*  All of these are described in the long version of the paper; some are    */
+/*    described in the short version.  All return an integer that is the     */
+/*    length of h.  Those with suffix _zeroelim perform zero elimination,    */
+/*    and are recommended over their counterparts.  The procedure            */
+/*    fast_expansion_sum_zeroelim() (or linear_expansion_sum_zeroelim() on   */
+/*    processors that do not use the round-to-even tiebreaking rule) is      */
+/*    recommended over expansion_sum_zeroelim().  Each procedure has a       */
+/*    little note next to it (in the code below) that tells you whether or   */
+/*    not the output expansion may be the same array as one of the input     */
+/*    expansions.                                                            */
+/*                                                                           */
+/*                                                                           */
+/*  If you look around below, you'll also find macros for a bunch of         */
+/*    simple unrolled arithmetic operations, and procedures for printing     */
+/*    expansions (commented out because they don't work with all C           */
+/*    compilers) and for generating random floating-point numbers whose      */
+/*    significand bits are all random.  Most of the macros have undocumented */
+/*    requirements that certain of their parameters should not be the same   */
+/*    variable; for safety, better to make sure all the parameters are       */
+/*    distinct variables.  Feel free to send email to jrs@cs.cmu.edu if you  */
+/*    have questions.                                                        */
+/*                                                                           */
+/*****************************************************************************/
+
+#include "defines.h"
+
+/* On some machines, the exact arithmetic routines might be defeated by the  */
+/*   use of internal extended precision floating-point registers.  Sometimes */
+/*   this problem can be fixed by defining certain values to be volatile,    */
+/*   thus forcing them to be stored to memory and rounded off.  This isn't   */
+/*   a great solution, though, as it slows the arithmetic down.              */
+/*                                                                           */
+/* To try this out, write "#define INEXACT volatile" below.  Normally,       */
+/*   however, INEXACT should be defined to be nothing.  ("#define INEXACT".) */
+
+#define INEXACT                          /* Nothing */
+/* #define INEXACT volatile */
+
+/* Which of the following two methods of finding the absolute values is      */
+/*   fastest is compiler-dependent.  A few compilers can inline and optimize */
+/*   the fabs() call; but most will incur the overhead of a function call,   */
+/*   which is disastrously slow.  A faster way on IEEE machines might be to  */
+/*   mask the appropriate bit, but that's difficult to do in C.              */
+
+#define Absolute(a)  ((a) >= 0.0 ? (a) : -(a))
+/* #define Absolute(a)  fabs(a) */
+
+/* Many of the operations are broken up into two pieces, a main part that    */
+/*   performs an approximate operation, and a "tail" that computes the       */
+/*   roundoff error of that operation.                                       */
+/*                                                                           */
+/* The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(),    */
+/*   Split(), and Two_Product() are all implemented as described in the      */
+/*   reference.  Each of these macros requires certain variables to be       */
+/*   defined in the calling routine.  The variables `bvirt', `c', `abig',    */
+/*   `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because   */
+/*   they store the result of an operation that may incur roundoff error.    */
+/*   The input parameter `x' (or the highest numbered `x_' parameter) must   */
+/*   also be declared `INEXACT'.                                             */
+
+#define Fast_Two_Sum_Tail(a, b, x, y) \
+  bvirt = x - a; \
+  y = b - bvirt
+
+#define Fast_Two_Sum(a, b, x, y) \
+  x = (REAL) (a + b); \
+  Fast_Two_Sum_Tail(a, b, x, y)
+
+#define Fast_Two_Diff_Tail(a, b, x, y) \
+  bvirt = a - x; \
+  y = bvirt - b
+
+#define Fast_Two_Diff(a, b, x, y) \
+  x = (REAL) (a - b); \
+  Fast_Two_Diff_Tail(a, b, x, y)
+
+#define Two_Sum_Tail(a, b, x, y) \
+  bvirt = (REAL) (x - a); \
+  avirt = x - bvirt; \
+  bround = b - bvirt; \
+  around = a - avirt; \
+  y = around + bround
+
+#define Two_Sum(a, b, x, y) \
+  x = (REAL) (a + b); \
+  Two_Sum_Tail(a, b, x, y)
+
+#define Two_Diff_Tail(a, b, x, y) \
+  bvirt = (REAL) (a - x); \
+  avirt = x + bvirt; \
+  bround = bvirt - b; \
+  around = a - avirt; \
+  y = around + bround
+
+#define Two_Diff(a, b, x, y) \
+  x = (REAL) (a - b); \
+  Two_Diff_Tail(a, b, x, y)
+
+#define Split(a, ahi, alo) \
+  c = (REAL) (splitter * a); \
+  abig = (REAL) (c - a); \
+  ahi = c - abig; \
+  alo = a - ahi
+
+#define Two_Product_Tail(a, b, x, y) \
+  Split(a, ahi, alo); \
+  Split(b, bhi, blo); \
+  err1 = x - (ahi * bhi); \
+  err2 = err1 - (alo * bhi); \
+  err3 = err2 - (ahi * blo); \
+  y = (alo * blo) - err3
+
+#define Two_Product(a, b, x, y) \
+  x = (REAL) (a * b); \
+  Two_Product_Tail(a, b, x, y)
+
+/* Two_Product_Presplit() is Two_Product() where one of the inputs has       */
+/*   already been split.  Avoids redundant splitting.                        */
+
+#define Two_Product_Presplit(a, b, bhi, blo, x, y) \
+  x = (REAL) (a * b); \
+  Split(a, ahi, alo); \
+  err1 = x - (ahi * bhi); \
+  err2 = err1 - (alo * bhi); \
+  err3 = err2 - (ahi * blo); \
+  y = (alo * blo) - err3
+
+/* Two_Product_2Presplit() is Two_Product() where both of the inputs have    */
+/*   already been split.  Avoids redundant splitting.                        */
+
+#define Two_Product_2Presplit(a, ahi, alo, b, bhi, blo, x, y) \
+  x = (REAL) (a * b); \
+  err1 = x - (ahi * bhi); \
+  err2 = err1 - (alo * bhi); \
+  err3 = err2 - (ahi * blo); \
+  y = (alo * blo) - err3
+
+/* Square() can be done more quickly than Two_Product().                     */
+
+#define Square_Tail(a, x, y) \
+  Split(a, ahi, alo); \
+  err1 = x - (ahi * ahi); \
+  err3 = err1 - ((ahi + ahi) * alo); \
+  y = (alo * alo) - err3
+
+#define Square(a, x, y) \
+  x = (REAL) (a * a); \
+  Square_Tail(a, x, y)
+
+/* Macros for summing expansions of various fixed lengths.  These are all    */
+/*   unrolled versions of Expansion_Sum().                                   */
+
+#define Two_One_Sum(a1, a0, b, x2, x1, x0) \
+  Two_Sum(a0, b , _i, x0); \
+  Two_Sum(a1, _i, x2, x1)
+
+#define Two_One_Diff(a1, a0, b, x2, x1, x0) \
+  Two_Diff(a0, b , _i, x0); \
+  Two_Sum( a1, _i, x2, x1)
+
+#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \
+  Two_One_Sum(a1, a0, b0, _j, _0, x0); \
+  Two_One_Sum(_j, _0, b1, x3, x2, x1)
+
+#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \
+  Two_One_Diff(a1, a0, b0, _j, _0, x0); \
+  Two_One_Diff(_j, _0, b1, x3, x2, x1)
+
+#define Four_One_Sum(a3, a2, a1, a0, b, x4, x3, x2, x1, x0) \
+  Two_One_Sum(a1, a0, b , _j, x1, x0); \
+  Two_One_Sum(a3, a2, _j, x4, x3, x2)
+
+#define Four_Two_Sum(a3, a2, a1, a0, b1, b0, x5, x4, x3, x2, x1, x0) \
+  Four_One_Sum(a3, a2, a1, a0, b0, _k, _2, _1, _0, x0); \
+  Four_One_Sum(_k, _2, _1, _0, b1, x5, x4, x3, x2, x1)
+
+#define Four_Four_Sum(a3, a2, a1, a0, b4, b3, b1, b0, x7, x6, x5, x4, x3, x2, \
+                      x1, x0) \
+  Four_Two_Sum(a3, a2, a1, a0, b1, b0, _l, _2, _1, _0, x1, x0); \
+  Four_Two_Sum(_l, _2, _1, _0, b4, b3, x7, x6, x5, x4, x3, x2)
+
+#define Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b, x8, x7, x6, x5, x4, \
+                      x3, x2, x1, x0) \
+  Four_One_Sum(a3, a2, a1, a0, b , _j, x3, x2, x1, x0); \
+  Four_One_Sum(a7, a6, a5, a4, _j, x8, x7, x6, x5, x4)
+
+#define Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, x9, x8, x7, \
+                      x6, x5, x4, x3, x2, x1, x0) \
+  Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b0, _k, _6, _5, _4, _3, _2, \
+                _1, _0, x0); \
+  Eight_One_Sum(_k, _6, _5, _4, _3, _2, _1, _0, b1, x9, x8, x7, x6, x5, x4, \
+                x3, x2, x1)
+
+#define Eight_Four_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b4, b3, b1, b0, x11, \
+                       x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0) \
+  Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, _l, _6, _5, _4, _3, \
+                _2, _1, _0, x1, x0); \
+  Eight_Two_Sum(_l, _6, _5, _4, _3, _2, _1, _0, b4, b3, x11, x10, x9, x8, \
+                x7, x6, x5, x4, x3, x2)
+
+/* Macros for multiplying expansions of various fixed lengths.               */
+
+#define Two_One_Product(a1, a0, b, x3, x2, x1, x0) \
+  Split(b, bhi, blo); \
+  Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \
+  Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \
+  Two_Sum(_i, _0, _k, x1); \
+  Fast_Two_Sum(_j, _k, x3, x2)
+
+#define Four_One_Product(a3, a2, a1, a0, b, x7, x6, x5, x4, x3, x2, x1, x0) \
+  Split(b, bhi, blo); \
+  Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \
+  Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \
+  Two_Sum(_i, _0, _k, x1); \
+  Fast_Two_Sum(_j, _k, _i, x2); \
+  Two_Product_Presplit(a2, b, bhi, blo, _j, _0); \
+  Two_Sum(_i, _0, _k, x3); \
+  Fast_Two_Sum(_j, _k, _i, x4); \
+  Two_Product_Presplit(a3, b, bhi, blo, _j, _0); \
+  Two_Sum(_i, _0, _k, x5); \
+  Fast_Two_Sum(_j, _k, x7, x6)
+
+#define Two_Two_Product(a1, a0, b1, b0, x7, x6, x5, x4, x3, x2, x1, x0) \
+  Split(a0, a0hi, a0lo); \
+  Split(b0, bhi, blo); \
+  Two_Product_2Presplit(a0, a0hi, a0lo, b0, bhi, blo, _i, x0); \
+  Split(a1, a1hi, a1lo); \
+  Two_Product_2Presplit(a1, a1hi, a1lo, b0, bhi, blo, _j, _0); \
+  Two_Sum(_i, _0, _k, _1); \
+  Fast_Two_Sum(_j, _k, _l, _2); \
+  Split(b1, bhi, blo); \
+  Two_Product_2Presplit(a0, a0hi, a0lo, b1, bhi, blo, _i, _0); \
+  Two_Sum(_1, _0, _k, x1); \
+  Two_Sum(_2, _k, _j, _1); \
+  Two_Sum(_l, _j, _m, _2); \
+  Two_Product_2Presplit(a1, a1hi, a1lo, b1, bhi, blo, _j, _0); \
+  Two_Sum(_i, _0, _n, _0); \
+  Two_Sum(_1, _0, _i, x2); \
+  Two_Sum(_2, _i, _k, _1); \
+  Two_Sum(_m, _k, _l, _2); \
+  Two_Sum(_j, _n, _k, _0); \
+  Two_Sum(_1, _0, _j, x3); \
+  Two_Sum(_2, _j, _i, _1); \
+  Two_Sum(_l, _i, _m, _2); \
+  Two_Sum(_1, _k, _i, x4); \
+  Two_Sum(_2, _i, _k, x5); \
+  Two_Sum(_m, _k, x7, x6)
+
+/* An expansion of length two can be squared more quickly than finding the   */
+/*   product of two different expansions of length two, and the result is    */
+/*   guaranteed to have no more than six (rather than eight) components.     */
+
+#define Two_Square(a1, a0, x5, x4, x3, x2, x1, x0) \
+  Square(a0, _j, x0); \
+  _0 = a0 + a0; \
+  Two_Product(a1, _0, _k, _1); \
+  Two_One_Sum(_k, _1, _j, _l, _2, x1); \
+  Square(a1, _j, _1); \
+  Two_Two_Sum(_j, _1, _l, _2, x5, x4, x3, x2)
+
+REAL splitter;     /* = 2^ceiling(p / 2) + 1.  Used to split floats in half. */
+REAL epsilon;                /* = 2^(-p).  Used to estimate roundoff errors. */
+/* A set of coefficients used to calculate maximum roundoff errors.          */
+REAL resulterrbound;
+REAL ccwerrboundA, ccwerrboundB, ccwerrboundC;
+REAL o3derrboundA, o3derrboundB, o3derrboundC;
+REAL iccerrboundA, iccerrboundB, iccerrboundC;
+REAL isperrboundA, isperrboundB, isperrboundC;
+
+/*****************************************************************************/
+/*                                                                           */
+/*  exactinit()   Initialize the variables used for exact arithmetic.        */
+/*                                                                           */
+/*  `epsilon' is the largest power of two such that 1.0 + epsilon = 1.0 in   */
+/*  floating-point arithmetic.  `epsilon' bounds the relative roundoff       */
+/*  error.  It is used for floating-point error analysis.                    */
+/*                                                                           */
+/*  `splitter' is used to split floating-point numbers into two half-        */
+/*  length significands for exact multiplication.                            */
+/*                                                                           */
+/*  I imagine that a highly optimizing compiler might be too smart for its   */
+/*  own good, and somehow cause this routine to fail, if it pretends that    */
+/*  floating-point arithmetic is too much like real arithmetic.              */
+/*                                                                           */
+/*  Don't change this routine unless you fully understand it.                */
+/*                                                                           */
+/*****************************************************************************/
+
+void exactinit()
+{
+/* Here is the code configure Intel CPUs to correctly execute my code. For   */
+/*  detail please see:                                                       */
+/*    http://www.cs.cmu.edu/~quake/robust.pc.html                            */
+
+#ifdef INTEL_MSC_TURBOC
+#ifdef SINGLE
+  _control87(PC_24, MCW_PC);    /* set FPU control word for single precision */
+#else /* not SINGLE */
+  _control87(PC_53, MCW_PC);    /* set FPU control word for double precision */
+#endif /* not SINGLE */
+#endif /* defined INTEL_MSC_TURBOC */
+
+#ifdef INTEL_GCC_LINUX
+#include <i386/fpu_control.h>
+#ifdef SINGLE
+__setfpucw(4210);               /* set FPU control word for single precision */
+#else /* not SINGLE */
+__setfpucw(4722);               /* set FPU control word for double precision */
+#endif /* not SINGLE */
+#endif /* defined INTEL_GCC_LINUX */
+
+#ifdef INTEL_GCC
+#include <i386/fpu_control.h>
+void set_ctrlword(v)
+int v;
+{
+  asm("fldcw %0" :: "m" (v));
+}
+#ifdef SINGLE
+set_ctrlword(4210);             /* set FPU control word for single precision */
+#else /* not SINGLE */
+set_ctrlword(4722);             /* set FPU control word for double precision */
+#endif /* not SINGLE */
+#endif /* defined INTEL_GCC */
+
+  REAL half;
+  REAL check, lastcheck;
+  int every_other;
+
+  every_other = 1;
+  half = 0.5;
+  epsilon = 1.0;
+  splitter = 1.0;
+  check = 1.0;
+  /* Repeatedly divide `epsilon' by two until it is too small to add to    */
+  /*   one without causing roundoff.  (Also check if the sum is equal to   */
+  /*   the previous sum, for machines that round up instead of using exact */
+  /*   rounding.  Not that this library will work on such machines anyway. */
+  do {
+    lastcheck = check;
+    epsilon *= half;
+    if (every_other) {
+      splitter *= 2.0;
+    }
+    every_other = !every_other;
+    check = 1.0 + epsilon;
+  } while ((check != 1.0) && (check != lastcheck));
+  splitter += 1.0;
+
+  /* Error bounds for orientation and incircle tests. */
+  resulterrbound = (3.0 + 8.0 * epsilon) * epsilon;
+  ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon;
+  ccwerrboundB = (2.0 + 12.0 * epsilon) * epsilon;
+  ccwerrboundC = (9.0 + 64.0 * epsilon) * epsilon * epsilon;
+  o3derrboundA = (7.0 + 56.0 * epsilon) * epsilon;
+  o3derrboundB = (3.0 + 28.0 * epsilon) * epsilon;
+  o3derrboundC = (26.0 + 288.0 * epsilon) * epsilon * epsilon;
+  iccerrboundA = (10.0 + 96.0 * epsilon) * epsilon;
+  iccerrboundB = (4.0 + 48.0 * epsilon) * epsilon;
+  iccerrboundC = (44.0 + 576.0 * epsilon) * epsilon * epsilon;
+  isperrboundA = (16.0 + 224.0 * epsilon) * epsilon;
+  isperrboundB = (5.0 + 72.0 * epsilon) * epsilon;
+  isperrboundC = (71.0 + 1408.0 * epsilon) * epsilon * epsilon;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  grow_expansion()   Add a scalar to an expansion.                         */
+/*                                                                           */
+/*  Sets h = e + b.  See the long version of my paper for details.           */
+/*                                                                           */
+/*  Maintains the nonoverlapping property.  If round-to-even is used (as     */
+/*  with IEEE 754), maintains the strongly nonoverlapping and nonadjacent    */
+/*  properties as well.  (That is, if e has one of these properties, so      */
+/*  will h.)                                                                 */
+/*                                                                           */
+/*****************************************************************************/
+
+int grow_expansion(int elen, REAL* e, REAL b, REAL* h)
+/* e and h can be the same. */
+{
+  REAL Q;
+  INEXACT REAL Qnew;
+  int eindex;
+  REAL enow;
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+
+  Q = b;
+  for (eindex = 0; eindex < elen; eindex++) {
+    enow = e[eindex];
+    Two_Sum(Q, enow, Qnew, h[eindex]);
+    Q = Qnew;
+  }
+  h[eindex] = Q;
+  return eindex + 1;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  grow_expansion_zeroelim()   Add a scalar to an expansion, eliminating    */
+/*                              zero components from the output expansion.   */
+/*                                                                           */
+/*  Sets h = e + b.  See the long version of my paper for details.           */
+/*                                                                           */
+/*  Maintains the nonoverlapping property.  If round-to-even is used (as     */
+/*  with IEEE 754), maintains the strongly nonoverlapping and nonadjacent    */
+/*  properties as well.  (That is, if e has one of these properties, so      */
+/*  will h.)                                                                 */
+/*                                                                           */
+/*****************************************************************************/
+
+int grow_expansion_zeroelim(int elen, REAL* e, REAL b, REAL* h)
+/* e and h can be the same. */
+{
+  REAL Q, hh;
+  INEXACT REAL Qnew;
+  int eindex, hindex;
+  REAL enow;
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+
+  hindex = 0;
+  Q = b;
+  for (eindex = 0; eindex < elen; eindex++) {
+    enow = e[eindex];
+    Two_Sum(Q, enow, Qnew, hh);
+    Q = Qnew;
+    if (hh != 0.0) {
+      h[hindex++] = hh;
+    }
+  }
+  if ((Q != 0.0) || (hindex == 0)) {
+    h[hindex++] = Q;
+  }
+  return hindex;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  expansion_sum()   Sum two expansions.                                    */
+/*                                                                           */
+/*  Sets h = e + f.  See the long version of my paper for details.           */
+/*                                                                           */
+/*  Maintains the nonoverlapping property.  If round-to-even is used (as     */
+/*  with IEEE 754), maintains the nonadjacent property as well.  (That is,   */
+/*  if e has one of these properties, so will h.)  Does NOT maintain the     */
+/*  strongly nonoverlapping property.                                        */
+/*                                                                           */
+/*****************************************************************************/
+
+int expansion_sum(int elen, REAL* e, int flen, REAL* f, REAL* h)
+/* e and h can be the same, but f and h cannot. */
+{
+  REAL Q;
+  INEXACT REAL Qnew;
+  int findex, hindex, hlast;
+  REAL hnow;
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+
+  Q = f[0];
+  for (hindex = 0; hindex < elen; hindex++) {
+    hnow = e[hindex];
+    Two_Sum(Q, hnow, Qnew, h[hindex]);
+    Q = Qnew;
+  }
+  h[hindex] = Q;
+  hlast = hindex;
+  for (findex = 1; findex < flen; findex++) {
+    Q = f[findex];
+    for (hindex = findex; hindex <= hlast; hindex++) {
+      hnow = h[hindex];
+      Two_Sum(Q, hnow, Qnew, h[hindex]);
+      Q = Qnew;
+    }
+    h[++hlast] = Q;
+  }
+  return hlast + 1;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  expansion_sum_zeroelim1()   Sum two expansions, eliminating zero         */
+/*                              components from the output expansion.        */
+/*                                                                           */
+/*  Sets h = e + f.  See the long version of my paper for details.           */
+/*                                                                           */
+/*  Maintains the nonoverlapping property.  If round-to-even is used (as     */
+/*  with IEEE 754), maintains the nonadjacent property as well.  (That is,   */
+/*  if e has one of these properties, so will h.)  Does NOT maintain the     */
+/*  strongly nonoverlapping property.                                        */
+/*                                                                           */
+/*****************************************************************************/
+
+int expansion_sum_zeroelim1(int elen, REAL* e, int flen, REAL* f, REAL* h)
+/* e and h can be the same, but f and h cannot. */
+{
+  REAL Q;
+  INEXACT REAL Qnew;
+  int index, findex, hindex, hlast;
+  REAL hnow;
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+
+  Q = f[0];
+  for (hindex = 0; hindex < elen; hindex++) {
+    hnow = e[hindex];
+    Two_Sum(Q, hnow, Qnew, h[hindex]);
+    Q = Qnew;
+  }
+  h[hindex] = Q;
+  hlast = hindex;
+  for (findex = 1; findex < flen; findex++) {
+    Q = f[findex];
+    for (hindex = findex; hindex <= hlast; hindex++) {
+      hnow = h[hindex];
+      Two_Sum(Q, hnow, Qnew, h[hindex]);
+      Q = Qnew;
+    }
+    h[++hlast] = Q;
+  }
+  hindex = -1;
+  for (index = 0; index <= hlast; index++) {
+    hnow = h[index];
+    if (hnow != 0.0) {
+      h[++hindex] = hnow;
+    }
+  }
+  if (hindex == -1) {
+    return 1;
+  } else {
+    return hindex + 1;
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  expansion_sum_zeroelim2()   Sum two expansions, eliminating zero         */
+/*                              components from the output expansion.        */
+/*                                                                           */
+/*  Sets h = e + f.  See the long version of my paper for details.           */
+/*                                                                           */
+/*  Maintains the nonoverlapping property.  If round-to-even is used (as     */
+/*  with IEEE 754), maintains the nonadjacent property as well.  (That is,   */
+/*  if e has one of these properties, so will h.)  Does NOT maintain the     */
+/*  strongly nonoverlapping property.                                        */
+/*                                                                           */
+/*****************************************************************************/
+
+int expansion_sum_zeroelim2(int elen, REAL* e, int flen, REAL* f, REAL* h)
+/* e and h can be the same, but f and h cannot. */
+{
+  REAL Q, hh;
+  INEXACT REAL Qnew;
+  int eindex, findex, hindex, hlast;
+  REAL enow;
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+
+  hindex = 0;
+  Q = f[0];
+  for (eindex = 0; eindex < elen; eindex++) {
+    enow = e[eindex];
+    Two_Sum(Q, enow, Qnew, hh);
+    Q = Qnew;
+    if (hh != 0.0) {
+      h[hindex++] = hh;
+    }
+  }
+  h[hindex] = Q;
+  hlast = hindex;
+  for (findex = 1; findex < flen; findex++) {
+    hindex = 0;
+    Q = f[findex];
+    for (eindex = 0; eindex <= hlast; eindex++) {
+      enow = h[eindex];
+      Two_Sum(Q, enow, Qnew, hh);
+      Q = Qnew;
+      if (hh != 0) {
+        h[hindex++] = hh;
+      }
+    }
+    h[hindex] = Q;
+    hlast = hindex;
+  }
+  return hlast + 1;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  fast_expansion_sum()   Sum two expansions.                               */
+/*                                                                           */
+/*  Sets h = e + f.  See the long version of my paper for details.           */
+/*                                                                           */
+/*  If round-to-even is used (as with IEEE 754), maintains the strongly      */
+/*  nonoverlapping property.  (That is, if e is strongly nonoverlapping, h   */
+/*  will be also.)  Does NOT maintain the nonoverlapping or nonadjacent      */
+/*  properties.                                                              */
+/*                                                                           */
+/*****************************************************************************/
+
+int fast_expansion_sum(int elen, REAL* e, int flen, REAL* f, REAL* h)
+/* h cannot be e or f. */
+{
+  REAL Q;
+  INEXACT REAL Qnew;
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+  int eindex, findex, hindex;
+  REAL enow, fnow;
+
+  enow = e[0];
+  fnow = f[0];
+  eindex = findex = 0;
+  if ((fnow > enow) == (fnow > -enow)) {
+    Q = enow;
+    enow = e[++eindex];
+  } else {
+    Q = fnow;
+    fnow = f[++findex];
+  }
+  hindex = 0;
+  if ((eindex < elen) && (findex < flen)) {
+    if ((fnow > enow) == (fnow > -enow)) {
+      Fast_Two_Sum(enow, Q, Qnew, h[0]);
+      enow = e[++eindex];
+    } else {
+      Fast_Two_Sum(fnow, Q, Qnew, h[0]);
+      fnow = f[++findex];
+    }
+    Q = Qnew;
+    hindex = 1;
+    while ((eindex < elen) && (findex < flen)) {
+      if ((fnow > enow) == (fnow > -enow)) {
+        Two_Sum(Q, enow, Qnew, h[hindex]);
+        enow = e[++eindex];
+      } else {
+        Two_Sum(Q, fnow, Qnew, h[hindex]);
+        fnow = f[++findex];
+      }
+      Q = Qnew;
+      hindex++;
+    }
+  }
+  while (eindex < elen) {
+    Two_Sum(Q, enow, Qnew, h[hindex]);
+    enow = e[++eindex];
+    Q = Qnew;
+    hindex++;
+  }
+  while (findex < flen) {
+    Two_Sum(Q, fnow, Qnew, h[hindex]);
+    fnow = f[++findex];
+    Q = Qnew;
+    hindex++;
+  }
+  h[hindex] = Q;
+  return hindex + 1;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  fast_expansion_sum_zeroelim()   Sum two expansions, eliminating zero     */
+/*                                  components from the output expansion.    */
+/*                                                                           */
+/*  Sets h = e + f.  See the long version of my paper for details.           */
+/*                                                                           */
+/*  If round-to-even is used (as with IEEE 754), maintains the strongly      */
+/*  nonoverlapping property.  (That is, if e is strongly nonoverlapping, h   */
+/*  will be also.)  Does NOT maintain the nonoverlapping or nonadjacent      */
+/*  properties.                                                              */
+/*                                                                           */
+/*****************************************************************************/
+
+int fast_expansion_sum_zeroelim(int elen, REAL* e, int flen, REAL* f, REAL* h)
+/* h cannot be e or f. */
+{
+  REAL Q;
+  INEXACT REAL Qnew;
+  INEXACT REAL hh;
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+  int eindex, findex, hindex;
+  REAL enow, fnow;
+
+  enow = e[0];
+  fnow = f[0];
+  eindex = findex = 0;
+  if ((fnow > enow) == (fnow > -enow)) {
+    Q = enow;
+    enow = e[++eindex];
+  } else {
+    Q = fnow;
+    fnow = f[++findex];
+  }
+  hindex = 0;
+  if ((eindex < elen) && (findex < flen)) {
+    if ((fnow > enow) == (fnow > -enow)) {
+      Fast_Two_Sum(enow, Q, Qnew, hh);
+      enow = e[++eindex];
+    } else {
+      Fast_Two_Sum(fnow, Q, Qnew, hh);
+      fnow = f[++findex];
+    }
+    Q = Qnew;
+    if (hh != 0.0) {
+      h[hindex++] = hh;
+    }
+    while ((eindex < elen) && (findex < flen)) {
+      if ((fnow > enow) == (fnow > -enow)) {
+        Two_Sum(Q, enow, Qnew, hh);
+        enow = e[++eindex];
+      } else {
+        Two_Sum(Q, fnow, Qnew, hh);
+        fnow = f[++findex];
+      }
+      Q = Qnew;
+      if (hh != 0.0) {
+        h[hindex++] = hh;
+      }
+    }
+  }
+  while (eindex < elen) {
+    Two_Sum(Q, enow, Qnew, hh);
+    enow = e[++eindex];
+    Q = Qnew;
+    if (hh != 0.0) {
+      h[hindex++] = hh;
+    }
+  }
+  while (findex < flen) {
+    Two_Sum(Q, fnow, Qnew, hh);
+    fnow = f[++findex];
+    Q = Qnew;
+    if (hh != 0.0) {
+      h[hindex++] = hh;
+    }
+  }
+  if ((Q != 0.0) || (hindex == 0)) {
+    h[hindex++] = Q;
+  }
+  return hindex;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  linear_expansion_sum()   Sum two expansions.                             */
+/*                                                                           */
+/*  Sets h = e + f.  See either version of my paper for details.             */
+/*                                                                           */
+/*  Maintains the nonoverlapping property.  (That is, if e is                */
+/*  nonoverlapping, h will be also.)                                         */
+/*                                                                           */
+/*****************************************************************************/
+
+int linear_expansion_sum(int elen, REAL* e, int flen, REAL* f, REAL* h)
+/* h cannot be e or f. */
+{
+  REAL Q, q;
+  INEXACT REAL Qnew;
+  INEXACT REAL R;
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+  int eindex, findex, hindex;
+  REAL enow, fnow;
+  REAL g0;
+
+  enow = e[0];
+  fnow = f[0];
+  eindex = findex = 0;
+  if ((fnow > enow) == (fnow > -enow)) {
+    g0 = enow;
+    enow = e[++eindex];
+  } else {
+    g0 = fnow;
+    fnow = f[++findex];
+  }
+  if ((eindex < elen) && ((findex >= flen)
+                          || ((fnow > enow) == (fnow > -enow)))) {
+    Fast_Two_Sum(enow, g0, Qnew, q);
+    enow = e[++eindex];
+  } else {
+    Fast_Two_Sum(fnow, g0, Qnew, q);
+    fnow = f[++findex];
+  }
+  Q = Qnew;
+  for (hindex = 0; hindex < elen + flen - 2; hindex++) {
+    if ((eindex < elen) && ((findex >= flen)
+                            || ((fnow > enow) == (fnow > -enow)))) {
+      Fast_Two_Sum(enow, q, R, h[hindex]);
+      enow = e[++eindex];
+    } else {
+      Fast_Two_Sum(fnow, q, R, h[hindex]);
+      fnow = f[++findex];
+    }
+    Two_Sum(Q, R, Qnew, q);
+    Q = Qnew;
+  }
+  h[hindex] = q;
+  h[hindex + 1] = Q;
+  return hindex + 2;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  linear_expansion_sum_zeroelim()   Sum two expansions, eliminating zero   */
+/*                                    components from the output expansion.  */
+/*                                                                           */
+/*  Sets h = e + f.  See either version of my paper for details.             */
+/*                                                                           */
+/*  Maintains the nonoverlapping property.  (That is, if e is                */
+/*  nonoverlapping, h will be also.)                                         */
+/*                                                                           */
+/*****************************************************************************/
+
+int linear_expansion_sum_zeroelim(int elen, REAL* e, int flen, REAL* f, REAL* h)
+/* h cannot be e or f. */
+{
+  REAL Q, q, hh;
+  INEXACT REAL Qnew;
+  INEXACT REAL R;
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+  int eindex, findex, hindex;
+  int count;
+  REAL enow, fnow;
+  REAL g0;
+
+  enow = e[0];
+  fnow = f[0];
+  eindex = findex = 0;
+  hindex = 0;
+  if ((fnow > enow) == (fnow > -enow)) {
+    g0 = enow;
+    enow = e[++eindex];
+  } else {
+    g0 = fnow;
+    fnow = f[++findex];
+  }
+  if ((eindex < elen) && ((findex >= flen)
+                          || ((fnow > enow) == (fnow > -enow)))) {
+    Fast_Two_Sum(enow, g0, Qnew, q);
+    enow = e[++eindex];
+  } else {
+    Fast_Two_Sum(fnow, g0, Qnew, q);
+    fnow = f[++findex];
+  }
+  Q = Qnew;
+  for (count = 2; count < elen + flen; count++) {
+    if ((eindex < elen) && ((findex >= flen)
+                            || ((fnow > enow) == (fnow > -enow)))) {
+      Fast_Two_Sum(enow, q, R, hh);
+      enow = e[++eindex];
+    } else {
+      Fast_Two_Sum(fnow, q, R, hh);
+      fnow = f[++findex];
+    }
+    Two_Sum(Q, R, Qnew, q);
+    Q = Qnew;
+    if (hh != 0) {
+      h[hindex++] = hh;
+    }
+  }
+  if (q != 0) {
+    h[hindex++] = q;
+  }
+  if ((Q != 0.0) || (hindex == 0)) {
+    h[hindex++] = Q;
+  }
+  return hindex;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  scale_expansion()   Multiply an expansion by a scalar.                   */
+/*                                                                           */
+/*  Sets h = be.  See either version of my paper for details.                */
+/*                                                                           */
+/*  Maintains the nonoverlapping property.  If round-to-even is used (as     */
+/*  with IEEE 754), maintains the strongly nonoverlapping and nonadjacent    */
+/*  properties as well.  (That is, if e has one of these properties, so      */
+/*  will h.)                                                                 */
+/*                                                                           */
+/*****************************************************************************/
+
+int scale_expansion(int elen, REAL* e, REAL b, REAL* h)
+/* e and h cannot be the same. */
+{
+  INEXACT REAL Q;
+  INEXACT REAL sum;
+  INEXACT REAL product1;
+  REAL product0;
+  int eindex, hindex;
+  REAL enow;
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+  INEXACT REAL c;
+  INEXACT REAL abig;
+  REAL ahi, alo, bhi, blo;
+  REAL err1, err2, err3;
+
+  Split(b, bhi, blo);
+  Two_Product_Presplit(e[0], b, bhi, blo, Q, h[0]);
+  hindex = 1;
+  for (eindex = 1; eindex < elen; eindex++) {
+    enow = e[eindex];
+    Two_Product_Presplit(enow, b, bhi, blo, product1, product0);
+    Two_Sum(Q, product0, sum, h[hindex]);
+    hindex++;
+    Two_Sum(product1, sum, Q, h[hindex]);
+    hindex++;
+  }
+  h[hindex] = Q;
+  return elen + elen;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  scale_expansion_zeroelim()   Multiply an expansion by a scalar,          */
+/*                               eliminating zero components from the        */
+/*                               output expansion.                           */
+/*                                                                           */
+/*  Sets h = be.  See either version of my paper for details.                */
+/*                                                                           */
+/*  Maintains the nonoverlapping property.  If round-to-even is used (as     */
+/*  with IEEE 754), maintains the strongly nonoverlapping and nonadjacent    */
+/*  properties as well.  (That is, if e has one of these properties, so      */
+/*  will h.)                                                                 */
+/*                                                                           */
+/*****************************************************************************/
+
+int scale_expansion_zeroelim(int elen, REAL* e, REAL b, REAL* h)
+/* e and h cannot be the same. */
+{
+  INEXACT REAL Q, sum;
+  REAL hh;
+  INEXACT REAL product1;
+  REAL product0;
+  int eindex, hindex;
+  REAL enow;
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+  INEXACT REAL c;
+  INEXACT REAL abig;
+  REAL ahi, alo, bhi, blo;
+  REAL err1, err2, err3;
+
+  Split(b, bhi, blo);
+  Two_Product_Presplit(e[0], b, bhi, blo, Q, hh);
+  hindex = 0;
+  if (hh != 0) {
+    h[hindex++] = hh;
+  }
+  for (eindex = 1; eindex < elen; eindex++) {
+    enow = e[eindex];
+    Two_Product_Presplit(enow, b, bhi, blo, product1, product0);
+    Two_Sum(Q, product0, sum, hh);
+    if (hh != 0) {
+      h[hindex++] = hh;
+    }
+    Fast_Two_Sum(product1, sum, Q, hh);
+    if (hh != 0) {
+      h[hindex++] = hh;
+    }
+  }
+  if ((Q != 0.0) || (hindex == 0)) {
+    h[hindex++] = Q;
+  }
+  return hindex;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  compress()   Compress an expansion.                                      */
+/*                                                                           */
+/*  See the long version of my paper for details.                            */
+/*                                                                           */
+/*  Maintains the nonoverlapping property.  If round-to-even is used (as     */
+/*  with IEEE 754), then any nonoverlapping expansion is converted to a      */
+/*  nonadjacent expansion.                                                   */
+/*                                                                           */
+/*****************************************************************************/
+
+int compress(int elen, REAL* e, REAL* h)         /* e and h may be the same. */
+{
+  REAL Q, q;
+  INEXACT REAL Qnew;
+  int eindex, hindex;
+  INEXACT REAL bvirt;
+  REAL enow, hnow;
+  int top, bottom;
+
+  bottom = elen - 1;
+  Q = e[bottom];
+  for (eindex = elen - 2; eindex >= 0; eindex--) {
+    enow = e[eindex];
+    Fast_Two_Sum(Q, enow, Qnew, q);
+    if (q != 0) {
+      h[bottom--] = Qnew;
+      Q = q;
+    } else {
+      Q = Qnew;
+    }
+  }
+  top = 0;
+  for (hindex = bottom + 1; hindex < elen; hindex++) {
+    hnow = h[hindex];
+    Fast_Two_Sum(hnow, Q, Qnew, q);
+    if (q != 0) {
+      h[top++] = q;
+    }
+    Q = Qnew;
+  }
+  h[top] = Q;
+  return top + 1;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  estimate()   Produce a one-word estimate of an expansion's value.        */
+/*                                                                           */
+/*  See either version of my paper for details.                              */
+/*                                                                           */
+/*****************************************************************************/
+
+REAL estimate(int elen, REAL* e)
+{
+  REAL Q;
+  int eindex;
+
+  Q = e[0];
+  for (eindex = 1; eindex < elen; eindex++) {
+    Q += e[eindex];
+  }
+  return Q;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+//  orient2d()       Adaptive exact 2D orientation test.  Robust.            //
+//                                                                           //
+//               Return a positive value if the points pa, pb, and pc occur  //
+//               in counterclockwise order; a negative value if they occur   //
+//               in clockwise order; and zero if they are collinear.  The    //
+//               result is also a rough approximation of twice the signed    //
+//               area of the triangle defined by the three points.           //
+//                                                                           //
+//  orient2d() use exact arithmetic to ensure a correct answer.  The result  //
+//  returned is the determinant of a matrix.  In orient2d() only, this       //
+//  determinant is computed adaptively, in the sense that exact arithmetic   //
+//  is used only to the degree it is needed to ensure that the returned      //
+//  value has the correct sign.  Hence, orient2d() is usually quite fast,    //
+//  but will run more slowly when the input points are collinear or nearly   //
+//  so.                                                                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL orient2dadapt(REAL* pa, REAL* pb, REAL* pc, REAL detsum)
+{
+  INEXACT REAL acx, acy, bcx, bcy;
+  REAL acxtail, acytail, bcxtail, bcytail;
+  INEXACT REAL detleft, detright;
+  REAL detlefttail, detrighttail;
+  REAL det, errbound;
+  REAL B[4], C1[8], C2[12], D[16];
+  INEXACT REAL B3;
+  int C1length, C2length, Dlength;
+  REAL u[4];
+  INEXACT REAL u3;
+  INEXACT REAL s1, t1;
+  REAL s0, t0;
+
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+  INEXACT REAL c;
+  INEXACT REAL abig;
+  REAL ahi, alo, bhi, blo;
+  REAL err1, err2, err3;
+  INEXACT REAL _i, _j;
+  REAL _0;
+
+  acx = (REAL) (pa[0] - pc[0]);
+  bcx = (REAL) (pb[0] - pc[0]);
+  acy = (REAL) (pa[1] - pc[1]);
+  bcy = (REAL) (pb[1] - pc[1]);
+
+  Two_Product(acx, bcy, detleft, detlefttail);
+  Two_Product(acy, bcx, detright, detrighttail);
+
+  Two_Two_Diff(detleft, detlefttail, detright, detrighttail,
+               B3, B[2], B[1], B[0]);
+  B[3] = B3;
+
+  det = estimate(4, B);
+  errbound = ccwerrboundB * detsum;
+  if ((det >= errbound) || (-det >= errbound)) {
+    return det;
+  }
+
+  Two_Diff_Tail(pa[0], pc[0], acx, acxtail);
+  Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail);
+  Two_Diff_Tail(pa[1], pc[1], acy, acytail);
+  Two_Diff_Tail(pb[1], pc[1], bcy, bcytail);
+
+  if ((acxtail == 0.0) && (acytail == 0.0)
+      && (bcxtail == 0.0) && (bcytail == 0.0)) {
+    return det;
+  }
+
+  errbound = ccwerrboundC * detsum + resulterrbound * Absolute(det);
+  det += (acx * bcytail + bcy * acxtail)
+       - (acy * bcxtail + bcx * acytail);
+  if ((det >= errbound) || (-det >= errbound)) {
+    return det;
+  }
+
+  Two_Product(acxtail, bcy, s1, s0);
+  Two_Product(acytail, bcx, t1, t0);
+  Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
+  u[3] = u3;
+  C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1);
+
+  Two_Product(acx, bcytail, s1, s0);
+  Two_Product(acy, bcxtail, t1, t0);
+  Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
+  u[3] = u3;
+  C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2);
+
+  Two_Product(acxtail, bcytail, s1, s0);
+  Two_Product(acytail, bcxtail, t1, t0);
+  Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
+  u[3] = u3;
+  Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D);
+
+  return(D[Dlength - 1]);
+}
+
+REAL orient2d(REAL* pa, REAL* pb, REAL* pc)
+{
+  REAL detleft, detright, det;
+  REAL detsum, errbound;
+
+  detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]);
+  detright = (pa[1] - pc[1]) * (pb[0] - pc[0]);
+  det = detleft - detright;
+
+  if (detleft > 0.0) {
+    if (detright <= 0.0) {
+      return det;
+    } else {
+      detsum = detleft + detright;
+    }
+  } else if (detleft < 0.0) {
+    if (detright >= 0.0) {
+      return det;
+    } else {
+      detsum = -detleft - detright;
+    }
+  } else {
+    return det;
+  }
+
+  errbound = ccwerrboundA * detsum;
+  if ((det >= errbound) || (-det >= errbound)) {
+    return det;
+  }
+
+  return orient2dadapt(pa, pb, pc, detsum);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+//  orient3d()       Adaptive exact 3D orientation test.  Robust.            //
+//                                                                           //
+//               Return a positive value if the point pd lies below the      //
+//               plane passing through pa, pb, and pc; "below" is defined so //
+//               that pa, pb, and pc appear in counterclockwise order when   //
+//               viewed from above the plane.  Returns a negative value if   //
+//               pd lies above the plane.  Returns zero if the points are    //
+//               coplanar.  The result is also a rough approximation of six  //
+//               times the signed volume of the tetrahedron defined by the   //
+//               four points.                                                //
+//                                                                           //
+//  orient3d() use exact arithmetic to ensure a correct answer.  The result  //
+//  returned is the determinant of a matrix.  In orient3d() only, this       //
+//  determinant is computed adaptively, in the sense that exact arithmetic   //
+//  is used only to the degree it is needed to ensure that the returned      //
+//  value has the correct sign.  Hence, orient3d() is usually quite fast,    //
+//  but will run more slowly when the input points are coplanar or nearly    //
+//  so.                                                                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL orient3dadapt(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL permanent)
+{
+  INEXACT REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz;
+  REAL det, errbound;
+
+  INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1;
+  REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0;
+  REAL bc[4], ca[4], ab[4];
+  INEXACT REAL bc3, ca3, ab3;
+  REAL adet[8], bdet[8], cdet[8];
+  int alen, blen, clen;
+  REAL abdet[16];
+  int ablen;
+  REAL *finnow, *finother, *finswap;
+  REAL fin1[192], fin2[192];
+  int finlength;
+
+  REAL adxtail, bdxtail, cdxtail;
+  REAL adytail, bdytail, cdytail;
+  REAL adztail, bdztail, cdztail;
+  INEXACT REAL at_blarge, at_clarge;
+  INEXACT REAL bt_clarge, bt_alarge;
+  INEXACT REAL ct_alarge, ct_blarge;
+  REAL at_b[4], at_c[4], bt_c[4], bt_a[4], ct_a[4], ct_b[4];
+  int at_blen, at_clen, bt_clen, bt_alen, ct_alen, ct_blen;
+  INEXACT REAL bdxt_cdy1, cdxt_bdy1, cdxt_ady1;
+  INEXACT REAL adxt_cdy1, adxt_bdy1, bdxt_ady1;
+  REAL bdxt_cdy0, cdxt_bdy0, cdxt_ady0;
+  REAL adxt_cdy0, adxt_bdy0, bdxt_ady0;
+  INEXACT REAL bdyt_cdx1, cdyt_bdx1, cdyt_adx1;
+  INEXACT REAL adyt_cdx1, adyt_bdx1, bdyt_adx1;
+  REAL bdyt_cdx0, cdyt_bdx0, cdyt_adx0;
+  REAL adyt_cdx0, adyt_bdx0, bdyt_adx0;
+  REAL bct[8], cat[8], abt[8];
+  int bctlen, catlen, abtlen;
+  INEXACT REAL bdxt_cdyt1, cdxt_bdyt1, cdxt_adyt1;
+  INEXACT REAL adxt_cdyt1, adxt_bdyt1, bdxt_adyt1;
+  REAL bdxt_cdyt0, cdxt_bdyt0, cdxt_adyt0;
+  REAL adxt_cdyt0, adxt_bdyt0, bdxt_adyt0;
+  REAL u[4], v[12], w[16];
+  INEXACT REAL u3;
+  int vlength, wlength;
+  REAL negate;
+
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+  INEXACT REAL c;
+  INEXACT REAL abig;
+  REAL ahi, alo, bhi, blo;
+  REAL err1, err2, err3;
+  INEXACT REAL _i, _j, _k;
+  REAL _0;
+
+  adx = (REAL) (pa[0] - pd[0]);
+  bdx = (REAL) (pb[0] - pd[0]);
+  cdx = (REAL) (pc[0] - pd[0]);
+  ady = (REAL) (pa[1] - pd[1]);
+  bdy = (REAL) (pb[1] - pd[1]);
+  cdy = (REAL) (pc[1] - pd[1]);
+  adz = (REAL) (pa[2] - pd[2]);
+  bdz = (REAL) (pb[2] - pd[2]);
+  cdz = (REAL) (pc[2] - pd[2]);
+
+  Two_Product(bdx, cdy, bdxcdy1, bdxcdy0);
+  Two_Product(cdx, bdy, cdxbdy1, cdxbdy0);
+  Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]);
+  bc[3] = bc3;
+  alen = scale_expansion_zeroelim(4, bc, adz, adet);
+
+  Two_Product(cdx, ady, cdxady1, cdxady0);
+  Two_Product(adx, cdy, adxcdy1, adxcdy0);
+  Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]);
+  ca[3] = ca3;
+  blen = scale_expansion_zeroelim(4, ca, bdz, bdet);
+
+  Two_Product(adx, bdy, adxbdy1, adxbdy0);
+  Two_Product(bdx, ady, bdxady1, bdxady0);
+  Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]);
+  ab[3] = ab3;
+  clen = scale_expansion_zeroelim(4, ab, cdz, cdet);
+
+  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
+  finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1);
+
+  det = estimate(finlength, fin1);
+  errbound = o3derrboundB * permanent;
+  if ((det >= errbound) || (-det >= errbound)) {
+    return det;
+  }
+
+  Two_Diff_Tail(pa[0], pd[0], adx, adxtail);
+  Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail);
+  Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail);
+  Two_Diff_Tail(pa[1], pd[1], ady, adytail);
+  Two_Diff_Tail(pb[1], pd[1], bdy, bdytail);
+  Two_Diff_Tail(pc[1], pd[1], cdy, cdytail);
+  Two_Diff_Tail(pa[2], pd[2], adz, adztail);
+  Two_Diff_Tail(pb[2], pd[2], bdz, bdztail);
+  Two_Diff_Tail(pc[2], pd[2], cdz, cdztail);
+
+  if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0)
+      && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)
+      && (adztail == 0.0) && (bdztail == 0.0) && (cdztail == 0.0)) {
+    return det;
+  }
+
+  errbound = o3derrboundC * permanent + resulterrbound * Absolute(det);
+  det += (adz * ((bdx * cdytail + cdy * bdxtail)
+                 - (bdy * cdxtail + cdx * bdytail))
+          + adztail * (bdx * cdy - bdy * cdx))
+       + (bdz * ((cdx * adytail + ady * cdxtail)
+                 - (cdy * adxtail + adx * cdytail))
+          + bdztail * (cdx * ady - cdy * adx))
+       + (cdz * ((adx * bdytail + bdy * adxtail)
+                 - (ady * bdxtail + bdx * adytail))
+          + cdztail * (adx * bdy - ady * bdx));
+  if ((det >= errbound) || (-det >= errbound)) {
+    return det;
+  }
+
+  finnow = fin1;
+  finother = fin2;
+
+  if (adxtail == 0.0) {
+    if (adytail == 0.0) {
+      at_b[0] = 0.0;
+      at_blen = 1;
+      at_c[0] = 0.0;
+      at_clen = 1;
+    } else {
+      negate = -adytail;
+      Two_Product(negate, bdx, at_blarge, at_b[0]);
+      at_b[1] = at_blarge;
+      at_blen = 2;
+      Two_Product(adytail, cdx, at_clarge, at_c[0]);
+      at_c[1] = at_clarge;
+      at_clen = 2;
+    }
+  } else {
+    if (adytail == 0.0) {
+      Two_Product(adxtail, bdy, at_blarge, at_b[0]);
+      at_b[1] = at_blarge;
+      at_blen = 2;
+      negate = -adxtail;
+      Two_Product(negate, cdy, at_clarge, at_c[0]);
+      at_c[1] = at_clarge;
+      at_clen = 2;
+    } else {
+      Two_Product(adxtail, bdy, adxt_bdy1, adxt_bdy0);
+      Two_Product(adytail, bdx, adyt_bdx1, adyt_bdx0);
+      Two_Two_Diff(adxt_bdy1, adxt_bdy0, adyt_bdx1, adyt_bdx0,
+                   at_blarge, at_b[2], at_b[1], at_b[0]);
+      at_b[3] = at_blarge;
+      at_blen = 4;
+      Two_Product(adytail, cdx, adyt_cdx1, adyt_cdx0);
+      Two_Product(adxtail, cdy, adxt_cdy1, adxt_cdy0);
+      Two_Two_Diff(adyt_cdx1, adyt_cdx0, adxt_cdy1, adxt_cdy0,
+                   at_clarge, at_c[2], at_c[1], at_c[0]);
+      at_c[3] = at_clarge;
+      at_clen = 4;
+    }
+  }
+  if (bdxtail == 0.0) {
+    if (bdytail == 0.0) {
+      bt_c[0] = 0.0;
+      bt_clen = 1;
+      bt_a[0] = 0.0;
+      bt_alen = 1;
+    } else {
+      negate = -bdytail;
+      Two_Product(negate, cdx, bt_clarge, bt_c[0]);
+      bt_c[1] = bt_clarge;
+      bt_clen = 2;
+      Two_Product(bdytail, adx, bt_alarge, bt_a[0]);
+      bt_a[1] = bt_alarge;
+      bt_alen = 2;
+    }
+  } else {
+    if (bdytail == 0.0) {
+      Two_Product(bdxtail, cdy, bt_clarge, bt_c[0]);
+      bt_c[1] = bt_clarge;
+      bt_clen = 2;
+      negate = -bdxtail;
+      Two_Product(negate, ady, bt_alarge, bt_a[0]);
+      bt_a[1] = bt_alarge;
+      bt_alen = 2;
+    } else {
+      Two_Product(bdxtail, cdy, bdxt_cdy1, bdxt_cdy0);
+      Two_Product(bdytail, cdx, bdyt_cdx1, bdyt_cdx0);
+      Two_Two_Diff(bdxt_cdy1, bdxt_cdy0, bdyt_cdx1, bdyt_cdx0,
+                   bt_clarge, bt_c[2], bt_c[1], bt_c[0]);
+      bt_c[3] = bt_clarge;
+      bt_clen = 4;
+      Two_Product(bdytail, adx, bdyt_adx1, bdyt_adx0);
+      Two_Product(bdxtail, ady, bdxt_ady1, bdxt_ady0);
+      Two_Two_Diff(bdyt_adx1, bdyt_adx0, bdxt_ady1, bdxt_ady0,
+                  bt_alarge, bt_a[2], bt_a[1], bt_a[0]);
+      bt_a[3] = bt_alarge;
+      bt_alen = 4;
+    }
+  }
+  if (cdxtail == 0.0) {
+    if (cdytail == 0.0) {
+      ct_a[0] = 0.0;
+      ct_alen = 1;
+      ct_b[0] = 0.0;
+      ct_blen = 1;
+    } else {
+      negate = -cdytail;
+      Two_Product(negate, adx, ct_alarge, ct_a[0]);
+      ct_a[1] = ct_alarge;
+      ct_alen = 2;
+      Two_Product(cdytail, bdx, ct_blarge, ct_b[0]);
+      ct_b[1] = ct_blarge;
+      ct_blen = 2;
+    }
+  } else {
+    if (cdytail == 0.0) {
+      Two_Product(cdxtail, ady, ct_alarge, ct_a[0]);
+      ct_a[1] = ct_alarge;
+      ct_alen = 2;
+      negate = -cdxtail;
+      Two_Product(negate, bdy, ct_blarge, ct_b[0]);
+      ct_b[1] = ct_blarge;
+      ct_blen = 2;
+    } else {
+      Two_Product(cdxtail, ady, cdxt_ady1, cdxt_ady0);
+      Two_Product(cdytail, adx, cdyt_adx1, cdyt_adx0);
+      Two_Two_Diff(cdxt_ady1, cdxt_ady0, cdyt_adx1, cdyt_adx0,
+                   ct_alarge, ct_a[2], ct_a[1], ct_a[0]);
+      ct_a[3] = ct_alarge;
+      ct_alen = 4;
+      Two_Product(cdytail, bdx, cdyt_bdx1, cdyt_bdx0);
+      Two_Product(cdxtail, bdy, cdxt_bdy1, cdxt_bdy0);
+      Two_Two_Diff(cdyt_bdx1, cdyt_bdx0, cdxt_bdy1, cdxt_bdy0,
+                   ct_blarge, ct_b[2], ct_b[1], ct_b[0]);
+      ct_b[3] = ct_blarge;
+      ct_blen = 4;
+    }
+  }
+
+  bctlen = fast_expansion_sum_zeroelim(bt_clen, bt_c, ct_blen, ct_b, bct);
+  wlength = scale_expansion_zeroelim(bctlen, bct, adz, w);
+  finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
+                                          finother);
+  finswap = finnow; finnow = finother; finother = finswap;
+
+  catlen = fast_expansion_sum_zeroelim(ct_alen, ct_a, at_clen, at_c, cat);
+  wlength = scale_expansion_zeroelim(catlen, cat, bdz, w);
+  finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
+                                          finother);
+  finswap = finnow; finnow = finother; finother = finswap;
+
+  abtlen = fast_expansion_sum_zeroelim(at_blen, at_b, bt_alen, bt_a, abt);
+  wlength = scale_expansion_zeroelim(abtlen, abt, cdz, w);
+  finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
+                                          finother);
+  finswap = finnow; finnow = finother; finother = finswap;
+
+  if (adztail != 0.0) {
+    vlength = scale_expansion_zeroelim(4, bc, adztail, v);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v,
+                                            finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+  if (bdztail != 0.0) {
+    vlength = scale_expansion_zeroelim(4, ca, bdztail, v);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v,
+                                            finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+  if (cdztail != 0.0) {
+    vlength = scale_expansion_zeroelim(4, ab, cdztail, v);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v,
+                                            finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+
+  if (adxtail != 0.0) {
+    if (bdytail != 0.0) {
+      Two_Product(adxtail, bdytail, adxt_bdyt1, adxt_bdyt0);
+      Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdz, u3, u[2], u[1], u[0]);
+      u[3] = u3;
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
+                                              finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+      if (cdztail != 0.0) {
+        Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdztail, u3, u[2], u[1], u[0]);
+        u[3] = u3;
+        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
+                                                finother);
+        finswap = finnow; finnow = finother; finother = finswap;
+      }
+    }
+    if (cdytail != 0.0) {
+      negate = -adxtail;
+      Two_Product(negate, cdytail, adxt_cdyt1, adxt_cdyt0);
+      Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdz, u3, u[2], u[1], u[0]);
+      u[3] = u3;
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
+                                              finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+      if (bdztail != 0.0) {
+        Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdztail, u3, u[2], u[1], u[0]);
+        u[3] = u3;
+        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
+                                                finother);
+        finswap = finnow; finnow = finother; finother = finswap;
+      }
+    }
+  }
+  if (bdxtail != 0.0) {
+    if (cdytail != 0.0) {
+      Two_Product(bdxtail, cdytail, bdxt_cdyt1, bdxt_cdyt0);
+      Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adz, u3, u[2], u[1], u[0]);
+      u[3] = u3;
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
+                                              finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+      if (adztail != 0.0) {
+        Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adztail, u3, u[2], u[1], u[0]);
+        u[3] = u3;
+        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
+                                                finother);
+        finswap = finnow; finnow = finother; finother = finswap;
+      }
+    }
+    if (adytail != 0.0) {
+      negate = -bdxtail;
+      Two_Product(negate, adytail, bdxt_adyt1, bdxt_adyt0);
+      Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdz, u3, u[2], u[1], u[0]);
+      u[3] = u3;
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
+                                              finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+      if (cdztail != 0.0) {
+        Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdztail, u3, u[2], u[1], u[0]);
+        u[3] = u3;
+        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
+                                                finother);
+        finswap = finnow; finnow = finother; finother = finswap;
+      }
+    }
+  }
+  if (cdxtail != 0.0) {
+    if (adytail != 0.0) {
+      Two_Product(cdxtail, adytail, cdxt_adyt1, cdxt_adyt0);
+      Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdz, u3, u[2], u[1], u[0]);
+      u[3] = u3;
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
+                                              finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+      if (bdztail != 0.0) {
+        Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdztail, u3, u[2], u[1], u[0]);
+        u[3] = u3;
+        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
+                                                finother);
+        finswap = finnow; finnow = finother; finother = finswap;
+      }
+    }
+    if (bdytail != 0.0) {
+      negate = -cdxtail;
+      Two_Product(negate, bdytail, cdxt_bdyt1, cdxt_bdyt0);
+      Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adz, u3, u[2], u[1], u[0]);
+      u[3] = u3;
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
+                                              finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+      if (adztail != 0.0) {
+        Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adztail, u3, u[2], u[1], u[0]);
+        u[3] = u3;
+        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
+                                                finother);
+        finswap = finnow; finnow = finother; finother = finswap;
+      }
+    }
+  }
+
+  if (adztail != 0.0) {
+    wlength = scale_expansion_zeroelim(bctlen, bct, adztail, w);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
+                                            finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+  if (bdztail != 0.0) {
+    wlength = scale_expansion_zeroelim(catlen, cat, bdztail, w);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
+                                            finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+  if (cdztail != 0.0) {
+    wlength = scale_expansion_zeroelim(abtlen, abt, cdztail, w);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
+                                            finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+
+  return finnow[finlength - 1];
+}
+
+REAL orient3d(REAL* pa, REAL* pb, REAL* pc, REAL* pd)
+{
+  REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz;
+  REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
+  REAL det;
+  REAL permanent, errbound;
+
+  adx = pa[0] - pd[0];
+  bdx = pb[0] - pd[0];
+  cdx = pc[0] - pd[0];
+  ady = pa[1] - pd[1];
+  bdy = pb[1] - pd[1];
+  cdy = pc[1] - pd[1];
+  adz = pa[2] - pd[2];
+  bdz = pb[2] - pd[2];
+  cdz = pc[2] - pd[2];
+
+  bdxcdy = bdx * cdy;
+  cdxbdy = cdx * bdy;
+
+  cdxady = cdx * ady;
+  adxcdy = adx * cdy;
+
+  adxbdy = adx * bdy;
+  bdxady = bdx * ady;
+
+  det = adz * (bdxcdy - cdxbdy)
+      + bdz * (cdxady - adxcdy)
+      + cdz * (adxbdy - bdxady);
+
+  permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * Absolute(adz)
+            + (Absolute(cdxady) + Absolute(adxcdy)) * Absolute(bdz)
+            + (Absolute(adxbdy) + Absolute(bdxady)) * Absolute(cdz);
+  errbound = o3derrboundA * permanent;
+  if ((det > errbound) || (-det > errbound)) {
+    return det;
+  }
+
+  return orient3dadapt(pa, pb, pc, pd, permanent);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+//  incircle()       Adaptive exact 2D incircle test.  Robust.               //
+//                                                                           //
+//               Return a positive value if the point pd lies inside the     //
+//               circle passing through pa, pb, and pc; a negative value if  //
+//               it lies outside; and zero if the four points are cocircular.//
+//               The points pa, pb, and pc must be in counterclockwise       //
+//               order, or the sign of the result will be reversed.          //
+//                                                                           //
+//  incircle() use exact arithmetic to ensure a correct answer.  The result  //
+//  returned is the determinant of a matrix.  In incircle() only, this       //
+//  determinant is computed adaptively, in the sense that exact arithmetic   //
+//  is used only to the degree it is needed to ensure that the returned      //
+//  value has the correct sign.  Hence, incircle() is usually quite fast,    //
+//  but will run more slowly when the input points are cocircular or nearly  //
+//  so.                                                                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL incircleadapt(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL permanent)
+{
+  INEXACT REAL adx, bdx, cdx, ady, bdy, cdy;
+  REAL det, errbound;
+
+  INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1;
+  REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0;
+  REAL bc[4], ca[4], ab[4];
+  INEXACT REAL bc3, ca3, ab3;
+  REAL axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32];
+  int axbclen, axxbclen, aybclen, ayybclen, alen;
+  REAL bxca[8], bxxca[16], byca[8], byyca[16], bdet[32];
+  int bxcalen, bxxcalen, bycalen, byycalen, blen;
+  REAL cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32];
+  int cxablen, cxxablen, cyablen, cyyablen, clen;
+  REAL abdet[64];
+  int ablen;
+  REAL fin1[1152], fin2[1152];
+  REAL *finnow, *finother, *finswap;
+  int finlength;
+
+  REAL adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail;
+  INEXACT REAL adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1;
+  REAL adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0;
+  REAL aa[4], bb[4], cc[4];
+  INEXACT REAL aa3, bb3, cc3;
+  INEXACT REAL ti1, tj1;
+  REAL ti0, tj0;
+  REAL u[4], v[4];
+  INEXACT REAL u3, v3;
+  REAL temp8[8], temp16a[16], temp16b[16], temp16c[16];
+  REAL temp32a[32], temp32b[32], temp48[48], temp64[64];
+  int temp8len, temp16alen, temp16blen, temp16clen;
+  int temp32alen, temp32blen, temp48len, temp64len;
+  REAL axtbb[8], axtcc[8], aytbb[8], aytcc[8];
+  int axtbblen, axtcclen, aytbblen, aytcclen;
+  REAL bxtaa[8], bxtcc[8], bytaa[8], bytcc[8];
+  int bxtaalen, bxtcclen, bytaalen, bytcclen;
+  REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8];
+  int cxtaalen, cxtbblen, cytaalen, cytbblen;
+  REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8];
+  int axtbclen, aytbclen, bxtcalen, bytcalen, cxtablen, cytablen;
+  REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16];
+  int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen;
+  REAL axtbctt[8], aytbctt[8], bxtcatt[8];
+  REAL bytcatt[8], cxtabtt[8], cytabtt[8];
+  int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen;
+  REAL abt[8], bct[8], cat[8];
+  int abtlen, bctlen, catlen;
+  REAL abtt[4], bctt[4], catt[4];
+  int abttlen, bcttlen, cattlen;
+  INEXACT REAL abtt3, bctt3, catt3;
+  REAL negate;
+
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+  INEXACT REAL c;
+  INEXACT REAL abig;
+  REAL ahi, alo, bhi, blo;
+  REAL err1, err2, err3;
+  INEXACT REAL _i, _j;
+  REAL _0;
+
+  adx = (REAL) (pa[0] - pd[0]);
+  bdx = (REAL) (pb[0] - pd[0]);
+  cdx = (REAL) (pc[0] - pd[0]);
+  ady = (REAL) (pa[1] - pd[1]);
+  bdy = (REAL) (pb[1] - pd[1]);
+  cdy = (REAL) (pc[1] - pd[1]);
+
+  Two_Product(bdx, cdy, bdxcdy1, bdxcdy0);
+  Two_Product(cdx, bdy, cdxbdy1, cdxbdy0);
+  Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]);
+  bc[3] = bc3;
+  axbclen = scale_expansion_zeroelim(4, bc, adx, axbc);
+  axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc);
+  aybclen = scale_expansion_zeroelim(4, bc, ady, aybc);
+  ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc);
+  alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet);
+
+  Two_Product(cdx, ady, cdxady1, cdxady0);
+  Two_Product(adx, cdy, adxcdy1, adxcdy0);
+  Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]);
+  ca[3] = ca3;
+  bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca);
+  bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca);
+  bycalen = scale_expansion_zeroelim(4, ca, bdy, byca);
+  byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca);
+  blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet);
+
+  Two_Product(adx, bdy, adxbdy1, adxbdy0);
+  Two_Product(bdx, ady, bdxady1, bdxady0);
+  Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]);
+  ab[3] = ab3;
+  cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab);
+  cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab);
+  cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab);
+  cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab);
+  clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet);
+
+  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
+  finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1);
+
+  det = estimate(finlength, fin1);
+  errbound = iccerrboundB * permanent;
+  if ((det >= errbound) || (-det >= errbound)) {
+    return det;
+  }
+
+  Two_Diff_Tail(pa[0], pd[0], adx, adxtail);
+  Two_Diff_Tail(pa[1], pd[1], ady, adytail);
+  Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail);
+  Two_Diff_Tail(pb[1], pd[1], bdy, bdytail);
+  Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail);
+  Two_Diff_Tail(pc[1], pd[1], cdy, cdytail);
+  if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0)
+      && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)) {
+    return det;
+  }
+
+  errbound = iccerrboundC * permanent + resulterrbound * Absolute(det);
+  det += ((adx * adx + ady * ady) * ((bdx * cdytail + cdy * bdxtail)
+                                     - (bdy * cdxtail + cdx * bdytail))
+          + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx))
+       + ((bdx * bdx + bdy * bdy) * ((cdx * adytail + ady * cdxtail)
+                                     - (cdy * adxtail + adx * cdytail))
+          + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx))
+       + ((cdx * cdx + cdy * cdy) * ((adx * bdytail + bdy * adxtail)
+                                     - (ady * bdxtail + bdx * adytail))
+          + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx));
+  if ((det >= errbound) || (-det >= errbound)) {
+    return det;
+  }
+
+  finnow = fin1;
+  finother = fin2;
+
+  if ((bdxtail != 0.0) || (bdytail != 0.0)
+      || (cdxtail != 0.0) || (cdytail != 0.0)) {
+    Square(adx, adxadx1, adxadx0);
+    Square(ady, adyady1, adyady0);
+    Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]);
+    aa[3] = aa3;
+  }
+  if ((cdxtail != 0.0) || (cdytail != 0.0)
+      || (adxtail != 0.0) || (adytail != 0.0)) {
+    Square(bdx, bdxbdx1, bdxbdx0);
+    Square(bdy, bdybdy1, bdybdy0);
+    Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]);
+    bb[3] = bb3;
+  }
+  if ((adxtail != 0.0) || (adytail != 0.0)
+      || (bdxtail != 0.0) || (bdytail != 0.0)) {
+    Square(cdx, cdxcdx1, cdxcdx0);
+    Square(cdy, cdycdy1, cdycdy0);
+    Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]);
+    cc[3] = cc3;
+  }
+
+  if (adxtail != 0.0) {
+    axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc);
+    temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx,
+                                          temp16a);
+
+    axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc);
+    temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b);
+
+    axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb);
+    temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c);
+
+    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                            temp16blen, temp16b, temp32a);
+    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
+                                            temp32alen, temp32a, temp48);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
+                                            temp48, finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+  if (adytail != 0.0) {
+    aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc);
+    temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady,
+                                          temp16a);
+
+    aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb);
+    temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b);
+
+    aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc);
+    temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c);
+
+    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                            temp16blen, temp16b, temp32a);
+    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
+                                            temp32alen, temp32a, temp48);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
+                                            temp48, finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+  if (bdxtail != 0.0) {
+    bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca);
+    temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx,
+                                          temp16a);
+
+    bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa);
+    temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b);
+
+    bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc);
+    temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c);
+
+    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                            temp16blen, temp16b, temp32a);
+    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
+                                            temp32alen, temp32a, temp48);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
+                                            temp48, finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+  if (bdytail != 0.0) {
+    bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca);
+    temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy,
+                                          temp16a);
+
+    bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc);
+    temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b);
+
+    bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa);
+    temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c);
+
+    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                            temp16blen, temp16b, temp32a);
+    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
+                                            temp32alen, temp32a, temp48);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
+                                            temp48, finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+  if (cdxtail != 0.0) {
+    cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab);
+    temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx,
+                                          temp16a);
+
+    cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb);
+    temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b);
+
+    cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa);
+    temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c);
+
+    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                            temp16blen, temp16b, temp32a);
+    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
+                                            temp32alen, temp32a, temp48);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
+                                            temp48, finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+  if (cdytail != 0.0) {
+    cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab);
+    temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy,
+                                          temp16a);
+
+    cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa);
+    temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b);
+
+    cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb);
+    temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c);
+
+    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                            temp16blen, temp16b, temp32a);
+    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
+                                            temp32alen, temp32a, temp48);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
+                                            temp48, finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+
+  if ((adxtail != 0.0) || (adytail != 0.0)) {
+    if ((bdxtail != 0.0) || (bdytail != 0.0)
+        || (cdxtail != 0.0) || (cdytail != 0.0)) {
+      Two_Product(bdxtail, cdy, ti1, ti0);
+      Two_Product(bdx, cdytail, tj1, tj0);
+      Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
+      u[3] = u3;
+      negate = -bdy;
+      Two_Product(cdxtail, negate, ti1, ti0);
+      negate = -bdytail;
+      Two_Product(cdx, negate, tj1, tj0);
+      Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
+      v[3] = v3;
+      bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct);
+
+      Two_Product(bdxtail, cdytail, ti1, ti0);
+      Two_Product(cdxtail, bdytail, tj1, tj0);
+      Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]);
+      bctt[3] = bctt3;
+      bcttlen = 4;
+    } else {
+      bct[0] = 0.0;
+      bctlen = 1;
+      bctt[0] = 0.0;
+      bcttlen = 1;
+    }
+
+    if (adxtail != 0.0) {
+      temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a);
+      axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct);
+      temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx,
+                                            temp32a);
+      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                              temp32alen, temp32a, temp48);
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
+                                              temp48, finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+      if (bdytail != 0.0) {
+        temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8);
+        temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail,
+                                              temp16a);
+        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
+                                                temp16a, finother);
+        finswap = finnow; finnow = finother; finother = finswap;
+      }
+      if (cdytail != 0.0) {
+        temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8);
+        temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail,
+                                              temp16a);
+        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
+                                                temp16a, finother);
+        finswap = finnow; finnow = finother; finother = finswap;
+      }
+
+      temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail,
+                                            temp32a);
+      axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt);
+      temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx,
+                                            temp16a);
+      temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail,
+                                            temp16b);
+      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                              temp16blen, temp16b, temp32b);
+      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                              temp32blen, temp32b, temp64);
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
+                                              temp64, finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+    }
+    if (adytail != 0.0) {
+      temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a);
+      aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct);
+      temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady,
+                                            temp32a);
+      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                              temp32alen, temp32a, temp48);
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
+                                              temp48, finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+
+
+      temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail,
+                                            temp32a);
+      aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt);
+      temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady,
+                                            temp16a);
+      temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail,
+                                            temp16b);
+      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                              temp16blen, temp16b, temp32b);
+      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                              temp32blen, temp32b, temp64);
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
+                                              temp64, finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+    }
+  }
+  if ((bdxtail != 0.0) || (bdytail != 0.0)) {
+    if ((cdxtail != 0.0) || (cdytail != 0.0)
+        || (adxtail != 0.0) || (adytail != 0.0)) {
+      Two_Product(cdxtail, ady, ti1, ti0);
+      Two_Product(cdx, adytail, tj1, tj0);
+      Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
+      u[3] = u3;
+      negate = -cdy;
+      Two_Product(adxtail, negate, ti1, ti0);
+      negate = -cdytail;
+      Two_Product(adx, negate, tj1, tj0);
+      Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
+      v[3] = v3;
+      catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat);
+
+      Two_Product(cdxtail, adytail, ti1, ti0);
+      Two_Product(adxtail, cdytail, tj1, tj0);
+      Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]);
+      catt[3] = catt3;
+      cattlen = 4;
+    } else {
+      cat[0] = 0.0;
+      catlen = 1;
+      catt[0] = 0.0;
+      cattlen = 1;
+    }
+
+    if (bdxtail != 0.0) {
+      temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a);
+      bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat);
+      temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx,
+                                            temp32a);
+      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                              temp32alen, temp32a, temp48);
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
+                                              temp48, finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+      if (cdytail != 0.0) {
+        temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8);
+        temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail,
+                                              temp16a);
+        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
+                                                temp16a, finother);
+        finswap = finnow; finnow = finother; finother = finswap;
+      }
+      if (adytail != 0.0) {
+        temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8);
+        temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail,
+                                              temp16a);
+        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
+                                                temp16a, finother);
+        finswap = finnow; finnow = finother; finother = finswap;
+      }
+
+      temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail,
+                                            temp32a);
+      bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt);
+      temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx,
+                                            temp16a);
+      temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail,
+                                            temp16b);
+      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                              temp16blen, temp16b, temp32b);
+      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                              temp32blen, temp32b, temp64);
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
+                                              temp64, finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+    }
+    if (bdytail != 0.0) {
+      temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a);
+      bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat);
+      temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy,
+                                            temp32a);
+      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                              temp32alen, temp32a, temp48);
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
+                                              temp48, finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+
+
+      temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail,
+                                            temp32a);
+      bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt);
+      temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy,
+                                            temp16a);
+      temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail,
+                                            temp16b);
+      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                              temp16blen, temp16b, temp32b);
+      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                              temp32blen, temp32b, temp64);
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
+                                              temp64, finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+    }
+  }
+  if ((cdxtail != 0.0) || (cdytail != 0.0)) {
+    if ((adxtail != 0.0) || (adytail != 0.0)
+        || (bdxtail != 0.0) || (bdytail != 0.0)) {
+      Two_Product(adxtail, bdy, ti1, ti0);
+      Two_Product(adx, bdytail, tj1, tj0);
+      Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
+      u[3] = u3;
+      negate = -ady;
+      Two_Product(bdxtail, negate, ti1, ti0);
+      negate = -adytail;
+      Two_Product(bdx, negate, tj1, tj0);
+      Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
+      v[3] = v3;
+      abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt);
+
+      Two_Product(adxtail, bdytail, ti1, ti0);
+      Two_Product(bdxtail, adytail, tj1, tj0);
+      Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]);
+      abtt[3] = abtt3;
+      abttlen = 4;
+    } else {
+      abt[0] = 0.0;
+      abtlen = 1;
+      abtt[0] = 0.0;
+      abttlen = 1;
+    }
+
+    if (cdxtail != 0.0) {
+      temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a);
+      cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt);
+      temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx,
+                                            temp32a);
+      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                              temp32alen, temp32a, temp48);
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
+                                              temp48, finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+      if (adytail != 0.0) {
+        temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8);
+        temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail,
+                                              temp16a);
+        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
+                                                temp16a, finother);
+        finswap = finnow; finnow = finother; finother = finswap;
+      }
+      if (bdytail != 0.0) {
+        temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8);
+        temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail,
+                                              temp16a);
+        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
+                                                temp16a, finother);
+        finswap = finnow; finnow = finother; finother = finswap;
+      }
+
+      temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail,
+                                            temp32a);
+      cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt);
+      temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx,
+                                            temp16a);
+      temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail,
+                                            temp16b);
+      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                              temp16blen, temp16b, temp32b);
+      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                              temp32blen, temp32b, temp64);
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
+                                              temp64, finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+    }
+    if (cdytail != 0.0) {
+      temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a);
+      cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt);
+      temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy,
+                                            temp32a);
+      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                              temp32alen, temp32a, temp48);
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
+                                              temp48, finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+
+
+      temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail,
+                                            temp32a);
+      cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt);
+      temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy,
+                                            temp16a);
+      temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail,
+                                            temp16b);
+      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
+                                              temp16blen, temp16b, temp32b);
+      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                              temp32blen, temp32b, temp64);
+      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
+                                              temp64, finother);
+      finswap = finnow; finnow = finother; finother = finswap;
+    }
+  }
+
+  return finnow[finlength - 1];
+}
+
+REAL incircle(REAL* pa, REAL* pb, REAL* pc, REAL* pd)
+{
+  REAL adx, bdx, cdx, ady, bdy, cdy;
+  REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
+  REAL alift, blift, clift;
+  REAL det;
+  REAL permanent, errbound;
+
+  adx = pa[0] - pd[0];
+  bdx = pb[0] - pd[0];
+  cdx = pc[0] - pd[0];
+  ady = pa[1] - pd[1];
+  bdy = pb[1] - pd[1];
+  cdy = pc[1] - pd[1];
+
+  bdxcdy = bdx * cdy;
+  cdxbdy = cdx * bdy;
+  alift = adx * adx + ady * ady;
+
+  cdxady = cdx * ady;
+  adxcdy = adx * cdy;
+  blift = bdx * bdx + bdy * bdy;
+
+  adxbdy = adx * bdy;
+  bdxady = bdx * ady;
+  clift = cdx * cdx + cdy * cdy;
+
+  det = alift * (bdxcdy - cdxbdy)
+      + blift * (cdxady - adxcdy)
+      + clift * (adxbdy - bdxady);
+
+  permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift
+            + (Absolute(cdxady) + Absolute(adxcdy)) * blift
+            + (Absolute(adxbdy) + Absolute(bdxady)) * clift;
+  errbound = iccerrboundA * permanent;
+  if ((det > errbound) || (-det > errbound)) {
+    return det;
+  }
+
+  return incircleadapt(pa, pb, pc, pd, permanent);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+//  insphere()       Adaptive exact 3D insphere test.  Robust.               //
+//                                                                           //
+//               Return a positive value if the point pe lies inside the     //
+//               sphere passing through pa, pb, pc, and pd; a negative value //
+//               if it lies outside; and zero if the five points are         //
+//               cospherical.  The points pa, pb, pc, and pd must be ordered //
+//               so that they have a positive orientation (as defined by     //
+//               orient3d()), or the sign of the result will be reversed.    //
+//                                                                           //
+//  insphere() use exact arithmetic to ensure a correct answer.  The result  //
+//  returned is the determinant of a matrix.  In insphere() only, this       //
+//  determinant is computed adaptively, in the sense that exact arithmetic   //
+//  is used only to the degree it is needed to ensure that the returned      //
+//  value has the correct sign.  Hence, insphere() is usually quite fast,    //
+//  but will run more slowly when the input points are cospherical or nearly //
+//  so.                                                                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL insphereexact(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe)
+{
+  INEXACT REAL axby1, bxcy1, cxdy1, dxey1, exay1;
+  INEXACT REAL bxay1, cxby1, dxcy1, exdy1, axey1;
+  INEXACT REAL axcy1, bxdy1, cxey1, dxay1, exby1;
+  INEXACT REAL cxay1, dxby1, excy1, axdy1, bxey1;
+  REAL axby0, bxcy0, cxdy0, dxey0, exay0;
+  REAL bxay0, cxby0, dxcy0, exdy0, axey0;
+  REAL axcy0, bxdy0, cxey0, dxay0, exby0;
+  REAL cxay0, dxby0, excy0, axdy0, bxey0;
+  REAL ab[4], bc[4], cd[4], de[4], ea[4];
+  REAL ac[4], bd[4], ce[4], da[4], eb[4];
+  REAL temp8a[8], temp8b[8], temp16[16];
+  int temp8alen, temp8blen, temp16len;
+  REAL abc[24], bcd[24], cde[24], dea[24], eab[24];
+  REAL abd[24], bce[24], cda[24], deb[24], eac[24];
+  int abclen, bcdlen, cdelen, dealen, eablen;
+  int abdlen, bcelen, cdalen, deblen, eaclen;
+  REAL temp48a[48], temp48b[48];
+  int temp48alen, temp48blen;
+  REAL abcd[96], bcde[96], cdea[96], deab[96], eabc[96];
+  int abcdlen, bcdelen, cdealen, deablen, eabclen;
+  REAL temp192[192];
+  REAL det384x[384], det384y[384], det384z[384];
+  int xlen, ylen, zlen;
+  REAL detxy[768];
+  int xylen;
+  REAL adet[1152], bdet[1152], cdet[1152], ddet[1152], edet[1152];
+  int alen, blen, clen, dlen, elen;
+  REAL abdet[2304], cddet[2304], cdedet[3456];
+  int ablen, cdlen;
+  REAL deter[5760];
+  int deterlen;
+  int i;
+
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+  INEXACT REAL c;
+  INEXACT REAL abig;
+  REAL ahi, alo, bhi, blo;
+  REAL err1, err2, err3;
+  INEXACT REAL _i, _j;
+  REAL _0;
+
+  Two_Product(pa[0], pb[1], axby1, axby0);
+  Two_Product(pb[0], pa[1], bxay1, bxay0);
+  Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]);
+
+  Two_Product(pb[0], pc[1], bxcy1, bxcy0);
+  Two_Product(pc[0], pb[1], cxby1, cxby0);
+  Two_Two_Diff(bxcy1, bxcy0, cxby1, cxby0, bc[3], bc[2], bc[1], bc[0]);
+
+  Two_Product(pc[0], pd[1], cxdy1, cxdy0);
+  Two_Product(pd[0], pc[1], dxcy1, dxcy0);
+  Two_Two_Diff(cxdy1, cxdy0, dxcy1, dxcy0, cd[3], cd[2], cd[1], cd[0]);
+
+  Two_Product(pd[0], pe[1], dxey1, dxey0);
+  Two_Product(pe[0], pd[1], exdy1, exdy0);
+  Two_Two_Diff(dxey1, dxey0, exdy1, exdy0, de[3], de[2], de[1], de[0]);
+
+  Two_Product(pe[0], pa[1], exay1, exay0);
+  Two_Product(pa[0], pe[1], axey1, axey0);
+  Two_Two_Diff(exay1, exay0, axey1, axey0, ea[3], ea[2], ea[1], ea[0]);
+
+  Two_Product(pa[0], pc[1], axcy1, axcy0);
+  Two_Product(pc[0], pa[1], cxay1, cxay0);
+  Two_Two_Diff(axcy1, axcy0, cxay1, cxay0, ac[3], ac[2], ac[1], ac[0]);
+
+  Two_Product(pb[0], pd[1], bxdy1, bxdy0);
+  Two_Product(pd[0], pb[1], dxby1, dxby0);
+  Two_Two_Diff(bxdy1, bxdy0, dxby1, dxby0, bd[3], bd[2], bd[1], bd[0]);
+
+  Two_Product(pc[0], pe[1], cxey1, cxey0);
+  Two_Product(pe[0], pc[1], excy1, excy0);
+  Two_Two_Diff(cxey1, cxey0, excy1, excy0, ce[3], ce[2], ce[1], ce[0]);
+
+  Two_Product(pd[0], pa[1], dxay1, dxay0);
+  Two_Product(pa[0], pd[1], axdy1, axdy0);
+  Two_Two_Diff(dxay1, dxay0, axdy1, axdy0, da[3], da[2], da[1], da[0]);
+
+  Two_Product(pe[0], pb[1], exby1, exby0);
+  Two_Product(pb[0], pe[1], bxey1, bxey0);
+  Two_Two_Diff(exby1, exby0, bxey1, bxey0, eb[3], eb[2], eb[1], eb[0]);
+
+  temp8alen = scale_expansion_zeroelim(4, bc, pa[2], temp8a);
+  temp8blen = scale_expansion_zeroelim(4, ac, -pb[2], temp8b);
+  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
+                                          temp16);
+  temp8alen = scale_expansion_zeroelim(4, ab, pc[2], temp8a);
+  abclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
+                                       abc);
+
+  temp8alen = scale_expansion_zeroelim(4, cd, pb[2], temp8a);
+  temp8blen = scale_expansion_zeroelim(4, bd, -pc[2], temp8b);
+  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
+                                          temp16);
+  temp8alen = scale_expansion_zeroelim(4, bc, pd[2], temp8a);
+  bcdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
+                                       bcd);
+
+  temp8alen = scale_expansion_zeroelim(4, de, pc[2], temp8a);
+  temp8blen = scale_expansion_zeroelim(4, ce, -pd[2], temp8b);
+  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
+                                          temp16);
+  temp8alen = scale_expansion_zeroelim(4, cd, pe[2], temp8a);
+  cdelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
+                                       cde);
+
+  temp8alen = scale_expansion_zeroelim(4, ea, pd[2], temp8a);
+  temp8blen = scale_expansion_zeroelim(4, da, -pe[2], temp8b);
+  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
+                                          temp16);
+  temp8alen = scale_expansion_zeroelim(4, de, pa[2], temp8a);
+  dealen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
+                                       dea);
+
+  temp8alen = scale_expansion_zeroelim(4, ab, pe[2], temp8a);
+  temp8blen = scale_expansion_zeroelim(4, eb, -pa[2], temp8b);
+  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
+                                          temp16);
+  temp8alen = scale_expansion_zeroelim(4, ea, pb[2], temp8a);
+  eablen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
+                                       eab);
+
+  temp8alen = scale_expansion_zeroelim(4, bd, pa[2], temp8a);
+  temp8blen = scale_expansion_zeroelim(4, da, pb[2], temp8b);
+  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
+                                          temp16);
+  temp8alen = scale_expansion_zeroelim(4, ab, pd[2], temp8a);
+  abdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
+                                       abd);
+
+  temp8alen = scale_expansion_zeroelim(4, ce, pb[2], temp8a);
+  temp8blen = scale_expansion_zeroelim(4, eb, pc[2], temp8b);
+  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
+                                          temp16);
+  temp8alen = scale_expansion_zeroelim(4, bc, pe[2], temp8a);
+  bcelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
+                                       bce);
+
+  temp8alen = scale_expansion_zeroelim(4, da, pc[2], temp8a);
+  temp8blen = scale_expansion_zeroelim(4, ac, pd[2], temp8b);
+  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
+                                          temp16);
+  temp8alen = scale_expansion_zeroelim(4, cd, pa[2], temp8a);
+  cdalen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
+                                       cda);
+
+  temp8alen = scale_expansion_zeroelim(4, eb, pd[2], temp8a);
+  temp8blen = scale_expansion_zeroelim(4, bd, pe[2], temp8b);
+  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
+                                          temp16);
+  temp8alen = scale_expansion_zeroelim(4, de, pb[2], temp8a);
+  deblen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
+                                       deb);
+
+  temp8alen = scale_expansion_zeroelim(4, ac, pe[2], temp8a);
+  temp8blen = scale_expansion_zeroelim(4, ce, pa[2], temp8b);
+  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
+                                          temp16);
+  temp8alen = scale_expansion_zeroelim(4, ea, pc[2], temp8a);
+  eaclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
+                                       eac);
+
+  temp48alen = fast_expansion_sum_zeroelim(cdelen, cde, bcelen, bce, temp48a);
+  temp48blen = fast_expansion_sum_zeroelim(deblen, deb, bcdlen, bcd, temp48b);
+  for (i = 0; i < temp48blen; i++) {
+    temp48b[i] = -temp48b[i];
+  }
+  bcdelen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
+                                        temp48blen, temp48b, bcde);
+  xlen = scale_expansion_zeroelim(bcdelen, bcde, pa[0], temp192);
+  xlen = scale_expansion_zeroelim(xlen, temp192, pa[0], det384x);
+  ylen = scale_expansion_zeroelim(bcdelen, bcde, pa[1], temp192);
+  ylen = scale_expansion_zeroelim(ylen, temp192, pa[1], det384y);
+  zlen = scale_expansion_zeroelim(bcdelen, bcde, pa[2], temp192);
+  zlen = scale_expansion_zeroelim(zlen, temp192, pa[2], det384z);
+  xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy);
+  alen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, adet);
+
+  temp48alen = fast_expansion_sum_zeroelim(dealen, dea, cdalen, cda, temp48a);
+  temp48blen = fast_expansion_sum_zeroelim(eaclen, eac, cdelen, cde, temp48b);
+  for (i = 0; i < temp48blen; i++) {
+    temp48b[i] = -temp48b[i];
+  }
+  cdealen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
+                                        temp48blen, temp48b, cdea);
+  xlen = scale_expansion_zeroelim(cdealen, cdea, pb[0], temp192);
+  xlen = scale_expansion_zeroelim(xlen, temp192, pb[0], det384x);
+  ylen = scale_expansion_zeroelim(cdealen, cdea, pb[1], temp192);
+  ylen = scale_expansion_zeroelim(ylen, temp192, pb[1], det384y);
+  zlen = scale_expansion_zeroelim(cdealen, cdea, pb[2], temp192);
+  zlen = scale_expansion_zeroelim(zlen, temp192, pb[2], det384z);
+  xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy);
+  blen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, bdet);
+
+  temp48alen = fast_expansion_sum_zeroelim(eablen, eab, deblen, deb, temp48a);
+  temp48blen = fast_expansion_sum_zeroelim(abdlen, abd, dealen, dea, temp48b);
+  for (i = 0; i < temp48blen; i++) {
+    temp48b[i] = -temp48b[i];
+  }
+  deablen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
+                                        temp48blen, temp48b, deab);
+  xlen = scale_expansion_zeroelim(deablen, deab, pc[0], temp192);
+  xlen = scale_expansion_zeroelim(xlen, temp192, pc[0], det384x);
+  ylen = scale_expansion_zeroelim(deablen, deab, pc[1], temp192);
+  ylen = scale_expansion_zeroelim(ylen, temp192, pc[1], det384y);
+  zlen = scale_expansion_zeroelim(deablen, deab, pc[2], temp192);
+  zlen = scale_expansion_zeroelim(zlen, temp192, pc[2], det384z);
+  xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy);
+  clen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, cdet);
+
+  temp48alen = fast_expansion_sum_zeroelim(abclen, abc, eaclen, eac, temp48a);
+  temp48blen = fast_expansion_sum_zeroelim(bcelen, bce, eablen, eab, temp48b);
+  for (i = 0; i < temp48blen; i++) {
+    temp48b[i] = -temp48b[i];
+  }
+  eabclen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
+                                        temp48blen, temp48b, eabc);
+  xlen = scale_expansion_zeroelim(eabclen, eabc, pd[0], temp192);
+  xlen = scale_expansion_zeroelim(xlen, temp192, pd[0], det384x);
+  ylen = scale_expansion_zeroelim(eabclen, eabc, pd[1], temp192);
+  ylen = scale_expansion_zeroelim(ylen, temp192, pd[1], det384y);
+  zlen = scale_expansion_zeroelim(eabclen, eabc, pd[2], temp192);
+  zlen = scale_expansion_zeroelim(zlen, temp192, pd[2], det384z);
+  xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy);
+  dlen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, ddet);
+
+  temp48alen = fast_expansion_sum_zeroelim(bcdlen, bcd, abdlen, abd, temp48a);
+  temp48blen = fast_expansion_sum_zeroelim(cdalen, cda, abclen, abc, temp48b);
+  for (i = 0; i < temp48blen; i++) {
+    temp48b[i] = -temp48b[i];
+  }
+  abcdlen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
+                                        temp48blen, temp48b, abcd);
+  xlen = scale_expansion_zeroelim(abcdlen, abcd, pe[0], temp192);
+  xlen = scale_expansion_zeroelim(xlen, temp192, pe[0], det384x);
+  ylen = scale_expansion_zeroelim(abcdlen, abcd, pe[1], temp192);
+  ylen = scale_expansion_zeroelim(ylen, temp192, pe[1], det384y);
+  zlen = scale_expansion_zeroelim(abcdlen, abcd, pe[2], temp192);
+  zlen = scale_expansion_zeroelim(zlen, temp192, pe[2], det384z);
+  xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy);
+  elen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, edet);
+
+  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
+  cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet);
+  cdelen = fast_expansion_sum_zeroelim(cdlen, cddet, elen, edet, cdedet);
+  deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdelen, cdedet, deter);
+
+  return deter[deterlen - 1];
+}
+
+REAL insphereadapt(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe, REAL permanent)
+{
+  INEXACT REAL aex, bex, cex, dex, aey, bey, cey, dey, aez, bez, cez, dez;
+  REAL det, errbound;
+
+  INEXACT REAL aexbey1, bexaey1, bexcey1, cexbey1;
+  INEXACT REAL cexdey1, dexcey1, dexaey1, aexdey1;
+  INEXACT REAL aexcey1, cexaey1, bexdey1, dexbey1;
+  REAL aexbey0, bexaey0, bexcey0, cexbey0;
+  REAL cexdey0, dexcey0, dexaey0, aexdey0;
+  REAL aexcey0, cexaey0, bexdey0, dexbey0;
+  REAL ab[4], bc[4], cd[4], da[4], ac[4], bd[4];
+  INEXACT REAL ab3, bc3, cd3, da3, ac3, bd3;
+  REAL abeps, bceps, cdeps, daeps, aceps, bdeps;
+  REAL temp8a[8], temp8b[8], temp8c[8], temp16[16], temp24[24], temp48[48];
+  int temp8alen, temp8blen, temp8clen, temp16len, temp24len, temp48len;
+  REAL xdet[96], ydet[96], zdet[96], xydet[192];
+  int xlen, ylen, zlen, xylen;
+  REAL adet[288], bdet[288], cdet[288], ddet[288];
+  int alen, blen, clen, dlen;
+  REAL abdet[576], cddet[576];
+  int ablen, cdlen;
+  REAL fin1[1152];
+  int finlength;
+
+  REAL aextail, bextail, cextail, dextail;
+  REAL aeytail, beytail, ceytail, deytail;
+  REAL aeztail, beztail, ceztail, deztail;
+
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+  INEXACT REAL c;
+  INEXACT REAL abig;
+  REAL ahi, alo, bhi, blo;
+  REAL err1, err2, err3;
+  INEXACT REAL _i, _j;
+  REAL _0;
+
+  aex = (REAL) (pa[0] - pe[0]);
+  bex = (REAL) (pb[0] - pe[0]);
+  cex = (REAL) (pc[0] - pe[0]);
+  dex = (REAL) (pd[0] - pe[0]);
+  aey = (REAL) (pa[1] - pe[1]);
+  bey = (REAL) (pb[1] - pe[1]);
+  cey = (REAL) (pc[1] - pe[1]);
+  dey = (REAL) (pd[1] - pe[1]);
+  aez = (REAL) (pa[2] - pe[2]);
+  bez = (REAL) (pb[2] - pe[2]);
+  cez = (REAL) (pc[2] - pe[2]);
+  dez = (REAL) (pd[2] - pe[2]);
+
+  Two_Product(aex, bey, aexbey1, aexbey0);
+  Two_Product(bex, aey, bexaey1, bexaey0);
+  Two_Two_Diff(aexbey1, aexbey0, bexaey1, bexaey0, ab3, ab[2], ab[1], ab[0]);
+  ab[3] = ab3;
+
+  Two_Product(bex, cey, bexcey1, bexcey0);
+  Two_Product(cex, bey, cexbey1, cexbey0);
+  Two_Two_Diff(bexcey1, bexcey0, cexbey1, cexbey0, bc3, bc[2], bc[1], bc[0]);
+  bc[3] = bc3;
+
+  Two_Product(cex, dey, cexdey1, cexdey0);
+  Two_Product(dex, cey, dexcey1, dexcey0);
+  Two_Two_Diff(cexdey1, cexdey0, dexcey1, dexcey0, cd3, cd[2], cd[1], cd[0]);
+  cd[3] = cd3;
+
+  Two_Product(dex, aey, dexaey1, dexaey0);
+  Two_Product(aex, dey, aexdey1, aexdey0);
+  Two_Two_Diff(dexaey1, dexaey0, aexdey1, aexdey0, da3, da[2], da[1], da[0]);
+  da[3] = da3;
+
+  Two_Product(aex, cey, aexcey1, aexcey0);
+  Two_Product(cex, aey, cexaey1, cexaey0);
+  Two_Two_Diff(aexcey1, aexcey0, cexaey1, cexaey0, ac3, ac[2], ac[1], ac[0]);
+  ac[3] = ac3;
+
+  Two_Product(bex, dey, bexdey1, bexdey0);
+  Two_Product(dex, bey, dexbey1, dexbey0);
+  Two_Two_Diff(bexdey1, bexdey0, dexbey1, dexbey0, bd3, bd[2], bd[1], bd[0]);
+  bd[3] = bd3;
+
+  temp8alen = scale_expansion_zeroelim(4, cd, bez, temp8a);
+  temp8blen = scale_expansion_zeroelim(4, bd, -cez, temp8b);
+  temp8clen = scale_expansion_zeroelim(4, bc, dez, temp8c);
+  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a,
+                                          temp8blen, temp8b, temp16);
+  temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c,
+                                          temp16len, temp16, temp24);
+  temp48len = scale_expansion_zeroelim(temp24len, temp24, aex, temp48);
+  xlen = scale_expansion_zeroelim(temp48len, temp48, -aex, xdet);
+  temp48len = scale_expansion_zeroelim(temp24len, temp24, aey, temp48);
+  ylen = scale_expansion_zeroelim(temp48len, temp48, -aey, ydet);
+  temp48len = scale_expansion_zeroelim(temp24len, temp24, aez, temp48);
+  zlen = scale_expansion_zeroelim(temp48len, temp48, -aez, zdet);
+  xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet);
+  alen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, adet);
+
+  temp8alen = scale_expansion_zeroelim(4, da, cez, temp8a);
+  temp8blen = scale_expansion_zeroelim(4, ac, dez, temp8b);
+  temp8clen = scale_expansion_zeroelim(4, cd, aez, temp8c);
+  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a,
+                                          temp8blen, temp8b, temp16);
+  temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c,
+                                          temp16len, temp16, temp24);
+  temp48len = scale_expansion_zeroelim(temp24len, temp24, bex, temp48);
+  xlen = scale_expansion_zeroelim(temp48len, temp48, bex, xdet);
+  temp48len = scale_expansion_zeroelim(temp24len, temp24, bey, temp48);
+  ylen = scale_expansion_zeroelim(temp48len, temp48, bey, ydet);
+  temp48len = scale_expansion_zeroelim(temp24len, temp24, bez, temp48);
+  zlen = scale_expansion_zeroelim(temp48len, temp48, bez, zdet);
+  xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet);
+  blen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, bdet);
+
+  temp8alen = scale_expansion_zeroelim(4, ab, dez, temp8a);
+  temp8blen = scale_expansion_zeroelim(4, bd, aez, temp8b);
+  temp8clen = scale_expansion_zeroelim(4, da, bez, temp8c);
+  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a,
+                                          temp8blen, temp8b, temp16);
+  temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c,
+                                          temp16len, temp16, temp24);
+  temp48len = scale_expansion_zeroelim(temp24len, temp24, cex, temp48);
+  xlen = scale_expansion_zeroelim(temp48len, temp48, -cex, xdet);
+  temp48len = scale_expansion_zeroelim(temp24len, temp24, cey, temp48);
+  ylen = scale_expansion_zeroelim(temp48len, temp48, -cey, ydet);
+  temp48len = scale_expansion_zeroelim(temp24len, temp24, cez, temp48);
+  zlen = scale_expansion_zeroelim(temp48len, temp48, -cez, zdet);
+  xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet);
+  clen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, cdet);
+
+  temp8alen = scale_expansion_zeroelim(4, bc, aez, temp8a);
+  temp8blen = scale_expansion_zeroelim(4, ac, -bez, temp8b);
+  temp8clen = scale_expansion_zeroelim(4, ab, cez, temp8c);
+  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a,
+                                          temp8blen, temp8b, temp16);
+  temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c,
+                                          temp16len, temp16, temp24);
+  temp48len = scale_expansion_zeroelim(temp24len, temp24, dex, temp48);
+  xlen = scale_expansion_zeroelim(temp48len, temp48, dex, xdet);
+  temp48len = scale_expansion_zeroelim(temp24len, temp24, dey, temp48);
+  ylen = scale_expansion_zeroelim(temp48len, temp48, dey, ydet);
+  temp48len = scale_expansion_zeroelim(temp24len, temp24, dez, temp48);
+  zlen = scale_expansion_zeroelim(temp48len, temp48, dez, zdet);
+  xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet);
+  dlen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, ddet);
+
+  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
+  cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet);
+  finlength = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, fin1);
+
+  det = estimate(finlength, fin1);
+  errbound = isperrboundB * permanent;
+  if ((det >= errbound) || (-det >= errbound)) {
+    return det;
+  }
+
+  Two_Diff_Tail(pa[0], pe[0], aex, aextail);
+  Two_Diff_Tail(pa[1], pe[1], aey, aeytail);
+  Two_Diff_Tail(pa[2], pe[2], aez, aeztail);
+  Two_Diff_Tail(pb[0], pe[0], bex, bextail);
+  Two_Diff_Tail(pb[1], pe[1], bey, beytail);
+  Two_Diff_Tail(pb[2], pe[2], bez, beztail);
+  Two_Diff_Tail(pc[0], pe[0], cex, cextail);
+  Two_Diff_Tail(pc[1], pe[1], cey, ceytail);
+  Two_Diff_Tail(pc[2], pe[2], cez, ceztail);
+  Two_Diff_Tail(pd[0], pe[0], dex, dextail);
+  Two_Diff_Tail(pd[1], pe[1], dey, deytail);
+  Two_Diff_Tail(pd[2], pe[2], dez, deztail);
+  if ((aextail == 0.0) && (aeytail == 0.0) && (aeztail == 0.0)
+      && (bextail == 0.0) && (beytail == 0.0) && (beztail == 0.0)
+      && (cextail == 0.0) && (ceytail == 0.0) && (ceztail == 0.0)
+      && (dextail == 0.0) && (deytail == 0.0) && (deztail == 0.0)) {
+    return det;
+  }
+
+  errbound = isperrboundC * permanent + resulterrbound * Absolute(det);
+  abeps = (aex * beytail + bey * aextail)
+        - (aey * bextail + bex * aeytail);
+  bceps = (bex * ceytail + cey * bextail)
+        - (bey * cextail + cex * beytail);
+  cdeps = (cex * deytail + dey * cextail)
+        - (cey * dextail + dex * ceytail);
+  daeps = (dex * aeytail + aey * dextail)
+        - (dey * aextail + aex * deytail);
+  aceps = (aex * ceytail + cey * aextail)
+        - (aey * cextail + cex * aeytail);
+  bdeps = (bex * deytail + dey * bextail)
+        - (bey * dextail + dex * beytail);
+  det += (((bex * bex + bey * bey + bez * bez)
+           * ((cez * daeps + dez * aceps + aez * cdeps)
+              + (ceztail * da3 + deztail * ac3 + aeztail * cd3))
+           + (dex * dex + dey * dey + dez * dez)
+           * ((aez * bceps - bez * aceps + cez * abeps)
+              + (aeztail * bc3 - beztail * ac3 + ceztail * ab3)))
+          - ((aex * aex + aey * aey + aez * aez)
+           * ((bez * cdeps - cez * bdeps + dez * bceps)
+              + (beztail * cd3 - ceztail * bd3 + deztail * bc3))
+           + (cex * cex + cey * cey + cez * cez)
+           * ((dez * abeps + aez * bdeps + bez * daeps)
+              + (deztail * ab3 + aeztail * bd3 + beztail * da3))))
+       + 2.0 * (((bex * bextail + bey * beytail + bez * beztail)
+                 * (cez * da3 + dez * ac3 + aez * cd3)
+                 + (dex * dextail + dey * deytail + dez * deztail)
+                 * (aez * bc3 - bez * ac3 + cez * ab3))
+                - ((aex * aextail + aey * aeytail + aez * aeztail)
+                 * (bez * cd3 - cez * bd3 + dez * bc3)
+                 + (cex * cextail + cey * ceytail + cez * ceztail)
+                 * (dez * ab3 + aez * bd3 + bez * da3)));
+  if ((det >= errbound) || (-det >= errbound)) {
+    return det;
+  }
+
+  return insphereexact(pa, pb, pc, pd, pe);
+}
+
+REAL insphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe)
+{
+  REAL aex, bex, cex, dex;
+  REAL aey, bey, cey, dey;
+  REAL aez, bez, cez, dez;
+  REAL aexbey, bexaey, bexcey, cexbey, cexdey, dexcey, dexaey, aexdey;
+  REAL aexcey, cexaey, bexdey, dexbey;
+  REAL alift, blift, clift, dlift;
+  REAL ab, bc, cd, da, ac, bd;
+  REAL abc, bcd, cda, dab;
+  REAL aezplus, bezplus, cezplus, dezplus;
+  REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus;
+  REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus;
+  REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus;
+  REAL det;
+  REAL permanent, errbound;
+
+  aex = pa[0] - pe[0];
+  bex = pb[0] - pe[0];
+  cex = pc[0] - pe[0];
+  dex = pd[0] - pe[0];
+  aey = pa[1] - pe[1];
+  bey = pb[1] - pe[1];
+  cey = pc[1] - pe[1];
+  dey = pd[1] - pe[1];
+  aez = pa[2] - pe[2];
+  bez = pb[2] - pe[2];
+  cez = pc[2] - pe[2];
+  dez = pd[2] - pe[2];
+
+  aexbey = aex * bey;
+  bexaey = bex * aey;
+  ab = aexbey - bexaey;
+  bexcey = bex * cey;
+  cexbey = cex * bey;
+  bc = bexcey - cexbey;
+  cexdey = cex * dey;
+  dexcey = dex * cey;
+  cd = cexdey - dexcey;
+  dexaey = dex * aey;
+  aexdey = aex * dey;
+  da = dexaey - aexdey;
+
+  aexcey = aex * cey;
+  cexaey = cex * aey;
+  ac = aexcey - cexaey;
+  bexdey = bex * dey;
+  dexbey = dex * bey;
+  bd = bexdey - dexbey;
+
+  abc = aez * bc - bez * ac + cez * ab;
+  bcd = bez * cd - cez * bd + dez * bc;
+  cda = cez * da + dez * ac + aez * cd;
+  dab = dez * ab + aez * bd + bez * da;
+
+  alift = aex * aex + aey * aey + aez * aez;
+  blift = bex * bex + bey * bey + bez * bez;
+  clift = cex * cex + cey * cey + cez * cez;
+  dlift = dex * dex + dey * dey + dez * dez;
+
+  det = (dlift * abc - clift * dab) + (blift * cda - alift * bcd);
+
+  aezplus = Absolute(aez);
+  bezplus = Absolute(bez);
+  cezplus = Absolute(cez);
+  dezplus = Absolute(dez);
+  aexbeyplus = Absolute(aexbey);
+  bexaeyplus = Absolute(bexaey);
+  bexceyplus = Absolute(bexcey);
+  cexbeyplus = Absolute(cexbey);
+  cexdeyplus = Absolute(cexdey);
+  dexceyplus = Absolute(dexcey);
+  dexaeyplus = Absolute(dexaey);
+  aexdeyplus = Absolute(aexdey);
+  aexceyplus = Absolute(aexcey);
+  cexaeyplus = Absolute(cexaey);
+  bexdeyplus = Absolute(bexdey);
+  dexbeyplus = Absolute(dexbey);
+  permanent = ((cexdeyplus + dexceyplus) * bezplus
+               + (dexbeyplus + bexdeyplus) * cezplus
+               + (bexceyplus + cexbeyplus) * dezplus)
+            * alift
+            + ((dexaeyplus + aexdeyplus) * cezplus
+               + (aexceyplus + cexaeyplus) * dezplus
+               + (cexdeyplus + dexceyplus) * aezplus)
+            * blift
+            + ((aexbeyplus + bexaeyplus) * dezplus
+               + (bexdeyplus + dexbeyplus) * aezplus
+               + (dexaeyplus + aexdeyplus) * bezplus)
+            * clift
+            + ((bexceyplus + cexbeyplus) * aezplus
+               + (cexaeyplus + aexceyplus) * bezplus
+               + (aexbeyplus + bexaeyplus) * cezplus)
+            * dlift;
+  errbound = isperrboundA * permanent;
+  if ((det > errbound) || (-det > errbound)) {
+    return det;
+  }
+
+  return insphereadapt(pa, pb, pc, pd, pe, permanent);
+}
diff --git a/Tetgen/quality.cpp b/Tetgen/quality.cpp
new file mode 100644
index 0000000000..879673f8d8
--- /dev/null
+++ b/Tetgen/quality.cpp
@@ -0,0 +1,1723 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// quality.cpp    Implement the Delaunay Mesh Refinement Algorithm of        //
+//                Shewchuk[2] to generate an almost good mesh.               //
+//                                                                           //
+// Tetgen Version 1.0 beta                                                   //
+// November, 2001                                                            //
+//                                                                           //
+// Si hang                                                                   //
+// Email: sihang@weboo.com                                                   //
+// http://www.weboo.com/sh/tetgen.htm                                        //
+//                                                                           //
+// You are free to use, copy and modify the sources under certain            //
+// circumstances, provided this copyright notice remains intact.             //
+// See the file LICENSE for details.                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Generating a mesh whose elements have small aspect ratio and their sizes  //
+// conform to a given control spacing function is one of the most important  //
+// steps in numerical simulations. The aspect ratio of an element is usually //
+// defined as the ratio of the radius of its circumsphere to the radius of   //
+// its inscribed sphere. An alternative but weaker quality measurement is    //
+// radius-edge ratio, which is the ratio of the circumradius to the shortest //
+// edge length of the tetrahedron.                                           //
+//                                                                           //
+// In two-dimensions, many methods guaranteed to generate well-shaped meshes,//
+// such as the two-dimensional Delaunay refinement method of J. Ruppert[1].  //
+// Surprisingly, in three-dimensions, generating well-shaped meshes is       //
+// considerablely more difficult, because it is difficult to identify and    //
+// remove some bad-shaped tetrahedra(like sliver) from the mesh. Even so,    //
+// generating a three-dimensional mesh with small radius-edge ratio is well  //
+// understood. Shewchuk[2] extend the Ruppert's method to three-dimensions   //
+// by proving that all tetrahedron will have radius-edge ratio no more than  //
+// 2.                                                                        //
+//                                                                           //
+// In this file, I implement Shewchuk's algorithm to generate an almost good //
+// tetrahedral mesh with good grading effect. But there is no guarantee that //
+// slivers can be eliminated.  It can be done by an additional mesh smooth-  //
+// ing and mesh improvement routines. This algorithm does not guarantee to   //
+// terminate when there exists small angles in the domain. It may cause      //
+// infinite loop in boundary protection step. For Tetgen can terminate in    //
+// all conditions, I modified the algorithm slightly on the split encroached //
+// subfaces rule. When a encroached subface is determined, it not always be  //
+// splited, only there is no small angle at this subface(that is, angle      //
+// between suface-to-subface and subface-to-subsegment is not a small angle  //
+// (<=45 degree)). (I'm looking for a pleasant way to fix this problem.)     //
+// Despite these unpleasant facts, the Delaunay refinement algorithm falls   //
+// into the class of algorithms that usually outperform their worst-case     //
+// bounds. One can apply a tighter bound (as low as 1.1)on radius-edge ratio //
+// than the theory suggests is possible, or even apply bounds on dihedral    //
+// angles, and still produce a small, nicely graded mesh.                    //
+//                                                                           //
+// Refernces:                                                                //
+//                                                                           //
+// [1] Jim Ruppert, A Delaunay Refinement Algorithm for Quality Two-         //
+//     Dimensional Mesh Generation, Journal of Algorithms 18(3):548-585,     //
+//     May 1995.                                                             //
+// [2] Jonathan Richard Shewchuk, Delaunay Refinement Mesh Generation.       //
+//     PhD thesis, School of Computer Science, Carnegie Mellon University,   //
+//     May 1997.                                                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tetlib.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dumplist()    Debug functions. Write the items of list to a text file.    //
+//                                                                           //
+// type = 0 tetrahedron, type = 1 subface, type = 2 subsegments.             //
+// If sort > 0, sort list before output.                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::dumplist(char* dumpfile, list* checklist, int type, int sort)
+{
+  FILE *outfile;
+  triface *checktet;
+  face *checksh;
+  point3d torg, tdest, tapex, toppo;
+  int i;
+
+  outfile = fopen(dumpfile, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("Error:  Cannot create file %s.\n", dumpfile);
+    return;
+  }
+  if (!quiet) {
+    printf("Writing %s.\n", dumpfile);
+  }
+  if (verbose < 1) {
+    numbernodes(1);
+  }
+  if (sort > 0) {
+    checklist->sort();
+  }
+  fprintf(outfile, "# Dumping %d items.\n", checklist->len());
+  for (i = 0; i < checklist->len(); i++) {
+    if (type == 0) {
+      checktet = (triface*)(*checklist)[i];
+      fprintf(outfile, "%4d  x%lx ", i, (unsigned long)(checktet->tet));
+      if (isdead(checktet)) {
+        fprintf(outfile, "(dead)\n");
+      } else {
+        org (*checktet, torg);
+        dest(*checktet, tdest);
+        apex(*checktet, tapex);
+        oppo(*checktet, toppo);
+        fprintf(outfile, "(%d, %d, %d, %d)\n", pointmark(torg),
+                pointmark(tdest), pointmark(tapex), pointmark(toppo));
+      }
+    } else if (type == 1) {
+      checksh = (face*)(*checklist)[i];
+      fprintf(outfile, "%4d  x%lx ", i, (unsigned long)(checksh->sh));
+      if (isdead(checksh)) {
+        fprintf(outfile, "(dead)\n");
+      } else {
+        sorg (*checksh, torg);
+        sdest(*checksh, tdest);
+        sapex(*checksh, tapex);
+        fprintf(outfile, "(%d, %d, %d)\n",
+                pointmark(torg), pointmark(tdest), pointmark(tapex));
+      }
+    } else if (type == 2) {
+      checksh = (face*)(*checklist)[i];
+      fprintf(outfile, "%4d  x%lx ", i, (unsigned long)(checksh->sh));
+      if (isdead(checksh)) {
+        fprintf(outfile, "(dead)\n");
+      } else {
+        sorg (*checksh, torg);
+        sdest(*checksh, tdest);
+        fprintf(outfile, "(%d, %d)\n", pointmark(torg), pointmark(tdest));
+      }
+    }
+  }
+  fclose(outfile);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Mesh quality testing routines                                             //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkquality()    To test edges of the face is encroached if they are     //
+//                   subsegments, otherwise to test if it is encroached if   //
+//                   it is a subface, last to test if the two tets abuting   //
+//                   this face are good quality.                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::checkquality(triface* testface)
+{
+  if (shsegflaws) {
+    face testseg;
+    int i;
+    for (i = 0; i < 3; i++) {
+      enextself(*testface);
+      tsspivot(testface, &testseg);
+      if (testseg.sh != dummysh) {
+        uncheckedshseglist->append(&testseg);
+      }
+    }
+  }
+  if (shflaws) {
+    face testsh;
+    tspivot(*testface, testsh);
+    if (testsh.sh != dummysh) {
+      uncheckedshlist->append(&testsh);
+    }
+  }
+  if (tetflaws) {
+    triface neighbortet;
+    uncheckedtetlist->append(testface);
+    sym(*testface, neighbortet);
+    if (neighbortet.tet != dummytet) {
+      uncheckedtetlist->append(&neighbortet);
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkedge4encroach()    Check a segment to see if it is encroached; add   //
+//                         it to the list if it is.                          //
+//                                                                           //
+// An encroached segment is an unflippable edge that has a point in its      //
+// diametral sphere (that is, it faces an angle greater than 90 degrees).    //
+// This definition is due to Ruppert[1]. While in three dimension, A         //
+// subsegment is encroached if a vertex other than its endpoints lies inside //
+// or on its diametral sphere (that is, it faces an angle greater than or    //
+// equal 90 degrees). This definition is due to Shewchuk[2]. This definition //
+// of encroachment is slightly stronger than Ruppert's, to ensure that all   //
+// unencroached subsegments are strongly Delaunay.                           //
+//                                                                           //
+// Returns a nonzero value if the edge is encroached.                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// Check whether the apex('eapex') is inside the diametral sphere of the
+//   subsegment(from 'eorg' to 'edest'). Pythagoras' Theorem is used to
+//   check whether the angle at the vertex is greater than 90 degrees.
+
+inline bool isedgeencroached(point3d eapex, point3d eorg, point3d edest)
+{
+  return (eapex[0] * (eorg[0] + edest[0]) +
+          eapex[1] * (eorg[1] + edest[1]) +
+          eapex[2] * (eorg[2] + edest[2]) >=
+          eapex[0] * eapex[0] + eorg[0] * edest[0] +
+          eapex[1] * eapex[1] + eorg[1] * edest[1] +
+          eapex[2] * eapex[2] + eorg[2] * edest[2]);
+}
+
+int mesh3d::checkedge4encroach(face *testedge, point3d testpoint)
+{
+  badface3d *badedge;
+  triface neighbortet, spintet;
+  triface tmptet;
+  face tmpseg;
+  point3d eorg, edest, eapex;
+  point3d torg, tdest, tapex;
+  int encroachflag, smallangleflag;
+  int hitbdry;
+
+  encroachflag = 0;
+  eorg = sorg(*testedge);
+  edest = sdest(*testedge);
+
+  if (testpoint == (point3d) NULL) {
+    // Spin around subsegment 'testedge', find all faces which contained
+    //   it. For each face, check whether its apex is inside the diametral
+    //   sphere of the 'testedge'.
+    sstpivot(testedge, &neighbortet);
+    spintet = neighbortet;
+    tapex = apex(neighbortet);
+    hitbdry = 0;
+    while (true) {
+      if (fnextself(spintet)) {
+        eapex = apex(spintet);
+        if (eapex == tapex) {
+          break; // Rewind, can leave now.
+        }
+        if (isedgeencroached(eapex, eorg, edest)) {
+          encroachflag = 1;
+          break;
+        }
+      } else {
+        hitbdry ++;
+        if (hitbdry >= 2) {
+          break;
+        } else {
+          esym(neighbortet, spintet);
+        }
+      }
+    }
+    if (!encroachflag) {
+      eapex = apex(neighbortet);
+      if (isedgeencroached(eapex, eorg, edest)) {
+        encroachflag = 1;
+      }
+    }
+  } else {
+    // Check does 'testedge' be encroached by 'testpoint'.
+    if ((testpoint != eorg) && (testpoint != edest)) {
+      if (isedgeencroached(testpoint, eorg, edest)) {
+        encroachflag = 1;
+        sstpivot(testedge, &neighbortet);
+      }
+    }
+  }
+
+  if (encroachflag && (!sinfected(*testedge)) &&
+      (!nobisect || ((nobisect == 1) && !isridge(&neighbortet)))) {
+    // 'testedge' is being encroached. It will be splitted by inserting its
+    //   midpoint.
+    // If 'testedge' is belong to one or more triangular faces which its
+    //  (or their) three edges are all subsegments. Don't insert midpoint.
+    //  Because it will create small angles which can't be removed by edge
+    //  flips.
+    spintet = neighbortet;
+    tapex = apex(neighbortet);
+    hitbdry = smallangleflag = 0;
+    while (true) {
+      if (fnextself(spintet)) {
+        eapex = apex(spintet);
+        if (eapex == tapex) {
+          break; // Rewind, can leave now.
+        }
+        tmptet = spintet;
+        enextself(tmptet);
+        tsspivot(&tmptet, &tmpseg);
+        if (tmpseg.sh != dummysh) {
+          enextself(tmptet);
+          tsspivot(&tmptet, &tmpseg);
+          if (tmpseg.sh != dummysh) {
+            smallangleflag = 1;
+            break;
+          }
+        }
+      } else {
+        hitbdry ++;
+        if (hitbdry >= 2) {
+          break;
+        } else {
+          esym(neighbortet, spintet);
+        }
+      }
+    }
+    if (!smallangleflag) {
+      tmptet = neighbortet;
+      enextself(tmptet);
+      tsspivot(&tmptet, &tmpseg);
+      if (tmpseg.sh != dummysh) {
+        enextself(tmptet);
+        tsspivot(&tmptet, &tmpseg);
+        if (tmpseg.sh != dummysh) {
+          smallangleflag = 1;
+        }
+      }
+    }
+
+    if (!smallangleflag) {
+      if (verbose > 2) {
+        printf("    Queueing encroached segment from %d to %d.\n",
+               pointmark(eorg), pointmark(edest));
+      }
+      // Add the shell edge to the list of encroached segments.
+      badedge = (badface3d *) badsegments.alloc();
+      badedge->shface = *testedge;
+      badedge->faceorg = eorg;
+      badedge->facedest = edest;
+    } else {
+      if (!quiet && verbose) {
+        printf("Warning:  Not split encroached subsegment:\n");
+        printf("  from (%.12g, %.12g, %.12g)\n",eorg[0], eorg[1], eorg[2]);
+        printf("  to   (%.12g, %.12g, %.12g)\n", edest[0], edest[1], edest[2]);
+      }
+      // Set a flag in 'testedge' to avoid multiple tests later.
+      //   Here temporarily use the tenth pointer ('testedge->sh[10]'), infect
+      //   its shver field.
+      sinfect(*testedge);
+    }
+  }
+
+  // The return value indicate 'testedge' is being encroached.
+  return encroachflag;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkface4encroach()    Check a subface to see if it is encroached; add   //
+//                         it to the list if it is.                          //
+//                                                                           //
+// An encroached subface is an unflippable face that has a point lies in or  //
+// on its equatorial sphere. This definition is due to Shewchuk[2].          //
+//                                                                           //
+// A priority queue used for keep Encroached faces. Why? The question 's     //
+// answer could be found at Shewchuk's paper[2]:                             //
+//   ...                                                                     //
+//   One further amendment to the algorithm is necessary to obtain the best  //
+// possible bound on the circumradius-to-shortest edge ratios of the tetrah- //
+// edra. When several encroached subfacets exist, they should not be split   //
+// in arbitrary order. If a vertex p encroaches upon a subfacet f of a facet //
+// F, but the projection of p to F dest not lie in f,  then splitting f is   //
+// not the best choice. One can show(Lemma 1) that there is some subfacet g  //
+// of F that is encroached upon by p and contain the projection point of p   //
+// to F. (The lemma assume that there are no encroached subsegments in the   //
+// mesh, as they have priority.) A better bound is achieved if the algorithm //
+// splits g first and delays the splitting of f indefinitely.                //
+//   ...                                                                     //
+//                                                                           //
+// Returns a nonzero value if the edge is encroached.                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::checkface4encroach(face* testface, point3d testpoint)
+{
+  triface testtet, tmptet, tmptmptet;
+  face testsh, neighborsh;
+  point3d forg, fdest, fapex, foppo;
+  enum locateresult loc;
+  REAL cent[3], proj[3];
+  REAL dx, dy, dz;
+  REAL radius2, dist2;
+  int encroachflag;
+
+  // If its a nonsolid face, need not check.
+  if (isnonsolid(*testface)) return 0;
+
+  // Find circumcenter of the face.
+  forg = sorg(*testface);
+  fdest = sdest(*testface);
+  fapex = sapex(*testface);
+  if ((testpoint != (point3d) NULL) &&
+      ((testpoint == forg) || (testpoint == fdest) || (testpoint == fapex))) {
+    return 0;
+  }
+  circumcenter(forg, fdest, fapex, cent);
+
+  // Get the square radius of equatorial sphere.
+  dx = forg[0] - cent[0];
+  dy = forg[1] - cent[1];
+  dz = forg[2] - cent[2];
+  radius2 = dx * dx + dy * dy + dz * dz;
+
+  encroachflag = 0;
+  if (testpoint == (point3d) NULL) {
+    // Check two opposite vertex to find encroaching point.
+    testsh = *testface;
+    stpivot(testsh, testtet);
+    if (testtet.tet != dummytet) {
+      foppo = oppo(testtet);
+      dx = foppo[0] - cent[0];
+      dy = foppo[1] - cent[1];
+      dz = foppo[2] - cent[2];
+      dist2 = dx * dx + dy * dy + dz * dz;
+      if (dist2 <= radius2) {
+        encroachflag = 1;
+      }
+    }
+    if (!encroachflag) {
+      sesymself(testsh);
+      stpivot(testsh, testtet);
+      if (testtet.tet != dummytet) {
+        foppo = oppo(testtet);
+        dx = foppo[0] - cent[0];
+        dy = foppo[1] - cent[1];
+        dz = foppo[2] - cent[2];
+        dist2 = dx * dx + dy * dy + dz * dz;
+        if (dist2 <= radius2) {
+          encroachflag = 1;
+        }
+      }
+    }
+  } else {
+    foppo = testpoint;
+    dx = foppo[0] - cent[0];
+    dy = foppo[1] - cent[1];
+    dz = foppo[2] - cent[2];
+    dist2 = dx * dx + dy * dy + dz * dz;
+    if (dist2 <= radius2) {
+      encroachflag = 1;
+      testsh = *testface;
+      stpivot(testsh, testtet);
+      if (testtet.tet == dummytet) {
+        sesymself(testsh);
+        stpivot(testsh, testtet);
+        assert(testtet.tet != dummytet);
+      }
+    }
+  }
+
+  if (encroachflag) {
+    // Before add it to bad face queue, we need check its project point
+    //   of this face to determine which queue(0 or 1) it should keep.
+    proj[0] = foppo[0];
+    proj[1] = foppo[1];
+    proj[2] = foppo[2];
+    projontoface(forg, fdest, fapex, proj);
+    loc = iscoplanarintri(proj, &testtet);
+    if (loc != OUTSIDE) {
+      enqueuebadface(testface, cent, 1);
+    } else {
+      enqueuebadface(testface, cent, 0);
+    }
+  }
+
+  return encroachflag;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// testtetrahedron()    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.                                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::testtetrahedron(triface* testtet)
+{
+  point3d 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 edgelen[6], cent[3], smedgelen, radius, ratio2, volume;
+  int i;
+
+  torg = org(*testtet);
+  tdest = dest(*testtet);
+  tapex = apex(*testtet);
+  toppo = oppo(*testtet);
+
+  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];
+
+  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];
+
+  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;
+
+  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 lengths of the tetrahedron's siz edges.
+  edgelen[0] = dxod2 + dyod2 + dzod2;
+  edgelen[1] = dxda2 + dyda2 + dzda2;
+  edgelen[2] = dxao2 + dyao2 + dzao2;
+  edgelen[3] = dxop2 + dyop2 + dzop2;
+  edgelen[4] = dxdp2 + dydp2 + dzdp2;
+  edgelen[5] = dxap2 + dyap2 + dzap2;
+
+  smedgelen = edgelen[0];
+  for (i = 1; i < 6; i++) {
+    if (smedgelen > edgelen[i]) smedgelen = edgelen[i];
+  }
+  if (smedgelen <= usertolerance) {
+    printf("Precssion error in testtetrahedron(): \n");
+    printf("  The shortest edge length %.12g is smaller than tolerance.\n",
+           smedgelen);
+    printf("  This probably means that I am trying to refine mesh to a\n");
+    printf("    smaller size than can be accommodated by the finite \n");
+    printf("    precision of floating point arithmetic. \n");
+    precisionerror();
+  }
+
+  circumcenter(torg, tdest, tapex, toppo, cent);
+
+  dxoc = torg[0] - cent[0];
+  dyoc = torg[1] - cent[1];
+  dzoc = torg[2] - cent[2];
+  dxoc2 = dxoc * dxoc;
+  dyoc2 = dyoc * dyoc;
+  dzoc2 = dzoc * dzoc;
+
+  radius = dxoc2 + dyoc2 + dzoc2;
+  ratio2 = radius / smedgelen;
+
+  // Check whether the ratio is smaller than permitted.
+  if (ratio2 > goodratio) {
+    // It's a bad-shaped tet, before we decide to split it, we need check
+    //   if this bad-shaped tet is les on boundary with a small (dihedral)
+    //   angle. If so, we should not split it, or it maybe cause endless
+    //   loop until run out of your machine's precission.
+    // Not done yet.
+    // Add this tet to the list of bad tetrahedra.
+    enqueuebadtet(testtet, ratio2, torg, tdest, tapex, toppo, cent);
+    return;
+  }
+  if (varvolume || fixedvolume) {
+    // Check whether the volume is larger than permitted.
+    volume = tetvolume(torg, tdest, tapex, toppo);
+    if (volume < 0) volume = -volume;
+    if (fixedvolume && (volume > maxvolume)) {
+      // Add this tetrahedron to the list of bad tetrahedra.
+      enqueuebadtet(testtet, 0, torg, tdest, tapex, toppo, cent);
+    } else if (varvolume) {
+      // Nonpositive volume constraints are treated as unconstrained.
+      if ((volume > volumebound(testtet->tet)) &&
+          (volumebound(testtet->tet) > 0.0)) {
+        // Add this tetrahedron to the list of bad tetrahedron.
+        enqueuebadtet(testtet, 0, torg, tdest, tapex, toppo, cent);
+      }
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// enqueuebadface()    Add a bad subface to the end of a queue.              //
+//                                                                           //
+// The queue is actually a set of 2 queues.  'rank' should be 0 or 1.        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::enqueuebadface(face *insface, point3d inscent, int rank)
+{
+  badface3d *newface;
+
+  if (verbose > 2) {
+    printf("    Queueing bad face: (%d, %d, %d) rank %i.\n",
+           pointmark(sorg(*insface)), pointmark(sdest(*insface)),
+           pointmark(sapex(*insface)), rank);
+  }
+  // Allocate space for the bad face.
+  newface = (badface3d *) badfaces.alloc();
+  newface->shface = *insface;
+  if (inscent != NULL) {
+    // We need not re-calculate circumcenter when split face.
+    newface->badfacetet.tet = dummytet;
+    newface->cent[0] = inscent[0];
+    newface->cent[1] = inscent[1];
+    newface->cent[2] = inscent[2];
+  } else {
+    // We need re-calculate circumcenter when split face.
+    newface->badfacetet.tet = (tetrahedron *) NULL;
+  }
+  sapex(*insface, newface->faceapex);
+  sorg(*insface, newface->faceorg);
+  sdest(*insface, newface->facedest);
+  newface->nextface = (badface3d *) NULL;
+  // Add the face to the end of a queue.
+  *facequetail[rank] = newface;
+  // Maintain a pointer to the NULL pointer at the end of the queue.
+  facequetail[rank] = &newface->nextface;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dequeuebadface()    Remove a face from the front of the queue.            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+badface3d* mesh3d::dequeuebadface()
+{
+  badface3d *result;
+  int queuenumber;
+
+  // Look for a nonempty queue.
+  for (queuenumber = 1; queuenumber >= 0; queuenumber--) {
+    result = facequefront[queuenumber];
+    if (result != (badface3d *) NULL) {
+      // Remove the face from the queue.
+      facequefront[queuenumber] = result->nextface;
+      // Maintain a pointer to the NULL pointer at the end of the queue.
+      if (facequefront[queuenumber] == (badface3d *) NULL) {
+        facequetail[queuenumber] = &facequefront[queuenumber];
+      }
+      return result;
+    }
+  }
+  return (badface3d *) NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// enqueuebadtet()    Add a bad tetrahedron to the end of a queue.           //
+//                                                                           //
+// The queue is actually a set of 64 queues.                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::enqueuebadtet(triface *instet, REAL ratio, point3d insorg,
+                           point3d insdest, point3d insapex, point3d insoppo,
+                           point3d inscent)
+{
+  badtet *newtet;
+  int queuenumber;
+
+  // Allocate space for the bad tetrahedron.
+  newtet = (badtet *) badtets.alloc();
+  newtet->btet = *instet;
+  newtet->key = ratio;
+  newtet->cent[0] = inscent[0];
+  newtet->cent[1] = inscent[1];
+  newtet->cent[2] = inscent[2];
+  newtet->tetorg = insorg;
+  newtet->tetdest = insdest;
+  newtet->tetapex = insapex;
+  newtet->tetoppo = insoppo;
+  newtet->nexttet = (badtet *) NULL;
+  // Determine the appropriate queue to put the bad tetrahedron into.
+  if (ratio > goodratio) { // square of 1.414
+    queuenumber = (int) ((ratio - goodratio) / 0.5);
+    if (queuenumber > 63) {
+      queuenumber = 63;
+    } else if (queuenumber < 0) {
+      // The integer overflow( caused by a very large ratio.)
+      queuenumber = 63;
+    }
+  } else {
+    // It's not a bad ratio; put the tetrahedron in the lowest-priority
+    //   queue.
+    queuenumber = 0;
+  }
+  // Add the tetrahedron to the end of a queue.
+  *tetquetail[queuenumber] = newtet;
+  // Maintain a pointer to the NULL pointer at the end of the queue.
+  tetquetail[queuenumber] = &newtet->nexttet;
+
+  if (verbose > 2) {
+    printf("    Queueing bad tet: (%d, %d, %d, %d), ratio %g, qnum %d.\n",
+           pointmark(insorg), pointmark(insdest), pointmark(insapex),
+           pointmark(insoppo), sqrt(ratio), queuenumber);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dequeuebadtet()    Remove a tetrahedron from the front of the queue.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+badtet* mesh3d::dequeuebadtet()
+{
+  badtet *result;
+  int queuenumber;
+
+  // Look for a nonempty queue.
+  for (queuenumber = 63; queuenumber >= 0; queuenumber--) {
+    result = tetquefront[queuenumber];
+    if (result != (badtet *) NULL) {
+      // Remove the tetrahedron from the queue.
+      tetquefront[queuenumber] = result->nexttet;
+      // Maintain a pointer to the NULL pointer at the end of the queue.
+      if (tetquefront[queuenumber] == (badtet *) NULL) {
+        tetquetail[queuenumber] = &tetquefront[queuenumber];
+      }
+      return result;
+    }
+  }
+  return (badtet *) NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tallyencsegs()   Traverse the entire list of shell edges, check each edge //
+//                  to see if it is encroached.  If so, add it to the list.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::tallyencsegs()
+{
+  face edgeloop;
+
+  if (verbose) {
+    printf("  Making a list of encroached segments.\n");
+  }
+  subsegs.traversalinit();
+  edgeloop.shver = 0;
+  edgeloop.sh = shellfacetraverse(&subsegs);
+  while (edgeloop.sh != (shellface *) NULL) {
+    // If the segment is encroached, add it to the list.
+    checkedge4encroach(&edgeloop);
+    edgeloop.sh = shellfacetraverse(&subsegs);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tallyencfaces()     Traverse the entire list of shell faces, check each   //
+//                     face to see if it is encroached.  If so, add it to    //
+//                     the list.                                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::tallyencfaces()
+{
+  face faceloop;
+
+  if (verbose) {
+    printf("  Making a list of encroached subfaces.\n");
+  }
+  subfaces.traversalinit();
+  faceloop.shver = 0;
+  faceloop.sh = shellfacetraverse(&subfaces);
+  while (faceloop.sh != (shellface *) NULL) {
+    // If the subface is encroached, add it to the list.
+    checkface4encroach(&faceloop);
+    faceloop.sh = shellfacetraverse(&subfaces);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tallytets()     Traverse the entire list of tetrahedra, check each tet to //
+//                 see if it is bad quality.  If so, add it to the list.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::tallytets()
+{
+  triface tetloop;
+
+  if (verbose) {
+    printf("  Making a list of bad tetrahedra.\n");
+  }
+  tetrahedrons.traversalinit();
+  tetloop.loc = 0;
+  tetloop.ver = 0;
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    testtetrahedron(&tetloop);
+    tetloop.tet = tetrahedrontraverse();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// Mesh quality testing routines                                             //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// Mesh quality maintenance routines                                         //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// repairencsegs()    Find and repair all the encroached segments.           //
+//                                                                           //
+// Encroached segments are repaired by splitting them by inserting a point   //
+// at or near their centers.                                                 //
+//                                                                           //
+// When a segment is split, the two resulting subsegments are always tested  //
+// to see if they are encroached upon, regardless of the value of 'flaws'.   //                                                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::repairencsegs()
+{
+  badface3d *encloop;
+  triface enctet;
+  triface *checktet, *skiptet;
+  face *checksh, *skipsh;
+  point3d eorg, edest;
+  point3d newpoint;
+  REAL segmentlength, nearestpoweroftwo;
+  REAL split;
+  int acuteorg, acutedest;
+  int flipcount;
+  int i;
+
+  while ((badsegments.items > 0) && (steinerleft != 0)) {
+    badsegments.traversalinit();
+    encloop = badsegmenttraverse();
+    while ((encloop != (badface3d *) NULL) && (steinerleft != 0)) {
+      // Check this edge is not splitted.
+      eorg = sorg(encloop->shface);
+      edest = sdest(encloop->shface);
+      if (((eorg != (point3d) NULL) && (edest != (point3d) NULL)) &&
+          ((eorg == encloop->faceorg) && (edest == encloop->facedest))) {
+        // To decide where to split a segment, we need to know if the
+        //   segment shares an endpoint with an adjacent segment.
+        //   The concern is that, if we simply split every encroached
+        //   segment in its center, two adjacent segments with a small
+        //   angle between them might lead to an infinite loop; each
+        //   point added to split one segment will encroach upon the
+        //   other segment, which must then be split with a point that
+        //   will encroach upon the first segment, and so on forever.
+        // To avoid this, imagine a set of concentric circles, whose
+        //   radii are powers of two, about each segment endpoint.
+        //   These concentric circles determine where the segment is
+        //   split.  (If both endpoints are shared with adjacent
+        //   segments, split the segment in the middle, and apply the
+        //   concentric shells for later splittings.)
+
+        // Is the origin shared with another segment?
+        acuteorg = isexistincidentseg(&(encloop->shface));
+        // Is the destination shared with another segment?
+        sesymself(encloop->shface);
+        acutedest = isexistincidentseg(&(encloop->shface));
+        sesymself(encloop->shface);
+
+        // Use the concentric circles if exactly one endpoint is shared
+        //   with another adjacent segment.
+        if (acuteorg ^ acutedest) {
+          segmentlength = sqrt((edest[0] - eorg[0]) * (edest[0] - eorg[0])
+                               + (edest[1] - eorg[1]) * (edest[1] - eorg[1])
+                               + (edest[2] - eorg[2]) * (edest[2] - eorg[2]));
+          // Find the power of two nearest the segment's length.
+          nearestpoweroftwo = 1.0;
+          while (segmentlength > SQUAREROOTTWO * nearestpoweroftwo) {
+            nearestpoweroftwo *= 2.0;
+          }
+          while (segmentlength < (0.5 * SQUAREROOTTWO) * nearestpoweroftwo) {
+            nearestpoweroftwo *= 0.5;
+          }
+          // Where do we split the segment?
+          split = 0.5 * nearestpoweroftwo / segmentlength;
+          if (acutedest) {
+            split = 1.0 - split;
+          }
+        } else {
+          // If we're not worried about adjacent segments, split
+          //   this segment in the middle.
+          split = 0.5;
+        }
+
+        // Create the new point.
+        newpoint = (point3d) points.alloc();
+        // Interpolate its coordinate and attributes.
+        for (i = 0; i < 3 + nextras; i++) {
+          newpoint[i] = (1.0 - split) * eorg[i] + split * edest[i];
+        }
+        // The new point must lies on subsegment.
+        setpointmark(newpoint, mark(encloop->shface));
+        if (verbose > 1) {
+          // Set pointmark of newpoint for Debuging outputs.
+          setpointmark(newpoint, points.items);
+        }
+        // Check whether the new point lies on an endpoint.
+        if ((compare2points(&newpoint, &eorg) == 0) ||
+            (compare2points(&newpoint, &edest) == 0)) {
+          printf("Error:  Ran out of precision at (%.12g, %.12g, %.12g).\n",
+                 newpoint[0], newpoint[1], newpoint[2]);
+          printf("  I attempted to split a segment to a smaller size than\n");
+          printf("    can be accommodated by the finite precision of floating\n");
+          printf("    point arithmetic.\n");
+          precisionerror();
+        }
+        if (verbose > 1) {
+          printf("  Insert circumcenter: (%.12g, %.12g, %.12g) %d\n",
+                 newpoint[0], newpoint[1], newpoint[2], pointmark(newpoint));
+          printf("    to split subsegment (%d, %d).\n",
+                 pointmark(eorg), pointmark(edest));
+        }
+        if (shsegflaws) {
+          uncheckedshseglist->clear();
+        }
+        if (shflaws) {
+          uncheckedshlist->clear();
+        }
+        if (tetflaws) {
+          uncheckedtetlist->clear();
+        }
+        // Find a tetra contain this subsegment.
+        sstpivot(&(encloop->shface), &enctet);
+        findversion(&enctet, &(encloop->shface));
+        // Insert the splitting point.  This should always succssed.
+        flipcount = insertonedge(newpoint, &enctet, &(encloop->shface));
+        if (verbose > 1) {
+          printf("  Successfully split subsegment with %d flips.\n", flipcount);
+        }
+        if (steinerleft > 0) {
+          steinerleft--;
+        }
+        // Check all encroached segments, subfaces and bad tetrahedra caused
+        //   by insert this point if there need.
+        if (shsegflaws && (uncheckedshseglist->len() > 0)) {
+          uncheckedshseglist->sort();
+          skipsh = checksh = (face*)(*uncheckedshseglist)[0];
+          if (!isdead(checksh)) {
+            checkedge4encroach(checksh);
+          }
+          for (i = 1; i < uncheckedshseglist->len(); i++) {
+            checksh = (face*)(*uncheckedshseglist)[i];
+            if (checksh->sh != skipsh->sh) {
+              if (!isdead(checksh)) {
+                checkedge4encroach(checksh);
+              }
+              skipsh = checksh;
+            }
+          }
+        }
+        if (shflaws && (uncheckedshlist->len() > 0)) {
+          uncheckedshlist->sort();
+          skipsh = checksh = (face*)(*uncheckedshlist)[0];
+          if (!isdead(checksh)) {
+            checkface4encroach(checksh);
+          }
+          for (i = 1; i < uncheckedshlist->len(); i++) {
+            checksh = (face*)(*uncheckedshlist)[i];
+            if (checksh->sh != skipsh->sh) {
+              if (!isdead(checksh)) {
+                checkface4encroach(checksh);
+              }
+              skipsh = checksh;
+            }
+          }
+        }
+        if (tetflaws && (uncheckedtetlist->len() > 0)) {
+          uncheckedtetlist->sort();
+          skiptet = checktet = (triface*)(*uncheckedtetlist)[0];
+          if (!isdead(checktet)) {
+            testtetrahedron(checktet);
+          }
+          for (i = 1; i < uncheckedtetlist->len(); i++) {
+            checktet = (triface*)(*uncheckedtetlist)[i];
+            if (checktet->tet != skiptet->tet) {
+              if (!isdead(checktet)) {
+                testtetrahedron(checktet);
+              }
+              skiptet = checktet;
+            }
+          }
+        }
+        // Check the two new subsegments to see if they're encroached.
+        checkedge4encroach(&(encloop->shface));
+        senextself(encloop->shface);
+        spivotself(encloop->shface);
+        encloop->shface.shver = 0;
+        checkedge4encroach(&(encloop->shface));
+      }
+      badsegmentdealloc(encloop);
+      encloop = badsegmenttraverse();
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// repairencfaces()    Find and repair all the encroached subfaces.          //
+//                                                                           //
+// Encroached subfaces are repaired by splitting them by inserting a point   //
+// at or near their circumcenters. However, if the new point would encroach  //
+// upon any any subsegment, it is not inserted; instead, all the subsegments //
+// it would encroach upon are split.                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::repairencfaces()
+{
+  list *neartetlist, *nearseglist;
+  badface3d* badface;
+  triface badfacetet;
+  triface testtet, neighbortet;
+  triface *checktet, *skiptet;
+  face testseg;
+  face *checksh, *skipsh;
+  point3d borg, bdest, bapex;
+  point3d newpoint;
+  enum locateresult intersect;
+  enum insertsiteresult success;
+  int encroachedseg;
+  int errorflag, flipcount;
+  int i, j;
+
+  neartetlist = nearseglist = NULL;
+
+  while (badfaces.items > 0) {
+    // Fix one encroached subfaces by inserting a point at its circumcenter.
+    badface = dequeuebadface();
+    assert(badface);
+    borg = sorg(badface->shface);
+    bdest = sdest(badface->shface);
+    bapex = sapex(badface->shface);
+    // Make sure that this subface is still the same subface when it was
+    //   tested and determined to be encroached. Subsequent transformations
+    //   may have made it a different subface.
+    if (((borg != (point3d) NULL) && (bdest != (point3d) NULL) &&
+         (bapex != (point3d) NULL)) && ((borg == badface->faceorg) &&
+         (bdest == badface->facedest) && (bapex == badface->faceapex))) {
+      errorflag = 0;
+      // Create a new point at the subface's circumcenter.
+      newpoint = (point3d) points.alloc();
+      // Check if we need calculate circumcenter.
+      if (badface->badfacetet.tet == (tetrahedron *) NULL) {
+        circumcenter(borg, bdest, bapex, badface->cent);
+      }
+      newpoint[0] = badface->cent[0];
+      newpoint[1] = badface->cent[1];
+      newpoint[2] = badface->cent[2];
+      if (issamepoint(newpoint, borg) || issamepoint(newpoint, bdest)
+          || issamepoint(newpoint, bapex)) {
+        if (!quiet) {
+          printf("Warning:  Newpoint (%.12g, %.12g, %.12g) falls on",
+                 newpoint[0], newpoint[1], newpoint[2]);
+          printf(" existing vertex.\n");
+        }
+        errorflag = 1;
+        pointdealloc(newpoint);
+      } else {
+        setpointmark(newpoint, mark(badface->shface));
+        if (verbose > 1) {
+          // Set pointmark of newpoint for Debuging outputs.
+          setpointmark(newpoint, points.items);
+        }
+        // Find a tetrahedron that contain this face.
+        stpivot(badface->shface, badfacetet);
+        if (badfacetet.tet == dummytet) {
+          sesymself(badface->shface);
+          stpivot(badface->shface, badfacetet);
+          assert(badfacetet.tet != dummytet);
+        }
+        // Find where the newpoint locates(ONFACE or ONEDGE), keep the
+        //   result in 'badfacetet'.
+        intersect = iscoplanarintri(newpoint, &badfacetet);
+        if (intersect == OUTSIDE) {
+          adjustedgering(badfacetet, CCW);
+          intersect = preciselocate(newpoint, &badfacetet);
+        }
+
+        if ((intersect == ONFACE) || (intersect == ONEDGE)) {
+          // If 'newpoint' is located ONFACE or ONEDGE, check if its
+          //   location encroaches on any nearby subsegments. It's a two
+          //   step process: First, gather all nearby subsegments; Second,
+          //   check each subsegment to discover its encroachness.
+          encroachedseg = 0;
+          assert(badfacetet.tet != dummytet);
+          if (!neartetlist) {
+            neartetlist = new list(sizeof(triface));
+            neartetlist->setcomp((compfunc) &compare2tets);
+            nearseglist = new list(sizeof(face));
+            nearseglist->setcomp((compfunc) &compare2shfaces);
+          } else {
+            neartetlist->clear();
+            nearseglist->clear();
+          }
+          // Step 1, gather all nearby subsegments, store them in list
+          //   'nearseglist'.
+          // To address this, Boywer-Watson's scheme (Cavity) is adopted.
+          //   All tetrahedra whose circumspheres contain 'newpoint' are
+          //   found. Check the edges for each tetrahedron, if there exist
+          //   a subsegment abutting this edge, add it to 'nearseglist'.
+          testtet = badfacetet;
+          // Check three edges of 'testtet''s current face.
+          for (i = 0; i < 3; i++) {
+            tsspivot(&testtet, &testseg);
+            if (testseg.sh != dummysh) {
+              nearseglist->append(&testseg);
+            }
+            enextself(testtet);
+          }
+          neartetlist->append(&testtet);
+          sym(testtet, neighbortet);
+          if (neighbortet.tet != dummytet) {
+            if (iinsphere(&neighbortet, newpoint) == 1) {
+              neartetlist->append(&neighbortet);
+            }
+          }
+          for (i = 0; i < neartetlist->len(); i++) {
+            // Get a tetra, which its circumsphere contain 'newpoint'.
+            testtet = *(triface *)(* neartetlist)[i];
+            adjustedgering(testtet, CCW);
+            // Check other three edges of this tetra. At the same time,
+            //   check other three neighbors of this tetra to see if their
+            //   circumsphere contain 'newpoint'.
+            for (j = 0; j < 3; j++) {
+              fnext(testtet, neighbortet);
+              enextself(neighbortet);
+              tsspivot(&neighbortet, &testseg);
+              if (testseg.sh != dummysh) {
+                if (nearseglist->hasitem(&testseg) == -1) {
+                  nearseglist->append(&testseg);
+                }
+              }
+              symself(neighbortet);
+              if (neighbortet.tet != dummytet) {
+                if (iinsphere(&neighbortet, newpoint) == 1) {
+                  if (neartetlist->hasitem(&neighbortet) == -1) {
+                    neartetlist->append(&neighbortet);
+                  }
+                }
+              }
+              enextself(testtet);
+            }
+          }
+          // Step 2, Check each segment to discover if they will be
+          //   encroached by 'newpoint'.
+          for (i = 0; i < nearseglist->len(); i++) {
+            testseg = *(face *)(* nearseglist)[i];
+            if (checkedge4encroach(&testseg, newpoint)) {
+              encroachedseg++;
+            }
+          }
+
+          if (encroachedseg == 0) {
+            if (verbose > 1) {
+              printf("  Insert circumcenter: (%.12g, %.12g, %.12g) %d\n",
+                     newpoint[0], newpoint[1], newpoint[2],
+                     pointmark(newpoint));
+              printf("    to split subface (%d, %d, %d).\n",
+                     pointmark(borg), pointmark(bdest), pointmark(bapex));
+            }
+            uncheckedshseglist->clear();
+            if (shflaws) {
+              uncheckedshlist->clear();
+            }
+            if (tetflaws) {
+              uncheckedtetlist->clear();
+            }
+            if (intersect == ONFACE) {
+              tspivot(badfacetet, badface->shface);
+              assert(badface->shface.sh != dummysh);
+              flipcount = insertonface(newpoint, &badfacetet,
+                                       &(badface->shface));
+            } else { // must intersect == ONEDGE
+              flipcount = insertonedge(newpoint, &badfacetet, (face*) NULL);
+            }
+            if (verbose > 1) {
+              printf("  Successfully split subface with %d flips.\n",
+                     flipcount);
+            }
+            success = SUCCESSFUL;
+          } else {
+            success = VIOLATINGEDGE;
+          }
+        } else if (intersect == OUTSIDE) {
+          success = FAILED;
+        } else if (intersect == ONVERTEX) {
+          success = DUPLICATE;
+        } else {  // intersect == INTETRAHEDRON
+          printf("Precision error in repairencface(): INTETRAHEDRON.\n");
+          printf("  Failed to locate a subface to contain newpoint.\n");
+          precisionerror();
+        }
+
+        if (success == SUCCESSFUL) {
+          if (steinerleft > 0) {
+            steinerleft--;
+          }
+          // We need check if new insert point cause other subfaces be
+          //   encroached and cause bad quality tetrahedra.
+          if (shflaws && (uncheckedshlist->len() > 0)) {
+            uncheckedshlist->sort();
+            skipsh = checksh = (face*)(*uncheckedshlist)[0];
+            if (!isdead(checksh)) {
+              checkface4encroach(checksh);
+            }
+            for (i = 1; i < uncheckedshlist->len(); i++) {
+              checksh = (face*)(*uncheckedshlist)[i];
+              if (checksh->sh != skipsh->sh) {
+                if (!isdead(checksh)) {
+                  checkface4encroach(checksh);
+                }
+                skipsh = checksh;
+              }
+            }
+          }
+          if (tetflaws && (uncheckedtetlist->len() > 0)) {
+            uncheckedtetlist->sort();
+            skiptet = checktet = (triface*)(*uncheckedtetlist)[0];
+            if (!isdead(checktet)) {
+              testtetrahedron(checktet);
+            }
+            for (i = 1; i < uncheckedtetlist->len(); i++) {
+              checktet = (triface*)(*uncheckedtetlist)[i];
+              if (checktet->tet != skiptet->tet) {
+                if (!isdead(checktet)) {
+                  testtetrahedron(checktet);
+                }
+                skiptet = checktet;
+              }
+            }
+          }
+        } else if (success == VIOLATINGEDGE) {
+          // Failed to insert the new point, but some segment was
+          //   marked as being encroached.
+          pointdealloc(newpoint);
+        } else if (success == VIOLATINGFACE) {
+          printf("Internalerror in splitface(): Unexpected condition");
+          printf(" success == VIOLATINGFACE.\n");
+          internalerror();
+        } else if (success == FAILED) {
+          if (!quiet && verbose) {
+            // Failed to insert the new point because it fails outside the
+            //   mesh. It's a except condition caused by the existing of
+            //   small angles in input model.
+            printf("Warning:  New point (%.12g, %.12g, %.12g) falls",
+                   newpoint[0], newpoint[1], newpoint[2]);
+            printf("  outside the mesh.\n");
+          }
+          pointdealloc(newpoint);
+        } else { // success == DUPLICATE
+          if (!quiet) {
+            // Failed to insert the new point because a vertex is already
+            //   there.
+            printf("Warning:  New point (%.12g, %.12g, %.12g) falls on",
+                   newpoint[0], newpoint[1], newpoint[2]);
+            printf(" existing vertex.\n");
+          }
+          pointdealloc(newpoint);
+          errorflag = 1;
+        }
+      }
+      if (errorflag) {
+        if (verbose) {
+          printf("  The new point is at the circumcenter of subface.\n");
+          printf("    (%.12g, %.12g, %.12g) (%.12g, %.12g, %.12g)",
+                 borg[0], borg[1], borg[2], bdest[0], bdest[1], bdest[2]);
+          printf(" (%.12g, %.12g, %.12g)\n", bapex[0], bapex[1], bapex[2]);
+        }
+        printf("  This probably means that I am trying to refine subfaces\n");
+        printf("    to a smaller size than can be accommodated by the finite\n");
+        printf("    precision of floating point arithmetic.\n");
+        precisionerror();
+      }
+    }
+    // Return the badface to the pool.
+    badfaces.dealloc((void *) badface);
+    // Fix any encroached segments that may have resulted.
+    if (badsegments.items > 0) {
+      repairencsegs();
+    }
+  }
+
+  if (neartetlist) {
+    delete neartetlist;
+    delete nearseglist;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// splittet()    Inserts a point at the circumsphere of a bad quality        //
+//               tetrahedron, thus eliminating the tetrahedron.              //
+//                                                                           //
+// If the new point would encroach upon any subsegment or subfacet, then it  //
+// is not inserted; instead, all the subsegments it would encroach upon are  //
+// split. If the bad quality tetrahedron is not eliminated as a result, then //
+// all the subfacets its circumcenter would encroach upon are split.         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::splittet(badtet* intet)
+{
+  triface searchtet;
+  triface testtet, neighbortet;
+  triface *checktet, *skiptet;
+  face testsh, testseg;
+  face *checksh, *skipsh;
+  point3d borg, bdest, bapex, boppo;
+  point3d newpoint;
+  enum locateresult intersect;
+  enum insertsiteresult success;
+  int encroachedseg, encroachedface;
+  int errorflag, flipcount;
+  int i, j;
+
+  borg = org(intet->btet);
+  bdest = dest(intet->btet);
+  bapex = apex(intet->btet);
+  boppo = oppo(intet->btet);
+  // Make sure that this tet is still the same tet it was when it was tested
+  //   and determined to be encroached. Subsequent transformations may have
+  //   made it a different tet.
+  if (((borg != (point3d) NULL) && (bdest != (point3d) NULL) &&
+       (bapex != (point3d) NULL) && (boppo != (point3d) NULL)) &&
+      ((borg == intet->tetorg) && (bdest == intet->tetdest) &&
+       (bapex == intet->tetapex) && (boppo == intet->tetoppo))) {
+    errorflag = 0;
+    // Create a new point at the tetrahedron's circumsphere.
+    newpoint = (point3d) points.alloc();
+    newpoint[0] = intet->cent[0];
+    newpoint[1] = intet->cent[1];
+    newpoint[2] = intet->cent[2];
+    if (issamepoint(newpoint, borg) || issamepoint(newpoint, bdest)
+        || issamepoint(newpoint, bapex) || issamepoint(newpoint, boppo)) {
+      if (!quiet) {
+        printf("Warning:  Newpoint (%.12g, %.12g, %.12g) falls on",
+               newpoint[0], newpoint[1], newpoint[2]);
+        printf(" existing vertex.\n");
+      }
+      pointdealloc(newpoint);
+      errorflag = 1;
+    } else {
+      // The new point must be in mesh, set a marker of zero.
+      setpointmark(newpoint, 0);
+      if (verbose > 1) {
+        // Set pointmark of newpoint for Debuging outputs.
+        setpointmark(newpoint, points.items);
+      }
+      // Ensure that the circumcenter must above 'intet->btet', so point
+      //   location will work.
+      searchtet = intet->btet;
+      searchtet.ver = 0;
+      for (searchtet.loc = 0; searchtet.loc < 4; searchtet.loc++) {
+        if (isaboveplane(&(searchtet), newpoint)) break;
+      }
+      assert(searchtet.loc < 4);
+      // Find where the newpoint locates, keep the result in 'searchtet'.
+      intersect = preciselocate(newpoint, &searchtet);
+
+      if ((intersect == INTETRAHEDRON) || (intersect == ONFACE)
+          || (intersect == ONEDGE)) {
+        // If 'newpoint' is located inside current mesh, insert the point
+        //   to split tetrahedron. Before insertion, check if its location
+        //   encroaches on any nearby subsegments or subfaces. Use Boywer-
+        //   Watson insertion scheme for encroach checking.
+        encroachedseg = encroachedface = 0;
+        cavetetlist->clear();
+        caveshlist->clear();
+        cavebdfacelist->clear();
+
+        // Collect all tetra to form the cavity. At the same time, collect
+        //   the boundary faces of this cavity and all encountered subfaces.
+        testtet = searchtet;
+        cavetetlist->append(&testtet);
+        tspivot(testtet, testsh);
+        if ((testsh.sh != dummysh) && !isnonsolid(testsh)) {
+          caveshlist->append(&testsh);
+          adjustedgering(testtet, CCW);
+          cavebdfacelist->append(&testtet);
+        } else {
+          sym(testtet, neighbortet);
+          assert(neighbortet.tet != dummytet);
+          if (iinsphere(&neighbortet, newpoint) == 1) {
+            cavetetlist->append(&neighbortet);
+          } else {
+            adjustedgering(testtet, CCW);
+            cavebdfacelist->append(&testtet);
+          }
+        }
+        for (i = 0; i < cavetetlist->len(); i++) {
+          // Get a tetra, which its circumsphere contain 'newpoint'.
+          testtet = *(triface *)(* cavetetlist)[i];
+          adjustedgering(testtet, CCW);
+          // Check other three neighbors of this tet.
+          for (j = 0; j < 3; j++) {
+            fnext(testtet, neighbortet);
+            tspivot(neighbortet, testsh);
+            if ((testsh.sh != dummysh) && !isnonsolid(testsh)) {
+              caveshlist->append(&testsh);
+              adjustedgering(neighbortet, CCW);
+              cavebdfacelist->append(&neighbortet);
+            } else {
+              symself(neighbortet);
+              assert(neighbortet.tet != dummytet);
+              if (iinsphere(&neighbortet, newpoint) == 1) {
+                if (cavetetlist->hasitem(&neighbortet) == -1) {
+                  cavetetlist->append(&neighbortet);
+                }
+              } else {
+                symself(neighbortet);
+                adjustedgering(neighbortet, CCW);
+                cavebdfacelist->append(&neighbortet);
+              }
+            }
+            enextself(testtet);
+          }
+        }
+        // Check for any encroached subsegments first.
+        for (i = 0; i < caveshlist->len(); i++) {
+          testsh = *(face *)(* caveshlist)[i];
+          for (j = 0; j < 3; j++) {
+            sspivot(testsh, testseg);
+            if (testseg.sh != dummysh) {
+              if (checkedge4encroach(&testseg, newpoint)) {
+                encroachedseg++;
+              }
+            }
+            senextself(testsh);
+          }
+        }
+        if (encroachedseg) {
+          success = VIOLATINGEDGE;
+        } else {
+          // If no subsegment be encroached, then check subfaces.
+          for (i = 0; i < caveshlist->len(); i++) {
+            testsh = *(face *)(* caveshlist)[i];
+            if (checkface4encroach(&testsh, newpoint)) {
+              encroachedface++;
+            }
+          }
+          if (encroachedface) {
+            success = VIOLATINGFACE;
+          }
+        }
+        if ((!encroachedseg) && (!encroachedface)) {
+          if (cavetetlist->hasitem(&(intet->btet)) != -1) {
+            if (verbose > 1) {
+              printf("  Insert circumcenter: (%.12g, %.12g, %.12g) %d\n",
+                     newpoint[0], newpoint[1], newpoint[2],
+                     pointmark(newpoint));
+              printf("    to split tetra (%d, %d, %d, %d).\n",
+                     pointmark(borg), pointmark(bdest), pointmark(bapex),
+                     pointmark(boppo));
+            }
+            uncheckedshseglist->clear();
+            uncheckedshlist->clear();
+            uncheckedtetlist->clear();
+            if (intersect == INTETRAHEDRON) {
+              flipcount = insertininterior(newpoint, &searchtet);
+            } else if (intersect == ONFACE) {
+              tspivot(searchtet, testsh);
+              if (testsh.sh != dummysh) {
+                // Note: 'testsh' must be an nonsolid subface.
+                assert(isnonsolid(testsh));
+                flipcount = insertonface(newpoint, &searchtet, &testsh);
+              } else {
+                flipcount = insertonface(newpoint, &searchtet, (face*) NULL);
+              }
+            } else { // must intersect == ONEDGE
+              // Note: 'newpoint' must locate on a interior edge.
+              flipcount = insertonedge(newpoint, &searchtet, (face*) NULL);
+            }
+            if (verbose > 1) {
+              printf("  Successfully split tetra with %d flips.\n", flipcount);
+            }
+            success = SUCCESSFUL;
+          } else {
+            // Do not insert 'newpoint', because it can't eliminate bad tet.
+            if (!quiet && verbose) {
+              printf("Warning:  A bad-quality tet survived.\n");
+            }
+            success = VIOLATINGEDGE;
+          }
+        }
+      } else if (intersect == ONVERTEX) {
+        success = DUPLICATE;
+      } else { // intersect == OUTSIDE
+        success = FAILED;
+      }
+
+      if (success == SUCCESSFUL) {
+        if (steinerleft > 0) {
+          steinerleft--;
+        }
+        // Check and queue the bad quality tetrahedra caused by inserting
+        //   'newpoint'.
+        if (uncheckedtetlist->len() > 0) {
+          uncheckedtetlist->sort();
+          skiptet = checktet = (triface*)(*uncheckedtetlist)[0];
+          if (!isdead(checktet)) {
+            testtetrahedron(checktet);
+          }
+          for (i = 1; i < uncheckedtetlist->len(); i++) {
+            checktet = (triface*)(*uncheckedtetlist)[i];
+            if (checktet->tet != skiptet->tet) {
+              if (!isdead(checktet)) {
+                testtetrahedron(checktet);
+              }
+              skiptet = checktet;
+            }
+          }
+        }
+      } else if ((success == VIOLATINGEDGE) || (success == VIOLATINGFACE)) {
+        // Failed to insert the new point, but some segment and subfaces
+        //   was marked as being encroached.
+        pointdealloc(newpoint);
+      } else if (success == FAILED) {
+        if (!quiet && verbose) {
+          // Failed to insert the new point because it fails outside the
+          //   mesh. It's an except condition caused by the existing of
+          //   small angles in input model.
+          printf("Warning:  New point (%.12g, %.12g, %.12g) falls outside",
+                 newpoint[0], newpoint[1], newpoint[2]);
+          printf(" the mesh.\n");
+        }
+        pointdealloc(newpoint);
+      } else { // success == DUPLICATE
+        if (!quiet) {
+          // Failed to insert the new point because a vertex is already there.
+          printf("Warning:  New point (%.12g, %.12g, %.12g) falls on",
+                 newpoint[0], newpoint[1], newpoint[2]);
+          printf(" existing vertex.\n");
+        }
+        pointdealloc(newpoint);
+        errorflag = 1;
+      }
+    }
+    if (errorflag) {
+      if (verbose) {
+        printf("  The new point is at the circumsphere of tetrahedron:\n");
+        printf("    (%.12g, %.12g, %.12g) (%.12g, %.12g, %.12g)\n",
+               borg[0], borg[1], borg[2], bdest[0], bdest[1], bdest[2]);
+        printf("    (%.12g, %.12g, %.12g) (%.12g, %.12g, %.12g)\n",
+               bapex[0], bapex[1], bapex[2], boppo[0], boppo[1], boppo[2]);
+      }
+      printf("  This probably means that I am trying to refine tetrahedra\n");
+      printf("    to a smaller size than can be accommodated by the finite\n");
+      printf("    precision of floating point arithmetic.\n");
+      precisionerror();
+    }
+  }
+  // Return the badtet to the pool.
+  badtets.dealloc((void *) intet);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// enforcequality()    Remove all the encroached edges and bad triangles     //
+//                     from the triangulation.                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::enforcequality()
+{
+  int i;
+
+  if (!quiet) {
+    printf("Adding Steiner points to enforce quality.\n");
+  }
+
+  // Initialize the pool of encroached segments.
+  badsegments.init(sizeof(badface3d), BADSHELLFACEPERBLOCK, POINTER, 0);
+  // Initialize the queue of subsegments which might be encroached.
+  uncheckedshseglist = new list(sizeof(face));
+  uncheckedshseglist->setcomp((compfunc) &compare2shfaces);
+  if (verbose) {
+    printf("  Looking for encroached segments.\n");
+  }
+  // Test all segments to see if they're encroached.
+  tallyencsegs();
+  // Note that steinerleft == -1 if an unlimited number
+  //   of Steiner points is allowed.
+  while ((badsegments.items > 0) && (steinerleft != 0)) {
+    if (verbose > 1) {
+      printf("  Splitting %d encroached segments.\n", badsegments.items);
+    }
+    // Fix the segments without noting newly encroached segments or
+    //   subfaces.
+    repairencsegs();
+    // Now, find all the segments that became encroached while adding
+    //   points to split encroached segments.
+    tallyencsegs();
+  }
+
+  // Initialize the pool of encroached subfaces.
+  badfaces.init(sizeof(badface3d), BADSHELLFACEPERBLOCK, POINTER, 0);
+  // Initialize the queue of subfaces which might be encroached.
+  uncheckedshlist = new list(sizeof(face));
+  uncheckedshlist->setcomp((compfunc) &compare2shfaces);
+  // Initialize the queues of bad subfaces.
+  for (i = 0; i < 2; i++) {
+    facequefront[i] = (badface3d *) NULL;
+    facequetail[i] = &facequefront[i];
+  }
+  if (verbose) {
+    printf("  Looking for encroached subfaces.\n");
+  }
+  // Test all subfaces to see if they're encroached.
+  tallyencfaces();
+  shsegflaws = 1;
+  // Note that steinerleft == -1 if an unlimited number
+  //   of Steiner points is allowed.
+  while ((badfaces.items > 0) && (steinerleft != 0)) {
+    if (verbose > 1) {
+      printf("  Splitting %d encroached subfaces.\n", badfaces.items);
+    }
+    // Fix the subfaces without noting newly encroached subfaces.
+    repairencfaces();
+    // Now, find all the subfaces that became encroached while adding
+    //   points to split encroached subfaces.
+    tallyencfaces();
+  }
+  // At this point, if we haven't run out of Steiner points, the
+  //   triangulation should be (conforming) Delaunay.
+
+  // Next, we worry about enforcing tetrahedra quality.
+  if ((minratio > 0.0) || varvolume || fixedvolume) {
+    // Initialize the pool of bad tetrahedra.
+    badtets.init(sizeof(badtet), BADTETPERBLOCK, POINTER, 0);
+    // Initialize the queue of tetrahedra which might have bad quality.
+    uncheckedtetlist = new list(sizeof(triface));
+    uncheckedtetlist->setcomp((compfunc) &compare2tets);
+    // Initialize lists for Boywer-Watson point insertion scheme.
+    cavetetlist = new list(sizeof(triface));
+    cavetetlist->setcomp((compfunc) &compare2tets);
+    caveshlist = new list(sizeof(face));
+    caveshlist->setcomp((compfunc) &compare2shfaces);
+    cavebdfacelist = new list(sizeof(triface));
+    cavebdfacelist->setcomp((compfunc) &compare2tets);
+    // Initialize the queues of bad tetrahedra.
+    for (i = 0; i < 64; i++) {
+      tetquefront[i] = (badtet *) NULL;
+      tetquetail[i] = &tetquefront[i];
+    }
+    // Test all tetrahedra to see if they're bad.
+    tallytets();
+    if (verbose) {
+      printf("  Splitting bad tetrahedra.\n");
+    }
+    shflaws = shsegflaws = tetflaws = 1;
+    while ((badtets.items > 0) && (steinerleft != 0)) {
+      // Fix one bad tetrahedron by inserting a point at its circumsphere.
+      splittet(dequeuebadtet());
+      // Fix any encroached segments and subfaces that may have resulted.
+      //   Record any new bad tetrahedra or encroached segments, subfaces
+      //   that result.
+      if (badsegments.items > 0) {
+        repairencsegs();
+      }
+      if (badfaces.items > 0) {
+        repairencfaces();
+      }
+    }
+    delete cavetetlist;
+    delete caveshlist;
+    delete cavebdfacelist;
+    delete uncheckedtetlist;
+  }
+  delete uncheckedshseglist;
+  delete uncheckedshlist;
+
+  // At this point, if we haven't run out of Steiner points, the
+  //   triangulation should be (conforming) Delaunay and have no
+  //   low-quality tetrahedra except slivers.
+
+  // Might we have run out of Steiner points too soon?
+  if (!quiet && ((badsegments.items > 0) || (badfaces.items > 0))
+      && (steinerleft == 0)) {
+    printf("\nWarning:  I ran out of Steiner points, but the mesh has\n");
+    printf("  %ld encroached segments and %ld encroached subfaces,\n",
+           badsegments.items, badfaces.items);
+    printf("  therefore might not be truly Delaunay.\n");
+    printf("  If the Delaunay property is important to you, try increasing\n");
+    printf("  the number of Steiner points (controlled by the -S switch)\n");
+    printf("  slightly and try again.\n\n");
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// Mesh quality maintenance routines                                         //
+///////////////////////////////////////////////////////////////////////////////
diff --git a/Tetgen/tetlib.cpp b/Tetgen/tetlib.cpp
new file mode 100644
index 0000000000..19e74aabde
--- /dev/null
+++ b/Tetgen/tetlib.cpp
@@ -0,0 +1,10847 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetlib.cpp    The implementation file for class mesh3d.  Include the mesh //
+//               data structure and the kernel member functions.             //
+//                                                                           //
+// Tetgen Version 1.0 beta                                                   //
+// November, 2001                                                            //
+//                                                                           //
+// Si hang                                                                   //
+// Email: sihang@weboo.com                                                   //
+// http://www.weboo.com/sh/tetgen.htm                                        //
+//                                                                           //
+// You are free to use, copy and modify the sources under certain            //
+// circumstances, provided this copyright notice remains intact.             //
+// See the file LICENSE for details.                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tetlib.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Initialize all the lookup tables used by mesh manipulation primitives.    //                                             //
+//                                                                           //
+// The internal representation of the tetrahedron-based and triangle-edge    //
+// data structures takes advantage of the predefined numbering scheme for    //
+// vertices and faces of a tetrahedron, also takes advantage of that the     //
+// structure of two edge rings of each face is identical. Therefore, it can  //
+// be implemented by several global lookup tables as following.              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// For enext() primitive, use 'ver' as index.
+int mesh3d::ve[6] = { 2, 5, 4, 1, 0, 3 };
+
+// For org(), dest() and apex() primitives, use 'ver' as index.
+int mesh3d::vo[6] = { 0, 1, 1, 2, 2, 0 };
+int mesh3d::vd[6] = { 1, 0, 2, 1, 0, 2 };
+int mesh3d::va[6] = { 2, 2, 0, 0, 1, 1 };
+
+// For org(), dest() and apex() primitives, use 'loc' as first index and
+//   'ver' as second index.
+int mesh3d::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 };
+int mesh3d::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 };
+int mesh3d::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 };
+
+// For oppo() primitives, use 'loc' as index.
+int mesh3d::loc2oppo[4] = { 3, 2, 0, 1 };
+
+// For fnext() primitives, use 'loc' as first index and 'ver' as second
+//   index, return a new 'loc' and new 'ver' in an int array.
+// Note: Only valid for face version = 0, 2, 4.
+int mesh3d::locver2nextf[4][6][2] =
+               { { {1, 5}, {-1, -1}, {2, 5}, {-1, -1}, {3, 5}, {-1, -1} },
+                 { {3, 3}, {-1, -1}, {2, 1}, {-1, -1}, {0, 1}, {-1, -1} },
+                 { {1, 3}, {-1, -1}, {3, 1}, {-1, -1}, {0, 3}, {-1, -1} },
+                 { {2, 3}, {-1, -1}, {1, 1}, {-1, -1}, {0, 5}, {-1, -1} } };
+
+int mesh3d::plus1mod3[3] = {1, 2, 0};
+int mesh3d::minus1mod3[3] = {2, 0, 1};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh data type linar-order functions used in list and link.  Refer to     //
+// file linklist.h for the description about linar-order functions.          //
+//                                                                           //
+// compare2points()    Compare two points by their x-coordinate, using the   //
+//                     y-coordinate as a secondary key, and the z-coordinate //
+//                     if their need.                                        //
+// compare2tets()      Compare two handles of tetrahedra by their addresses. //
+// compare2shfaces()   Compare two handles of subfaces/subsegments by their  //
+//                     addresses.                                            //
+//                                                                           //
+// Return 0 if they are same. Return 1 or -1 if they are not same.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int compare2points(point3d *point1, point3d *point2)
+{
+  if ((*point1)[0] < (*point2)[0]) {
+    return -1;
+  } else if ((*point1)[0] > (*point2)[0]) {
+    return +1;
+  } else {
+    if ((*point1)[1] < (*point2)[1]) {
+      return -1;
+    } else if ((*point1)[1] > (*point2)[1]) {
+      return +1;
+    } else {
+      if ((*point1)[2] < (*point2)[2]) {
+        return -1;
+      } else if ((*point1)[2] > (*point2)[2]) {
+        return +1;
+      } else {
+        return 0;
+      }
+    }
+  }
+}
+
+int compare2tets(triface* tface1, triface* tface2)
+{
+  if (tface1->tet == tface2->tet) {
+    return 0;                                   // These two tets are same.
+  } else if (tface1->tet < tface2->tet) {
+    return -1;
+  } else {
+    return 1;
+  }
+}
+
+int compare2shfaces(face* sface1, face* sface2)
+{
+  if (sface1->sh == sface2->sh) {
+    return 0;                      // These two subfaces/segments are same.
+  } else if (sface1->sh < sface2->sh) {
+    return -1;
+  } else {
+    return 1;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Advanced Mesh Manipulaton Primitives                                      //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// getnextface()    Get next face of 'tface1' in the same face ring.         //
+//                                                                           //
+// The right-hand rule is used to determine where the next face is.          //
+//                                                                           //
+// The next face is returned in 'tface2' or 'tface1'(if tface2 == NULL).     //                                                                //
+// If next face exists, return true. Otherwise, (it's a outer boundary face),//
+// return false, and the return handle remain unchanged.                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool mesh3d::getnextface(triface* tface1, triface* tface2)
+{
+  // First we need decide where the next face in the face ring locate:
+  //   in this tet('tface1') or in it's neigbhour?  This can do quickly by
+  //   checking which edge ring of the 'tface1' version belong to.
+  if (EdgeRing(tface1->ver) == CW) {
+    // Indicate the next face is in the neigbhour tet.
+    if (!issymexist(tface1)) {
+      // Encounter Outer Space when spin face around edge. return.
+      return false;
+    }
+
+    point3d torg, tdest;
+
+    org(*tface1, torg);
+    dest(*tface1, tdest);
+    if (tface2) {
+      sym(*tface1, *tface2);
+      findversion(tface2, torg, tdest, 0); // 0 mean don't reverse direction.
+    } else {
+      symself(*tface1);
+      findversion(tface1, torg, tdest, 0);
+    }
+  } else {
+    // Indicate the next face is still in this tet('tface1').
+    if (tface2) {
+      *tface2 = *tface1;
+    }
+  }
+  // At here,  we know the next face must in retface.tet.
+  // assert(EdgeRing(tface2->ver) == CCW);
+  int tloc, tver;
+
+  if (tface2) {
+    tloc = tface2->loc; tver = tface2->ver;
+    tface2->loc = locver2nextf[tloc][tver][0];
+    tface2->ver = locver2nextf[tloc][tver][1];
+  } else {
+    tloc = tface1->loc; tver = tface1->ver;
+    tface1->loc = locver2nextf[tloc][tver][0];
+    tface1->ver = locver2nextf[tloc][tver][1];
+  }
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tsspivot()    Finds a subsegment abutting on this tetrahderon's edge.     //
+//                                                                           //
+// To find if there has a subsegment adjoining to this tetrahedron's edge,   //
+// first we need find a subface around this edge to see if there exist a     //
+// subsegment adjoining to it. Why? Because There are no pointers directly   //
+// connecting tetrahedron and adjoining subsegments. Connections between     //
+// tetrahedron and subsegments are entirely mediate througth subfaces.       //
+// Because a subsegment may be shared by any number of subfaces and          //
+// tetrahedra, each subsegment has a pointer to only one adjoining subfaces  //
+// (choose arbitrarly).                                                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::tsspivot(triface* tface, face* tseg)
+{
+  triface spintet;
+  face tmpface;
+  point3d tapex;
+  int hitbdry;
+
+  spintet = *tface;
+  apex(*tface, tapex);
+  hitbdry = 0;
+  while (true) {
+    if (fnextself(spintet)) {
+      if (apex(spintet) == tapex) {
+        break; // Rewind, can leave now.
+      }
+      tspivot(spintet, tmpface);
+      if (tmpface.sh != dummysh) {
+        findversion(&tmpface, tface);
+        sspivot(tmpface, *tseg);
+        return;
+      }
+    } else {
+      hitbdry ++;
+      if(hitbdry >= 2) {
+        break;
+      } else {
+        esym(*tface, spintet);
+      }
+    }
+  }
+  // Check myself last.
+  tspivot(*tface, tmpface);
+  if (tmpface.sh != dummysh) {
+    findversion(&tmpface, tface);
+    sspivot(tmpface, *tseg);
+    return;
+  }
+  // Not find a subsegment.
+  tseg->sh = dummysh;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// sstpivot()    Finds a tetrahedron abutting a subsegment.                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::sstpivot(face* tseg, triface* tface)
+{
+  face parentface;
+
+  // Get the subface which contains the segment.
+  sdecode(tseg->sh[0], parentface);
+  assert(parentface.sh != dummysh);
+  // Get the tetrahera which the subface attches to.
+  stpivot(parentface, *tface);
+  if (tface->tet == dummytet) {
+    sesymself(parentface);
+    stpivot(parentface, *tface);
+    assert(tface->tet != dummytet);
+  }
+  findversion(tface, tseg, 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// Advanced Mesh Manipulaton Primitives                                      //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// Auxiliary Mesh Manipulaton Primitives                                     //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// findversion()    Find and set version to indicate the directed edge in    //
+//                  the input handle('tface' or 'sface'), which its origin   //
+//                  is 'dorg' and destination is 'ddest'.                    //
+//                                                                           //
+// If 'symflag' = 1, inverse the edge direction(esymself) before return.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::
+findversion(triface* tface, point3d dorg, point3d ddest, int symflag)
+{
+  point3d torg, tdest;
+
+  tface->ver = 0;
+  while (tface->ver < 6) {
+    org(*tface, torg);
+    dest(*tface, tdest);
+    if ((torg == dorg) && (tdest == ddest)) {
+      break;
+    } else if ((torg == ddest) && (tdest == dorg)) {
+      tface->ver++;
+      break;
+    }
+    tface->ver += 2;
+  }
+  assert(tface->ver < 6);
+  if (symflag) {
+    esymself(*tface);
+  }
+}
+
+void mesh3d::findversion(triface* tface, triface* dface, int symflag)
+{
+  findversion(tface, org(*dface), dest(*dface), symflag);
+}
+
+void mesh3d::findversion(triface* tface, face* sface, int symflag)
+{
+  findversion(tface, sorg(*sface), sdest(*sface), symflag);
+}
+
+void mesh3d::
+findversion(face* sface, point3d dorg, point3d ddest, int symflag)
+{
+  point3d shorg, shdest;
+
+  sface->shver = 0;
+  while (sface->shver < 6) {
+    sorg(*sface, shorg);
+    sdest(*sface, shdest);
+    if ((shorg == dorg) && (shdest == ddest)) {
+      break;
+    } else if ((shorg == ddest) && (shdest == dorg)) {
+      sface->shver++;
+      break;
+    }
+    sface->shver += 2;
+  }
+  assert(sface->shver < 6);
+  if (symflag) {
+    sesymself(*sface);
+  }
+}
+
+void mesh3d::findversion(face* sface, triface* dface, int symflag)
+{
+  findversion(sface, org(*dface), dest(*dface), symflag);
+}
+
+void mesh3d::findversion(face* sface, face* sface1, int symflag)
+{
+  findversion(sface, sorg(*sface1), sdest(*sface1), symflag);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// findorg()    Find and set the version to indicate the desired point.      //
+//                                                                           //
+// If 'dorg' is a one of vertices of 'tface', set the origin of 'tface' be   //
+// 'dorg' and return true, else return false.                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool mesh3d::findorg(triface* tface, point3d dorg)
+{
+  if (org(*tface) == dorg) {
+    return true;
+  }
+  if (dest(*tface) == dorg) {
+    enextself(*tface);
+  } else {
+    if (apex(*tface) == dorg) {
+      enext2self(*tface);
+    } else {
+      if (oppo(*tface) == dorg) {
+        // Keep in the same tet after fnext().
+        adjustedgering(*tface, CCW);
+        fnextself(*tface);
+        enext2self(*tface);
+      } else {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+bool mesh3d::findorg(face* sface, point3d dorg)
+{
+  point3d pointptr;
+
+  sorg(*sface, pointptr);
+  if (pointptr == dorg) {
+    return true;
+  }
+  sdest(*sface, pointptr);
+  if (pointptr == dorg) {
+    senextself(*sface);
+  } else {
+    sapex(*sface, pointptr);
+    if (pointptr == dorg) {
+      senext2self(*sface);
+    } else {
+      return false;
+    }
+  }
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// isridge()    Returns true if the edge of tetrahedron(specified by loc and //
+//              ver) is a ridge in the mesh.                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool mesh3d::isridge(triface* tface)
+{
+  triface testtet;
+  point3d tapex;
+
+  // Spin current edge(loc and ver) to see if there will encounter
+  //   'Outer boundary' (dummytet).
+  if (!fnext(*tface, testtet)) {
+    return true;
+  }
+
+  apex(*tface, tapex);
+  do {
+    if(!fnextself(testtet)) {
+      return true;
+    }
+  } while (apex(testtet) != tapex);
+
+  return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// isexistincidentseg()    Test if there exist any segment shares with input //
+//                         segment's origin. return true if there exists at  //
+//                         least one incident segment, otherwise return      //
+//                         false.                                            //
+//                                                                           //
+// This primitive is used to help decide where to split a segment.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool mesh3d::isexistincidentseg(face* tseg)
+{
+  triface neighbortet, spintet, testtet;
+  face testseg;
+  point3d tapex;
+  int findsegflag, reverseflag, hitbdry;
+
+  // Get a tet that contain this segment with the same origin and
+  //   destination of this segment.
+  sstpivot(tseg, &neighbortet);
+  // Spin around the tet, skip myself(tseg).
+  apex(neighbortet, tapex);
+  spintet = neighbortet;
+  hitbdry = reverseflag = findsegflag = 0;
+  while (true) {
+    if (fnextself(spintet)) {
+      if (apex(spintet) == tapex) {
+        break; // Rewind, can leave now.
+      }
+      // Get the correct edge. Note the 'reverseflag'.
+      if (!reverseflag) {
+        enext2(spintet, testtet);
+      } else {
+        enext(spintet, testtet);
+      }
+      tsspivot(&testtet, &testseg);
+      if (testseg.sh != dummysh) {
+        findsegflag = 1;
+        break;
+      }
+    } else {
+      hitbdry ++;
+      if(hitbdry >= 2) {
+        break;
+      } else {
+        reverseflag = 1;
+        esym(neighbortet, spintet);
+      }
+    }
+  }
+  if (!findsegflag) {
+    enext2(neighbortet, testtet);
+    tsspivot(&testtet, &testseg);
+    if (testseg.sh != dummysh) {
+      findsegflag = 1;
+    }
+  }
+  return findsegflag == 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// issameface(), issameedge()    Compare the vertices of two faces/edges to  //
+//                               see if they are the same face/edge. The     //
+//                               inputs are handles of two tetrahedra.       //
+//                               Return 0 (same) or 1 (diffrent).            //
+//                                                                           //
+// These two primitives mainly used as list or link's linear order functions.//
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::issameface(triface* tface1, triface* tface2)
+{
+  point3d torg1, tdest1, tapex1;
+  point3d torg2, tdest2, tapex2;
+  int oldver, tmpver;
+
+  org(*tface1, torg1);
+  dest(*tface1, tdest1);
+  apex(*tface1, tapex1);
+
+  oldver = tface2->ver;
+  tmpver = 0;
+  while (tmpver < 6) {
+    tface2->ver = tmpver;
+    org(*tface2, torg2);
+    dest(*tface2, tdest2);
+    apex(*tface2, tapex2);
+    if (((torg1 == torg2) && (tdest1 == tdest2) && (tapex1 == tapex2))
+        || ((torg1 == tdest2) && (tdest1 == torg2) && (tapex1 == tapex2))) {
+      break;
+    }
+    tmpver += 2;
+  }
+
+  tface2->ver = oldver;
+  if (tmpver < 6) {
+    return 0;  // These two faces are same.
+  } else {
+    return 1;
+  }
+}
+
+int mesh3d::issameedge(triface* tface1, triface* tface2)
+{
+  point3d torg1, tdest1;
+  point3d torg2, tdest2;
+
+  org(*tface1, torg1);
+  dest(*tface1, tdest1);
+  org(*tface2, torg2);
+  dest(*tface2, tdest2);
+
+  if (((torg1 == torg2) && (tdest1 == tdest2))
+        || ((torg1 == tdest2) && (tdest1 == torg2))) {
+    return 0; // These two edges are same.
+  } else {
+    return 1;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dump()    For debuging, Print out the details of a tetrahedron/shellfacet //
+//           handle to standard output.                                      //
+//                                                                           //
+// It can be called directly from the debugger, and presents information     //
+// about a tetrahedron handle in digestible form. It's also used when the    //
+// highest level of verbosity (`-VVV') is specified.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::dump(triface* tface)
+{
+  triface tmpface, prtface;
+  point3d tmppt;
+  face tmpsh;
+  int facecount;
+
+  printf("Tetra x%lx with loc(%i) and ver(%i):\n",
+         (unsigned long)(tface->tet), tface->loc, tface->ver);
+
+  tmpface = *tface;
+  facecount = 0;
+  while(facecount < 4) {
+    tmpface.loc = facecount;
+    sym(tmpface, prtface);
+    if(prtface.tet == dummytet) {
+      printf("      [%i] Outer space.\n", facecount);
+    } else {
+      printf("      [%i] x%lx  loc(%i).\n", facecount,
+             (unsigned long)(prtface.tet), prtface.loc);
+    }
+    facecount ++;
+  }
+
+  org(*tface, tmppt);
+  if(tmppt == (point3d) NULL) {
+    printf("      Org [%i] NULL\n", locver2org[tface->loc][tface->ver]);
+  } else {
+    printf("      Org [%i] x%lx (%.12g,%.12g,%.12g) %d\n",
+           locver2org[tface->loc][tface->ver], (unsigned long)(tmppt),
+           tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt));
+  }
+  dest(*tface, tmppt);
+  if(tmppt == (point3d) NULL) {
+    printf("      Dest[%i] NULL\n", locver2dest[tface->loc][tface->ver]);
+  } else {
+    printf("      Dest[%i] x%lx (%.12g,%.12g,%.12g) %d\n",
+           locver2dest[tface->loc][tface->ver], (unsigned long)(tmppt),
+           tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt));
+  }
+  apex(*tface, tmppt);
+  if(tmppt == (point3d) NULL) {
+    printf("      Apex[%i] NULL\n", locver2apex[tface->loc][tface->ver]);
+  } else {
+    printf("      Apex[%i] x%lx (%.12g,%.12g,%.12g) %d\n",
+           locver2apex[tface->loc][tface->ver], (unsigned long)(tmppt),
+           tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt));
+  }
+  oppo(*tface, tmppt);
+  if(tmppt == (point3d) NULL) {
+    printf("      Oppo[%i] NULL\n", loc2oppo[tface->loc]);
+  } else {
+    printf("      Oppo[%i] x%lx (%.12g,%.12g,%.12g) %d\n",
+           loc2oppo[tface->loc], (unsigned long)(tmppt),
+           tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt));
+  }
+
+  if (useshelles) {
+    tmpface = *tface;
+    facecount = 0;
+    while(facecount < 4) {
+      tmpface.loc = facecount;
+      tspivot(tmpface, tmpsh);
+      if(tmpsh.sh != dummysh) {
+        printf("      [%i] x%lx  ver(%i).\n", facecount,
+               (unsigned long)(tmpsh.sh), tmpsh.shver);
+      }
+      facecount ++;
+    }
+  }
+}
+
+void mesh3d::dump(face* sface)
+{
+  face printsh;
+  triface printtet;
+  point3d tapex, printpoint;
+
+  sapex(*sface, tapex);
+  if (tapex != NULL) {
+    printf("subface x%lx with version %d and mark %d:\n",
+           (unsigned long)(sface->sh), sface->shver, mark(*sface));
+  } else {
+    printf("Subsegment x%lx with version %d and mark %d:\n",
+           (unsigned long)(sface->sh), sface->shver, mark(*sface));
+  }
+
+  if (tapex != NULL) {
+    // Current we don't use the first three pointers in subface,
+    //   so their values are always NULL. Skipped.
+    /*sdecode(sface->sh[0], printsh);
+    if (printsh.sh == dummysh) {
+      printf("      [0] = No shell\n");
+    } else {
+      printf("      [0] = x%lx  %d\n",
+             (unsigned long)(printsh.sh), printsh.shver);
+    }
+    sdecode(sface->sh[1], printsh);
+    if (printsh.sh == dummysh) {
+      printf("      [1] = No shell\n");
+    } else {
+      printf("      [1] = x%lx  %d\n",
+             (unsigned long)(printsh.sh), printsh.shver);
+    }
+    sdecode(sface->sh[2], printsh);
+    if (printsh.sh == dummysh) {
+      printf("      [2] = No shell\n");
+    } else {
+      printf("      [2] = x%lx  %d\n",
+             (unsigned long)(printsh.sh), printsh.shver);
+    }*/
+  } else {
+    sdecode(sface->sh[0], printsh);
+    if (printsh.sh == dummysh) {
+      printf("      [0] = No shell\n");
+    } else {
+      printf("      [0] = x%lx  %d\n",
+             (unsigned long)(printsh.sh), printsh.shver);
+    }
+    sdecode(sface->sh[1], printsh);
+    if (printsh.sh != dummysh) {
+      printf("      [1] = x%lx  %d\n",
+             (unsigned long)(printsh.sh), printsh.shver);
+    }
+    sdecode(sface->sh[2], printsh);
+    if (printsh.sh != dummysh) {
+      printf("      [2] = x%lx  %d\n",
+             (unsigned long)(printsh.sh), printsh.shver);
+    }
+  }
+
+  sorg(*sface, printpoint);
+  if (printpoint == (point3d) NULL)
+    printf("      Org [%d] = NULL\n", vo[sface->shver]);
+  else
+    printf("      Org [%d] = x%lx  (%.12g,%.12g,%.12g) %d\n",
+           vo[sface->shver], (unsigned long)(printpoint), printpoint[0],
+           printpoint[1], printpoint[2], pointmark(printpoint));
+  sdest(*sface, printpoint);
+  if (printpoint == (point3d) NULL)
+    printf("      Dest[%d] = NULL\n", vd[sface->shver]);
+  else
+    printf("      Dest[%d] = x%lx  (%.12g,%.12g,%.12g) %d\n",
+            vd[sface->shver], (unsigned long)(printpoint), printpoint[0],
+            printpoint[1], printpoint[2], pointmark(printpoint));
+
+  if (tapex != NULL) {
+    sapex(*sface, printpoint);
+    if (printpoint == (point3d) NULL)
+      printf("      Apex[%d] = NULL\n", va[sface->shver]);
+    else
+      printf("      Apex[%d] = x%lx  (%.12g,%.12g,%.12g) %d\n",
+             va[sface->shver], (unsigned long)(printpoint), printpoint[0],
+             printpoint[1], printpoint[2], pointmark(printpoint));
+
+    decode(sface->sh[6], printtet);
+    if (printtet.tet == dummytet) {
+      printf("      [6] = Outer space\n");
+    } else {
+      printf("      [6] = x%lx  %d\n",
+             (unsigned long)(printtet.tet), printtet.loc);
+    }
+    decode(sface->sh[7], printtet);
+    if (printtet.tet == dummytet) {
+      printf("      [7] = Outer space\n");
+    } else {
+      printf("      [7] = x%lx  %d\n",
+             (unsigned long)(printtet.tet), printtet.loc);
+    }
+
+    sdecode(sface->sh[8], printsh);
+    if (printsh.sh == dummysh) {
+      printf("      [8] = No subsegment\n");
+    } else {
+      printf("      [8] = x%lx  %d\n",
+             (unsigned long)(printsh.sh), printsh.shver);
+    }
+    sdecode(sface->sh[9], printsh);
+    if (printsh.sh == dummysh) {
+      printf("      [9] = No subsegment\n");
+    } else {
+      printf("      [9] = x%lx  %d\n",
+             (unsigned long)(printsh.sh), printsh.shver);
+    }
+    sdecode(sface->sh[10], printsh);
+    if (printsh.sh == dummysh) {
+      printf("      [10]= No subsegment\n");
+    } else {
+      printf("      [10]= x%lx  %d\n",
+             (unsigned long)(printsh.sh), printsh.shver);
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// Auxiliary Mesh Manipulaton Primitives                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// Memory Management Routines                                                //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dummyinit()    Initialize the tetrahedron that fills "outer space" and    //
+//                the omnipresent subface.                                   //
+//                                                                           //
+// The tetrahedron that fills "outer space" called 'dummytet', is pointed to //
+// by every tetrahedron and subface on a boundary (be it outer or inner) of  //
+// the tetrahedralization. Also, 'dummytet' points to one of the tetrahedron //
+// on the convex hull(until the holes and concavities are carved), making it //
+// possible to find a starting tetrahedron for point location.               //
+//                                                                           //
+// The omnipresent subface,'dummysh', is pointed to by every tetrahedron or  //
+// subface that doesn't have a full complement of real subface to point to.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::dummyinit(int ttetwords, int tshwords)
+{
+  unsigned long alignptr;
+
+  // 'tetwords' and 'shwords' are used by the mesh manipulation primitives
+  //   to extract orientations of tetrahedra and subfaces from pointers.
+  tetwords = ttetwords;           // Initialize `tetwords' once and for all.
+  shwords = tshwords;              // Initialize `shwords' once and for all.
+
+  // Set up 'dummytet', the 'tetrahedron' that occupies "outer space".
+  dummytetbase = (tetrahedron *) new BYTE[tetwords * sizeof(tetrahedron)
+                                          + tetrahedrons.alignbytes];
+  // Align 'dummytet' on a 'tetrahedrons.alignbytes'-byte boundary.
+  alignptr = (unsigned long) dummytetbase;
+  dummytet = (tetrahedron *)
+    (alignptr + (unsigned long) tetrahedrons.alignbytes
+     - (alignptr % (unsigned long) tetrahedrons.alignbytes));
+  // Initialize the four adjoining tetrahedrons to be "outer space". These
+  //   will eventually be changed by various bonding operations, but their
+  //   values don't really matter, as long as they can legally be
+  //   dereferenced.
+  dummytet[0] = (tetrahedron) dummytet;
+  dummytet[1] = (tetrahedron) dummytet;
+  dummytet[2] = (tetrahedron) dummytet;
+  dummytet[3] = (tetrahedron) dummytet;
+  // Four NULL vertex points.
+  dummytet[4] = (tetrahedron) NULL;
+  dummytet[5] = (tetrahedron) NULL;
+  dummytet[6] = (tetrahedron) NULL;
+  dummytet[7] = (tetrahedron) NULL;
+
+  if (useshelles) {
+    // Set up 'dummysh', the omnipresent "subface" pointed to by any
+    //   tetrahedron side or subface end that isn't attached to a real
+    //   subface.
+    dummyshbase = (shellface *) new BYTE[shwords * sizeof(shellface)
+                                         + subfaces.alignbytes];
+    // Align 'dummysh' on a 'subfaces.alignbytes'-byte boundary.
+    alignptr = (unsigned long) dummyshbase;
+    dummysh = (shellface *)
+      (alignptr + (unsigned long) subfaces.alignbytes
+       - (alignptr % (unsigned long) subfaces.alignbytes));
+    // Initialize the three adjoining subfaces to be the omnipresent subface.
+    //   These will eventually be changed by various bonding operations, but
+    //   their values don't really matter, as long as they can legally be
+    //   dereferenced.
+    dummysh[0] = (shellface) dummysh;
+    dummysh[1] = (shellface) dummysh;
+    dummysh[2] = (shellface) dummysh;
+    // Three NULL vertex points.
+    dummysh[3] = (shellface) NULL;
+    dummysh[4] = (shellface) NULL;
+    dummysh[5] = (shellface) NULL;
+    // Initialize the two adjoining tetrahedra to be "outer space".
+    dummysh[6] = (shellface) dummytet;
+    dummysh[7] = (shellface) dummytet;
+    // Initialize the three adjoining subsegments to be "out boundary".
+    dummysh[8]  = (shellface) dummysh;
+    dummysh[9]  = (shellface) dummysh;
+    dummysh[10] = (shellface) dummysh;
+    // Set the boundary marker to zero.
+    * (int *) (dummysh + 11) = 0;
+    // Initialize the four adjoining subfaces of 'dummytet' to be the
+    //   omnipresent subface.
+    dummytet[8 ] = (tetrahedron) dummysh;
+    dummytet[9 ] = (tetrahedron) dummysh;
+    dummytet[10] = (tetrahedron) dummysh;
+    dummytet[11] = (tetrahedron) dummysh;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// initializepointpool()    Calculate the size of the point data structure   //
+//                          and initialize its memory pool.                  //
+//                                                                           //
+// This routine also computes the 'pointmarkindex' and `point2tetindex'      //
+// indices used to find values within each point.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::initializepointpool()
+{
+  int pointsize;
+
+  // The index within each point at which the boundary marker is found.
+  //   Ensure the point marker is aligned to a sizeof(int)-byte address.
+  pointmarkindex = ((3 + nextras) * sizeof(REAL) + sizeof(int) - 1)
+                 / sizeof(int);
+  pointsize = (pointmarkindex + 1) * sizeof(int);
+  if (poly || smesh) {
+    // The index within each point at which a tetrahedron pointer is found.
+    //   Ensure the pointer is aligned to a sizeof(tetrahedron)-byte address.
+    point2tetindex = (pointsize + sizeof(tetrahedron) - 1)
+                   / sizeof(tetrahedron);
+    pointsize = (point2tetindex + 1) * sizeof(tetrahedron);
+  }
+  // Initialize the pool of points.
+  points.init(pointsize, POINTPERBLOCK,
+    (sizeof(REAL) >= sizeof(tetrahedron)) ? FLOATINGPOINT : POINTER, 4);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// initializetetshpools()    Calculate the sizes of the tetrahedron and      //
+//                           subface data structures and initialize their    //
+//                           memory pools.                                   //
+//                                                                           //
+// This routine also computes the 'highorderindex', 'elemattribindex', and   //
+// 'volumeboundindex' indices used to find values within each tetrahedron.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::initializetetshpools()
+{
+  int tetsize;
+
+  // There are four pointers to other tetrahedra, four pointers to
+  //   corners, and possibly four pointers to subfaces.
+  highorderindex = 8 + (useshelles * 4);
+  // The number of bytes occupied by a tetrahedron.
+  tetsize = highorderindex * sizeof(tetrahedron);
+  // The index  within each tetrahedron at which its attributes are found,
+  //   where the index is measured in REALs.
+  elemattribindex = (tetsize + sizeof(REAL) - 1) / sizeof(REAL);
+  // The index within each tetrahedron at which the maximum volume
+  //   constraint is found, where the index is measured in REALs.  Note that
+  //   if the 'regionattrib' flag is set, an additional attribute will be
+  //   added.
+  volumeboundindex = elemattribindex + eextras + regionattrib;
+  // If tetrahedron attributes or a volume bound are needed, increase the
+  //   number of bytes occupied by a tetrahedron.
+  if (varvolume) {
+    tetsize = (volumeboundindex + 1) * sizeof(REAL);
+  } else if (eextras + regionattrib > 0) {
+    tetsize = volumeboundindex * sizeof(REAL);
+  }
+  // If a Voronoi diagram or tetrahedron neighbor graph is requested, make
+  //   sure there's room to store an integer index in each tetrahedron. This
+  //   integer index can occupy the same space as the subfaces or attributes
+  //   or volume constraint or extra nodes.
+  if ((voronoi || neighbors) &&
+      (tetsize < 8 * sizeof(tetrahedron) + sizeof(int))) {
+    tetsize = 8 * sizeof(tetrahedron) + sizeof(int);
+  }
+  // Having determined the memory size of a tetrahedron, initialize the pool.
+  tetrahedrons.init(tetsize, TETPERBLOCK, POINTER, 8);
+
+  if (useshelles) {
+    // Initialize the pool of subfaces. Note: Here we need eight-byte
+    //   aligned for each subface record (to keep six version).
+    subfaces.init(11 * sizeof(shellface) + sizeof(int), SUBFACEPERBLOCK,
+                  POINTER, 8);
+    // Initialize the pool of subsegments. The subsegment's record is same
+    //   with subface.
+    subsegs.init(11 * sizeof(shellface) + sizeof(int), SUBSEGPERBLOCK,
+                 POINTER, 8);
+    // Initialize the "outer space" tetrahedron and omnipresent subface.
+    dummyinit(tetrahedrons.itemwords, subfaces.itemwords);
+  } else {
+    // Initialize the "outer space" tetrahedron.
+    dummyinit(tetrahedrons.itemwords, 0);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetrahedrondealloc()    Deallocate space for a tetrahedron, marking it    //
+//                         dead.                                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::tetrahedrondealloc(tetrahedron *dyingtetrahedron)
+{
+  // Set tetrahedron's vertices to NULL. This makes it possible to detect
+  //   dead tetrahedra when traversing the list of all tetrahedra.
+  dyingtetrahedron[4] = (tetrahedron) NULL;
+  dyingtetrahedron[5] = (tetrahedron) NULL;
+  dyingtetrahedron[6] = (tetrahedron) NULL;
+  dyingtetrahedron[7] = (tetrahedron) NULL;
+  tetrahedrons.dealloc((void *) dyingtetrahedron);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetrahedrontraverse()    Traverse the tetrahedra, skipping dead ones.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+tetrahedron* mesh3d::tetrahedrontraverse()
+{
+  tetrahedron *newtetrahedron;
+
+  do {
+    newtetrahedron = (tetrahedron *) tetrahedrons.traverse();
+    if (newtetrahedron == (tetrahedron *) NULL) {
+      return (tetrahedron *) NULL;
+    }
+  } while (newtetrahedron[4] == (tetrahedron) NULL);      // Skip dead ones.
+  return newtetrahedron;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// shellfacedealloc()    Deallocate space for a shellface, marking it dead.  //
+//                       Used both for dealloc a subface and subsegment.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::shellfacedealloc(memorypool *pool, shellface *dyingshellface)
+{
+  // Set shellface's vertices to NULL. This makes it possible to detect dead
+  //   shellfaces when traversing the list of all shellfaces.
+  dyingshellface[3] = (shellface) NULL;
+  dyingshellface[4] = (shellface) NULL;
+  dyingshellface[5] = (shellface) NULL;
+  pool->dealloc((void *) dyingshellface);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// shellfaceraverse()    Traverse the subfaces, skipping dead ones. Used for //
+//                       both subfaces and subsegments pool traverse.        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+shellface* mesh3d::shellfacetraverse(memorypool *pool)
+{
+  shellface *newshellface;
+
+  do {
+    newshellface = (shellface *) pool->traverse();
+    if (newshellface == (shellface *) NULL) {
+      return (shellface *) NULL;
+    }
+  } while (newshellface[3] == (shellface) NULL);        // Skip dead ones.
+  return newshellface;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// badsegmentdealloc()    Deallocate space for a bad segment, marking it     //
+//                        dead.                                              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::badsegmentdealloc(badface3d *dyingshseg)
+{
+  // Set segment's faceorg to NULL. This makes it possible to detect dead
+  //   segments when traversing the list of all segments.
+  dyingshseg->faceorg = (point3d) NULL;
+  badsegments.dealloc((void *) dyingshseg);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// badsegmenttraverse()    Traverse the bad segments, skipping dead ones.    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+badface3d* mesh3d::badsegmenttraverse()
+{
+  badface3d *newsh;
+
+  do {
+    newsh = (badface3d *) badsegments.traverse();
+    if (newsh == (badface3d *) NULL) {
+      return (badface3d *) NULL;
+    }
+  } while (newsh->faceorg == (point3d) NULL);             // Skip dead ones.
+  return newsh;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// pointdealloc()    Deallocate space for a point, marking it dead.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::pointdealloc(point3d dyingpoint)
+{
+  // Mark the point as dead. This  makes it possible to detect dead points
+  //   when traversing the list of all points.
+  setpointmark(dyingpoint, DEADPOINT);
+  points.dealloc((void *) dyingpoint);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// pointtraverse()    Traverse the points, skipping dead ones.               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+point3d mesh3d::pointtraverse()
+{
+  point3d newpoint;
+
+  do {
+    newpoint = (point3d) points.traverse();
+    if (newpoint == (point3d) NULL) {
+      return (point3d) NULL;
+    }
+  } while (pointmark(newpoint) == DEADPOINT);             // Skip dead ones.
+  return newpoint;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// getpoint()    Get a specific point, by number, from the list.             //
+//                                                                           //
+// The first point is number 'firstnumber'.                                  //
+//                                                                           //
+// Note that this takes O(n) time ( with a small constant, if POINTPERBLOCK  //
+// is large ). I don't care to take the trouble to make it work in constant  //
+// time.                                                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+point3d mesh3d::getpoint(int number)
+{
+  void **getblock;
+  point3d foundpoint;
+  unsigned long alignptr;
+  int current;
+
+  getblock = points.firstblock;
+  current = firstnumber;
+  // Find the right block.
+  while (current + points.itemsperblock <= number) {
+    getblock = (void **) *getblock;
+    current += points.itemsperblock;
+  }
+  // Now find the right point.
+  alignptr = (unsigned long) (getblock + 1);
+  foundpoint = (point3d) (alignptr + (unsigned long) points.alignbytes
+                     - (alignptr % (unsigned long) points.alignbytes));
+  while (current < number) {
+    foundpoint += points.itemwords;
+    current++;
+  }
+  return foundpoint;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// maketetrahedron()    Create a new tetrahedron.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::maketetrahedron(triface *newtet)
+{
+  newtet->tet = (tetrahedron *) tetrahedrons.alloc();
+  // Initialize the four adjoining tetrahedra to be "outer space".
+  newtet->tet[0] = (tetrahedron) dummytet;
+  newtet->tet[1] = (tetrahedron) dummytet;
+  newtet->tet[2] = (tetrahedron) dummytet;
+  newtet->tet[3] = (tetrahedron) dummytet;
+  // Four NULL vertex points.
+  newtet->tet[4] = (tetrahedron) NULL;
+  newtet->tet[5] = (tetrahedron) NULL;
+  newtet->tet[6] = (tetrahedron) NULL;
+  newtet->tet[7] = (tetrahedron) NULL;
+  // Initialize the four adjoining subfaces to be the omnipresent subface.
+  if (useshelles) {
+    newtet->tet[8 ] = (tetrahedron) dummysh;
+    newtet->tet[9 ] = (tetrahedron) dummysh;
+    newtet->tet[10] = (tetrahedron) dummysh;
+    newtet->tet[11] = (tetrahedron) dummysh;
+  }
+  for (int i = 0; i < eextras; i++) {
+    setelemattribute(newtet->tet, i, 0.0);
+  }
+  if (varvolume) {
+    setvolumebound(newtet->tet, -1.0);
+  }
+  // Initialize the location and version to be Zero.
+  newtet->loc = 0;
+  newtet->ver = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// makeshellface()    Create a new shellface with version zero. Used both    //
+//                    for subfaces and seusegments.                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::makeshellface(memorypool *pool, face *newface)
+{
+  newface->sh = (shellface *) pool->alloc();
+  //Initialize the three adjoining subfaces to be the omnipresent subface.
+  newface->sh[0] = (shellface) dummysh;
+  newface->sh[1] = (shellface) dummysh;
+  newface->sh[2] = (shellface) dummysh;
+  // Three NULL vertex points.
+  newface->sh[3] = (shellface) NULL;
+  newface->sh[4] = (shellface) NULL;
+  newface->sh[5] = (shellface) NULL;
+  // Initialize the two adjoining tetrahedra to be "outer space".
+  newface->sh[6] = (shellface) dummytet;
+  newface->sh[7] = (shellface) dummytet;
+  // Initialize the three adjoining subsegments to be the omnipresent
+  //   subsegments.
+  newface->sh [8] = (shellface) dummysh;
+  newface->sh [9] = (shellface) dummysh;
+  newface->sh[10] = (shellface) dummysh;
+  // Set the boundary marker to zero.
+  * (int *) (newface->sh + 11) = 0;
+  // Initialize the version to be Zero.
+  newface->shver = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// Memory Management Routines                                                //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// Geometric Primitives                                                      //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+inline bool mesh3d::iszero(const REAL value)
+{
+  if (noroundoff) {
+    return value == 0.0;
+  } else {
+    return fabs(value) <= usertolerance;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// iorient3d()    3D Orientation test.                                       //
+//                                                                           //
+// Return +1 if the point pd lies "below" the plane passing through pa, pb,  //
+// and pc;  Return -1 if pd lies "above" the plane.  Return 0 if the points  //
+// are coplanar.                                                             //
+//                                                                           //
+// "below" and "above" is defined use Right-Hand Rule, so that pa, pb, and   //
+// pc appear in counterclockwise order when making a fist, the thumb points  //
+// to the "above" direction of the plane.                                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::iorient3d(point3d pa, point3d pb, point3d pc, point3d pd)
+{
+  orient3dcount++;
+
+  if (!noexact) {
+    // Using adaptive precision arithmetic and tolerance.
+    REAL sign = orient3d(pa, pb, pc, pd);
+    if (iszero(sign)) sign = 0.0;
+    if (sign > 0) return (1);
+    else if (sign < 0) return (-1);
+    else return (0);
+  } else {
+    // Using as nearly exact arithmetic as required.
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#define MINMAX4(da, db, dc, dd, dMin, dMax) { \
+      REAL dMax1, dMax2, dMin1, dMin2; \
+      if (da > db) {dMax1 = da; dMin1 = db;} \
+      else         {dMax1 = db; dMin1 = da;} \
+      if (dc > dd) {dMax2 = dc; dMin2 = dd;} \
+      else         {dMax2 = dd; dMin2 = dc;} \
+      if (dMax1 > dMax2) dMax = dMax1; \
+      else               dMax = dMax2; \
+      if (dMin1 < dMin2) dMin = dMin1; \
+      else               dMin = dMin2; \
+    }
+    REAL dXa = pa[0], dYa = pa[1], dZa = pa[2];
+    REAL dXb = pb[0], dYb = pb[1], dZb = pb[2];
+    REAL dXc = pc[0], dYc = pc[1], dZc = pc[2];
+    REAL dXd = pd[0], dYd = pd[1], dZd = pd[2];
+
+    REAL dMaxX, dMinX, dMaxY, dMinY, dMaxZ, dMinZ;
+
+    REAL dDX2 = dXb - dXa;
+    REAL dDX3 = dXc - dXa;
+    REAL dDX4 = dXd - dXa;
+    MINMAX4(dXa, dXb, dXc, dXd, dMinX, dMaxX);
+
+    REAL dDY2 = dYb - dYa;
+    REAL dDY3 = dYc - dYa;
+    REAL dDY4 = dYd - dYa;
+    MINMAX4(dYa, dYb, dYc, dYd, dMinY, dMaxY);
+
+    REAL dDZ2 = dZb - dZa;
+    REAL dDZ3 = dZc - dZa;
+    REAL dDZ4 = dZd - dZa;
+    MINMAX4(dZa, dZb, dZc, dZd, dMinZ, dMaxZ);
+    REAL dMax = MAX( MAX(dMaxX-dMinX, dMaxY-dMinY), dMaxZ-dMinZ);
+
+    // dDet is proportional to the cell volume
+    REAL dDet = (dDX2*(dDY3*dDZ4 - dDY4*dDZ3)
+                 + dDX3*(dDY4*dDZ2 - dDY2*dDZ4)
+                 + dDX4*(dDY2*dDZ3 - dDY3*dDZ2));
+
+    // Compute an upper bound on the error bound.
+    REAL dError = usertolerance * dMax*dMax*dMax;
+
+    // Note: This is an left-hand direction, we need translate
+    //   it to right-hand direction we used.
+    if (dDet > dError)
+      return (-1);  // return (1);
+    else if (dDet < -dError)
+      return (1);   // return (-1);
+    return(0);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// iinsphere()    Insphere test.                                             //
+//                                                                           //
+// Determines whether point 'pe' is inside or outside the circumsphere of    //
+// the tetrahedron formed by point pa, pb, pc, pd.                           //
+//                                                                           //
+// Return a positive value if the point 'pe' lies inside the sphere passing  //
+// through pa, pb, pc, and pd; a negative value if it lies outside; and zero //
+// if the five points are cospherical. The points pa, pb, pc, and pd must be //
+// ordered so that they have a positive orientation (as defined by orient3d),//
+// or the sign of the result will be reversed.                               //
+//                                                                           //
+// Note: We can skip to test pa, pb, pc, and pd 's orientation, because we   //
+// always known the orientation of pa, pb, pc and pd in advance.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::iinsphere(point3d pa, point3d pb, point3d pc, point3d pd,
+                      point3d pe)
+{
+#ifdef SELF_CHECK
+  assert(iorient3d(pa, pb, pc, pd) > 0);
+#endif // defined SELF_CHECK
+
+  inspherecount++;
+
+  if (!noexact) {
+    // Using adaptive precision arithmetic and tolerance.
+    REAL sign = insphere(pa, pb, pc, pd, pe);
+    if (iszero(sign)) sign = 0.0;
+    if (sign > 0.) return (1);
+    else if (sign < 0.) return (-1);
+    else return (0);
+  } else {
+    // Using as nearly exact arithmetic as required.
+#define dDet4By4(Mat4)                                    \
+    (  Mat4[0][0] * (  Mat4[1][1]*Mat4[2][2]*Mat4[3][3]   \
+                     + Mat4[1][2]*Mat4[2][3]*Mat4[3][1]   \
+                     + Mat4[1][3]*Mat4[2][1]*Mat4[3][2]   \
+                     - Mat4[3][1]*Mat4[2][2]*Mat4[1][3]   \
+                     - Mat4[3][2]*Mat4[2][3]*Mat4[1][1]   \
+                     - Mat4[3][3]*Mat4[2][1]*Mat4[1][2] ) \
+     - Mat4[0][1] * (  Mat4[1][0]*Mat4[2][2]*Mat4[3][3]   \
+                     + Mat4[1][2]*Mat4[2][3]*Mat4[3][0]   \
+                     + Mat4[1][3]*Mat4[2][0]*Mat4[3][2]   \
+                     - Mat4[3][0]*Mat4[2][2]*Mat4[1][3]   \
+                     - Mat4[3][2]*Mat4[2][3]*Mat4[1][0]   \
+                     - Mat4[3][3]*Mat4[2][0]*Mat4[1][2] ) \
+     + Mat4[0][2] * (  Mat4[1][0]*Mat4[2][1]*Mat4[3][3]   \
+                     + Mat4[1][1]*Mat4[2][3]*Mat4[3][0]   \
+                     + Mat4[1][3]*Mat4[2][0]*Mat4[3][1]   \
+                     - Mat4[3][0]*Mat4[2][1]*Mat4[1][3]   \
+                     - Mat4[3][1]*Mat4[2][3]*Mat4[1][0]   \
+                     - Mat4[3][3]*Mat4[2][0]*Mat4[1][1] ) \
+     - Mat4[0][3] * (  Mat4[1][0]*Mat4[2][1]*Mat4[3][2]   \
+                     + Mat4[1][1]*Mat4[2][2]*Mat4[3][0]   \
+                     + Mat4[1][2]*Mat4[2][0]*Mat4[3][1]   \
+                     - Mat4[3][0]*Mat4[2][1]*Mat4[1][2]   \
+                     - Mat4[3][1]*Mat4[2][2]*Mat4[1][0]   \
+                     - Mat4[3][2]*Mat4[2][0]*Mat4[1][1] ) \
+    )
+    REAL dXa = pa[0], dYa = pa[1], dZa = pa[2];
+    REAL dXb = pb[0], dYb = pb[1], dZb = pb[2];
+    REAL dXc = pc[0], dYc = pc[1], dZc = pc[2];
+    REAL dXd = pd[0], dYd = pd[1], dZd = pd[2];
+    REAL dXe = pe[0], dYe = pe[1], dZe = pe[2];
+
+    REAL a2dInSphMat[4][4], dWa;
+    dWa = dXa*dXa + dYa*dYa + dZa*dZa;
+
+    a2dInSphMat[0][0] = dXb - dXa;
+    a2dInSphMat[0][1] = dYb - dYa;
+    a2dInSphMat[0][2] = dZb - dZa;
+    a2dInSphMat[0][3] = dXb*dXb + dYb*dYb + dZb*dZb - dWa;
+
+    a2dInSphMat[1][0] = dXc - dXa;
+    a2dInSphMat[1][1] = dYc - dYa;
+    a2dInSphMat[1][2] = dZc - dZa;
+    a2dInSphMat[1][3] = dXc*dXc + dYc*dYc + dZc*dZc - dWa;
+
+    a2dInSphMat[2][0] = dXd - dXa;
+    a2dInSphMat[2][1] = dYd - dYa;
+    a2dInSphMat[2][2] = dZd - dZa;
+    a2dInSphMat[2][3] = dXd*dXd + dYd*dYd + dZd*dZd - dWa;
+
+    a2dInSphMat[3][0] = dXe - dXa;
+    a2dInSphMat[3][1] = dYe - dYa;
+    a2dInSphMat[3][2] = dZe - dZa;
+    a2dInSphMat[3][3] = dXe*dXe + dYe*dYe + dZe*dZe - dWa;
+
+    // Set up a scale that is the average of the distance from A to each
+    // of the other verts.  Use some trickery to take advantage of
+    // already knowing what the differences in coordinates are.
+    REAL dAveLen = 0.25 * (Mag3D(a2dInSphMat[0])
+                           + Mag3D(a2dInSphMat[1])
+                           + Mag3D(a2dInSphMat[2])
+                           + Mag3D(a2dInSphMat[3]));
+    REAL dScale = pow(dAveLen, 5);
+    // REAL dDet = dDet4By4(a2dInSphMat) / dScale *
+    //             iorient3d(pa, pb, pc, pd);
+    REAL dDet = dDet4By4(a2dInSphMat) / dScale;
+    if (dDet >  userubtolerance) {
+      return (1); // return (-1);
+    } else if (dDet < -userubtolerance) {
+      return (-1); // return ( 1);
+    } else {
+      return (0);
+    }
+  }
+}
+
+int mesh3d::iinsphere(triface* tface, point3d testpoint)
+{
+  point3d torg, tdest, tapex, toppo;
+
+  org(*tface, torg);
+  dest(*tface, tdest);
+  apex(*tface, tapex);
+  oppo(*tface, toppo);
+  // We need form a positive orientation of this points before test.
+  if (EdgeRing(tface->ver) == CCW) {
+    return iinsphere(tdest, torg, tapex, toppo, testpoint);
+  } else {
+    return iinsphere(torg, tdest, tapex, toppo, testpoint);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Some convient functions for Geometric Primitives.                         //
+//                                                                           //
+// isbelowplane     Return ture iff point is 'below' the plane.              //
+// isaboveplane     Return true iff point is 'above' the plane.              //
+// iscoplane        Return true iff points are coplane.                      //
+// iscoline         Return true iff three points are colinear.               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool mesh3d::isbelowplane(triface* tface, point3d testpoint)
+{
+  point3d torg, tdest, tapex;
+
+  org(*tface, torg);
+  dest(*tface, tdest);
+  apex(*tface, tapex);
+  return iorient3d(torg, tdest, tapex, testpoint) > 0;
+}
+
+bool mesh3d::isaboveplane(triface* tface, point3d testpoint)
+{
+  point3d torg, tdest, tapex;
+
+  org(*tface, torg);
+  dest(*tface, tdest);
+  apex(*tface, tapex);
+  return iorient3d(torg, tdest, tapex, testpoint) < 0;
+}
+
+bool mesh3d::iscoplane(triface* tface, point3d testpoint)
+{
+  point3d torg, tdest, tapex;
+
+  org(*tface, torg);
+  dest(*tface, tdest);
+  apex(*tface, tapex);
+  return iorient3d(torg, tdest, tapex, testpoint) == 0;
+}
+
+bool mesh3d::isbelowplane(point3d pa, point3d pb, point3d pc, point3d pd)
+{
+  return iorient3d(pa, pb, pc, pd) > 0;
+}
+
+bool mesh3d::isaboveplane(point3d pa, point3d pb, point3d pc, point3d pd)
+{
+  return iorient3d(pa, pb, pc, pd) < 0;
+}
+
+bool mesh3d::iscoplane(point3d pa, point3d pb, point3d pc, point3d pd)
+{
+  return iorient3d(pa, pb, pc, pd) == 0;
+}
+
+bool mesh3d::iscoline(point3d pa, point3d pb, point3d pc)
+{
+  REAL v0[3], v1[3], v2[3];
+
+  Sub3D(pa, pc, v0);
+  Sub3D(pb, pc, v1);
+  Cross3D(v0, v1, v2);
+  return (iszero(v2[0])) && (iszero(v2[1])) && (iszero(v2[2]));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// Geometric Primitives                                                      //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// Geometric Functions                                                       //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// projontoface()    Get the orthogonal projection of point 'p' onto the     //
+//                   plane passing through points a, b and c. Return by 'p'. //
+//                                                                           //
+// Given a facet F(contains point a, b and c) and a point p, the orthogonal  //
+// projection p' of p onto F is the point that is coplanar with points a, b  //
+// and c, and satisfies the requirement that the line pp' is orthogonal to F.//
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::projontoface(point3d a, point3d b, point3d c, point3d p)
+{
+  REAL ba[3], ca[3], pa[3], n[3];
+  REAL dist;
+
+  // Get unit normal of face abc.
+  Sub3D(b, a, ba);
+  Sub3D(c, a, ca);
+  Cross3D(ba, ca, n);
+  Normalize3D(n);
+
+  Sub3D(p, a, pa);
+  dist = Dot3D(pa, n);
+
+  p[0] -= dist * n[0];
+  p[1] -= dist * n[1];
+  p[2] -= dist * n[2];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// circumcenter()    Get the equatorial shpere center of a triangular face   //
+//                   defines by vertices a, b and c. Return by 'res'.        //
+//                                                                           //
+// Equatorial shpere of a triangular face is the smallest sphere that passes //
+// through the three vertices of the face.                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::circumcenter(point3d a, point3d b, point3d c, point3d res)
+{
+  REAL adRow1[3], adRow2[3], adRow3[3];
+  REAL dRHS1, dRHS2, dRHS3;
+  REAL dTemp;
+
+  Sub3D(a, b, adRow1);
+  Sub3D(a, c, adRow2);
+  Cross3D(adRow1, adRow2, adRow3);
+
+#ifdef SELF_CHECK
+  if (noexact) {
+    noexact = 0;
+    // Check three dividers to catch precission problems before going on.
+    REAL adOrg[3] = {0, 0, 0};
+    if (iorient3d(adRow1, adRow2, adRow3, adOrg) == 0) {
+      printf("Precssion error in circumcenter():\n");
+      printf("  Try to find circumcenter from three almost colinear points:\n");
+      printf("    point 1: (%.12g, %.12g, %.12g).\n", a[0], a[1], a[2]);
+      printf("    point 2: (%.12g, %.12g, %.12g).\n", b[0], b[1], b[2]);
+      printf("    point 3: (%.12g, %.12g, %.12g).\n", c[0], c[1], c[2]);
+      printf("  This probably means I am trying to refine mesh by splitting\n");
+      printf("    a nearly degenerate subface(which created by the approximate\n");
+      printf("    finite precision of floating point arithmetic).\n");
+      noexact = 1;
+      precisionerror();
+    }
+    noexact = 1;
+  }
+#endif // defined SELF_CHECK
+
+  dRHS1 = 0.5 * (Dot3D(a, a) - Dot3D(b, b));
+  dRHS2 = 0.5 * (Dot3D(a, a) - Dot3D(c, c));
+  dRHS3 = Dot3D(a, adRow3);
+
+  // Gussian elimination. Solve 3 by 3 linear system.
+
+  // Pivot first column
+  if (fabs(adRow1[0]) >= fabs(adRow2[0]) &&
+      fabs(adRow1[0]) >= fabs(adRow3[0])) {
+    ;
+  } else if (fabs(adRow2[0]) >= fabs(adRow3[0])) {
+    dTemp = dRHS1;
+    dRHS1 = dRHS2;
+    dRHS2 = dTemp;
+    Swap3D(adRow1, adRow2);
+  } else {
+    dTemp = dRHS1;
+    dRHS1 = dRHS3;
+    dRHS3 = dTemp;
+    Swap3D(adRow1, adRow3);
+  }
+
+  // Eliminate first column
+  dRHS2 -= dRHS1 * adRow2[0]/adRow1[0];
+  dRHS3 -= dRHS1 * adRow3[0]/adRow1[0];
+  adRow2[1] = adRow2[1] - adRow1[1] * (adRow2[0]/adRow1[0]);
+  adRow2[2] = adRow2[2] - adRow1[2] * (adRow2[0]/adRow1[0]);
+  adRow3[1] = adRow3[1] - adRow1[1] * (adRow3[0]/adRow1[0]);
+  adRow3[2] = adRow3[2] - adRow1[2] * (adRow3[0]/adRow1[0]);
+
+  // Pivot second column
+  if (fabs(adRow2[1]) >= fabs(adRow3[1])) {
+    ;
+  } else {
+    dTemp = dRHS2;
+    dRHS2 = dRHS3;
+    dRHS3 = dTemp;
+    Swap3D(adRow2, adRow3);
+  }
+
+  // Eliminate second column
+  dRHS3 -= dRHS2 * adRow3[1]/adRow2[1];
+  adRow3[2] = adRow3[2] - adRow2[2] * (adRow3[1]/adRow2[1]);
+
+  // Solve for dRHS3 and back-substitute
+  res[2] = dRHS3 /= adRow3[2];
+  dRHS2 -= adRow2[2] * dRHS3;
+  dRHS1 -= adRow1[2] * dRHS3;
+
+  // Solve for dRHS2 and back-substitute
+  res[1] = dRHS2 /= adRow2[1];
+  dRHS1 -= adRow1[1] * dRHS2;
+
+  // Solve for dRHS1
+  res[0] = dRHS1 /= adRow1[0];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// circumcenter()    Get the circumcenter of four points a, b, c and d.      //
+//                   Return by 'res'.                                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::circumcenter(point3d a, point3d b, point3d c, point3d d,
+                          point3d res)
+{
+  REAL adRow1[3], adRow2[3], adRow3[3];
+  REAL dRHS1, dRHS2, dRHS3;
+  REAL dTemp;
+
+  Sub3D(a, b, adRow1);
+  Sub3D(a, c, adRow2);
+  Sub3D(a, d, adRow3);
+
+#ifdef SELF_CHECK
+  if (noexact) {
+    noexact = 0;
+    if (iorient3d(a, b, c, d) == 0) {
+      printf("Precssion error in circumcenter():\n");
+      printf("  Try to find circumcenter from four almost coplanar points:\n");
+      printf("    point 1: (%.12g, %.12g, %.12g).\n", a[0], a[1], a[2]);
+      printf("    point 2: (%.12g, %.12g, %.12g).\n", b[0], b[1], b[2]);
+      printf("    point 3: (%.12g, %.12g, %.12g).\n", c[0], c[1], c[2]);
+      printf("    point 4: (%.12g, %.12g, %.12g).\n", d[0], d[1], d[2]);
+      printf("  This probably means I am trying to refine mesh by splitting\n");
+      printf("    a nearly degenerate tetrahedron(which created by the \n");
+      printf("    approximate finite precision of floating point arithmetic).\n");
+      noexact = 1;
+      precisionerror();
+    }
+    noexact = 1;
+  }
+#endif // defined SELF_CHECK
+
+  dRHS1 = 0.5 * (Dot3D(a, a) - Dot3D(b, b));
+  dRHS2 = 0.5 * (Dot3D(a, a) - Dot3D(c, c));
+  dRHS3 = 0.5 * (Dot3D(a, a) - Dot3D(d, d));
+
+  // Gussian elimination. Solve 3 by 3 linear system.
+
+  // Pivot first column
+  if (fabs(adRow1[0]) >= fabs(adRow2[0]) &&
+      fabs(adRow1[0]) >= fabs(adRow3[0])) {
+    ;
+  } else if (fabs(adRow2[0]) >= fabs(adRow3[0])) {
+    dTemp = dRHS1;
+    dRHS1 = dRHS2;
+    dRHS2 = dTemp;
+    Swap3D(adRow1, adRow2);
+  } else {
+    dTemp = dRHS1;
+    dRHS1 = dRHS3;
+    dRHS3 = dTemp;
+    Swap3D(adRow1, adRow3);
+  }
+
+  // Eliminate first column
+  dRHS2 -= dRHS1 * adRow2[0]/adRow1[0];
+  dRHS3 -= dRHS1 * adRow3[0]/adRow1[0];
+  adRow2[1] = adRow2[1] - adRow1[1] * (adRow2[0]/adRow1[0]);
+  adRow2[2] = adRow2[2] - adRow1[2] * (adRow2[0]/adRow1[0]);
+  adRow3[1] = adRow3[1] - adRow1[1] * (adRow3[0]/adRow1[0]);
+  adRow3[2] = adRow3[2] - adRow1[2] * (adRow3[0]/adRow1[0]);
+
+  // Pivot second column
+  if (fabs(adRow2[1]) >= fabs(adRow3[1])) {
+    ;
+  } else {
+    dTemp = dRHS2;
+    dRHS2 = dRHS3;
+    dRHS3 = dTemp;
+    Swap3D(adRow2, adRow3);
+  }
+
+  // Eliminate second column
+  dRHS3 -= dRHS2 * adRow3[1]/adRow2[1];
+  adRow3[2] = adRow3[2] - adRow2[2] * (adRow3[1]/adRow2[1]);
+
+  // Solve for dRHS3 and back-substitute
+  res[2] = dRHS3 /= adRow3[2];
+  dRHS2 -= adRow2[2] * dRHS3;
+  dRHS1 -= adRow1[2] * dRHS3;
+
+  // Solve for dRHS2 and back-substitute
+  res[1] = dRHS2 /= adRow2[1];
+  dRHS1 -= adRow1[1] * dRHS2;
+
+  // Solve for dRHS1
+  res[0] = dRHS1 /= adRow1[0];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetvolume()    Get the volume of tetrahedron formed by vertices a, b, c   //
+//                and d.                                                     //
+//                                                                           //
+// Note: The return value may be negative. True volume is fabs(retval).      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL mesh3d::tetvolume(point3d a, point3d b, point3d c, point3d d)
+{
+  REAL adVec1[3], adVec2[3], adVec3[3];
+  REAL adCross[3];
+
+  Sub3D(b, a, adVec1);
+  Sub3D(c, a, adVec2);
+  Sub3D(d, a, adVec3);
+
+  Cross3D(adVec2, adVec3, adCross);
+  return Dot3D(adCross, adVec1) / 6.;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// facedihedral()    Get the diahedral angle of two faces, given by their    //
+//                   vertices.                                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL mesh3d::facedihedral(point3d forg1, point3d fdest1, point3d fapex1,
+                          point3d forg2, point3d fdest2, point3d fapex2)
+{
+  REAL adNorm0[3], adNorm1[3];
+  REAL dScale, dDot;
+
+  Normal3D(forg1, fdest1, fapex1, adNorm0);
+  Normalize3D(adNorm0);
+  Normal3D(forg2, fdest2, fapex2, adNorm1);
+  Normalize3D(adNorm1);
+
+  dScale = 180. / acos(-1.);
+  dDot = -Dot3D(adNorm0, adNorm1);
+  if (dDot > 1.) dDot = 1.;
+  else if (dDot < -1.) dDot = -1.;
+  return acos(dDot) * dScale;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetalldihedral()    Get all(six) dihedral angles in tetrahedron form by   //
+//                     vertices a, b, c and d. Return by array adDihed[6].   //
+//                                                                           //
+// 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.                                                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::tetalldihedral(point3d a, point3d b, point3d c, point3d d,
+                            REAL adDihed[6])
+{
+  REAL adNorm0[3], adNorm1[3], adNorm2[3], adNorm3[3];
+  REAL dScale, dDot;
+
+  Normal3D(c, b, d, adNorm0);
+  Normalize3D(adNorm0);
+  Normal3D(a, c, d, adNorm1);
+  Normalize3D(adNorm1);
+  Normal3D(b, a, d, adNorm2);
+  Normalize3D(adNorm2);
+  Normal3D(a, b, c, adNorm3);
+  Normalize3D(adNorm3);
+
+  dScale = 180. / acos(-1.);
+  dDot = -Dot3D(adNorm0, adNorm1);
+  if (dDot > 1.) dDot = 1.;
+  else if (dDot < -1.) dDot = -1.;
+  adDihed[5] = acos(dDot) * dScale; // Edge CD
+
+  dDot = -Dot3D(adNorm0, adNorm2);
+  if (dDot > 1.) dDot = 1.;
+  else if (dDot < -1.) dDot = -1.;
+  adDihed[4] = acos(dDot) * dScale; // Edge BD
+
+  dDot = -Dot3D(adNorm0, adNorm3);
+  if (dDot > 1.) dDot = 1.;
+  else if (dDot < -1.) dDot = -1.;
+  adDihed[3] = acos(dDot) * dScale; // Edge BC
+
+  dDot = -Dot3D(adNorm1, adNorm2);
+  if (dDot > 1.) dDot = 1.;
+  else if (dDot < -1.) dDot = -1.;
+  adDihed[2] = acos(dDot) * dScale; // Edge AD
+
+  dDot = -Dot3D(adNorm1, adNorm3);
+  if (dDot > 1.) dDot = 1.;
+  else if (dDot < -1.) dDot = -1.;
+  adDihed[1] = acos(dDot) * dScale; // Edge AC
+
+  dDot = -Dot3D(adNorm2, adNorm3);
+  if (dDot > 1.) dDot = 1.;
+  else if (dDot < -1.) dDot = -1.;
+  adDihed[0] = acos(dDot) * dScale; // Edge AB
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// Geometric Functions                                                       //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// Point Location Routines                                                   //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+//   A crucial step in implementing many mesh generation algorithms is the   //
+// point location problem. For example, in incremental insertion algorithms, //
+// for each vertex to be inserted, we need to find the tetrahedron in which  //
+// this vertex lies, so that it may be inserted.  In many circumstances, the //
+// dominant cost is the time required for point location.                    //
+//                                                                           //
+//   Fortunately the point location problem is well studied in computational //
+// geometry literature and and several theoretically optimal algorithms have //
+// been proposed, such as the "Bucketing" algorithm of Asano et al.[1], the  //
+// "Alternating Digital Tree(ADT)" algorithm of Bonet and Peraire[2] and the //
+// Fast Randomized Point Location algorithm of Mucke, Isaac and Zhu[3], etc. //
+// Where [3] is more suitable and faster algorithm for our 3D Delaunay mesh  //
+// generator.                                                                //
+//                                                                           //
+//   Our mesh data structure is very suitable for implementing the algorithm //
+// in [3], and with using the Adaptive Exact Geometric Predicates package of //
+// Shewchuk to improve the robustness of implementation(use -X swith).       //
+//                                                                           //
+// Please see tetlib.h and predicate.h to learn more about the mesh data     //
+// structure and exact floating-point arithmetic.                            //
+//                                                                           //
+// Refernces:                                                                //
+//                                                                           //
+// [1] T. Asano, M. Edahiro, H. Imai, M. Iri, and K. Murota. Practical use   //
+//     of bucketing techniques in computational geometry. In G. T. Toussaint,//
+//     editor, Computational Geometry, pages 153-195. North-Holland,         //
+//     Amsterdam, Netherlands, 1985.                                         //
+// [2] J. Bonet and J. Peraire. An alternating digital tree (ADT) algorithm  //
+//     for 3D geometric searching and intersection problems. International   //
+//     Journal for Numerical Methods in Engineering, 31:1-17, 1991.          //
+// [3] Ernst P. Mucke, Isaac Saias, and Binhai Zhu, Fast Randomized Point    //
+//     Location Without Preprocessing in Two- and Three-dimensional Delaunay //
+//     Triangulations, Proceedings of the Twelfth Annual Symposium on        //
+//     Computational Geometry, ACM, May 1996.                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// randomnation()    Generate a random number between 0 and 'choices' - 1.   //
+//                                                                           //
+// This is a simple linear congruential random number generator. Hence,it is //
+// a bad random number generator, but good enough for most randomized geome- //
+// tric algorithms.                                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+unsigned long mesh3d::randomnation(unsigned int choices)
+{
+  randomseed = (randomseed * 1366l + 150889l) % 714025l;
+  return randomseed / (714025l / choices + 1);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// makepointmap()    Construct a mapping from points to tetrahedra to        //
+//                   improve the speed of point location for subsegment and  //
+//                   subfacet insertion.                                     //
+//                                                                           //
+// Traverses all the tetrahedra, and provides each corner of each            //
+// tetrahedron with a pointer to that tetrahedera. Of course, pointers will  //
+// be overwritten by other pointers because (almost) each point is a corner  //
+// of several tetrahedra, but in the end every point will point to some      //
+// tetrahedron that contains it.                                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::makepointmap()
+{
+  triface tetloop;
+  point3d pointptr;
+
+  if (verbose) {
+    printf("  Constructing mapping from points to tetrahedra.\n");
+  }
+  tetrahedrons.traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    // Check all four points of the tetrahedron.
+    org(tetloop, pointptr);
+    setpoint2tet(pointptr, encode(tetloop));
+    dest(tetloop, pointptr);
+    setpoint2tet(pointptr, encode(tetloop));
+    apex(tetloop, pointptr);
+    setpoint2tet(pointptr, encode(tetloop));
+    oppo(tetloop, pointptr);
+    setpoint2tet(pointptr, encode(tetloop));
+    // Get another tet.
+    tetloop.tet = tetrahedrontraverse();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// isintet()    Determine whether a vertex lies inside, on or outside a      //
+//              tetrahedron.                                                 //
+//                                                                           //
+// For 'testpoint' to be inside the tetrahedron formed by pa, pb, pc and pd, //
+// the orientation has to be right with respect to every face of tetrahedron.//
+//                                                                           //
+// Return OUTSIDE if the point lies outside the tet; Return ONVERTEX if it   //
+// coincides with a vertex in the tet;  Return ONEDGE if it lies on an edge; //
+// Return ONFACE if it lies on a face; and Return INTETRAHEDRON if it lies   //
+// strictly inside.                                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum mesh3d::locateresult
+mesh3d::isintet(point3d pa, point3d pb, point3d pc, point3d pd,
+                point3d testpoint)
+{
+  int isign, icheck, iretval;
+
+  // Get orientation of pa, pb, pc and pd.
+  isign = iorient3d(pa, pb, pc, pd);
+  assert(isign != 0);
+
+  iretval = 0;
+  icheck = iorient3d(pb, pd, pc, testpoint) * isign;
+  if (icheck == -1) return OUTSIDE;
+  iretval += icheck;
+
+  icheck = iorient3d(pc, pd, pa, testpoint) * isign;
+  if (icheck == -1) return OUTSIDE;
+  iretval += icheck;
+
+  icheck = iorient3d(pa, pd, pb, testpoint) * isign;
+  if (icheck == -1) return OUTSIDE;
+  iretval += icheck;
+
+  icheck = iorient3d(pa, pb, pc, testpoint) * isign;
+  if (icheck == -1) return OUTSIDE;
+  iretval += icheck;
+
+  if (iretval == 1) {
+    return ONVERTEX;
+  } else if (iretval == 2) {
+    return ONEDGE;
+  } else if (iretval == 3) {
+    return ONFACE;
+  } else {
+    return INTETRAHEDRON;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// distance()    Returns the minimum "distance" of triface to point p.       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+static REAL square (REAL x)
+{
+  return (x * x);
+}
+
+REAL mesh3d::distance(triface* tface, point3d p)
+{
+#define Min(X,Y)  (((X) < (Y)) ? (X) : (Y))
+  REAL d, da, db, dc;
+  point3d tp;
+
+  org(*tface, tp);
+  da = square(p[0] - tp[0]) + square(p[1] - tp[1]) + square(p[2] - tp[2]);
+  dest(*tface, tp);
+  db = square(p[0] - tp[0]) + square(p[1] - tp[1]) + square(p[2] - tp[2]);
+  apex(*tface, tp);
+  dc = square(p[0] - tp[0]) + square(p[1] - tp[1]) + square(p[2] - tp[2]);
+  d = Min (da, db);
+  return (Min (d, dc));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// iscoplanarintri()    Determine whether a vertex lies inside, on or        //
+//                      outside a triangle in 3D. It assume the vert and the //
+//                      triangle are coplanar. Approximate test. Nonrobust.  //
+//                                                                           //
+// Return OUTSIDE if the vertex lies outside the triangle.                   //
+//                                                                           //
+// Returns ONVERTEX if the point lies on an existing vertex.  'searchtet' is //
+// a handle whose origin is the existing vertex.                             //
+//                                                                           //
+// Returns ONEDGE if the point lies on a mesh edge.  'searchtet' is a handle //
+// whose face version is the edge on which the point lies.                   //
+//                                                                           //
+// Returns ONFACE if the point lies strictly within a facet.  1searchtet' is //
+// a handle whose location is the face on which the point lies.              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum mesh3d::locateresult
+mesh3d::iscoplanarintri(point3d searchpoint, triface* searchtet)
+{
+  point3d torg, tdest, tapex;
+  const REAL dTol = 5.e-9;
+  const REAL dFloor = 1.e-6;
+  REAL dSum, dDiff;                // Tempory variables used in fuzzycomp().
+  int iCompRes;
+
+#define fuzzycomp(dA, dB, iRes)                                            \
+  dSum  = fabs(dA) + fabs(dB);                                             \
+  dDiff = dA - dB;                                                         \
+  dSum = (dSum > dFloor) ? dSum : dFloor;                                  \
+  if (dDiff > dTol * dSum) iRes = 1;                                       \
+  else if (dDiff < - dTol * dSum) iRes = -1;                               \
+  else iRes = 0;
+
+#define orient2dfast(pa, pb, pc)                                           \
+  ((pa[0] - pc[0]) * (pb[1] - pc[1]) - (pa[1] - pc[1]) * (pb[0] - pc[0]))
+
+// #define iszero3(v) (iszero(v[0]) && iszero(v[1]) && iszero(v[2]))
+#define iszero3(v) \
+  (sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]) <= userubtolerance)
+
+  org(*searchtet, torg); //  torg = searchtet->org();
+  // First find out the on vertex case, this must do first.
+  fuzzycomp(searchpoint[0], torg[0], iCompRes);
+  if (iCompRes == 0) {
+    fuzzycomp(searchpoint[1], torg[1], iCompRes);
+    if (iCompRes == 0) {
+      fuzzycomp(searchpoint[2], torg[2], iCompRes);
+      if (iCompRes == 0) {
+        return ONVERTEX;
+      }
+    }
+  }
+
+  dest(*searchtet, tdest); // tdest = searchtet->dest();
+  fuzzycomp(searchpoint[0], tdest[0], iCompRes);
+  if (iCompRes == 0) {
+    fuzzycomp(searchpoint[1], tdest[1], iCompRes);
+    if (iCompRes == 0) {
+      fuzzycomp(searchpoint[2], tdest[2], iCompRes);
+      if (iCompRes == 0) {
+        enextself(*searchtet);
+        return ONVERTEX;
+      }
+    }
+  }
+
+  apex(*searchtet, tapex); // tapex = searchtet->apex();
+  fuzzycomp(searchpoint[0], tapex[0], iCompRes);
+  if (iCompRes == 0) {
+    fuzzycomp(searchpoint[1], tapex[1], iCompRes);
+    if (iCompRes == 0) {
+      fuzzycomp(searchpoint[2], tapex[2], iCompRes);
+      if (iCompRes == 0) {
+        enext2self(*searchtet);
+        return ONVERTEX;
+      }
+    }
+  }
+
+  // Next find out the on edge case.
+  REAL v0[3], v1[3], v2[3];
+  int iCompRes1, iCompRes2;
+
+  Sub3D(torg, searchpoint, v0);
+  Sub3D(tdest, searchpoint, v1);
+  Cross3D(v0, v1, v2);
+  if (iszero3(v2)) {
+    fuzzycomp(torg[0], searchpoint[0], iCompRes1);
+    fuzzycomp(searchpoint[0], tdest[0], iCompRes2);
+    if ((iCompRes1 != 1) == (iCompRes2 != 1)) {
+      fuzzycomp(torg[1], searchpoint[1], iCompRes1);
+      fuzzycomp(searchpoint[1], tdest[1], iCompRes2);
+      if ((iCompRes1 != 1) == (iCompRes2 != 1)) {
+        fuzzycomp(torg[2], searchpoint[2], iCompRes1);
+        fuzzycomp(searchpoint[2], tdest[2], iCompRes2);
+        if ((iCompRes1 != 1) == (iCompRes2 != 1)) {
+          return ONEDGE;
+        }
+      }
+    }
+  }
+  Sub3D(tapex, searchpoint, v0);
+  Cross3D(v0, v1, v2);
+  if (iszero3(v2)) {
+    fuzzycomp(tdest[0], searchpoint[0], iCompRes1);
+    fuzzycomp(searchpoint[0], tapex[0], iCompRes2);
+    if ((iCompRes1 != 1) == (iCompRes2 != 1)) {
+      fuzzycomp(tdest[1], searchpoint[1], iCompRes1);
+      fuzzycomp(searchpoint[1], tapex[1], iCompRes2);
+      if ((iCompRes1 != 1) == (iCompRes2 != 1)) {
+        fuzzycomp(tdest[2], searchpoint[2], iCompRes1);
+        fuzzycomp(searchpoint[2], tapex[2], iCompRes2);
+        if ((iCompRes1 != 1) == (iCompRes2 != 1)) {
+          enextself(*searchtet);
+          return ONEDGE;
+        }
+      }
+    }
+  }
+  Sub3D(torg, searchpoint, v1);
+  Cross3D(v0, v1, v2);
+  if (iszero3(v2)) {
+    fuzzycomp(tapex[0], searchpoint[0], iCompRes1);
+    fuzzycomp(searchpoint[0], torg[0], iCompRes2);
+    if ((iCompRes1 != 1) == (iCompRes2 != 1)) {
+      fuzzycomp(tapex[1], searchpoint[1], iCompRes1);
+      fuzzycomp(searchpoint[1], torg[1], iCompRes2);
+      if ((iCompRes1 != 1) == (iCompRes2 != 1)) {
+        fuzzycomp(tapex[2], searchpoint[2], iCompRes1);
+        fuzzycomp(searchpoint[2], torg[2], iCompRes2);
+        if ((iCompRes1 != 1) == (iCompRes2 != 1)) {
+          enext2self(*searchtet);
+          return ONEDGE;
+        }
+      }
+    }
+  }
+
+  // Finally, to find if this point lies on face.
+  REAL adNorm[3], adBasisX[3], adBasisY[3];
+  REAL VProjA[2], VProjB[2], VProjC[2], VProj[2];
+  REAL sign0, sign1, sign2;
+
+  // Find a normal and two vectors in the plane.
+  Sub3D(tdest, torg, v0);
+  Sub3D(tapex, torg, v1);
+  Cross3D(v0, v1, adNorm);
+  Normalize3D(adNorm);
+  Assign3D(v0, adBasisX);
+  Normalize3D(adBasisX);
+  Cross3D(adNorm, adBasisX, adBasisY);
+
+  // Project onto a plane (adBasisX, adBasisY).
+  VProjA[0] = Dot3D(torg, adBasisX);
+  VProjA[1] = Dot3D(torg, adBasisY);
+  VProjB[0] = Dot3D(tdest, adBasisX);
+  VProjB[1] = Dot3D(tdest, adBasisY);
+  VProjC[0] = Dot3D(tapex, adBasisX);
+  VProjC[1] = Dot3D(tapex, adBasisY);
+  VProj [0] = Dot3D(searchpoint, adBasisX);
+  VProj [1] = Dot3D(searchpoint, adBasisY);
+
+  sign0 = orient2dfast(VProjA, VProjB, VProj);
+  sign1 = orient2dfast(VProjB, VProjC, VProj);
+  sign2 = orient2dfast(VProjC, VProjA, VProj);
+
+  if (((sign0 > 0.) == (sign1 > 0.)) && ((sign1 > 0.) == (sign2 > 0.))) {
+    return ONFACE;
+  } else {
+    return OUTSIDE;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// preciselocate()    Find a tetrahedron, a face or an edge containing a     //
+//                    given point.                                           //
+//                                                                           //
+// Begins its search from 'searchtet'. It is important that 'searchtet' be a //
+// handle with the property that 'searchpoint' is strictly lies 'above' of   //
+// the facet denoted by 'searchtet', or is colplanar with that facet and     //
+// does not intersect that facet. (In particular, 'searchpoint' should not   //
+// be the vertex of that facet.)                                             //
+//                                                                           //
+// Returns ONVERTEX if the point lies on an existing vertex.  'searchtet' is //
+// a handle whose origin is the existing vertex.                             //
+//                                                                           //
+// Returns ONEDGE if the point lies on a mesh edge.  'searchtet' is a handle //
+// whose face version is the edge on which the point lies.                   //
+//                                                                           //
+// Returns ONFACE if the point lies strictly within a facet.  'searchtet' is //
+// a handle whose location is the face on which the point lies.              //
+//                                                                           //
+// Returns INTETRAHEDRON if the point lies strictly within a tetrahededron.  //
+// 'searchtet' is a handle on the tetrahedron that contains the point.       //
+//                                                                           //
+// Returns OUTSIDE if the point lies outside the mesh. 'searchtet' is a      //
+// handle whose location is the face the point is to 'above' of. This might  //
+// occur when the circumcenter of a tetrahedron falls just slightly outside  //
+// the mesh due to floating-point roundoff error.  It also occurs when       //
+// seeking a hole or region point that a foolish user has placed outside the //
+// mesh.                                                                     //
+//                                                                           //
+// WARNING: This routine is designed for convex triangulations, and will not //
+// generally work after the holes and concavities have been carved. However, //
+// it can still be used to find the circumcenter of a triangle, a tetrahedron//
+// as long as the search is begun from the tetrahedron in question.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum mesh3d::locateresult
+mesh3d::preciselocate(point3d searchpoint, triface* searchtet)
+{
+  triface checkface, backtracetet;
+  point3d torg, tdest, toppo;
+  enum locateresult retval;
+  int ahead, turns;
+
+  assert(searchtet->tet != dummytet);
+  if (verbose > 2) {
+    printf("    Searching for point %d.\n", pointmark(searchpoint));
+  }
+
+  while (true) {
+    // Check if we walk off the boundary of the triangulation.
+    if (searchtet->tet == dummytet) {
+      *searchtet = backtracetet;
+      if (verbose > 2) {
+        printf("    End Searching: Outside current mesh.\n");
+      }
+      return OUTSIDE;
+    }
+    if (verbose > 2) {
+      printf("    From face (%d, %d, %d, %d)\n",
+             pointmark(org(*searchtet)), pointmark(dest(*searchtet)),
+             pointmark(apex(*searchtet)), pointmark(oppo(*searchtet)));
+    }
+    searchtet->ver = 0;
+    // 'toppo' is the shared vertex at all orientation tests.
+    oppo(*searchtet, toppo);
+    // Check three side faces of 'searchtet' in order.
+    //   To see if we need walk through this face.
+    for (turns = 0; turns < 3; turns++) {
+      fnext(*searchtet, checkface);
+      org(checkface, torg);
+      dest(checkface, tdest);
+      ahead = iorient3d(torg, tdest, toppo, searchpoint);
+      if (ahead == 0) {
+        // Check if `searchpoint' is locate on face, on edge or on vertex.
+        retval = iscoplanarintri(searchpoint, &checkface);
+        if (retval != OUTSIDE) {
+          *searchtet = checkface;
+          if (verbose > 2) {
+            printf("    End Searching: ");
+            if (retval == ONVERTEX) {
+              printf("On Vertex.");
+            } else if (retval == ONEDGE) {
+              printf("On Edge.");
+            } else if (retval == ONFACE) {
+              printf("On Face.");
+            }
+            printf("\n");
+          }
+          return retval;
+        }
+      } else if (ahead < 0) {
+        // We need walk through this face and continue to search.
+        backtracetet = checkface;
+        sym(checkface, *searchtet);
+        break;
+      }
+      enextself(*searchtet);
+    }
+    if (turns >= 3) {
+      // Found! Inside tetrahedron.
+      if (verbose > 2) {
+        printf("    End Searching: Inside tetraheda.\n");
+      }
+      return INTETRAHEDRON;
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// locate()    Find a tetrahedron, a face or an edge containing a given      //
+//             point.                                                        //
+//                                                                           //
+// Searching begins from one of:  the input 'searchtet', a recently encount- //
+// ered tetrahedron 'recenttet',  or from a tetrahedra chosen from a random  //
+// sample.  The choice is made by determining which tetrahedron's vertexs is //
+// closest to the point we are searcing for. Normally, 'searchtet' should be //
+// a handle on the convex hull of the tetrahedrization.                      //
+//                                                                           //
+// On completion, 'searchtet' is a tetrahedron that contains 'searchpoint'.  //
+//                                                                           //
+// Returns ONVERTEX if the point lies on an existing vertex.  'searchtet' is //
+// a handle whose origin is the existing vertex.                             //
+//                                                                           //
+// Returns ONEDGE if the point lies on a mesh edge.  'searchtet' is a handle //
+// whose face version is the edge on which the point lies.                   //
+//                                                                           //
+// Returns ONFACE if the point lies strictly within a facet.  1searchtet' is //
+// a handle whose location is the face on which the point lies.              //
+//                                                                           //
+// Returns INTETRAHEDRON if the point lies strictly within a tetrahededron.  //
+// 'searchtet' is a handle on the tetrahedron that contains the point.       //
+//                                                                           //
+// Returns OUTSIDE if the point lies outside the mesh. 'searchtet' is a      //
+// handle whose location is the face the point is to 'above' of. This might  //
+// occur when the circumcenter of a tetrahedron falls just slightly outside  //
+// the mesh due to floating-point roundoff error.  It also occurs when       //
+// seeking a hole or region point that a foolish user has placed outside the //
+// mesh.                                                                     //
+//                                                                           //
+// WARNING: This routine is designed for convex triangulations, and will not //
+// not generally work after the holes and concavities have been carved.      //
+//                                                                           //
+// Details on the random sampling method can be found in [3].                //
+//                                                                           //
+// The simple method to implement this algorithm use  tet-tri data structure //
+// is listed here: ( Suppose T is the current tetrahedrization, and p is the //
+// point we are searching.)                                                  //
+//                                                                           //
+//   (1). Choose a random facet a (a belong to T), such that p belong to a+. //
+//   (2). If T union a = NULL, then p lies outside the current triangulation,//
+//        and a is visible from p. Otherwise,  there is a unique tetrahedron //
+//        t(t include a+, t belong to T), If p belong to t, then p is locat- //
+//        ed inside(the tetrahedron t(a+) of)T. In both cases we are done.If //
+//        p not belong to t(a+), then there exists some facet b of the tetr- //
+//        ahedron t(a+), with the same orientation of a, and p belong to b+. //
+//        Repeat step (2) with a = b.                                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum mesh3d::locateresult
+mesh3d::locate(point3d searchpoint, triface *searchtet)
+{
+  triface checkface;
+  tetrahedron *firsttet, *tetptr;
+  point3d torg, tdest, tapex;
+  void **sampleblock;
+  long sampleblocks, samplesperblock, samplenum;
+  long tetblocks, i, j;
+  unsigned long alignptr;
+  REAL searchdist, dist;
+  int ahead;
+
+  // Record the distance from the suggested starting tetrahedron to the
+  //   point we seek.
+  if(searchtet->tet == dummytet) {
+    // This is an 'Outer Space' handle, get a hull tetrahedron.
+    searchtet->loc = 0;
+    symself(*searchtet);
+  }
+  searchdist = distance(searchtet, searchpoint);
+
+  // Select "good" candidate using k random samples, taking the closest one.
+  //   (The trick here is that we use just normal FP distance() function.)
+
+  // If a recently encountered tetrahedron has been recorded and has not
+  //   been deallocated, test it as a good starting point.
+  if (!isdead(&recenttet)) {
+    // adjustedgering(recenttet, CCW);
+    dist = distance(&recenttet, searchpoint);
+    if (dist < searchdist) {
+      *searchtet = recenttet;
+      searchdist = dist;
+    }
+  }
+
+  // The number of random samples taken is proportional to the cube 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) {
+    samples++;
+  }
+  // Find how much blocks in current tet pool.
+  tetblocks = (tetrahedrons.maxitems + TETPERBLOCK - 1) / TETPERBLOCK;
+  // Find the average samles per block. Each block at least have 1 sample.
+  samplesperblock = 1 + (samples / tetblocks);
+  sampleblocks = samples / samplesperblock;
+  sampleblock = tetrahedrons.firstblock;
+  for (i = 0; i < sampleblocks; i++) {
+    alignptr = (unsigned long) (sampleblock + 1);
+    firsttet = (tetrahedron *)
+               (alignptr + (unsigned long) tetrahedrons.alignbytes
+               - (alignptr % (unsigned long) tetrahedrons.alignbytes));
+    for (j = 0; j < samplesperblock; j++) {
+      if (i == tetblocks - 1) {
+        // This is the last block.
+        samplenum = randomnation((int)
+                      (tetrahedrons.maxitems - (i * TETPERBLOCK)));
+      } else {
+        samplenum = randomnation(TETPERBLOCK);
+      }
+      tetptr = (tetrahedron *)
+               (firsttet + (samplenum * tetrahedrons.itemwords));
+      if (tetptr[4] != (tetrahedron) NULL) {
+        checkface.tet = tetptr;
+        dist = distance(&checkface, searchpoint);
+        if (dist < searchdist) {
+          *searchtet = checkface;
+          searchdist = dist;
+        }
+      }
+    }
+    sampleblock = (void **) *sampleblock;
+  }
+  if (verbose > 2) {
+    printf("    Randomly sampling %d times.\n", sampleblocks * samplesperblock);
+  }
+
+  // Orient 'searchtet' to fit the preconditions of calling preciselocate().
+  adjustedgering(*searchtet, CCW);
+  org(*searchtet, torg);
+  dest(*searchtet, tdest);
+  apex(*searchtet, tapex);
+  ahead = iorient3d(torg, tdest, tapex, searchpoint);
+  if (ahead > 0) {
+    // 'searchpoint' is below the face, get the other side of the face.
+    // Note: Must check first if searchtet is located on 'Outer Boundary'.
+    if(!issymexist(searchtet)) {
+      return OUTSIDE;
+    }
+    symself(*searchtet);
+  } else if (ahead == 0) {
+    // Check if `searchpoint' is locate on face, on edge or on vertex.
+    enum locateresult retval = iscoplanarintri(searchpoint, searchtet);
+    if (retval != OUTSIDE) {
+      if (verbose > 2) {
+        printf("    End Searching: ");
+        if (retval == ONVERTEX) {
+          printf("On Vertex.");
+        } else if (retval == ONEDGE) {
+          printf("On Edge.");
+        } else if (retval == ONFACE) {
+          printf("On Face.");
+        }
+        printf("\n");
+      }
+      return retval;
+    }
+  }
+  return preciselocate(searchpoint, searchtet);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// Point Location Routines                                                   //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// Mesh Transformation Routines                                              //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Three-dimensional flip operators and algorithm.                           //
+//                                                                           //
+//   The "local transformation" (LTRANS for short) procedure for three-      //
+// dimensional triangulations is analogous to the edge flipping procedure    //
+// used first by Lawson[1] to construct two-dimensional triangulations. The  //
+// LTRANS methods was instroduced (first) by Barry Joe[2]. He proved that    //
+// the LTRANS can be used to construct a Delaunay triangulation when apply   //
+// in an appropriate order to a special triangulation with his incermental   //
+// flip algorithm[2].                                                        //
+//                                                                           //
+//   The LTRANS procedure is based on the possible configurations of five    //
+// distinct non-coplanar three-dimensional points, a, b, c, d, e. See Barry  //
+// Joe 's paper[2] fig 1 and fig 2. There show five possible configurations  //
+// of the five points, named configuration 1 ,..., configuration 5. Let T be //
+// a triangulation of the five points. the LTRANS procedure is that if the   //
+// five points are in congiguration 1 or 3, then replace the triangulation   //
+// T by other possible triangulation of the five points.The LTRANS procedure //
+// can be consider to be a face swap. Joe also show that the LOTRANS applied //
+// to the T are of the one of four types, called type 1 to 4(2-3 swap, 3-2   //
+// swap, 2-2 swap, 4-4 swap, See paper[2] fig 3).                            //
+//                                                                           //
+//   Let T(i, 0) be the preliminary triangulation of the first i vertices    //
+// obtained by joining the ith vertex to the visible bondary faces of T(i-1, //
+// D). For k >= 1, let T(i, k) be the triangualtion obtained by applying the //
+// LOTRANS procedure to a non-locally-optimal transformable(paper[1], defin- //
+// ition 1 and 2) interior face of T(i, k-1). The following therom is proved //
+// by Barry Joe(paper[2], Therom 3):                                         //
+//   If T(i-1, D) is a Delaunay triangulation, then there exists a finite    //
+//   m(m >= 0) such that T(i, m) = T(i, D) is a Delaunay triangulation.      //
+//                                                                           //
+//   Another useful notion in programming is face type, which described in   //
+// [3]. Let abc be an interior face in a triangulation T of a point set V.   //
+// Then abc is incident on two tetrahedron abcd and abce. We assign a face   //
+// type to abc of the form 'Trs' and 'Nrs' where 'T' stands for transform-   //
+// able and 'N' stands for nontransformable, and the possible types are:     //
+// T23, T32, T22, T44, N44, N40, N30, N20. Except for the case r=s=4, 'r' is //
+// number of tetrahedroa in the triangulation of a, b, c, d, e containing    //
+// abcd and abce, and either 's' is zero if the configuration has only one   //
+// possible triangulation or 's' is the number of tetrahedron in the other   //
+// triangulation of a, b, c, d, e. the T44 and N44 types involv a sixth ver- //
+// tex and a pair of simultaneous local transformations(involve 4 tetrahedron//
+// before and after) as explained in paper[3].                               //
+//                                                                           //
+// Refernces:                                                                //
+//                                                                           //
+// [1] Lawson, C.L. (1977), Software for C1 surface interpolation, in J.R.   //
+//     Rice, ed,. Mathematic Software III, Acadmeic Press, New York, 161-194.//
+// [2] Barry Joe. Construction of three-dimensional Delaunay triangulations  //
+//     using local transformations. Computer Aided Geometric Design, 8(1991),//
+//     pp. 123-142.                                                          //
+// [3] Barry Joe. Construction of Three-Dimensional Improved-Quality Triang- //
+//     ulati on Using Local Transformations".  SIAM Journal on Scientific    //
+//     Computing, 16(6):1292�C1307, November 1995.                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// categorizeface()    Decide which type of triangular face this is, anyway. //
+//                                                                           //
+// The input is a handle of triangular face of a tetrahedron. Return an      //
+// enumerate type of facecategory. Normally, the input handle will not be    //
+// changed. If return 'eT32' and 'eN32',  function will reset the face       //
+// version to the edge which is tansformable('eT32') or non-transformable    //
+// ('eN32'). If return 'eT22', 'eT44', or 'eN44', function will reset the    //
+// input face version to be the diagonal edge.                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum mesh3d::facecategory mesh3d::categorizeface(triface& horiz)
+{
+  triface symhoriz, abdcasing, bcdcasing, cadcasing;
+  triface bad, abe, symbad, symabe;
+  face tmpsh0, tmpsh1, tmpseg;
+  point3d pa, pb, pc, pd, pe;
+  point3d abdoppo, bcdoppo, cadoppo;
+  int sharecount;
+
+  sym(horiz, symhoriz);
+  if (symhoriz.tet == dummytet) {
+    return LOCKED;  // Can't swap a boundary face.
+  }
+  if (checksegments) {
+    tspivot(horiz, tmpsh0);
+    if (tmpsh0.sh != dummysh) {
+      if (!isnonsolid(tmpsh0)) {
+        return LOCKED;   // Can't swap a subface.
+      }
+    }
+  }
+  // Now we assume 'horiz' is tet<a, b, c, d>,
+  adjustedgering(horiz, CCW);
+  // Set 'symhoriz' be tet<b, a, c, e>.
+  findversion(&symhoriz, &horiz);
+
+  org(horiz, pa);
+  dest(horiz, pb);
+  apex(horiz, pc);
+  oppo(horiz, pd);
+  oppo(symhoriz, pe);
+
+  // Find the number of tetrahedra that be a neighbor of both of the
+  //   first two.
+  sharecount = 2;
+  abdoppo = bcdoppo = cadoppo = (point3d) NULL;
+
+  // Set 'abdcasing', 'bcdcasing', 'cadcasing'.
+  fnext(horiz, abdcasing);  // at edge<a, b>.
+  if (issymexist(&abdcasing)) {
+    symself(abdcasing);
+    oppo(abdcasing, abdoppo);
+    if (abdoppo == pe) sharecount++;
+  }
+  enextself(horiz);
+  fnext(horiz, bcdcasing);  // at edge<b, c>.
+  if (issymexist(&bcdcasing)) {
+    symself(bcdcasing);
+    oppo(bcdcasing, bcdoppo);
+    if (bcdoppo == pe) sharecount++;
+  }
+  enextself(horiz);
+  fnext(horiz, cadcasing);  // at edge<c, a>
+  if (issymexist(&cadcasing)) {
+    symself(cadcasing);
+    oppo(cadcasing, cadoppo);
+    if (cadoppo == pe) sharecount++;
+  }
+  enextself(horiz);  // Rewind.
+
+  if (sharecount == 4) { // Four tet case.
+    return N40;
+  }
+
+  if (sharecount == 3) { // Three tet case.
+    if (abdoppo == pe) {
+      // Check if edge<a, b> cross face<c, d, e>.
+      if (!isbelowplane(pc, pd, pe, pa))
+        return N30; // Either eN30 or eOther.
+      if (!isaboveplane(pc, pd, pe, pb))
+        return N30; // Either eN30 or eOther.
+      // return eT32;  // Return edge<a, b>.
+    } else if (bcdoppo == pe) {
+      // Check if edge<b, c> cross the face<a, d, e>.
+      if (!isbelowplane(pa, pd, pe, pb))
+        return N30; // Either eN30 or eOther.
+      if (!isaboveplane(pa, pd, pe, pc))
+        return N30; // Either eN30 or eOther.
+      enextself(horiz);
+      // return eT32;  // Return edge<b, c>.
+    } else {
+      assert(cadoppo == pe);
+      // Check if edge<c, a> cross the face<b, d, e>.
+      if (!isbelowplane(pb, pd, pe, pc))
+        return N30; // Either eN30 or eOther.
+      if (!isaboveplane(pb, pd, pe, pa))
+        return N30; // Either eN30 or eOther.
+      enext2self(horiz);
+      // return T32;  // Return edge<c, a>.
+    }
+    if (checksegments) {
+      tsspivot(&horiz, &tmpseg);
+      if (tmpseg.sh != dummysh) {
+        // Unfortunately, it's a subsegment, not swappable.
+        return LOCKED;
+      }
+    }
+    return T32;
+  } // End of three tet case.
+
+  // Only leave two tets case: 'horiz' and 'symhoriz'.
+  assert(sharecount == 2);
+  // These returns take out all cases which allow the saving of an
+  //   orientation primitive evaluation.  This is very useful, as
+  //   this is a critical code path.
+  // Check if e above face<b, c, d>.
+  int iOrientA = iorient3d(pb, pc, pd, pe);
+  if (iOrientA == -1) {
+    enextself(horiz);
+    return N32;  // Return edge<b, c>.
+  }
+  // Check if e above face<c, a, d>.
+  int iOrientB = iorient3d(pc, pa, pd, pe);
+  if (iOrientB == -1) {
+    enext2self(horiz);
+    return N32;  // Return edge<c, a>.
+  }
+  if (iOrientA + iOrientB == 0) return N20;
+  // Check if e above face<a, b, d>.
+  int iOrientC = iorient3d(pa, pb, pd, pe);
+  if (iOrientC == -1) {
+    return N32;  // Return edge<a, b>.
+  }
+
+  switch (iOrientA + iOrientB + iOrientC) {
+    case 0:
+      // Impossible, but included for completeness.
+    case 1:
+      // Two orientations are zero (three points co-linear). Hopelessly
+      //   unswappable.  Bail out.
+	    return N20;
+    case 2:
+      // Four points are coplanar; (T22, T44, N44) One orientation must
+      //   be 0; verts are re-labeled to make it iOrientC. This implies
+      //   that edge<a, b> is the coplanar edge.
+      assert(!(iOrientA && iOrientB && iOrientC));
+      if (iOrientA == 0) {
+        // edge<b, c> is the diagonal.
+        enextself(horiz);
+        enext2self(symhoriz);
+        org(horiz, pa);
+        dest(horiz, pb);
+        apex(horiz, pc);
+      } else if (iOrientB == 0) {
+        // edge<c, a> is the diagonal.
+        enext2self(horiz);
+        enextself(symhoriz);
+        org(horiz, pa);
+        dest(horiz, pb);
+        apex(horiz, pc);
+      }
+      // Now we can sure edge<a, b> is the diagonal. Verify that the
+      //   re-labeling was done correctly.
+	    // assert(iorient3d(pa, pb, pd, pe) == 0);
+      if (checksegments) {
+        tsspivot(&horiz, &tmpseg);
+        if (tmpseg.sh != dummysh) {
+          // Unfortunately, it's a subsegment, not swappable.
+          return LOCKED;
+        }
+      }
+
+      // The configuration of these two tets is classified based on the
+      //   properties of the coplanar faces:
+      // 1 If both are BFaces with the same boundary condition, swappable
+      //   two tets to two.
+      // 2 If both are BFaces with different bdry cond, not swappable.
+      // 3 If one is a BFace and the other not, not swappable.
+      // 4 If neither is a BFace, both opposite cells are tets, and the
+      //   tets have the same fourth vert, swappable four to four.
+      // 5 If neither is a BFace, both opposite cells are tets, and the
+      //   tets do not have the same fourth vert, not swappable, although
+      //   some non-local transformations might make it so.
+      // 6 If neither is a BFace and one or both opposite cells is not a
+      //   tet, not swappable.
+      fnext(horiz, bad);
+      fnext(symhoriz, abe);
+      sym(bad, symbad);
+      sym(abe, symabe);
+
+      if ((symbad.tet == dummytet) && (symabe.tet == dummytet)) {
+        // Both faces are on the boundary.
+        if (checksegments) {
+          tspivot(bad, tmpsh0);
+          tspivot(abe, tmpsh1);
+          if ((tmpsh0.sh == dummysh) && (tmpsh1.sh == dummysh)) {
+            return T22;       // case 1.
+          } else if ((tmpsh0.sh != dummysh) && (tmpsh1.sh != dummysh)) {
+            if (mark(tmpsh0) == mark(tmpsh1)) {
+              return T22;     // case 1.
+            } else {
+              return LOCKED;  // case 2.
+            }
+          } else {
+            if (tmpsh0.sh != dummysh) {
+              if (isnonsolid(tmpsh0)) {
+                return T22;   // case 1.
+              }
+            } else { // tmpsh1.sh != dummysh
+              if (isnonsolid(tmpsh1)) {
+                return T22;   // case 1.
+              }
+            }
+            return LOCKED;    // case 2.
+          }
+        } else {
+          return T22;         // case 1.
+        }
+      } else if ((symbad.tet != dummytet) && (symabe.tet != dummytet)) {
+        // Both faces are inner facets.
+        point3d badoppo, abeoppo;
+        oppo(symbad, badoppo);
+        oppo(symabe, abeoppo);
+        if (badoppo == abeoppo) {
+          if (checksegments) {
+            tspivot(bad, tmpsh0);
+            tspivot(abe, tmpsh1);
+            if ((tmpsh0.sh == dummysh) && (tmpsh1.sh == dummysh)) {
+              return T44;     // case 1.
+            } else if ((tmpsh0.sh != dummysh) && (tmpsh1.sh != dummysh)) {
+              if (mark(tmpsh0) == mark(tmpsh1)) {
+                return T44;   // case 1.
+              } else {
+                return LOCKED; // case 2.
+              }
+            } else {
+              if (tmpsh0.sh == dummysh) {
+                if (isnonsolid(tmpsh1)) {
+                  return T44; // case 1.
+                }
+              } else {
+                if (isnonsolid(tmpsh0)) {
+                  return T44; // case 1.
+                }
+              }
+              return LOCKED;   // case 2.
+            }
+          } else {
+            return T44;       // case 4.
+          }
+        } else {
+          return N44;         // case 5.
+        }
+      } else {
+        // Exactly one face on the boundary or internal faces with cells
+        //   other than tets
+	      return LOCKED;         // cases 3, 6.
+      }
+    case 3:
+      // Configuration is convex and therefore swappable two tets to three.
+	    return T23;
+    default:
+	    // No other cases should be possible
+	    assert(0);
+      return LOCKED;
+  } // End of switch.
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// querydoswap()    Determines whether swapping is needed for current seting //
+//                  swaptype.                                                //
+//                                                                           //
+// There are many measures can be used, like Delaunay criterion, local max-  //
+// min solid angle criterion and max-min dihedral angle, etc. Current only   //
+// use the Delaunay criterion.                                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool mesh3d::querydoswap(triface& queryface)
+{
+  triface symface;
+  point3d symoppo;
+
+  sym(queryface, symface);
+  assert(symface.tet != dummytet);
+  oppo(symface, symoppo);
+  int sign = iinsphere(&queryface, symoppo);
+  if (sign > 0) {
+    return (true);
+  } else if (sign < 0) {
+    return (false);
+  } else {
+    cospherecount ++;
+    return (false);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// preservesubsegments()    Preserve subsegments that abutting a flipping    //
+//                          subface(must be nonsolid).                       //
+//                                                                           //
+// This routine used in all local transformation routines to prevent missing //
+// subsegments when flip away a nonsolid subface. The inputs are a handle    //
+// of flipping face 'abc'(must be a nonsolid subface) and a handle of tetra  //
+// that abutting this face 'abcd'. This routine will check each side of face //
+// 'abc', to see if their exist a subsegment abutting at this side. If find, //
+// still need determine whether there exist another subfaces hold this       //
+// subsegment. If no such subface be found. We must insert a subface for     //
+// holding this subsegment, otherwise, this subsegment will missing after do //
+// flip. At each case, the face 'abc' will dealloc at end. Before 'abc' is   //
+// deallocated, we must dissolve it from its two adjacent tets, otherwise,   //
+// one of tet may still think it is connecting a subface.                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::preservesubsegments(face& abc, triface& abcd)
+{
+  triface tmpabcd, spintet;
+  face checkseg, checksh;
+  point3d tapex;
+  int edgecount, successbonded, hitbdry;
+
+  tmpabcd = abcd;
+  adjustedgering(tmpabcd, CCW);              // For fnext() should be exist.
+  findversion(&abc, &tmpabcd, false);    // For keep same enext() direction.
+
+  edgecount = 0;
+  while (edgecount < 3) {
+    sspivot(abc, checkseg);
+    if (checkseg.sh != dummysh) {
+      // Find a subsegment adjoining at a nonsolid subface('abc').
+      spivot(checkseg, checksh);
+      if (checksh.sh != abc.sh) {
+        // There must exist another subface that hold this segment. We can
+        //   safely deallocte this subface.
+      } else {
+        // We must find another subface to hold this segment, if no such
+        //   subface be found. Then we should insert a nonsolid subface.
+        spintet = tmpabcd;
+        apex(tmpabcd, tapex);
+        successbonded = hitbdry = 0;
+        while (true) {
+          if (fnextself(spintet)) {
+            if (apex(spintet) == tapex) {
+              break; // Rewind, can leave now.
+            }
+            tspivot(spintet, checksh);
+            if (checksh.sh != dummysh) {
+              findversion(&checksh, &spintet);
+              ssbond(checksh, checkseg);
+              successbonded = 1;
+              break;
+            }
+          } else {
+            hitbdry ++;
+            if(hitbdry >= 2) {
+              break;
+            } else {
+              esym(tmpabcd, spintet);
+            }
+          }
+        }
+        if (!successbonded) {
+          // Badly, We must insert a subface for holding this subsegment;
+          //   otherwise, this subsegment will missing after do flip.
+          triface tmptet;
+          fnext(tmpabcd, tmptet);
+          insertsubface(&tmptet, NONSOLIDFLAG, 1);
+          face newsh;
+          tspivot(tmptet, newsh);
+          findversion(&newsh, &tmptet);
+          ssbond(newsh, checkseg);
+        }
+      }
+    }
+    senextself(abc);
+    enextself(tmpabcd);
+    edgecount ++;
+  }
+
+  // Before dealloc subface, must dissolve it from its two side.
+  tsdissolve(abcd);
+  sym(abcd, tmpabcd);
+  if (tmpabcd.tet != dummytet) {
+    tsdissolve(tmpabcd);
+  }
+  // This subface can be dealloced now.
+  shellfacedealloc(&subfaces, abc.sh);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip23()    Swap two tets for three.                                      //
+//                                                                           //
+// See Barry Joe's paper [2] as listed at above. See figure 1 in this paper. //
+// We change configuration 1A to 1B. The input 'flipface' is face<abc>.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::flip23(triface& flipface)
+{
+  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;
+  face abcsh;                                           // Flipping subface.
+  triface edab, edbc, edca;                            // New configuration.
+  point3d pa, pb, pc, pd, pe;
+  REAL attrib, volume;
+  int flipcount, i;
+
+  flip_t23s++;
+
+  if (verbose > 2) {
+    printf("    Do T23 on face (%d, %d, %d, %d).\n",
+           pointmark(org(flipface)), pointmark(dest(flipface)),
+           pointmark(apex(flipface)), pointmark(oppo(flipface)));
+  }
+
+  abcd = flipface;
+  abcd.ver = 0;  // adjust at edge<ab>.
+  sym(abcd, bace);
+  findversion(&bace, &abcd); // adjust at edge<ba>.
+  // Keep all old faces and their casings before doflip.
+  oldabd = oldbcd = oldcad = abcd;
+  fnextself(oldabd);
+  enextfnextself(oldbcd);
+  enext2fnextself(oldcad);
+  oldbae = oldcbe = oldace = bace;
+  fnextself(oldbae);
+  enext2fnextself(oldcbe);
+  enextfnextself(oldace);
+  sym(oldabd, abdcasing);
+  sym(oldbcd, bcdcasing);
+  sym(oldcad, cadcasing);
+  sym(oldbae, baecasing);
+  sym(oldcbe, cbecasing);
+  sym(oldace, acecasing);
+  if (checksegments) {
+    // Check the flip face<a, b, c> 's three edges to see if there exist
+    //   subsegment. This step must do first.
+    tspivot(abcd, abcsh);
+    if (abcsh.sh != dummysh) {
+      assert(isnonsolid(abcsh));
+      preservesubsegments(abcsh, abcd);
+    }
+    // Now, we can find all subfaces abutting faces in old configuration.
+    tspivot(oldabd, abdsh);
+    tspivot(oldbcd, bcdsh);
+    tspivot(oldcad, cadsh);
+    tspivot(oldbae, baesh);
+    tspivot(oldcbe, cbesh);
+    tspivot(oldace, acesh);
+  }
+  org (abcd, pa);
+  dest(abcd, pb);
+  apex(abcd, pc);
+  oppo(abcd, pd);
+  oppo(bace, pe);
+
+  // Set new configuration.
+  edab.tet = abcd.tet;
+  // default: 'edab' loc = 0, ver = 0.
+  setorg (edab, pe);
+  setdest(edab, pd);
+  setapex(edab, pa);
+  setoppo(edab, pb);
+
+  edbc.tet = bace.tet;
+  // defult: 'edbc' loc = 0, ver = 0.
+  setorg (edbc, pe);
+  setdest(edbc, pd);
+  setapex(edbc, pb);
+  setoppo(edbc, pc);
+
+  maketetrahedron(&edca);
+  // default: 'edca' loc = 0, ver = 0.
+  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 < eextras; i++) {
+    attrib = elemattribute(abcd.tet, i);
+    setelemattribute(edca.tet, i, attrib);
+  }
+  // Set the volume constraint of the new tetrahedron('edca').
+  if (varvolume) {
+    volume = volumebound(abcd.tet);
+    setvolumebound(edca.tet, volume);
+  }
+
+  // There may be shell facets that need to be bonded to new configuarton.
+  if (checksegments) {
+    // Clear old flags in 'edab'('abcd') and 'edbc'('bace').
+    for (i = 0; i < 4; i ++) {
+      edab.loc = i;
+      tsdissolve(edab);
+      edbc.loc = i;
+      tsdissolve(edbc);
+    }
+    if (abdsh.sh != dummysh) {
+      edab.loc = 2; // face<a, b, d>.
+      tsbond(edab, abdsh);
+    }
+    if (baesh.sh != dummysh) {
+      edab.loc = 3; // face<b, a, e>.
+      tsbond(edab, baesh);
+    }
+    if (bcdsh.sh != dummysh) {
+      edbc.loc = 2; // face<b, c, d>.
+      tsbond(edbc, bcdsh);
+    }
+    if (cbesh.sh != dummysh) {
+      edbc.loc = 3; // face<c, b, e>.
+      tsbond(edbc, cbesh);
+    }
+    if (cadsh.sh != dummysh) {
+      edca.loc = 2; // face<c, a, d>.
+      tsbond(edca, cadsh);
+    }
+    if (acesh.sh != dummysh) {
+      edca.loc = 3; // face<a, c, e>.
+      tsbond(edca, acesh);
+    }
+  }
+
+  // Clear old bonds in 'edab'('abcd') and 'edbc'('bace').
+  for (i = 0; i < 4; i ++) {
+    edab.loc = i;
+    dissolve(edab);
+    edbc.loc = i;
+    dissolve(edbc);
+  }
+  // Bond the three tetrahedra.
+  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 each casing faces.
+  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);
+
+  edab.loc = 0;
+  edbc.loc = 0;
+  edca.loc = 0;
+#ifdef SELF_CHECK
+  if (!isaboveplane(&edab, pb)) {
+    printf("Internal error in flip23():\n");
+    printf("  Clockwise tetrahedron after flip (edab).\n");
+    internalerror();
+  }
+  if (!isaboveplane(&edbc, pc)) {
+    printf("Internal error in flip23():\n");
+    printf("  Clockwise tetrahedron after flip (edbc).\n");
+    internalerror();
+  }
+  if (!isaboveplane(&edca, pa)) {
+    printf("Internal error in flip23():\n");
+    printf("  Clockwise tetrahedron after flip (edca).\n");
+    internalerror();
+  }
+#endif // defined SELF_CHECK
+  if (verbose > 2) {
+    printf("    Updating edab ");
+    dump(&edab);
+    printf("    Updating edbc ");
+    dump(&edbc);
+    printf("    Creating edca ");
+    dump(&edca);
+  }
+
+  if(usefliplist) {
+    flipcount = 0;
+    edab.loc = 2; // face<a, b, d>.
+    enqueuefliplist(edab);
+    edab.loc = 3; // face<b, a, e>.
+    enqueuefliplist(edab);
+    edbc.loc = 2; // face<b, c, d>.
+    enqueuefliplist(edbc);
+    edbc.loc = 3; // face<c, b, e>.
+    enqueuefliplist(edbc);
+    edca.loc = 2; // face<c, a, d>.
+    enqueuefliplist(edca);
+    edca.loc = 3; // face<a, c, e>.
+    enqueuefliplist(edca);
+  } else {
+    flipcount = 1;
+    edab.loc = 2; // face<a, b, d>.
+    flipcount += flip(edab);
+    edab.loc = 3; // face<b, a, e>.
+    flipcount += flip(edab);
+    edbc.loc = 2; // face<b, c, d>.
+    flipcount += flip(edbc);
+    edbc.loc = 3; // face<c, b, e>.
+    flipcount += flip(edbc);
+    edca.loc = 2; // face<c, a, d>.
+    flipcount += flip(edca);
+    edca.loc = 3; // face<a, c, e>.
+    flipcount += flip(edca);
+  }
+
+  return flipcount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip32()    Swap three tets for two.                                      //
+//                                                                           //
+// See Barry Joe's paper [2] as listed at above. See figure 1 in this paper. //
+// We change configuration 1B to 1A. The input 'flipface' is edge<de>.       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::flip32(triface& flipface)
+{
+  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.
+  point3d pa, pb, pc, pd, pe;
+  int flipcount, i;
+
+  flip_t32s++;
+
+  if (verbose > 2) {
+    printf("    Do T32 on face (%d, %d, %d, %d).\n",
+           pointmark(org(flipface)), pointmark(dest(flipface)),
+           pointmark(apex(flipface)), pointmark(oppo(flipface)));
+  }
+
+  // 'flipface' must be tet<e, d, a, b> or tet<d, e, a, -b>.
+  edab = flipface;
+  // Adjust face version first, so 'edab' be tet<e, d, a, b>.
+  adjustedgering(edab, CCW);
+  // Set 'edbc' and 'edca'.
+  fnext(edab, edbc);
+  symself(edbc);
+  findversion(&edbc, &edab, 0);
+  fnext(edbc, edca);
+  symself(edca);
+  findversion(&edca, &edab, 0);
+  // Keep all old faces and their casings before doflip.
+  oldabd = oldbae = edab;
+  enextfnextself(oldabd);
+  enext2fnextself(oldbae);
+  oldbcd = oldcbe = edbc;
+  enextfnextself(oldbcd);
+  enext2fnextself(oldcbe);
+  oldcad = oldace = edca;
+  enextfnextself(oldcad);
+  enext2fnextself(oldace);
+  sym(oldabd, abdcasing);
+  sym(oldbcd, bcdcasing);
+  sym(oldcad, cadcasing);
+  sym(oldbae, baecasing);
+  sym(oldcbe, cbecasing);
+  sym(oldace, acecasing);
+  if (checksegments) {
+    // Check faces around flip edge<e, d> to see if there exist subsegment
+    //   attaching it. This step must do first. The three face are ed(abc).
+    face tmpface;
+    tspivot(edab, tmpface);
+    if (tmpface.sh != dummysh) {
+      assert(isnonsolid(tmpface));
+      preservesubsegments(tmpface, edab);
+    }
+    tspivot(edbc, tmpface);
+    if (tmpface.sh != dummysh) {
+      assert(isnonsolid(tmpface));
+      preservesubsegments(tmpface, edbc);
+    }
+    tspivot(edca, tmpface);
+    if (tmpface.sh != dummysh) {
+      assert(isnonsolid(tmpface));
+      preservesubsegments(tmpface, edca);
+    }
+    // Find all subfaces abutting faces in old configuration.
+    tspivot(oldabd, abdsh);
+    tspivot(oldbcd, bcdsh);
+    tspivot(oldcad, cadsh);
+    tspivot(oldbae, baesh);
+    tspivot(oldcbe, cbesh);
+    tspivot(oldace, acesh);
+  }
+  apex(edab, pa);
+  oppo(edab, pb);
+  oppo(edbc, pc);
+  dest(edab, pd);
+  org (edab, pe);
+
+  // Set new configuration.
+  abcd.tet = edab.tet;
+  // default: 'abcd' loc = 0, ver = 0.
+  setorg (abcd, pa);
+  setdest(abcd, pb);
+  setapex(abcd, pc);
+  setoppo(abcd, pd);
+
+  bace.tet = edbc.tet;
+  // default: 'bace' loc = 0, ver = 0.
+  setorg (bace, pb);
+  setdest(bace, pa);
+  setapex(bace, pc);
+  setoppo(bace, pe);
+
+  // In flip32 case, we needn't reset element attributes and volume
+  //   constraint, because no new tetrahedron be created.
+
+  // There may be shell facets that need to be bonded to the new
+  //   configuration.
+  if (checksegments) {
+    // Clear old flags in 'abcd'('edab') and 'bace'('edbc').
+    for (i = 0; i < 4; i ++) {
+      abcd.loc = i;
+      tsdissolve(abcd);
+      bace.loc = i;
+      tsdissolve(bace);
+    }
+    if (abdsh.sh != dummysh) {
+      abcd.loc = 1; // face<a, b, d>.
+      tsbond(abcd, abdsh);
+    }
+    if (baesh.sh != dummysh) {
+      bace.loc = 1; // face<b, a, e>.
+      tsbond(bace, baesh);
+    }
+    if (bcdsh.sh != dummysh) {
+      abcd.loc = 2; // face<b, c, d>.
+      tsbond(abcd, bcdsh);
+    }
+    if (cbesh.sh != dummysh) {
+      bace.loc = 3; // face<c, b, e>.
+      tsbond(bace, cbesh);
+    }
+    if (cadsh.sh != dummysh) {
+      abcd.loc = 3; // face<c, a, d>.
+      tsbond(abcd, cadsh);
+    }
+    if (acesh.sh != dummysh) {
+      bace.loc = 2; // face<a, c, e>.
+      tsbond(bace, acesh);
+    }
+  }
+
+  for (i = 0; i < 4; i ++) {
+    abcd.loc = i;
+    dissolve(abcd);
+    bace.loc = i;
+    dissolve(bace);
+  }
+  // Bond the new configuration.
+  abcd.loc = 0;
+  bace.loc = 0;
+  bond(abcd, bace);
+  // Bond each casing faces.
+  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);
+
+  abcd.loc = 0;
+  bace.loc = 0;
+#ifdef SELF_CHECK
+  if (!isaboveplane(&abcd, pd)) {
+    printf("Internal error in flip32():\n");
+    printf("  Clockwise tetrahedron after flip (abcd).\n");
+    internalerror();
+  }
+  if (!isaboveplane(&bace, pe)) {
+    printf("Internal error in flip32():\n");
+    printf("  Clockwise tetrahedron after flip (bace).\n");
+    internalerror();
+  }
+#endif // defined SELF_CHECK
+  if (verbose > 2) {
+    printf("    Updating abcd ");
+    dump(&abcd);
+    printf("    Updating bace ");
+    dump(&bace);
+    printf("    Deleting edca ");
+    dump(&edca);
+  }
+  // Dealloc 'edca'.
+  tetrahedrondealloc(edca.tet);
+
+  if (usefliplist) {
+    flipcount = 0;
+    abcd.loc = 1; // face<a, b, d>.
+    enqueuefliplist(abcd);
+    bace.loc = 1; // face<b, a, e>.
+    enqueuefliplist(bace);
+    abcd.loc = 2; // face<b, c, d>.
+    enqueuefliplist(abcd);
+    bace.loc = 3; // face<c, b, e>.
+    enqueuefliplist(bace);
+    abcd.loc = 3; // face<c, a, d>.
+    enqueuefliplist(abcd);
+    bace.loc = 2; // face<a, c, e>.
+    enqueuefliplist(bace);
+  } else {
+    flipcount = 1;
+    abcd.loc = 1; // face<a, b, d>.
+    flipcount += flip(abcd);
+    bace.loc = 1; // face<b, a, e>.
+    flipcount += flip(bace);
+    abcd.loc = 2; // face<b, c, d>.
+    flipcount += flip(abcd);
+    bace.loc = 3; // face<c, b, e>.
+    flipcount += flip(bace);
+    abcd.loc = 3; // face<c, a, d>.
+    flipcount += flip(abcd);
+    bace.loc = 2; // face<a, c, e>.
+    flipcount += flip(bace);
+  }
+
+  return flipcount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip22()    Swap two tets for two, in the case where two faces are        //
+//             coplanar.                                                     //
+//                                                                           //
+// See Barry Joe's paper [2] as listed at above. See figure 1 in this paper. //
+// We change configuration 3A to 3B. The input 'flipface' lock at edge<ab>.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::flip22(triface& flipface)
+{
+  triface abcd, bace;                                  // Old configuration.
+  triface oldbcd, oldcad, oldcbe, oldace;
+  triface bcdcasing, cadcasing, cbecasing, acecasing;
+  face bcdsh, cadsh, cbesh, acesh;
+  triface oldabd, oldbae;                                 // Flipping faces.
+  face abdsh, baesh, abcsh;                            // Flipping subfaces.
+  face abdrightseg, abdleftseg;
+  face baerightseg, baeleftseg;
+  triface ceda, cdeb;                                  // New configuration.
+  face debsh, edash;
+  triface ghosttet;
+  point3d pa, pb, pc, pd, pe;
+  int flipcount, i;
+
+  flip_t22s++;
+
+  if (verbose > 2) {
+    printf("    Do T22 on face (%d, %d, %d, %d).\n",
+           pointmark(org(flipface)), pointmark(dest(flipface)),
+           pointmark(apex(flipface)), pointmark(oppo(flipface)));
+  }
+
+  // Set a 'ghosttet' handle the Outer space.
+  ghosttet.tet = dummytet;
+
+  abcd = flipface;
+  adjustedgering(abcd, CCW);
+  sym(abcd, bace);
+  findversion(&bace, &abcd);
+  oldbcd = oldcad = abcd;
+  enextfnextself(oldbcd);
+  enext2fnextself(oldcad);
+  oldcbe = oldace = bace;
+  enext2fnextself(oldcbe);
+  enextfnextself(oldace);
+  sym(oldbcd, bcdcasing);
+  sym(oldcad, cadcasing);
+  sym(oldcbe, cbecasing);
+  sym(oldace, acecasing);
+  if (checksegments) {
+    // Check the flip face<a, b, c> 's three edges to see if there exist
+    //   subsegment. This step must do first.
+    tspivot(abcd, abcsh);
+    if (abcsh.sh != dummysh) {
+      assert(isnonsolid(abcsh));
+      preservesubsegments(abcsh, abcd);
+    }
+    // Now, we can find all subfaces abutting faces in old configuration.
+    tspivot(oldbcd, bcdsh);
+    tspivot(oldcad, cadsh);
+    tspivot(oldcbe, cbesh);
+    tspivot(oldace, acesh);
+    // Keep flip edge<ab> and its two(coplanar) flip faces.
+    fnext(abcd, oldabd);
+    fnext(bace, oldbae);
+    tspivot(oldabd, abdsh);
+    tspivot(oldbae, baesh);
+    if ((abdsh.sh != dummysh) || (baesh.sh != dummysh)) {
+      // Check if there missing a half subface.
+      if (abdsh.sh == dummysh) {
+        assert(baesh.sh != dummysh);
+        insertsubface(&oldabd, NONSOLIDFLAG, 1);
+        tspivot(oldabd, abdsh);
+      } else if (baesh.sh == dummysh) {
+        assert(abdsh.sh != dummysh);
+        insertsubface(&oldbae, NONSOLIDFLAG, 1);
+        tspivot(oldbae, baesh);
+      }
+      // Save segments which adhering to 'abdsh'.
+      findversion(&abdsh, &abcd, 0);  // lock at edge<ab>.
+      senextself(abdsh);              // arrive  edge<bd>.
+      sspivot(abdsh, abdrightseg);
+      senextself(abdsh);              // arrive  edge<da>
+      sspivot(abdsh, abdleftseg);
+      // Save segments which adhering to 'baesh'.
+      findversion(&baesh, &bace, 0);  // lock at edge<ba>.
+      senextself(baesh);              // arrive  edge<ae>.
+      sspivot(baesh, baerightseg);
+      senextself(baesh);              // arrive  edge<eb>.
+      sspivot(baesh, baeleftseg);
+    }
+  }
+  org (abcd, pa);
+  dest(abcd, pb);
+  apex(abcd, pc);
+  oppo(abcd, pd);
+  oppo(bace, pe);
+
+  // Set new configuration.
+  ceda.tet = abcd.tet;
+  // default: 'ceda' loc = 0, ver = 0.
+  setorg (ceda, pc);
+  setdest(ceda, pe);
+  setapex(ceda, pd);
+  setoppo(ceda, pa);
+
+  cdeb.tet = bace.tet;
+  // default: 'cdeb' loc = 0, ver = 0.
+  setorg (cdeb, pc);
+  setdest(cdeb, pd);
+  setapex(cdeb, pe);
+  setoppo(cdeb, pb);
+
+  // In flip22 case, we needn't reset element attributes and volume
+  //   constraint, because no new tetrahedron be created.
+
+  // There may be shell facets that need to be bonded to the new
+  //   configuration.
+  if (checksegments) {
+    // Clear old flags in 'ceda'('abcd') and 'cdeb'('bace').
+    for (i = 0; i < 4; i ++) {
+      ceda.loc = i;
+      tsdissolve(ceda);
+      cdeb.loc = i;
+      tsdissolve(cdeb);
+    }
+    if (bcdsh.sh != dummysh) {
+      cdeb.loc = 1; // face<b, c, d>.
+      tsbond(cdeb, bcdsh);
+    }
+    if (cbesh.sh != dummysh) {
+      cdeb.loc = 3; // face<c, b, e>.
+      tsbond(cdeb, cbesh);
+    }
+    if (cadsh.sh != dummysh) {
+      ceda.loc = 3; // face<c, a, d>.
+      tsbond(ceda, cadsh);
+    }
+    if (acesh.sh != dummysh) {
+      ceda.loc = 1; // face<a, c, e>.
+      tsbond(ceda, acesh);
+    }
+    if (abdsh.sh != dummysh) {
+      debsh.sh = abdsh.sh;
+      // default: 'debsh' ver = 0.
+      setsorg (debsh, pd);
+      setsdest(debsh, pe);
+      setsapex(debsh, pb);
+
+      edash.sh = baesh.sh;
+      // default: 'edash' ver = 0.
+      setsorg (edash, pe);
+      setsdest(edash, pd);
+      setsapex(edash, pa);
+
+      ssdissolve(debsh);
+      ssdissolve(edash);
+      senextself(debsh);
+      ssbond(debsh, baeleftseg);
+      senextself(debsh);
+      ssbond(debsh, abdrightseg);
+      senextself(edash);
+      ssbond(edash, abdleftseg);
+      senextself(edash);
+      ssbond(edash, baerightseg);
+
+      // Bond with cdeb(loc = 2).
+      cdeb.loc = 2;
+      tsbond(cdeb, debsh);
+      // Bond other side of cdeb('Outer space').
+      sesymself(debsh);
+      tsbond(ghosttet, debsh);
+      // Bond with ceda.
+      ceda.loc = 2;
+      tsbond(ceda, edash);
+      // Bond other side of ceda('Outer space').
+      sesymself(edash);
+      tsbond(ghosttet, edash);
+    }
+  }
+
+  // Clear old flags in 'ceda'('abcd') and 'cdeb'('bace').
+  for (i = 0; i < 4; i ++) {
+    ceda.loc = i;
+    dissolve(ceda);
+    cdeb.loc = i;
+    dissolve(cdeb);
+  }
+  // Bond the new configuration.
+  ceda.loc = 0;
+  cdeb.loc = 0;
+  bond(ceda, cdeb);
+  // Bond each casing facets.
+  cdeb.loc = 1;
+  bond(cdeb, bcdcasing);
+  ceda.loc = 3;
+  bond(ceda, cadcasing);
+  cdeb.loc = 3;
+  bond(cdeb, cbecasing);
+  ceda.loc = 1;
+  bond(ceda, acecasing);
+  // Bond 'Outer space', diffrent in flip44.
+  cdeb.loc = 2;
+  bond(cdeb, ghosttet);
+  ceda.loc = 2;
+  bond(ceda, ghosttet);
+
+  ceda.loc = 0;
+  cdeb.loc = 0;
+#ifdef SELF_CHECK
+  if (!isaboveplane(&ceda, pa)) {
+    printf("Internal error in flip22():\n");
+    printf("  Clockwise tetrahedron after flip (ceda).\n");
+    internalerror();
+  }
+  if (!isaboveplane(&cdeb, pb)) {
+    printf("Internal error in flip22():\n");
+    printf("  Clockwise tetrahedron after flip (cdeb).\n");
+    internalerror();
+  }
+#endif // defined SELF_CHECK
+  if (verbose > 2) {
+    printf("    Updating ceda ");
+    dump(&ceda);
+    printf("    Updating cdeb ");
+    dump(&cdeb);
+  }
+
+  if (usefliplist) {
+    flipcount = 0;
+    ceda.loc = 3; // face<c, a, d>.
+    enqueuefliplist(ceda);
+    ceda.loc = 1; // face<a, c, e>.
+    enqueuefliplist(ceda);
+    cdeb.loc = 1; // face<b, c, d>.
+    enqueuefliplist(cdeb);
+    cdeb.loc = 3; // face<c, b, e>.
+    enqueuefliplist(cdeb);
+  } else {
+    flipcount = 1;
+    ceda.loc = 3; // face<c, a, d>.
+    flipcount += flip(ceda);
+    ceda.loc = 1; // face<a, c, e>.
+    flipcount += flip(ceda);
+    cdeb.loc = 1; // face<b, c, d>.
+    flipcount += flip(cdeb);
+    cdeb.loc = 3; // face<c, b, e>.
+    flipcount += flip(cdeb);
+  }
+
+  return flipcount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip44()    Swap four tets for four, in the case where two faces are      //
+//             coplanar.                                                     //
+//                                                                           //
+// See Barry Joe's paper [2] as listed at above. See figure 1 in this paper. //
+// We change configuration 3A to 3B. The input 'flipface' lock at edge<ab>.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::flip44(triface& flipface)
+{
+  triface abcd, bace, bafd, abfe;                      // Old configuration.
+  triface oldbcd, oldcad, oldcbe, oldace;
+  triface oldfbd, oldafd, oldbfe, oldfae;
+  triface bcdcasing, cadcasing, cbecasing, acecasing;
+  triface fbdcasing, afdcasing, bfecasing, faecasing;
+  face bcdsh, cadsh, cbesh, acesh;
+  face fbdsh, afdsh, bfesh, faesh;
+  triface oldabd, oldbae;                                 // Flipping faces.
+  face abdsh, baesh, abcsh, abfsh;                     // Flipping subfaces.
+  face abdrightseg, abdleftseg;
+  face baerightseg, baeleftseg;
+  triface ceda, cdeb, fdea, fedb;                      // New configuration.
+  face debsh, edash;
+  point3d pa, pb, pc, pd, pe, pf;
+  int flipcount, i;
+
+  flip_t44s++;
+
+  if (verbose > 2) {
+    printf("    Do T44 on face (%d, %d, %d, %d).\n",
+           pointmark(org(flipface)), pointmark(dest(flipface)),
+           pointmark(apex(flipface)), pointmark(oppo(flipface)));
+  }
+
+  abcd = flipface;
+  adjustedgering(abcd, CCW);
+  sym(abcd, bace);
+  findversion(&bace, &abcd);
+
+  // Find the other side two tets of 'abcd' and 'bace'.
+  bafd = abcd;
+  fnextself(bafd);
+  fnextself(bafd);
+  esymself(bafd);
+  abfe = bace;
+  fnextself(abfe);
+  fnextself(abfe);
+  esymself(abfe);
+
+  oldbcd = oldcad = abcd;
+  enextfnextself(oldbcd);
+  enext2fnextself(oldcad);
+  oldcbe = oldace = bace;
+  enext2fnextself(oldcbe);
+  enextfnextself(oldace);
+
+  oldfbd = oldafd = bafd;
+  enext2fnextself(oldfbd);
+  enextfnextself(oldafd);
+  oldbfe = oldfae = abfe;
+  enextfnextself(oldbfe);
+  enext2fnextself(oldfae);
+
+  sym(oldbcd, bcdcasing);
+  sym(oldcad, cadcasing);
+  sym(oldcbe, cbecasing);
+  sym(oldace, acecasing);
+
+  sym(oldfbd, fbdcasing);
+  sym(oldafd, afdcasing);
+  sym(oldbfe, bfecasing);
+  sym(oldfae, faecasing);
+
+  if (checksegments) {
+    // Check the flip face<a, b, c> 's three edges to see if there exist
+    //   subsegment. This step must do first.
+    tspivot(abcd, abcsh);
+    if (abcsh.sh != dummysh) {
+      assert(isnonsolid(abcsh));
+      preservesubsegments(abcsh, abcd);
+    }
+    // Now, we can find all subfaces abutting faces in old configuration.
+    tspivot(oldbcd, bcdsh);
+    tspivot(oldcad, cadsh);
+    tspivot(oldcbe, cbesh);
+    tspivot(oldace, acesh);
+
+    // Check the flip face<a, b, f> 's three edges to see if there exist
+    //   subsegment. This step must do first.
+    tspivot(bafd, abfsh);
+    if (abfsh.sh != dummysh) {
+      assert(isnonsolid(abfsh));
+      preservesubsegments(abfsh, bafd);
+    }
+    // Now, we can find all subfaces abutting faces in old configuration.
+    tspivot(oldfbd, fbdsh);
+    tspivot(oldafd, afdsh);
+    tspivot(oldbfe, bfesh);
+    tspivot(oldfae, faesh);
+
+    // Keep flip edge and (coplanar) flip faces. This codes are diffrent
+    //   with flip22. 'abdsh' and 'baesh' may be 'dummysh'.
+    fnext(abcd, oldabd);
+    fnext(bace, oldbae);
+    tspivot(oldabd, abdsh);
+    tspivot(oldbae, baesh);
+    if ((abdsh.sh != dummysh) || (baesh.sh != dummysh)) {
+      // Check if there missing a half subface.
+      if (abdsh.sh == dummysh) {
+        assert(baesh.sh != dummysh);
+        insertsubface(&oldabd, NONSOLIDFLAG, 1);
+        tspivot(oldabd, abdsh);
+      } else if (baesh.sh == dummysh) {
+        assert(abdsh.sh != dummysh);
+        insertsubface(&oldbae, NONSOLIDFLAG, 1);
+        tspivot(oldbae, baesh);
+      }
+      // Save segments which adhering to 'abdsh'.
+      findversion(&abdsh, &abcd, 0);  // lock at edge<ab>.
+      senextself(abdsh);
+      sspivot(abdsh, abdrightseg);
+      senextself(abdsh);
+      sspivot(abdsh, abdleftseg);
+      // Save segments which adhering to 'baesh'.
+      findversion(&baesh, &bace, 0);  // lock at edge<ba>.
+      senextself(baesh);
+      sspivot(baesh, baerightseg);
+      senextself(baesh);
+      sspivot(baesh, baeleftseg);
+    }
+  }
+  org (abcd, pa);
+  dest(abcd, pb);
+  apex(abcd, pc);
+  oppo(abcd, pd);
+  oppo(bace, pe);
+  apex(bafd, pf);
+
+  // Set new configuration.
+  ceda.tet = abcd.tet;
+  // default: 'ceda' loc = 0, ver = 0.
+  setorg (ceda, pc);
+  setdest(ceda, pe);
+  setapex(ceda, pd);
+  setoppo(ceda, pa);
+
+  cdeb.tet = bace.tet;
+  // default: 'cdeb' loc = 0, ver = 0.
+  setorg (cdeb, pc);
+  setdest(cdeb, pd);
+  setapex(cdeb, pe);
+  setoppo(cdeb, pb);
+
+  fdea.tet = bafd.tet;
+  // default: 'fdea' loc = 0, ver = 0.
+  setorg (fdea, pf);
+  setdest(fdea, pd);
+  setapex(fdea, pe);
+  setoppo(fdea, pa);
+
+  fedb.tet = abfe.tet;
+  // default: 'fedb' loc = 0, ver = 0.
+  setorg (fedb, pf);
+  setdest(fedb, pe);
+  setapex(fedb, pd);
+  setoppo(fedb, pb);
+
+  // In flip44 case, we needn't reset element attributes and volume
+  //   constraint, because no new tetrahedron be created.
+
+  // There may be shell facets that need to be bonded to the new
+  //   configuration.
+  if (checksegments) {
+    // Clear old flags in 'ceda'('abcd') and 'cdeb'('bace').
+    for (i = 0; i < 4; i ++) {
+      ceda.loc = i;
+      tsdissolve(ceda);
+      cdeb.loc = i;
+      tsdissolve(cdeb);
+    }
+    if (bcdsh.sh != dummysh) {
+      cdeb.loc = 1; // face<b, c, d>.
+      tsbond(cdeb, bcdsh);
+    }
+    if (cbesh.sh != dummysh) {
+      cdeb.loc = 3; // face<c, b, e>.
+      tsbond(cdeb, cbesh);
+    }
+    if (cadsh.sh != dummysh) {
+      ceda.loc = 3; // face<c, a, d>.
+      tsbond(ceda, cadsh);
+    }
+    if (acesh.sh != dummysh) {
+      ceda.loc = 1; // face<a, c, e>.
+      tsbond(ceda, acesh);
+    }
+
+    // Clear old flags in 'fdea'('bafd') and 'fedb'('abfe').
+    for (i = 0; i < 4; i ++) {
+      fdea.loc = i;
+      tsdissolve(fdea);
+      fedb.loc = i;
+      tsdissolve(fedb);
+    }
+    if (fbdsh.sh != dummysh) {
+      fedb.loc = 3; // face<f, b, d>.
+      tsbond(fedb, fbdsh);
+    }
+    if (bfesh.sh != dummysh) {
+      fedb.loc = 1; // face<b, f, e>.
+      tsbond(fedb, bfesh);
+    }
+    if (afdsh.sh != dummysh) {
+      fdea.loc = 1; // face<a, f, d>.
+      tsbond(fdea, afdsh);
+    }
+    if (faesh.sh != dummysh) {
+      fdea.loc = 3; // face<f, a, e>.
+      tsbond(fdea, faesh);
+    }
+    if (abdsh.sh != dummysh) {
+      debsh.sh = abdsh.sh;
+      // default: 'debsh' ver = 0.
+      setsorg (debsh, pd);
+      setsdest(debsh, pe);
+      setsapex(debsh, pb);
+
+      edash.sh = baesh.sh;
+      // default: 'edash' ver = 0.
+      setsorg (edash, pe);
+      setsdest(edash, pd);
+      setsapex(edash, pa);
+
+      ssdissolve(debsh);
+      ssdissolve(edash);
+      senextself(debsh);
+      ssbond(debsh, baeleftseg);
+      senextself(debsh);
+      ssbond(debsh, abdrightseg);
+      senextself(edash);
+      ssbond(edash, abdleftseg);
+      senextself(edash);
+      ssbond(edash, baerightseg);
+
+      // Sandwich between 2 tets.
+      cdeb.loc = 2;
+      tsbond(cdeb, debsh);
+      sesymself(debsh);   // Don't forget to change edgering.
+      fedb.loc = 2;
+      tsbond(fedb, debsh);
+      // Sandwich between 2 tets.
+      ceda.loc = 2;
+      tsbond(ceda, edash);
+      sesymself(edash);  // Don't forget to change edgering.
+      fdea.loc = 2;
+      tsbond(fdea, edash); 
+    }
+  }
+
+  for (i = 0; i < 4; i ++) {
+    ceda.loc = i;
+    dissolve(ceda);
+    cdeb.loc = i;
+    dissolve(cdeb);
+  }
+  // Bond the new configuration.
+  ceda.loc = 0;
+  cdeb.loc = 0;
+  bond(ceda, cdeb);
+  // Bond each casing facets.
+  cdeb.loc = 1;
+  bond(cdeb, bcdcasing);
+  ceda.loc = 3;
+  bond(ceda, cadcasing);
+  cdeb.loc = 3;
+  bond(cdeb, cbecasing);
+  ceda.loc = 1;
+  bond(ceda, acecasing);
+
+  for (i = 0; i < 4; i ++) {
+    fdea.loc = i;
+    dissolve(fdea);
+    fedb.loc = i;
+    dissolve(fedb);
+  }
+  // Bond the two new tetrahedron at other side.
+  fdea.loc = 0;
+  fedb.loc = 0;
+  bond(fdea, fedb);
+  // Bond each casing facets.
+  fedb.loc = 3;
+  bond(fedb, fbdcasing);
+  fdea.loc = 1;
+  bond(fdea, afdcasing);
+  fedb.loc = 1;
+  bond(fedb, bfecasing);
+  fdea.loc = 3;
+  bond(fdea, faecasing);
+
+  // Bond two side tets.
+  ceda.loc = 2;
+  fdea.loc = 2;
+  bond(ceda, fdea);
+  cdeb.loc = 2;
+  fedb.loc = 2;
+  bond(cdeb, fedb);
+
+  ceda.loc = 0;
+  cdeb.loc = 0;
+  fdea.loc = 0;
+  fedb.loc = 0;
+#ifdef SELF_CHECK
+  if (!isaboveplane(&ceda, pa)) {
+    printf("Internal error in flip44():\n");
+    printf("  Clockwise tetrahedron after flip (ceda).\n");
+    internalerror();
+  }
+  if (!isaboveplane(&cdeb, pb)) {
+    printf("Internal error in flip44():\n");
+    printf("  Clockwise tetrahedron after flip (cdeb).\n");
+    internalerror();
+  }
+  if (!isaboveplane(&fdea, pa)) {
+    printf("Internal error in flip44():\n");
+    printf("  Clockwise tetrahedron after flip (fdea).\n");
+    internalerror();
+  }
+  if (!isaboveplane(&fedb, pb)) {
+    printf("Internal error in flip44():\n");
+    printf("  Clockwise tetrahedron after flip (fedb).\n");
+    internalerror();
+  }
+#endif // defined SELF_CHECK
+  if (verbose > 2) {
+    printf("    Updating ceda ");
+    dump(&ceda);
+    printf("    Updating cdeb ");
+    dump(&cdeb);
+    printf("    Updating fdea ");
+    dump(&fdea);
+    printf("    Updating fedb ");
+    dump(&fedb);
+  }
+
+  if (usefliplist) {
+    flipcount = 0;
+    ceda.loc = 3; // face<c, a, d>.
+    enqueuefliplist(ceda);
+    ceda.loc = 1; // face<a, c, e>.
+    enqueuefliplist(ceda);
+    cdeb.loc = 1; // face<b, c, d>.
+    enqueuefliplist(cdeb);
+    cdeb.loc = 3; // face<c, b, e>.
+    enqueuefliplist(cdeb);
+    fdea.loc = 1; // face<a, f, d>.
+    enqueuefliplist(fdea);
+    fdea.loc = 3; // face<f, a, e>.
+    enqueuefliplist(fdea);
+    fedb.loc = 3; // face<f, b, d>.
+    enqueuefliplist(fedb);
+    fedb.loc = 1; // face<b, f, e>.
+    enqueuefliplist(fedb);
+  } else {
+    flipcount = 1;
+    ceda.loc = 3; // face<c, a, d>.
+    flipcount += flip(ceda);
+    ceda.loc = 1; // face<a, c, e>.
+    flipcount += flip(ceda);
+    cdeb.loc = 1; // face<b, c, d>.
+    flipcount += flip(cdeb);
+    cdeb.loc = 3; // face<c, b, e>.
+    flipcount += flip(cdeb);
+    fdea.loc = 1; // face<a, f, d>.
+    flipcount += flip(fdea);
+    fdea.loc = 3; // face<f, a, e>.
+    flipcount += flip(fdea);
+    fedb.loc = 3; // face<f, b, d>.
+    flipcount += flip(fedb);
+    fedb.loc = 1; // face<b, f, e>.
+    flipcount += flip(fedb);
+  }
+
+  return flipcount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip()    Swap away face if this is legal and improves the mesh quality   //
+//           measure.                                                        //
+//                                                                           //
+// Swapping typically propagates through the mesh, and the return value is   //
+// the total number of swaps done during this invocation.                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::flip(triface& flipface)
+{
+  // If the face has been removed, don't bother
+  if (isdead(&flipface)) return (0);
+
+  enum facecategory fc = categorizeface(flipface);
+  // Determine the preferable configuration and swap if necessary.
+  switch (fc) {
+    // These cases are handled by edge swapping.
+    case N44:
+    case N32:
+      // if (edgeswapallow) {
+        // if (querydoswap(flipface)) {
+        //  return edgeswap(flipface, 0);
+        // }
+      // }
+      break;
+    // These cases are definitely unswappable
+    case N40:
+    case N30:
+    case N20:
+    case LOCKED:
+      break;
+    case T44:
+      if (querydoswap(flipface)) {
+        return flip44(flipface);
+      }
+      break;
+    case T22:
+      if (querydoswap(flipface)) {
+        return flip22(flipface);
+      }
+      break;
+    case T23:
+      if (querydoswap(flipface)) {
+        return flip23(flipface);
+      }
+      break;
+    case T32:
+      if (querydoswap(flipface)) {
+        return flip32(flipface);
+      }
+      break;
+    // Catch-all for bad cases
+    default:
+      // Shouldn't be here: face wasn't categorized.
+      break;
+  }
+  checkquality(&flipface);
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// enqueuefliplist()    Add a face which may be non-Delaunay to 'fliplist',  //
+//                      so we can batch process all (to be flipped) faces    //
+//                      together rather than flip a face at one time.        //
+//                                                                           //
+// This routine couple with dequeuefliplist() and dofliplist() are used for  //
+// the implementation of Randomized Incremental Delaunay Algorithm.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::enqueuefliplist(triface& flipface)
+{
+  badface3d queface;
+
+  queface.badfacetet = flipface;
+  org (flipface, queface.faceorg);
+  dest(flipface, queface.facedest);
+  apex(flipface, queface.faceapex); 
+  if (verbose > 2) {
+    printf("    Queueing flip face: (%d, %d, %d).\n",
+           pointmark(queface.faceorg), pointmark(queface.facedest),
+           pointmark(queface.faceapex));
+  }
+  fliplist->push(&queface);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dequeuefliplist()    Get a exist face from 'fliplist', check its Delaunay //
+//                      -hood and perform corresponding flip operator if it  //
+//                      is a non-Delaunay face.                              //
+//                                                                           //
+// This routine couple with enqueuefliplist() and dofliplist() are used for  //
+// the implementation of Randomized Incremental Delaunay Algorithm.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool mesh3d::dequeuefliplist(triface& flipface)
+{
+  badface3d queface;
+  point3d forg, fdest, fapex;
+
+  while (fliplist->get(&queface)) {
+    if (!isdead(&(queface.badfacetet))) {
+      org (queface.badfacetet, forg);
+      dest(queface.badfacetet, fdest);
+      apex(queface.badfacetet, fapex);
+      if ((forg == queface.faceorg)
+          && (fdest == queface.facedest)
+          && (fapex == queface.faceapex)) {
+        flipface = queface.badfacetet;
+        if (verbose > 2) {
+          printf("    Getting  flip face: (%d, %d, %d).\n",
+                 pointmark(queface.faceorg), pointmark(queface.facedest),
+                 pointmark(queface.faceapex));
+        }
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// Mesh Transformation Routines                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// Insert/Delete point routines                                              //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertsite()    Insert a vertex into Delaunay tetrahedrization, perform-  //
+//                 ing flips as necessary to maintain the Delaunay property. //
+//                                                                           //
+//   The point 'insertpoint' is located.  If 'searchtet.tet' is not NULL,    //
+// the search for the containing tetrahedron begins from 'searchtet'. If     //
+// 'searchtet.tet' is NULL, a full point location procedure is called. If    //
+// 'inseertpoint' is found inside a tetrahedron, the tetrahedra is split     //
+// into four by call routine insertininterior(); if 'insertpoint' lies on    //
+// an edge, the edge is split in two, thereby splitting the adjacent         //
+// tetrahedra. It will be done by call routine insertonedge();  if           //
+// 'insertpoint' lies on an face, the face is split into three, thereby      //
+// splitting the adjacent tetrahedra.  It will be done by call routine       //
+// insertonface().  Face or edge flips are used to restore the Delaunay      //
+// property.  If 'insertpoint' lies on an existing vertex, no action is      //
+// taken, and value DUPLICATEPOINT is returned. On return, 'searchtet' is    //
+// set to a handle contain the existing vertex.                              //
+//                                                                           //
+//   Normally, the parameter 'splitface' and 'splitedge' are set to NULL,    //
+// implying that no subface and subsegment should be split. In this case, if //
+// 'insertpoint' is found to lie on a subface or a subsegment, no action is  //
+// taken, and the value VIOLATINGFACE or VIOLATINGEDGE is returned. On       //
+// return, 'searchtet' is set to a handle whose primary face or edge is the  //
+// violated subface or subsegment.                                           //
+//                                                                           //
+//   If the calling routine wishes to split a subface or subsegment by       //
+// inserting a point in it, the parameter 'splitface' or 'splitedge' should  //
+// be that subface or subsegment. In this case, 'searchtet' MUST be the      //
+// tetrahedron handle reached by pivoting from that subface or subsegment;   //
+// no point location is done.                                                //
+//                                                                           //
+//   If a point being inserted,  the return value will be SUCCESSFUL. If a   //
+// point is found to locate outside the mesh and can't be inserted, the      //
+// return value will be FAILED otherwise. In either case, 'searchtet' is set //
+// to a handle whose contains the newly inserted vertex.                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum mesh3d::insertsiteresult
+mesh3d::insertsite(point3d insertpoint, triface* searchtet, face* splitface,
+                   face* splitedge)
+{
+  triface horiz;
+  face brokenshell;
+  badface3d *encroached;
+  enum locateresult intersect;
+  int flipcount;
+
+  if (verbose > 1) {
+    printf("  Insert point to mesh: (%.12g, %.12g, %.12g) %d.\n",
+           insertpoint[0], insertpoint[1], insertpoint[2],
+           pointmark(insertpoint));
+  }
+
+  if ((splitface == NULL) && (splitedge == NULL)) {
+    // Find the location of the point to be inserted. Check if a good
+    //   starting tetrahedron has already been provided by the caller.
+    if (isdead(searchtet)) {
+      // Find a boundary tetrahedron.
+      horiz.tet = dummytet;
+      horiz.loc = 0;
+      symself(horiz);
+      // Search for a tetrahedron containing 'insertpoint'.
+      intersect = locate(insertpoint, &horiz);
+    } else {
+      // Start searching from the tetrahedron provided by the caller.
+      horiz = *searchtet;
+      intersect = preciselocate(insertpoint, &horiz);
+    }
+  } else {
+    // The calling routine provides the edge or face in which the point
+    //   is inserted.
+    horiz = *searchtet;
+    if ((splitface != NULL) && (splitedge == NULL))  {
+      intersect = ONFACE;
+    } else if ((splitface == NULL) && (splitedge != NULL)) {
+      intersect = ONEDGE;
+    } else {
+      printf("Internal error in insertsite():");
+      printf("  splitface and splitedge couldn't use together.\n");
+      internalerror();
+    }
+  }
+
+  // Keep search stat.
+  *searchtet = horiz;
+  recenttet = horiz;
+
+  switch (intersect) {
+    case ONVERTEX:
+      // There's already a vertex there. Return in 'searchtet' a tetrahedron
+      //   whose origin is the existing vertex.
+      if (verbose > 1) {
+        printf("  Not insert for duplicating point.\n");
+      }
+      return DUPLICATE;
+
+    case ONEDGE:
+      // The vertex falls on an edge or boundary.
+      if (checksegments && (splitedge == NULL)) {
+        // Check whether the vertex falls on a shell edge.
+        tsspivot(&horiz, &brokenshell);
+        if (brokenshell.sh != dummysh) {
+          // The vertex falls on a shell edge.
+          if (shsegflaws) {
+            if (nobisect == 0) {
+              // Add the shell edge to the list of encroached segments.
+              encroached = (badface3d*) badsegments.alloc();
+              encroached->shface = brokenshell;
+              sorg (brokenshell, encroached->faceorg);
+              sdest(brokenshell, encroached->facedest);
+            } else if ((nobisect == 1) && (intersect == ONEDGE)) {
+              // This segment may be split only if it is an internal
+              //   boundary.
+              if (!isridge(&horiz)) {
+                // Add the shell edge to the list of encroached segments.
+                encroached = (badface3d*) badsegments.alloc();
+                encroached->shface = brokenshell;
+                sorg (brokenshell, encroached->faceorg);
+                sdest(brokenshell, encroached->facedest);
+              }
+            }
+          }
+          // Return a handle whose primary edge contains the point, which
+          //   has not been inserted.
+          if (verbose > 1) {
+            printf("  Not insert for landing right on other subsegment.\n");
+          }
+          return VIOLATINGEDGE;
+        }
+      }
+      flipcount = insertonedge(insertpoint, searchtet, splitedge);
+      if (verbose > 1) {
+        printf("  Successfully insert on edge with %d flips.\n", flipcount);
+      }
+      return SUCCESSFUL;
+
+    case ONFACE:
+      // The vertex falls on a facet or boundary.
+      if (checksegments && (splitface == NULL)) {
+        // Check whether the vertex falls on a shell facet.
+        tspivot(horiz, brokenshell);
+        if (brokenshell.sh != dummysh) {
+          // The vertex falls on a shell facet.
+          if (shflaws) {
+            if (nobisect == 0) {
+              // Add the shell facet to the list of encroached subfaces.
+              enqueuebadface(&brokenshell, (point3d)NULL, 1);
+            } else if ((nobisect == 1) && (intersect == ONEDGE)) {
+              // This subface may be split only if it is an internal
+              //   boundary.
+              if (issymexist(&horiz)) {
+                // Add the shell facet to the list of encroached subface.
+                enqueuebadface(&brokenshell, (point3d)NULL, 1);
+              }
+            }
+          }
+          // Return a handle whose primary face contains the point,
+          //   which has not been inserted.
+          if (verbose > 1) {
+            printf("  Not insert for landing right on other subface.\n");
+          }
+          return VIOLATINGFACE;
+        }
+      }
+      flipcount = insertonface(insertpoint, searchtet, splitface);
+      if (verbose > 1) {
+        printf("  Successfully insert on face with %d flips.\n", flipcount);
+      }
+      return SUCCESSFUL;
+
+    case INTETRAHEDRON:
+      // This vertex falls inside a tetrahedron.
+      flipcount = insertininterior(insertpoint, searchtet);
+      if (verbose > 1) {
+        printf("  Successfully insert in tetrahedron with %d flips.\n",
+               flipcount);
+      }
+      return SUCCESSFUL;
+
+    case OUTSIDE:
+      if (verbose > 1) {
+        printf("  Not insert for locating outside the mesh.\n");
+      }
+      return FAILED;
+  } // End of switch(intersect)
+
+  // Should never have a chance to reach here.
+  return FAILED;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertininterior()     Insert the point in a  tetrahedron,   splitting it //
+//                        into four.  Face or edge flips are used to restore //
+//                        the Delaunay property.                             //
+//                                                                           //
+// 'insertpoint'(v) lies above wrt 'horiz'(abcd).                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::insertininterior(point3d insertpoint, triface* horiz)
+{
+  triface oldabd, oldbcd, oldcad;                      // Old configuration.
+  triface abdcasing, bcdcasing, cadcasing;
+  face abdsh, bcdsh, cadsh;
+  triface abcv, badv, cbdv, acdv;                      // New configuration.
+  point3d pa, pb, pc, pd;
+  REAL attrib, volume;
+  int flipcount, i;
+
+  abcv = *horiz;
+  abcv.ver = 0;
+  // Set the vertices of changed and new tetrahedron.
+  org (abcv, pa);
+  dest(abcv, pb);
+  apex(abcv, pc);
+  oppo(abcv, pd);
+
+  oldabd = oldbcd = oldcad = abcv;
+  fnextself(oldabd);
+  enextfnextself(oldbcd);
+  enext2fnextself(oldcad);
+  sym(oldabd, abdcasing);
+  sym(oldbcd, bcdcasing);
+  sym(oldcad, cadcasing);
+  maketetrahedron(&badv);
+  maketetrahedron(&cbdv);
+  maketetrahedron(&acdv);
+
+  // Set 'badv' vertexs.
+  setorg (badv, pb);
+  setdest(badv, pa);
+  setapex(badv, pd);
+  setoppo(badv, insertpoint);
+  // Set 'cbdv' vertexs.
+  setorg (cbdv, pc);
+  setdest(cbdv, pb);
+  setapex(cbdv, pd);
+  setoppo(cbdv, insertpoint);
+  // Set 'acdv' vertexs.
+  setorg (acdv, pa);
+  setdest(acdv, pc);
+  setapex(acdv, pd);
+  setoppo(acdv, insertpoint);
+  // Set 'abcv' vertexs
+  setoppo(abcv, insertpoint);
+
+  // Set the element attributes of the new tetrahedron.
+  for (i = 0; i < eextras; 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 tetrahedron.
+  if (varvolume) {
+    volume = volumebound(abcv.tet);
+    setvolumebound(badv.tet, volume);
+    setvolumebound(cbdv.tet, volume);
+    setvolumebound(acdv.tet, volume);
+  }
+
+  // There may be shell facets that need to be bonded to
+  //   the new tetrahedron.
+  if (checksegments) {
+    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);
+    }
+  }
+
+  // Bond the new triangles to the surrounding tetrahedron.
+  bond(badv, abdcasing);
+  bond(cbdv, bcdcasing);
+  bond(acdv, cadcasing);
+
+  badv.loc = 3; // face<d, v, b>.
+  cbdv.loc = 2;
+  bond(badv, cbdv);
+  cbdv.loc = 3; // face<d, v, c>.
+  acdv.loc = 2;
+  bond(cbdv, acdv);
+  acdv.loc = 3; // face<d, v, a>.
+  badv.loc = 2;
+  bond(acdv, badv);
+  badv.loc = 1; // face<b, v, a>.
+  bond(badv, oldabd);
+  cbdv.loc = 1; // face<c, v, b>.
+  bond(cbdv, oldbcd);
+  acdv.loc = 1; // face<a, v, c>.
+  bond(acdv, oldcad);
+
+  badv.loc = 0;
+  cbdv.loc = 0;
+  acdv.loc = 0;
+#ifdef SELF_CHECK
+  if (!isaboveplane(&abcv, insertpoint)) {
+    printf("Internal error in insertininterior():\n");
+    printf("  Clockwise tetrahedron prior to point insertion(abcv).\n");
+    internalerror();
+  }
+  if (!isaboveplane(&badv, insertpoint)) {
+    printf("Internal error in insertininterior():\n");
+    printf("  Clockwise tetrahedron after point insertion (badv).\n");
+    internalerror();
+  }
+  if (!isaboveplane(&cbdv, insertpoint)) {
+    printf("Internal error in insertininterior():\n");
+    printf("  Clockwise tetrahedron after point insertion (cbdv).\n");
+    internalerror();
+  }
+  if (!isaboveplane(&acdv, insertpoint)) {
+    printf("Internal error in insertininterior():\n");
+    printf("  Clockwise tetrahedron after point insertion (acdv).\n");
+    internalerror();
+  }
+#endif // defined SELF_CHECK
+  if (verbose > 2) {
+    printf("    Updating abcv ");
+    dump(&abcv);
+    printf("    Creating badv ");
+    dump(&badv);
+    printf("    Creating cbdv ");
+    dump(&cbdv);
+    printf("    Creating acdv ");
+    dump(&acdv);
+  }
+
+  flipcount = 0;
+
+  if (usefliplist) {
+    enqueuefliplist(abcv);
+    enqueuefliplist(badv);
+    enqueuefliplist(cbdv);
+    enqueuefliplist(acdv);
+  } else {
+    flipcount += flip(abcv);
+    flipcount += flip(badv);
+    flipcount += flip(cbdv);
+    flipcount += flip(acdv);
+  }
+
+  if (isdead(horiz)) {
+    // We need return a live tet.
+    if (!isdead(&badv)) {
+      *horiz = badv;
+    } else if (!isdead(&cbdv)) {
+      *horiz = cbdv;
+    } else {
+      // assert(!acdv.isdead());
+      if (!isdead(&acdv)) {
+        *horiz = acdv;
+      } else {
+        if (verbose) {
+          printf("Warnning in insertininterior():\n");
+          printf("  After %d flips, we can't return a live tet.\n", flipcount);
+        }
+      }
+    }
+  }
+
+  return flipcount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertonface()    Insert a point on a face of tetrahedron, splitting one  //
+//                   tetrahedron into three (if the face lies on outer       //
+//                   boundary), or two tetrahedras into six.  Face or edge   //
+//                   flips are used to restore the Delaunay property.        //
+//                                                                           //
+// 'horiz.location()' indicates the face where 'insertpoint' lies on. If the //
+// 'splitface' != NULL, this mean insert a point on boundary face.   'horiz' //
+// should be a handle of this boundary face adjoining to.                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::insertonface(point3d insertpoint, triface* horiz, face* splitface)
+{
+  triface oldbcd, oldcad, oldace, oldcbe;              // Old configuration.
+  triface bcdcasing, cadcasing, acecasing, cbecasing;
+  face bcdsh, cadsh, acesh, cbesh;
+  triface badv, cbdv, acdv, abev, bcev, caev;          // New configuration.
+  point3d pa, pb, pc, pd, pe;
+  REAL attrib, volume;
+  bool mirrorflag;
+  int flipcount, i;
+
+  badv = *horiz;
+  badv.ver = 0;
+  // Now assume 'badv' is tet<a, b, c, d>.
+  org (badv, pa);
+  dest(badv, pb);
+  apex(badv, pc);
+  oppo(badv, pd);
+  // Is there a second tetrahderon?
+  mirrorflag = issymexist(&badv);
+  if (mirrorflag) {
+    // This is a interior face.
+    sym(badv, abev);
+    findversion(&abev, &badv);
+    // Now 'abev' is tet <b, a, c, e>.
+    oppo(abev, pe);
+  }
+
+  oldbcd = oldcad = badv;
+  enextfnextself(oldbcd);
+  enext2fnextself(oldcad);
+  fnextself(badv);
+  esymself(badv);  // Now 'badv' is tet<b, a, d, c>.
+  sym(oldbcd, bcdcasing);
+  sym(oldcad, cadcasing);
+  maketetrahedron(&cbdv);
+  maketetrahedron(&acdv);
+  // Is there a second tetrahderon?
+  if (mirrorflag) {
+    // This is a interior face.
+    oldace = oldcbe = abev;
+    enextfnextself(oldace);
+    enext2fnextself(oldcbe);
+    fnextself(abev);
+    esymself(abev);  // Now abev is tet<a, b, e, c>.
+    sym(oldace, acecasing);
+    sym(oldcbe, cbecasing);
+    maketetrahedron(&caev);
+    maketetrahedron(&bcev);
+  } else {
+    // Splitting the boundary face increases the number of boundary faces.
+    hullsize += 2;
+  }
+
+  // Set the vertices of changed and new tetrahedron.
+  // Set 'cbdv'.
+  setorg (cbdv, pc);
+  setdest(cbdv, pb);
+  setapex(cbdv, pd);
+  setoppo(cbdv, insertpoint);
+  // Set 'acdv'.
+  setorg (acdv, pa);
+  setdest(acdv, pc);
+  setapex(acdv, pd);
+  setoppo(acdv, insertpoint);
+  // Set 'badv'.
+  setoppo(badv, insertpoint);
+
+  // Set the element attributes of new tetrahedron.
+  for (i = 0; i < eextras; i++) {
+    attrib = elemattribute(badv.tet, i);
+    setelemattribute(cbdv.tet, i, attrib);
+    setelemattribute(acdv.tet, i, attrib);
+  }
+  if (varvolume) {
+    // Set the area constraint of new tetrahedron.
+    volume = volumebound(badv.tet);
+    setvolumebound(cbdv.tet, volume);
+    setvolumebound(acdv.tet, volume);
+  }
+
+  if (mirrorflag) {
+    // Set 'caev'.
+    setorg (caev, pc);
+    setdest(caev, pa);
+    setapex(caev, pe);
+    setoppo(caev, insertpoint);
+    // Set 'bcev'.
+    setorg(bcev, pb);
+    setdest(bcev, pc);
+    setapex(bcev, pe);
+    setoppo(bcev, insertpoint);
+    // Set 'abev'.
+    setoppo(abev, insertpoint);
+
+    // Set the element attributes of new tetrahedron.
+    for (i = 0; i < eextras; i++) {
+      attrib = elemattribute(abev.tet, i);
+      setelemattribute(bcev.tet, i, attrib);
+      setelemattribute(caev.tet, i, attrib);
+    }
+    if (varvolume) {
+      // Set the area constraint of new tetrahedron.
+      volume = volumebound(abev.tet);
+      setvolumebound(bcev.tet, volume);
+      setvolumebound(caev.tet, volume);
+    }
+  }
+
+  // There may be shell facets that need to be bonded to the
+  //   new tetrahedron.
+  if (checksegments) {
+    tspivot(oldbcd, bcdsh);
+    if (bcdsh.sh != dummysh) {
+      tsdissolve(oldbcd);
+      tsbond(cbdv, bcdsh);
+    }
+    tspivot(oldcad, cadsh);
+    if (cadsh.sh != dummysh) {
+      tsdissolve(oldcad);
+      tsbond(acdv, cadsh);
+    }
+    if (mirrorflag) {
+      tspivot(oldace, acesh);
+      if (acesh.sh != dummysh) {
+        tsdissolve(oldace);
+        tsbond(caev, acesh);
+      }
+      tspivot(oldcbe, cbesh);
+      if (cbesh.sh != dummysh) {
+        tsdissolve(oldcbe);
+        tsbond(bcev, cbesh);
+      }
+    }
+  }
+
+  // Bond the new tetrahedron to the surrounding tetrahedron.
+  bond(cbdv, bcdcasing);  // Default 'cbdv' loc = 0.
+  bond(acdv, cadcasing);  // Default 'acdv' loc = 0.
+  cbdv.loc = 2;
+  bond(cbdv, oldbcd);
+  cbdv.loc = 3;
+  acdv.loc = 2;
+  bond(cbdv, acdv);
+  acdv.loc = 3;
+  bond(acdv, oldcad);
+
+  if (mirrorflag) {
+    bond(caev, acecasing);  // Default 'bcev' loc = 0.
+    bond(bcev, cbecasing);  // Default 'caev' loc = 0.
+    caev.loc = 2;
+    bond(caev, oldace);
+    caev.loc = 3;
+    bcev.loc = 2;
+    bond(caev, bcev);
+    bcev.loc = 3;
+    bond(bcev, oldcbe);
+
+    // Bond two new coplanar facets.
+    cbdv.loc = 1;
+    bcev.loc = 1;
+    bond(cbdv, bcev);
+    acdv.loc = 1;
+    caev.loc = 1;
+    bond(acdv, caev);
+  }
+
+  cbdv.loc = 0;
+  acdv.loc = 0;
+  if (mirrorflag) {
+    bcev.loc = 0;
+    caev.loc = 0;
+  }
+
+  if (splitface != (face *) NULL) {
+    // We need insert two new subface into current mesh.
+    triface righttet, lefttet;
+    face oldrightshface, oldleftshface;
+    face rightshseg, leftshseg;
+    face newrightshface, newleftshface;
+
+    // Init 'splitface' be face<a, b, c>
+    findversion(splitface, pa, pb, 0);
+    senext(*splitface, oldrightshface);  // face<b, c, a>
+    senext2(*splitface, oldleftshface);  // face<c, a, b>
+
+    // Set 'splitface' be face<a, b, v>
+    setsapex(*splitface, insertpoint);
+    // Insert two new shell facets at cbdv(right), and acdv(left).
+    //   Set 'righttet' be tet<c, b, v, -d>.
+    fnext(cbdv, righttet);
+    //   Insert a new subface abutting 'righttet'.
+    insertsubface(&righttet, mark(*splitface), 0);
+    //   Set 'lefttet' tet<a, c, v, -d>.
+    fnext(acdv, lefttet);
+    //   Insert a new subface abutting 'leftete'.
+    insertsubface(&lefttet, mark(*splitface), 0);
+
+    // Set 'newrightshface' be face<b, c, v>
+    tspivot(righttet, newrightshface);
+    findversion(&newrightshface, pb, pc, 0);
+    // Set 'newleftshface' be face<c, a, v>
+    tspivot(lefttet, newleftshface);
+    findversion(&newleftshface, pc, pa, 0);
+
+    // Bond subsegments to two new shell facets if there have one. Do not
+    //   forget to dissolve orgin bond first.
+    sspivot(oldrightshface, rightshseg);
+    if (rightshseg.sh != dummysh) {
+      ssdissolve(oldrightshface);
+      ssbond(newrightshface, rightshseg);
+    }
+    sspivot(oldleftshface, leftshseg);
+    if (leftshseg.sh != dummysh) {
+      ssdissolve(oldleftshface);
+      ssbond(newleftshface, leftshseg);
+    }
+
+    if (shflaws) {
+      // Now, the original 'splitface' was splitted to 'splitface',
+      //   'newrightshface' and 'newleftshface'.
+      // In quality mesh generation step, we need check if these three
+      //   subfaces being encroached. (Because they are Delaunay faces
+      //   and needn't do flip).
+      uncheckedshlist->append(splitface);
+      uncheckedshlist->append(&newrightshface);
+      uncheckedshlist->append(&newleftshface);
+    }
+  } // if (splitface != (face *) NULL)
+
+#ifdef SELF_CHECK
+  if (!isaboveplane(&badv, insertpoint)) {
+    printf("Internal error in insertonface():\n");
+    printf("  Clockwise tetra prior to face point insertion (badv).\n");
+    internalerror();
+  }
+  if (!isaboveplane(&cbdv, insertpoint)) {
+    printf("Internal error in insertonface():\n");
+    printf("  Clockwise tetra after face point insertion (cbdv).\n");
+    internalerror();
+  }
+  if (!isaboveplane(&acdv, insertpoint)) {
+    printf("Internal error in insertonface():\n");
+    printf("  Clockwise tetra after face point insertion (acdv).\n");
+    internalerror();
+  }
+  if (mirrorflag) {
+    if (!isaboveplane(&abev, insertpoint)) {
+      printf("Internal error in insertonface():\n");
+      printf("  Clockwise tetra prior to face point insertion (abev).\n");
+      internalerror();
+    }
+    if (!isaboveplane(&bcev, insertpoint)) {
+      printf("Internal error in insertonface():\n");
+      printf("  Clockwise tetra after face point insertion (bcev).\n");
+      internalerror();
+    }
+    if (!isaboveplane(&caev, insertpoint)) {
+      printf("Internal error in insertonface():\n");
+      printf("  Clockwise tetra after face point insertion (caev).\n");
+      internalerror();
+    }
+  }
+#endif // defined SELF_CHECK
+  if (verbose > 2) {
+    printf("    Updating badv ");
+    dump(&badv);
+    printf("    Creating cbdv ");
+    dump(&cbdv);
+    printf("    Creating acdv ");
+    dump(&acdv);
+    if (mirrorflag) {
+      printf("    Updating abev ");
+      dump(&abev);
+      printf("    Creating bcev ");
+      dump(&bcev);
+      printf("    Creating caev ");
+      dump(&caev);
+    }
+  }
+
+  flipcount = 0;
+
+  if (usefliplist) {
+    enqueuefliplist(badv);
+    enqueuefliplist(cbdv);
+    enqueuefliplist(acdv);
+    if (mirrorflag) {
+      enqueuefliplist(abev);
+      enqueuefliplist(bcev);
+      enqueuefliplist(caev);
+    }
+  } else {
+    flipcount += flip(badv);
+    flipcount += flip(cbdv);
+    flipcount += flip(acdv);
+    if (mirrorflag) {
+      flipcount += flip(abev);
+      flipcount += flip(bcev);
+      flipcount += flip(caev);
+    }
+  }
+
+  if (isdead(horiz)) {
+    // We need return a live tet.
+    if (splitface != (face*) NULL) {
+      stpivot(*splitface, *horiz);
+      if (horiz->tet == dummytet) {
+        assert(mirrorflag == 0);
+        sesymself(*splitface);
+        stpivot(*splitface, *horiz);
+      }
+    } else if (!isdead(&cbdv)) {
+      *horiz = cbdv;
+    } else if (!isdead(&acdv)) {
+      *horiz = acdv;
+    } else {
+      assert(mirrorflag);
+      if (!isdead(&abev)) {
+        *horiz = abev;
+      } else if (!isdead(&bcev)) {
+        *horiz = bcev;
+      } else {
+        // assert(!caev.isdead());
+        if (!isdead(&caev)) {
+          *horiz = caev;
+        } else {
+          if (verbose) {
+            printf("Warnning in insertonface(): \n");
+            printf("  After %d flips, we can't return a live tet.\n",
+                   flipcount);
+          }
+        }
+      }
+    }
+  }
+
+  return flipcount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertonedge()    Insert a point on an edge, splitting all tetrahedra     //
+//                   which around this edge into two.  Face or edge flips    //
+//                   are used to restore the Delaunay property.              //
+//                                                                           //
+// 'horiz.org()' and 'horiz.dest()'  indicates the edge where 'insertpoint'  //
+// lies on. If the 'splitedge' != NULL, this mean insert a point on boundary //
+// edge. 'horiz' should be a handle of this boundary edge adjoining to.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::insertonedge(point3d insertpoint, triface* horiz, face* splitedge)
+{
+  triface bdrytet, spintet, tmptet;
+  triface *bots, *oldtops, *topcasings, *newtops;
+  face topshell;
+  triface tmpbond0, tmpbond1;
+  point3d pa, pb, nj, nj_1;
+  point3d tapex;
+  int wrapfacecount, wrapcount, hitbdry;
+  int flipcount, i, k;
+
+  // Adjust 'horiz''s face version. Let it belong to EdgeRing = 0.
+  adjustedgering(*horiz, CCW);
+  // Now, we can sure 'horiz' be tet<b, a, n1, n2>.
+
+  // First find how much tetrahedron wrap around edge<ba>. As a side effect,
+  //   we will find if edge<ba> lies on boundary, if so we keep the handle
+  //   of first encountered boundary tetrahedron in 'bdrytet'.
+  spintet = *horiz;
+  apex(*horiz, tapex);
+  wrapfacecount = 1;
+  hitbdry = 0;
+  while (true) {
+    if (fnextself(spintet)) {
+      if (apex(spintet) == tapex) {
+        break;
+      }
+      wrapfacecount ++;
+    } else {
+      hitbdry ++;
+      if (hitbdry >= 2) {
+        break;
+      } else {
+        esym(spintet, bdrytet);
+        esym(*horiz, spintet);
+      }
+    }
+  }
+
+  // Determine how much wrap tetrahedra from 'wrapfacecount'.
+  if (hitbdry == 0) {
+    wrapcount = wrapfacecount;
+  } else {
+    wrapcount = wrapfacecount - 1;
+    // Splitting the boundary face increases the number of boundary faces.
+    hullsize += 2;
+  }
+  assert(wrapcount >= 1);
+
+  // Current state:
+  //   Let i = wrapfacecount be the total found faces. Let the wrap faces'
+  //     apex sequence be: n[1], n[2], ..., n[i].
+  //   IF hitbdry = 0, THEN edge<ba> is inner edge. 'horiz' will be tet
+  //     <b, a, n[1], n[2]>; ELSE the edge <ba> is on boundary. 'bdrytet'
+  //     will be tet<a, b, n[j], n[j-1]>; (where 2 <= j <= i).
+  //   Note: the 'horiz' and 'bdrytet' has inversed fnext direction.
+  //
+  // For using the same process to cope with the diffrence between 'horiz'
+  //   and 'bdrytet', we adjust 'horiz' be tet<a, b, n[2], n[1]>. So they
+  //   have the same fnext direction.
+  if (hitbdry == 0) {
+    fnext(*horiz, spintet);
+    esymself(spintet);
+  } else {
+    spintet = bdrytet;
+  }
+
+  // Make lists of dividing(bot, oldtop) tetrahedra, Create new(newtop)
+  //   tetrahedra for each original tetrahedron.
+  bots = new triface[wrapcount];
+  oldtops = new triface[wrapcount];
+  topcasings = new triface[wrapcount];
+  newtops = new triface[wrapcount];
+
+  // Walk around the edge, gathering tetrahedra and setting up new tetra-
+  //   hedra. If 'hitbdry' != 0, start from 'bdrytet', otherwise, start
+  //   from 'horiz'. For convinence, we inverse the number sequence of the
+  //   apex of each wrapfaces in Owen's paper, and let the vertex sequence
+  //   be : 1, 2, ..., j-1, j. (where j = wrapcount.)
+  for (i = 0; i < wrapcount; i ++) {
+    fnextself(spintet);
+    // Set 'tmptet' be tet<b, a, n[j], n[j-1]>.
+    esym(spintet, tmptet);
+    // Set 'bots[i]' be tet<n[j], a, n[j-1], b>.
+    enextself(tmptet);
+    fnext(tmptet, bots[i]);
+    esymself(bots[i]);
+    // Set 'oldtops[i]' be tet<n[j], b, n[j-1], -a>.
+    enextself(tmptet);
+    fnext(tmptet, oldtops[i]);
+    // Set 'topcasing'.
+    sym(oldtops[i], topcasings[i]);
+    maketetrahedron(&(newtops[i]));
+  }
+
+  org (spintet, pa);
+  dest(spintet, pb);
+  // Set the vertices of changed and new tetrahedra.
+  for (i = 0; i < wrapcount; i ++) {
+    // 'bots[i]' is tet<n[j], a, n[j-1], b>.
+    org (bots[i], nj); //
+    apex(bots[i], nj_1);
+    // Set 'newtops[i]' be tet<b, n[j], n[j-1], v>.
+    setorg(newtops[i], pb);
+    setdest(newtops[i], nj);
+    setapex(newtops[i], nj_1);
+    setoppo(newtops[i], insertpoint);
+    // Set 'bots' be tet<n[j], a, n[j-1], v>.
+    setoppo(bots[i], insertpoint);
+    // Set the element attributes of a new tetrahedron.
+    for (k = 0; k < eextras; k++) {
+      setelemattribute(newtops[i].tet, k,
+                       elemattribute(bots[i].tet, k));
+    }
+    if (varvolume) {
+      // Set the area constraint of a new tetrahedron.
+      setvolumebound(newtops[i].tet, volumebound(bots[i].tet));
+    }
+  }
+
+  // There may be shell facets that need to be bonded to each new
+  //   tetrahedron's topcasing side.
+  if (checksegments) {
+    // Check topcasing shell at each newtops side.
+    for (i = 0; i < wrapcount; i ++) {
+      tspivot(oldtops[i], topshell);
+      if (topshell.sh != dummysh) {
+        tsdissolve(oldtops[i]);
+        tsbond(newtops[i], topshell);
+      }
+    }
+  }
+
+  // Bond newtops to topcasings and bots.
+  for (i = 0; i < wrapcount; i ++) {
+    // default: 'newtops[i]' loc = 0.
+    bond(newtops[i], topcasings[i]);
+    newtops[i].loc = 2;
+    bond(newtops[i], oldtops[i]);
+  }
+  // Bond between each newtops. Becareful the boundary case.
+  tmpbond0 = newtops[0];
+  for (i = 1; i <= wrapcount; i ++) {
+    if(i == wrapcount) {
+      if(hitbdry == 0) {
+        tmpbond1 = newtops[0];
+      } else {
+        break; // Insert on boundary edge case.
+      }
+    } else {
+      tmpbond1 = newtops[i];
+    }
+    tmpbond0.loc = 1;
+    tmpbond1.loc = 3;
+    bond(tmpbond0, tmpbond1);
+    tmpbond0 = tmpbond1;
+  }
+
+  for (i = 0; i < wrapcount; i ++) {
+    newtops[i].loc = 0;
+  }
+
+  // There may be shell facets that need to be bonded to each new
+  //   tetrahedron's sandwich side.
+  if (checksegments || (splitedge != (face*) NULL)) {
+    triface tmpbot, tmpnewtop;
+    face botsandwichsh, modibotleftsh, modibotrightsh;
+    face botleftshseg, botrightshseg;
+    face newtopsandwichsh;
+
+    for (i = 0; i < wrapcount; i ++) {
+      // Set 'tmpbot' be tet<a, n[j], v, n[j-1]>.
+      fnext(bots[i], tmpbot);
+      esymself(tmpbot);
+      tspivot(tmpbot, botsandwichsh);
+      if (botsandwichsh.sh != dummysh) {
+        findversion(&botsandwichsh, &tmpbot);
+        // Set 'botsandwichsh' be face<n[j], a, v>
+        setsapex(botsandwichsh, insertpoint);
+        // Set 'modibotleftsh' be face<v, n[j], a>
+        senext2(botsandwichsh, modibotleftsh);
+        // Set 'tmpnewtop' be tet<n[j], b, v, n[j-1]>.
+        fnext(newtops[i], tmpnewtop);
+        esymself(tmpnewtop);
+        // Insert a new shell facet at 'tmpnewtop'.
+        insertsubface(&tmpnewtop, mark(botsandwichsh), 0);
+        // Set 'newtopsandwichsh' be face<b, n[j], v>.
+        tspivot(tmpnewtop, newtopsandwichsh);
+        findversion(&newtopsandwichsh, &tmpnewtop);
+        // Check subsegment that need bond to 'botleftshseg'.
+        sspivot(modibotleftsh, botleftshseg);
+        if (botleftshseg.sh != dummysh) {
+          ssdissolve(modibotleftsh);
+          ssbond(newtopsandwichsh, botleftshseg);
+        }
+        // Here we can skip checking the right side's segment, because
+        //   if there exist a segment, it will be split later.
+        if (shflaws) {
+          // Now, the original 'botsandwichsh' was splitted to
+          //   'botsandwichsh' and 'newtopsandwichsh'.
+          // In quality mesh generation step, we need check if these two
+          //   subfaces being encroached. (Because they are Delaunay faces
+          //   and needn't do flip).
+          uncheckedshlist->append(&botsandwichsh);
+          uncheckedshlist->append(&newtopsandwichsh);
+        }
+      }
+    }
+    if (hitbdry != 0) {
+      // Additional shell facet at bots[0] other side need split.
+      // We recall: 'bots[0]' is tet<n[j], a, n[j-1], v>.
+      //         'newtops[0]' is tet<b, n[j], n[j-1], v>.
+      // Set 'tmpbot' be tet<n[j-1], pa, v, n[j]>.
+      tmpbot = bots[0];
+      enextfnextself(tmpbot);
+      esymself(tmpbot);
+      tspivot(tmpbot, botsandwichsh);
+      if (botsandwichsh.sh != dummysh) {
+        // Set 'botsandwichsh' be face<a, n[j-1], v>.
+        findversion(&botsandwichsh, &tmpbot);
+        setsapex(botsandwichsh, insertpoint);
+        // Set 'modibotrightsh' be face<n[j-1], v, a>.
+        senext(botsandwichsh, modibotrightsh);
+        // Set 'tmpnewtop' be tet<b, n[j-1], v, n[j]>.
+        tmpnewtop = newtops[0];
+        enext2fnextself(tmpnewtop);
+        esymself(tmpnewtop);
+        // Insert a new shell facet at 'tmpnewtop'.
+        insertsubface(&tmpnewtop, mark(botsandwichsh), 0);
+        // Set 'newtopsandwichsh' be face<n[j-1], b, v>.
+        tspivot(tmpnewtop, newtopsandwichsh);
+        findversion(&newtopsandwichsh, &tmpnewtop);
+        // Check subsegment that need bond to 'botrightshseg'.
+        sspivot(modibotrightsh, botrightshseg);
+        if (botrightshseg.sh != dummysh) {
+          ssdissolve(modibotrightsh);
+          ssbond(newtopsandwichsh, botrightshseg);
+        }
+        // Here we can skip checking the left side's segment, because
+        //   if there exist a segment, it will be split later.
+        if (shflaws) {
+          uncheckedshlist->append(&botsandwichsh);
+          uncheckedshlist->append(&newtopsandwichsh);
+        }
+      }
+    }
+
+    if (splitedge != (face*) NULL) {
+      face newseg;
+      face tmpbond0;
+      // We need insert a new subsegments into current mesh.
+      // Set 'splitedge' be edge<ab>.
+      findversion(splitedge, pa, pb, 0);
+      // Set 'splitedge' be edge<av>.
+      setsdest(*splitedge, insertpoint);
+      // Insert a new subsegment <vb> at 'tmpnewtop'.
+      fnext(newtops[0], tmpnewtop);
+      enext2self(tmpnewtop);
+      insertsubsegment(&tmpnewtop, mark(*splitedge));
+      tsspivot(&tmpnewtop, &newseg);
+      findversion(&newseg, insertpoint, pb, 0);
+      // Bond these two edges. So it can be quickly found each other after
+      //   splitting this subsegment.
+      senext(*splitedge, tmpbond0);
+      senext2self(newseg);
+      sbond(tmpbond0, newseg);
+    }
+  }
+
+#ifdef SELF_CHECK
+  for (i = 0; i < wrapcount; i ++) {
+    if (!isaboveplane(&(bots[i]), insertpoint)) {
+      printf("Internal error in insertonedge():\n");
+      printf("  Clockwise tetra prior to point insertion (bots[%i]).\n", i);
+      internalerror();
+    }
+    if (!isaboveplane(&(newtops[i]), insertpoint)) {
+      printf("Internal error in insertonedge():\n");
+      printf("  Clockwise tetra after point insertion (bots[%i]).\n", i);
+      internalerror();
+    }
+  }
+#endif // defined SELF_CHECK
+  if (verbose > 2) {
+    for (i = 0; i < wrapcount; i ++) {
+      printf("    Updating bots[%i] ", i);
+      dump(&(bots[i]));
+      printf("    Creating newtops[%i] ", i);
+      dump(&(newtops[i]));
+    }
+  }
+
+  flipcount = 0;
+
+  if (usefliplist) {
+    for (i = 0; i < wrapcount; i ++) {
+      enqueuefliplist(bots[i]);
+      enqueuefliplist(newtops[i]);
+    }
+  } else {
+    for (i = 0; i < wrapcount; i ++) {
+      flipcount += flip(bots[i]);
+      flipcount += flip(newtops[i]);
+    }
+  }
+
+  if (isdead(horiz)) {
+    // We need return a live tet.
+    if (splitedge != (face*) NULL) {
+      sstpivot(splitedge, horiz); // *horiz = splitedge->sstpivot();
+    } else {
+      for (i = 0; i < wrapcount; i ++) {
+        if (!isdead(&(bots[i]))) {
+          *horiz = bots[i];
+          break;
+        }
+        if (!isdead(&(newtops[i]))) {
+          *horiz = newtops[i];
+          break;
+        }
+      }
+      // assert(i < wrapcount);
+      if (!(i < wrapcount)) {
+        if (verbose) {
+          printf("Warnning in insertonedge(): \n");
+          printf("  After %d flips, we can't return a live tet.\n", flipcount);
+        }
+      }
+    }
+  }
+
+  delete [] bots;
+  delete [] oldtops;
+  delete [] topcasings;
+  delete [] newtops;
+
+  return flipcount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertsubface()    Create a new shell facet and insert it between two     //
+//                    tetrahedra.                                            //
+//                                                                           //
+// The new shell facet is created at the face described by the handle 'tet'. //
+// Its vertices are properly initialized. The marker 'shellemark' is applied //
+// to the shell facet and, if appropriate, its vertices.                     //
+//                                                                           //
+// The 'autobondsegs' flag is used to indicate whether we need do a segment  //
+// searching for the newly inserted subface. Generally, in mesh refinement   //
+// stage, we always need searching segments for newly inserted subface, so   //
+// the (triface).tsspivot() primitive will work correctly and efficiently.   //
+// But when do a local transformation on a face or edge, the segments around //
+// the subface always can be found before do flipping. So there need not do  //
+// segments searching (set autobondsegs = 0).                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::insertsubface(triface* tet, int shellemark, int autobondsegs)
+{
+  triface abcd, bace;
+  face newshell, bseg;
+  point3d pa, pb, pc;
+  int i;
+
+  abcd = *tet;
+  adjustedgering(abcd, CCW);
+  // Mark points if possible.
+  org (abcd, pa);
+  dest(abcd, pb);
+  apex(abcd, pc);
+  if (shellemark != NONSOLIDFLAG) {
+    if (pointmark(pa) == 0) {
+      setpointmark(pa, shellemark);
+    }
+    if (pointmark(pb) == 0) {
+      setpointmark(pb, shellemark);
+    }
+    if (pointmark(pc) == 0) {
+      setpointmark(pc, shellemark);
+    }
+  }
+
+  // Check if there's already exist a shell facet here.
+  tspivot(abcd, newshell);
+  if (newshell.sh == dummysh) {
+    // Make new shell facet and initialize its vertices.
+    makeshellface(&subfaces, &newshell);
+    setsorg (newshell, pb);
+    setsdest(newshell, pa);
+    setsapex(newshell, pc);
+    // Bond new shell facet to the two tetrahedra it is sandwiched
+    //   between.  Note that the facing tetrahedron 'oppotet' might be
+    //   equal to 'dummytet' (outer space), but the new shell facet is
+    //   bonded to it all the same.
+    tsbond(abcd, newshell);
+    sym(abcd, bace);
+    sesymself(newshell);
+    tsbond(bace, newshell);
+    if (autobondsegs) {
+      // Check if there exist subsegments at three edge of this new
+      //   subface. If so, set corresponding pointers in 'newshell' to
+      //   link these subsegments.
+      // Now 'abcd' and 'newshell' both locked at edge 'ab'.
+      for (i = 0; i < 3; i ++) {
+        enextself(abcd);
+        senextself(newshell);
+        tsspivot(&abcd, &bseg); // bseg = abcd.sspivot();
+        if (bseg.sh != dummysh) {
+          ssbond(newshell, bseg);
+        }
+      }
+    }
+    setmark(newshell, shellemark);
+    if (verbose > 2) {
+      printf("    Inserting new: ");
+      dump(&newshell);
+    }
+  } else {
+    // The exist shellface may be nonsolid(<0) or not have a marker(0), now
+    //   we can make it solid or set new shell's mark.
+    if (shellemark != NONSOLIDFLAG) {
+      if (isnonsolid(newshell) || (mark(newshell) == 0)) {
+        setmark(newshell, shellemark);
+      }
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertsubsegment()    Create a new subsegment and connect it to surround- //
+//                       ing subface.                                        //
+//                                                                           //
+// The new subsegment is created at the face described by the handle 'tet'.  //
+// Its vertices are properly initialized. The marker 'shellemark' is applied //
+// to the shell facet and, if appropriate, its vertices.                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::insertsubsegment(triface* tet, int shellemark)
+{
+  triface abcd, spintet;
+  face newseg, parentshell;
+  point3d pa, pb;
+  point3d tapex;
+  int hitbdry, subfacecount;
+
+  abcd = *tet;
+  adjustedgering(abcd, CCW);
+  org(abcd, pa);
+  dest(abcd, pb);
+  // Mark points if possible.
+  if (shellemark != NONSOLIDFLAG) {
+    if (pointmark(pa) == 0) {
+      setpointmark(pa, shellemark);
+    }
+    if (pointmark(pb) == 0) {
+      setpointmark(pb, shellemark);
+    }
+  }
+  // Check if there's already exist a subsegment at this face's side.
+  tsspivot(&abcd, &newseg); // newseg = abcd.sspivot();
+  if (newseg.sh == dummysh) {
+    // Make new subsegment and initialize its vertices.
+    makeshellface(&subsegs, &newseg);
+    setsorg(newseg, pb);
+    setsdest(newseg, pa);
+    setmark(newseg, shellemark);
+    // To insert this subsegment, spin around this edge, to find all surro-
+    //   unding subface and set connection between them. If there isn't
+    //   exist such subface, we need create a nonsolid subface, and insert
+    //   it to mesh for insert this subsegment.
+    spintet = abcd;
+    apex(abcd, tapex);
+    subfacecount = 0;
+    hitbdry = 0;
+    tspivot(spintet, parentshell);
+    if (parentshell.sh != dummysh) {
+      findversion(&parentshell, &spintet);
+      ssbond(parentshell, newseg);
+      subfacecount++;
+    }
+    while (true) {
+      if (fnextself(spintet)) {
+        if (apex(spintet) == tapex) {
+          break;  // Rewind, can leave now.
+        }
+        tspivot(spintet, parentshell);
+        if (parentshell.sh != dummysh) {
+          findversion(&parentshell, &spintet);
+          ssbond(parentshell, newseg);
+          subfacecount++;
+        }
+      } else {
+        hitbdry ++;
+        if(hitbdry >= 2) {
+          break;
+        } else {
+          esym(abcd, spintet);
+        }
+      }
+    }
+    if (subfacecount == 0) {
+      // Insert a new shell facet for holding the new subsegment.
+      if (verbose > 2) {
+        printf("    Inserting a nonsolid subface for holding subsegment.\n");
+      }
+      insertsubface(&abcd, NONSOLIDFLAG, 1);
+      tspivot(abcd, parentshell);
+      findversion(&parentshell, &abcd);
+      ssbond(parentshell, newseg);
+    }
+    if (verbose > 2) {
+      printf("    Inserting new: ");
+      dump(&newseg);
+    }
+  } else {
+    if (mark(newseg) == 0) {
+      setmark(newseg, shellemark);
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// deletesite()    Delete a vertex from a Delaunay triangulation, ensuring   //
+//                 that the triangulation remains Delaunay.                  //
+//                                                                           //
+// The origin of `deltet' is deleted. Only interior points that do not lie   //
+// on segments (shell edges) or boundaries may be deleted.                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::deletesite(triface *deltet)
+{
+  list *incitetlist, *incishlist;
+  list *equatorpointlist, *equatoredgelist;
+  list *northpointlist, *sourthpointlist;
+  list *equatorcasinglist;
+  list *northcasinglist, *sourthcasinglist;
+  list *northbacktracelist, *sourthbacktracelist;
+  triface *giftfaces;
+  triface *incitet, testtet, neighbortet;
+  face *incish,  testsh, testseg;
+  point3d *giftpoints;
+  point3d delorg, deldest, delapex;
+  point3d torg, tdest, tapex;
+  point3d tnorth;
+  triangulateio in, out;
+  REAL norm[3], xaxi[3], yaxi[3];
+  REAL v0[3], v1[3], dsin;
+  REAL *northattribs, *sourthattribs;
+  REAL northvolume, sourthvolume;
+  int *equatoredge, shellmark, add2north;
+  int bdrycount, bdry2count;
+  int orgori, destori, apexori;
+  int numberofgiftfaces, numberofgiftpoints;
+  int success;
+  int i, j, index;
+
+  testtet = *deltet;
+  delorg = org(testtet);
+  adjustedgering(testtet, CCW);
+  findorg(&testtet, delorg);
+
+  if (verbose > 1) {
+    printf("  Delete point from mesh: (%.12g, %.12g, %.12g) %d\n",
+           delorg[0], delorg[1], delorg[2], pointmark(delorg));
+  }
+
+  // Get all tetrahedra and subfaces which incidents to the delete point.
+  incitetlist = new list(sizeof(triface));
+  incishlist = new list(sizeof(face));
+  incitetlist->setcomp((compfunc) &compare2tets);
+  incishlist->setcomp((compfunc) &compare2shfaces);
+  bdrycount = bdry2count = 0;
+
+  if (verbose > 2) {
+    printf("    Queuing incident tet (%d, %d, %d, %d).\n",
+           pointmark(org(testtet)), pointmark(dest(testtet)),
+           pointmark(apex(testtet)), pointmark(oppo(testtet)));
+  }
+  incitetlist->append(&testtet);
+  symself(testtet);
+  if (testtet.tet != dummytet) {
+    adjustedgering(testtet, CCW);
+    findorg(&testtet, delorg);
+    if (verbose > 2) {
+      printf("    Queuing incident tet (%d, %d, %d, %d).\n",
+             pointmark(org(testtet)), pointmark(dest(testtet)),
+             pointmark(apex(testtet)), pointmark(oppo(testtet)));
+    }
+    incitetlist->append(&testtet);
+    tspivot(testtet, testsh);
+    if (testsh.sh != dummysh) {
+      if (!isnonsolid(testsh)) {
+        bdry2count++;
+        findorg(&testsh, delorg);
+        if (verbose > 2) {
+           printf("    Queuing incident face (%d, %d, %d) (inner).\n",
+                  pointmark(sorg(testsh)), pointmark(sdest(testsh)),
+                  pointmark(sapex(testsh)));
+        }
+        incishlist->append(&testsh);
+      }
+    }
+  } else {
+    tspivot(*deltet, testsh);
+    assert(testsh.sh != dummysh);
+    assert(!isnonsolid(testsh));
+    bdrycount++;
+    findorg(&testsh, delorg);
+    if (verbose > 2) {
+      printf("    Queuing incident boundary face (%d, %d, %d).\n",
+             pointmark(sorg(testsh)), pointmark(sdest(testsh)),
+             pointmark(sapex(testsh)));
+    }
+    incishlist->append(&testsh);
+  }
+  // Keep adding tets and subfaces incident on delpoint until they're
+  //   all there.
+  for (i = 0; i < incitetlist->len(); i++) {
+    incitet = (triface *)(* incitetlist)[i];
+    for (j = 0; j < 2; j++) {
+      testtet = *incitet;
+      if (j == 1) {
+        enext2self(testtet);
+      }
+      fnextself(testtet);
+      if (issymexist(&testtet)) {
+        symself(testtet);
+        if (incitetlist->hasitem(&testtet) == -1) {
+          // This tet need add to queue.
+          adjustedgering(testtet, CCW);
+          findorg(&testtet, delorg);
+          if (verbose > 2) {
+            printf("    Queuing incident tet (%d, %d, %d, %d).\n",
+                   pointmark(org(testtet)), pointmark(dest(testtet)),
+                   pointmark(apex(testtet)), pointmark(oppo(testtet)));
+          }
+          incitetlist->append(&testtet);
+          tspivot(testtet, testsh);
+          if (testsh.sh != dummysh) {
+            if (!isnonsolid(testsh)) {
+              bdry2count++;
+              findorg(&testsh, delorg);
+              if (verbose > 2) {
+                printf("    Queuing incident face (%d, %d, %d) (inner).\n",
+                       pointmark(sorg(testsh)), pointmark(sdest(testsh)),
+                       pointmark(sapex(testsh)));
+              }
+              incishlist->append(&testsh);
+            }
+          }
+        } else {
+          // This tet has been added to queue, we still need check if there
+          //   exist inner shell face at two side of this tet.
+          tspivot(testtet, testsh);
+          if (testsh.sh != dummysh) {
+            if (!isnonsolid(testsh)) {
+              if (incishlist->hasitem(&testsh) == -1) {
+                bdry2count++;
+                findorg(&testsh, delorg);
+                if (verbose > 2) {
+                  printf("    Queuing incident face (%d, %d, %d) (inner).\n",
+                         pointmark(sorg(testsh)), pointmark(sdest(testsh)),
+                         pointmark(sapex(testsh)));
+                }
+                incishlist->append(&testsh);
+              }
+            }
+          }
+        }
+      } else {
+        tspivot(testtet, testsh);
+        assert(testsh.sh != dummysh);
+        assert(!isnonsolid(testsh));
+        bdrycount++;
+        findorg(&testsh, delorg);
+        if (verbose > 2) {
+          printf("    Queuing incident boundary face (%d, %d, %d).\n",
+                 pointmark(sorg(testsh)), pointmark(sdest(testsh)),
+                 pointmark(sapex(testsh)));
+        }
+        incishlist->append(&testsh);
+      }
+    }
+  }
+
+  if (((bdry2count > 0) && (bdrycount > 0)) ||
+      ((bdry2count == 1) || (bdrycount == 1))) {
+    if (!quiet) {
+      printf("Warnning: ");
+      if ((bdry2count > 0) && (bdrycount > 0)) {
+        printf("Try to delete a point which seems locating on the");
+        printf(" intersection of two incident facets.\n");
+      } else {
+        printf("Try to delete a point which is an apex on boundary.\n");
+      }
+    }
+    delete incitetlist;
+    delete incishlist;
+    return 0;
+  }
+
+  if ((bdry2count > 0) || (bdrycount > 0)) {
+    if (verbose > 2) {
+      printf("    Generating a triangulation for coplanar subfaces.\n");
+    }
+    equatorpointlist = new list("point");
+    equatoredgelist = new list(sizeof(int) * 2);
+
+    testsh = *(face *)(* incishlist)[0];
+    assert(delorg == sorg(testsh));
+    deldest = sdest(testsh);
+    delapex = sapex(testsh);
+    equatorpointlist->append(&deldest);
+    equatorpointlist->append(&delapex);
+    equatoredge = (int*) equatoredgelist->alloc();
+    equatoredge[0] = 0;
+    equatoredge[1] = 1;
+    for (i = 1; i < incishlist->len(); i++) {
+      incish = (face *)(* incishlist)[i];
+      assert(delorg == sorg(*incish));
+      tdest = sdest(*incish);
+      tapex = sapex(*incish);
+#ifdef SELF_CHECK
+      if ((!iscoplane(delorg, deldest, delapex, tdest)) ||
+          (!iscoplane(delorg, deldest, delapex, tapex))) {
+        printf("Internal Error in deletesite(): Try to delete a point");
+        printf(" which is an apex on the boundary.\n");
+        internalerror();
+      }
+#endif // defined SELF_CHECK
+      equatoredge = (int*) equatoredgelist->alloc();
+      equatoredge[0] = equatorpointlist->hasitem(&tdest);
+      if (equatoredge[0] == -1) {
+        equatorpointlist->append(&tdest);
+        equatoredge[0] = equatorpointlist->len() - 1;
+      }
+      equatoredge[1] = equatorpointlist->hasitem(&tapex);
+      if (equatoredge[1] == -1) {
+        equatorpointlist->append(&tapex);
+        equatoredge[1] = equatorpointlist->len() - 1;
+      }
+    }
+    assert(equatorpointlist->len() > 0);
+    assert(equatoredgelist->len() > 0);
+    if (verbose > 2) {
+      printf("    There are %d points and %d segments at equator.\n",
+             equatorpointlist->len(), equatoredgelist->len());
+    }
+
+    triangulateioinit(&in);
+    triangulateioinit(&out);
+    in.numberofpoints = equatorpointlist->len();
+    in.pointlist = new REAL[in.numberofpoints * 2];
+    in.numberofsegments = equatoredgelist->len();
+    in.segmentlist = new int[in.numberofsegments * 2];
+    index = 0;
+    for (i = 0; i < in.numberofsegments; i ++) {
+      equatoredge = (int*) (*equatoredgelist)[i];
+      in.segmentlist[index++] = equatoredge[0];
+      in.segmentlist[index++] = equatoredge[1];
+    }
+    // Determine normal, verify closed polygon.
+    tdest = *(point3d*)(*equatorpointlist)[in.segmentlist[0]];
+    tapex = *(point3d*)(*equatorpointlist)[in.segmentlist[1]];
+    Sub3D(tapex, tdest, v0);
+    Normalize3D(v0);
+    index = 2;
+    dsin = 0;
+    for (i = 1; iszero(dsin); i++) {
+      tdest = *(point3d*)(*equatorpointlist)[in.segmentlist[index++]];
+      tapex = *(point3d*)(*equatorpointlist)[in.segmentlist[index++]];
+      Sub3D(tapex, tdest, v1);
+      Normalize3D(v1);
+      Cross3D(v0, v1, norm);
+      dsin = Mag3D(norm);
+      if (!iszero(dsin)) Scale3D(norm, 1./dsin);
+      if (i >= in.numberofsegments) {
+        printf("Internal Error in deletesite(): Can't find a normal.\n");
+        internalerror();
+      }
+    }
+    // Project onto a plane
+    Assign3D(v1, xaxi);
+    Cross3D(norm, xaxi, yaxi);
+    index = 0;
+    for (i = 0; i < in.numberofpoints; i ++) {
+      tdest = *(point*)(*equatorpointlist)[i];
+      in.pointlist[index++] = Dot3D(tdest, xaxi);
+      in.pointlist[index++] = Dot3D(tdest, yaxi);
+    }
+    // Now create the 2D mesh.
+    surfmesh->triangulate(&in, &out, NULL);
+    if (surfmesh->triangles.items <= 0) {
+      printf("Internal Error in deletesite(): Can't form a surface");
+      printf(" triangulation.\n");
+      internalerror();
+    }
+    if (verbose > 2) {
+      printf("    Triangulation result: %d triangles.\n",
+             surfmesh->triangles.items);
+    }
+    surfmesh->trianglerestart();
+  }
+
+  if (verbose > 2) {
+    printf("    Identify the casing faces at north");
+  }
+  northpointlist = new list("point");
+  northcasinglist = new list(sizeof(triface));
+  if (bdry2count > 0) {
+    if (verbose > 2) {
+      printf(" and sourth.\n");
+    }
+    sourthpointlist = new list("point");
+    sourthcasinglist = new list(sizeof(triface));
+    for (i = 0; i < incitetlist->len(); i++) {
+      testtet = *(triface *)(* incitetlist)[i];
+      enextfnextself(testtet);
+      tspivot(testtet, testsh);
+      torg = org(testtet);
+      tdest = dest(testtet);
+      tapex = apex(testtet);
+      orgori = iorient3d(delorg, deldest, delapex, torg);
+      destori = iorient3d(delorg, deldest, delapex, tdest);
+      apexori = iorient3d(delorg, deldest, delapex, tapex);
+      add2north = 1;
+      if (orgori != 0) {
+        if (orgori < 0) {
+          if (northpointlist->hasitem(&torg) == -1) {
+            northpointlist->append(&torg);
+          }
+        } else {
+          if (sourthpointlist->hasitem(&torg) == -1) {
+            sourthpointlist->append(&torg);
+          }
+          add2north = 0;
+        }
+      }
+      if (destori != 0) {
+        if (destori < 0) {
+          if (northpointlist->hasitem(&tdest) == -1) {
+            northpointlist->append(&tdest);
+          }
+        } else {
+          if (sourthpointlist->hasitem(&tdest) == -1) {
+            sourthpointlist->append(&tdest);
+          }
+          add2north = 0;
+        }
+      }
+      if (apexori != 0) {
+        if (apexori < 0) {
+          if (northpointlist->hasitem(&tapex) == -1) {
+            northpointlist->append(&tapex);
+          }
+        } else {
+          if (sourthpointlist->hasitem(&tapex) == -1) {
+            sourthpointlist->append(&tapex);
+          }
+          add2north = 0;
+        }
+      }
+      symself(testtet);
+      if (testtet.tet == dummytet) {
+        assert (testsh.sh != dummysh);
+        maketetrahedron(&testtet);
+        setorg(testtet, torg);
+        setdest(testtet, tdest);
+        setapex(testtet, tapex);
+        sesymself(testsh);
+        tsbond(testtet, testsh);
+        if (verbose > 2) {
+          printf("    Creating a fake tet for holding face(%d, %d, %d).\n",
+                 pointmark(torg), pointmark(tdest), pointmark(tapex));
+        }
+      }
+      adjustedgering(testtet, CCW);
+      if (add2north) {
+        if (verbose > 2) {
+          printf("    Queuing northcasing face (%d, %d, %d).\n",
+                 pointmark(org(testtet)), pointmark(dest(testtet)),
+                 pointmark(apex(testtet)));
+        }
+        northcasinglist->append(&testtet);
+      } else {
+        if (verbose > 2) {
+          printf("    Queuing sourthcasing face (%d, %d, %d).\n",
+                 pointmark(org(testtet)), pointmark(dest(testtet)),
+                 pointmark(apex(testtet)));
+        }
+        sourthcasinglist->append(&testtet);
+      }
+    }
+    assert(sourthcasinglist->len() > 0);
+    if (verbose > 2) {
+      printf("    There are %d points at sourth.\n", sourthpointlist->len());
+    }
+  } else {
+    if (verbose > 2) {
+      printf(".\n");
+    }
+    for (i = 0; i < incitetlist->len(); i++) {
+      testtet = *(triface *)(* incitetlist)[i];
+      enextfnextself(testtet);
+      tspivot(testtet, testsh);
+      torg = org(testtet);
+      tdest = dest(testtet);
+      tapex = apex(testtet);
+      if (bdrycount > 0) {
+        if (equatorpointlist->hasitem(&torg) == -1) {
+          if (northpointlist->hasitem(&torg) == -1) {
+            northpointlist->append(&torg);
+          }
+        }
+        if (equatorpointlist->hasitem(&tdest) == -1) {
+          if (northpointlist->hasitem(&tdest) == -1) {
+            northpointlist->append(&tdest);
+          }
+        }
+        if (equatorpointlist->hasitem(&tapex) == -1) {
+          if (northpointlist->hasitem(&tapex) == -1) {
+            northpointlist->append(&tapex);
+          }
+        }
+      } else {
+        if (northpointlist->hasitem(&torg) == -1) {
+          northpointlist->append(&torg);
+        }
+        if (northpointlist->hasitem(&tdest) == -1) {
+          northpointlist->append(&tdest);
+        }
+        if (northpointlist->hasitem(&tapex) == -1) {
+          northpointlist->append(&tapex);
+        }
+      }
+      symself(testtet);
+      if (testtet.tet == dummytet) {
+        assert (testsh.sh != dummysh);
+        maketetrahedron(&testtet);
+        setorg(testtet, torg);
+        setdest(testtet, tdest);
+        setapex(testtet, tapex);
+        sesymself(testsh);
+        tsbond(testtet, testsh);
+        if (verbose > 2) {
+          printf("    Creating a fake tet for holding face(%d, %d, %d).\n",
+                 pointmark(torg), pointmark(tdest), pointmark(tapex));
+        }
+      }
+      adjustedgering(testtet, CCW);
+      if (verbose > 2) {
+        printf("    Queuing northcasing face (%d, %d, %d).\n",
+               pointmark(org(testtet)), pointmark(dest(testtet)),
+               pointmark(apex(testtet)));
+      }
+      northcasinglist->append(&testtet);
+    }
+  }
+  assert(northcasinglist->len() > 0);
+  if (verbose > 2) {
+    printf("    There are %d points at north.\n", northpointlist->len());
+  }
+
+  if (verbose > 2) {
+    printf("    Protecting subsegments process.\n");
+  }
+  for (i = 0; i < northcasinglist->len(); i++) {
+    testtet = *(triface*)(*northcasinglist)[i];
+    tspivot(testtet, testsh);
+    if (testsh.sh == dummysh) {
+      for (j = 0; j < 3; j++) {
+        tsspivot(&testtet, &testseg);
+        if (testseg.sh != dummysh) {
+          if (verbose > 2) {
+            printf("    Segment (%d, %d) needs protect.\n",
+                   pointmark(sorg(testseg)), pointmark(sdest(testseg)));
+          }
+          insertsubface(&testtet, NONSOLIDFLAG, 1);
+          break;
+        }
+        enextself(testtet);
+      }
+    } else {
+      // Bond all segments to this subface to ensure
+      //   the subsegment-subface bond.
+      for (j = 0; j < 3; j++) {
+        sspivot(testsh, testseg);
+        if (testseg.sh != dummysh) {
+          ssbond(testsh, testseg);
+        }
+        senextself(testsh);
+      }
+    }
+  }
+  if (bdry2count > 0) {
+    for (i = 0; i < sourthcasinglist->len(); i++) {
+      testtet = *(triface*)(*sourthcasinglist)[i];
+      tspivot(testtet, testsh);
+      if (testsh.sh == dummysh) {
+        for (j = 0; j < 3; j++) {
+          tsspivot(&testtet, &testseg);
+          if (testseg.sh != dummysh) {
+            if (verbose > 2) {
+              printf("    Segment (%d, %d) needs protect.\n",
+                     pointmark(sorg(testseg)), pointmark(sdest(testseg)));
+            }
+            insertsubface(&testtet, NONSOLIDFLAG, 1);
+            break;
+          }
+          enextself(testtet);
+        }
+      } else {
+        // Bond all segments of to this subface to ensure
+        //   the subsegment-subface bond.
+        for (j = 0; j < 3; j++) {
+          sspivot(testsh, testseg);
+          if (testseg.sh != dummysh) {
+            ssbond(testsh, testseg);
+          }
+          senextself(testsh);
+        }
+      }
+    }
+  }
+
+  // Keep shellmark for subfaces.
+  if ((bdrycount > 0) || (bdry2count > 0)) {
+    incish = (face*)(*incishlist)[0];
+    shellmark = mark(*incish);
+#ifdef SELF_CHECK
+    for (i = 1; i < incishlist->len(); i++) {
+      incish = (face*)(*incishlist)[i];
+      if (shellmark != mark(*incish)) {
+        printf("Internal error in deletesite(): \n");
+        printf("  Try to delete a point which seems on a subsegment.\n");
+        internalerror();
+      }
+    }
+#endif // defined SELF_CHECK
+  }
+
+  // Keep attribs and varvolume for new tets.
+  if (eextras || varvolume) {
+    if (eextras > 0) {
+      northattribs = new REAL[eextras];
+      if (bdry2count > 0) {
+        sourthattribs = new REAL[eextras];
+      }
+    }
+    if (bdry2count > 0) {
+      // Find a incident tet which belong to sourth side.
+      incish = (face*)(*incishlist)[0];
+      // This is sourth side. (Above we use the first shell face as horiz).
+      stpivot(*incish, testtet);
+#ifdef SELF_CHECK
+      assert(isbelowplane(delorg, deldest, delapex, oppo(testtet)));
+#endif // defined SELF_CHECK
+      for (i = 0; i < eextras; i++) {
+        sourthattribs[i] = elemattribute(testtet.tet, i);
+      }
+      if (varvolume) {
+        sourthvolume = volumebound(testtet.tet);
+      }
+      // Set north side.
+      symself(testtet);
+      assert(testtet.tet != dummytet);
+      for (i = 0; i < eextras; i++) {
+        northattribs[i] = elemattribute(testtet.tet, i);
+      }
+      if (varvolume) {
+        northvolume = volumebound(testtet.tet);
+      }
+    } else {
+      incitet = (triface*)(*incitetlist)[0];
+      // There only north side.
+      for (i = 0; i < eextras; i++) {
+        northattribs[i] = elemattribute(incitet->tet, i);
+      }
+      if (varvolume) {
+        northvolume = volumebound(incitet->tet);
+      }
+    }
+  } else {
+    northattribs = sourthattribs = NULL;
+    northvolume = sourthvolume = 0;
+  }
+
+  if ((bdrycount > 0) || (bdry2count > 0)) {
+    if (verbose > 2) {
+      printf("    Creating casing faces for holding subfaces on equator.\n");
+    }
+    equatorcasinglist = new list(sizeof(triface));
+    tnorth = *(point3d*)(*northpointlist)[0];
+    for (i = 0; i < out.numberoftriangles; i++) {
+      index = i * 3;
+      orgori = out.trianglelist[index++];
+      destori = out.trianglelist[index++];
+      apexori = out.trianglelist[index++];
+      torg = *(point3d*)(*equatorpointlist)[orgori];
+      tdest = *(point3d*)(*equatorpointlist)[destori];
+      tapex = *(point3d*)(*equatorpointlist)[apexori];
+      maketetrahedron(&testtet);
+      makeshellface(&subfaces, &testsh);
+      setmark(testsh, shellmark);
+      add2north = iorient3d(torg, tdest, tapex, tnorth);
+      assert(add2north != 0);
+      if (add2north < 0) {
+        setorg(testtet, tdest);
+        setdest(testtet, torg);
+        setsorg(testsh, torg);
+        setsdest(testsh, tdest);
+      } else {
+        setorg(testtet, torg);
+        setdest(testtet, tdest);
+        setsorg(testsh, tdest);
+        setsdest(testsh, torg);
+      }
+      setapex(testtet, tapex);
+      setsapex(testsh, tapex);
+      tsbond(testtet, testsh);
+      if (verbose > 2) {
+        printf("    Creating and queuing equator casing face (%d, %d, %d).\n",
+               pointmark(org(testtet)), pointmark(dest(testtet)),
+               pointmark(apex(testtet)));
+        printf("    Creating and bonding equator subface (%d, %d, %d).\n",
+               pointmark(sorg(testsh)), pointmark(sdest(testsh)),
+               pointmark(sapex(testsh)));
+      }
+      equatorcasinglist->append(&testtet);
+    }
+    assert(equatorcasinglist->len() > 0);
+  }
+
+  if ((bdrycount > 0) || (bdry2count > 0)) {
+    numberofgiftfaces = equatorcasinglist->len() + northcasinglist->len();
+    numberofgiftpoints = equatorpointlist->len() + northpointlist->len();
+  } else {
+    numberofgiftfaces = northcasinglist->len();
+    numberofgiftpoints = northpointlist->len();
+  }
+  giftfaces = new triface[numberofgiftfaces];
+  giftpoints = new point3d[numberofgiftpoints];
+  // Create a backtrace list to keep all new tets be created during
+  //   gift-wrapping stage, so we can delete them if gift-wrapping failed.
+  northbacktracelist = new list(sizeof(triface));
+
+  if ((bdrycount > 0) || (bdry2count > 0)) {
+    //   Generate giftfaces.
+    for (i = 0; i < equatorcasinglist->len(); i++) {
+      giftfaces[i] = *(triface*)(*equatorcasinglist)[i];
+    }
+    for (j = i; j < numberofgiftfaces; j++) {
+      giftfaces[j] = *(triface*)(*northcasinglist)[j - i];
+    }
+    //   Generate giftpoints.
+    for (i = 0; i < equatorpointlist->len(); i++) {
+      giftpoints[i] = *(point3d*)(*equatorpointlist)[i];
+    }
+    for (j = i; j < numberofgiftpoints; j++) {
+      giftpoints[j] = *(point3d*)(*northpointlist)[j - i];
+    }
+  } else {
+    //   Generate giftfaces.
+    for (i = 0; i < numberofgiftfaces; i++) {
+      giftfaces[i] = *(triface*)(*northcasinglist)[i];
+    }
+    //   Generate giftpoints.
+    for (i = 0; i < numberofgiftpoints; i++) {
+      giftpoints[i] = *(point3d*)(*northpointlist)[i];
+    }
+  }
+
+  success = giftwrapping(numberofgiftfaces, giftfaces, numberofgiftpoints,
+                         giftpoints, northattribs, northvolume,
+                         northbacktracelist);
+
+  if ((bdry2count > 0) && success) {
+    if (verbose > 2) {
+      printf("    Removing and replacing fake tets at equator with real tets.\n");
+    }
+    for (i = 0; i < equatorcasinglist->len(); i++) {
+      incitet = (triface*)(*equatorcasinglist)[i];
+      assert(oppo(*incitet) == (point3d) NULL);
+      sym(*incitet, testtet);
+      tspivot(*incitet, testsh);
+      dissolve(testtet);
+      stdissolve(testsh);
+      // Remove fake tet.
+      tetrahedrondealloc(incitet->tet);
+      // Replace fake tet with a real tet.
+      adjustedgering(testtet, CCW);
+      *incitet = testtet;
+      if (verbose > 2) {
+        printf("    Changing (%d, %d, %d).\n", pointmark(org(testtet)),
+               pointmark(dest(testtet)), pointmark(apex(testtet)));
+      }
+    }
+    delete [] giftfaces;
+    delete [] giftpoints;
+
+    numberofgiftfaces = equatorcasinglist->len() + sourthcasinglist->len();
+    numberofgiftpoints = equatorpointlist->len() + sourthpointlist->len();
+    giftfaces = new triface[numberofgiftfaces];
+    giftpoints = new point3d[numberofgiftpoints];
+    // Create a backtrace list to keep all new tets be created during
+    //   gift-wrapping stage, so we can delete them if gift-wrapping failed.
+    sourthbacktracelist = new list(sizeof(triface));
+
+    //   Generate giftfaces.
+    for (i = 0; i < equatorcasinglist->len(); i++) {
+      giftfaces[i] = *(triface*)(*equatorcasinglist)[i];
+    }
+    for (j = i; j < numberofgiftfaces; j++) {
+      giftfaces[j] = *(triface*)(*sourthcasinglist)[j - i];
+    }
+    //   Generate giftpoints.
+    for (i = 0; i < equatorpointlist->len(); i++) {
+      giftpoints[i] = *(point3d*)(*equatorpointlist)[i];
+    }
+    for (j = i; j < numberofgiftpoints; j++) {
+      giftpoints[j] = *(point3d*)(*sourthpointlist)[j - i];
+    }
+
+    success = giftwrapping(numberofgiftfaces, giftfaces, numberofgiftpoints,
+                           giftpoints, sourthattribs, sourthvolume,
+                           sourthbacktracelist);
+    if (!success) {
+      if (verbose > 2) {
+        printf("    Badly, gift-wrapping failed, clear all new tets that");
+        printf(" created at sourthcasing.\n");
+      }
+      // Removing new subfaces at equators first. Because after new tets
+      //   being removed, subfaces will no holder.
+      for (i = 0; i < equatorcasinglist->len(); i++) {
+        testtet = *(triface*)(*equatorcasinglist)[i];
+        tspivot(testtet, testsh);
+        assert(testsh.sh != dummysh);
+        shellfacedealloc(&subfaces, testsh.sh);
+      }
+      // Clear equatorcasinglist to avoid deallocate subfaces twice.
+      equatorcasinglist->clear();
+      // Dealloc all new tets in which created during gift-wrapping.
+      for (i = 0; i < sourthbacktracelist->len(); i++) {
+        incitet = (triface*)(*sourthbacktracelist)[i];
+        if (verbose > 2) {
+          printf("    Deleting new tet (%d, %d, %d, %d).\n",
+                 pointmark(org(*incitet)), pointmark(dest(*incitet)),
+                 pointmark(apex(*incitet)), pointmark(oppo(*incitet)));
+        }
+        tetrahedrondealloc(incitet->tet);
+      }
+    }
+  }
+
+  if (!success) {
+    if (verbose > 2) {
+      printf("    Badly, gift-wrapping failed, clear all new tets that");
+      printf(" created during gift-wrapping.\n");
+    }
+    if ((bdrycount > 0) || (bdry2count > 0)) {
+      // Removing new subfaces at equators.
+      for (i = 0; i < equatorcasinglist->len(); i++) {
+        testtet = *(triface*)(*equatorcasinglist)[i];
+        tspivot(testtet, testsh);
+        assert(testsh.sh != dummysh);
+        shellfacedealloc(&subfaces, testsh.sh);
+        // It's a equator casing fake tet, delete it.
+        tetrahedrondealloc(testtet.tet);
+      }
+      equatorcasinglist->clear();
+    }
+    for (i = 0; i < northbacktracelist->len(); i++) {
+      incitet = (triface*)(*northbacktracelist)[i];
+      if (verbose > 2) {
+        printf("    Deleting new tet (%d, %d, %d, %d).\n",
+               pointmark(org(*incitet)), pointmark(dest(*incitet)),
+               pointmark(apex(*incitet)), pointmark(oppo(*incitet)));
+      }
+      tetrahedrondealloc(incitet->tet);
+    }
+  }
+
+  if (success) {
+    if (verbose > 2) {
+      printf("    Deleting all incident tets and incident faces.\n");
+    }
+    for (i = 0; i < incitetlist->len(); i++) {
+      incitet = (triface*)(*incitetlist)[i];
+      if (verbose > 2) {
+        printf("    Deleting tet (%d, %d, %d, %d).\n",
+               pointmark(org(*incitet)), pointmark(dest(*incitet)),
+               pointmark(apex(*incitet)), pointmark(oppo(*incitet)));
+      }
+      tspivot(*incitet, testsh);
+      if (testsh.sh != dummysh) {
+        if (verbose > 2) {
+          printf("    Deleting subface (%d, %d, %d).\n",
+                 pointmark(sorg(testsh)), pointmark(sdest(testsh)),
+                 pointmark(sapex(testsh)));
+        }
+        sym(*incitet, neighbortet);
+        tsdissolve(neighbortet);
+        shellfacedealloc(&subfaces, testsh.sh);
+      }
+      fnext(*incitet, testtet);
+      tspivot(testtet, testsh);
+      if (testsh.sh != dummysh) {
+        if (verbose > 2) {
+          printf("    Deleting subface (%d, %d, %d).\n",
+                 pointmark(sorg(testsh)), pointmark(sdest(testsh)),
+                 pointmark(sapex(testsh)));
+        }
+        sym(testtet, neighbortet);
+        tsdissolve(neighbortet);
+        shellfacedealloc(&subfaces, testsh.sh);
+      }
+      enext2(*incitet, testtet);
+      fnextself(testtet);
+      tspivot(testtet, testsh);
+      if (testsh.sh != dummysh) {
+        if (verbose > 2) {
+          printf("    Deleting subface (%d, %d, %d).\n",
+                 pointmark(sorg(testsh)), pointmark(sdest(testsh)),
+                 pointmark(sapex(testsh)));
+        }
+        sym(testtet, neighbortet);
+        tsdissolve(neighbortet);
+        shellfacedealloc(&subfaces, testsh.sh);
+      }
+      tetrahedrondealloc(incitet->tet);
+    }
+
+    // Now we can delete the point.
+    pointdealloc(delorg);
+    if (bdrycount > 0) {
+      // Deleting the boundary point decreases the number of boundary faces.
+      hullsize -= 2;
+    }
+  } else {
+    // Gift-wrapping failed, we need restore original configuration.
+    //   This time, all tets in 'incitetlist' are still keep the pointers
+    //   to its casing face, use this pointers to restore original config-
+    //   uration.
+    if (verbose > 2) {
+      printf("    Fail to delete point, restoring original configuration.\n");
+    }
+    for (i = 0; i < incitetlist->len(); i++) {
+      incitet = (triface*)(*incitetlist)[i];
+      enextfnextself(*incitet);
+      // Get and bond its casing face if its not a 'dummytet'.
+      sym(*incitet, testtet);
+      if (testtet.tet != dummytet) {
+        bond(*incitet, testtet);
+      }
+      // Get and bond the subface if its not a 'dummysh'.
+      tspivot(*incitet, testsh);
+      if (testsh.sh != dummysh) {
+        tsbond(*incitet, testsh);;
+      }
+    }
+  }
+
+  // Whatever success or not success, we must do the following step.
+  if (verbose > 2) {
+    printf("    Removing and replacing fake tets in north with dummytet.\n");
+  }
+  for (i = 0; i < northcasinglist->len(); i++) {
+    testtet = *(triface*)(*northcasinglist)[i];
+    if (oppo(testtet) == (point3d) NULL) {
+      if (verbose > 2) {
+        printf("    Changing (%d, %d, %d).\n", pointmark(org(testtet)),
+               pointmark(dest(testtet)), pointmark(apex(testtet)));
+      }
+      if (success) {
+        // Here do dissolve only success == 1.
+        sym(testtet, neighbortet);
+        dissolve(neighbortet);
+      }
+      tspivot(testtet, testsh);
+      if (testsh.sh != dummysh) {
+        stdissolve(testsh);
+      }
+      tetrahedrondealloc(testtet.tet);
+      testtet = neighbortet;
+      if (shflaws && success) {
+        uncheckedshlist->append(&testsh);
+      }
+    }
+    // Ensure adjoining tets quality at casing face.
+    if (tetflaws && success) {
+      uncheckedtetlist->append(&testtet);
+      sym(testtet, neighbortet);
+      if (neighbortet.tet != dummytet) {
+        uncheckedtetlist->append(&neighbortet);
+      }
+    }
+  }
+
+  if (bdry2count > 0) {
+    if (verbose > 2) {
+      printf("    Removing and replacing fake tets in sourth with dummytet.\n");
+    }
+    for (i = 0; i < sourthcasinglist->len(); i++) {
+      testtet = *(triface*)(*sourthcasinglist)[i];
+      if (oppo(testtet) == (point3d) NULL) {
+        // This is a fake tet, delete it and set it be 'dummytet'.
+        if (verbose > 2) {
+          printf("    Changing (%d, %d, %d).\n",
+                 pointmark(org(testtet)), pointmark(dest(testtet)),
+                 pointmark(apex(testtet)));
+        }
+        if (success) {
+          // Here do dissolve only success == 1.
+          sym(testtet, neighbortet);
+          dissolve(neighbortet);
+        }
+        tspivot(testtet, testsh);
+        if (testsh.sh != dummysh) {
+          stdissolve(testsh);
+        }
+        tetrahedrondealloc(testtet.tet);
+        testtet = neighbortet;
+        if (shflaws && success) {
+          uncheckedshlist->append(&testsh);
+        }
+      }
+      // Ensure adjoining tets quality at casing face.
+      if (tetflaws && success) {
+        uncheckedtetlist->append(&testtet);
+        sym(testtet, neighbortet);
+        if (neighbortet.tet != dummytet) {
+          uncheckedtetlist->append(&neighbortet);
+        }
+      }
+    }
+  }
+
+  if ((bdrycount > 0) || (bdry2count > 0)) {
+    if (verbose > 2) {
+      printf("    Bonding subsegments to equator subfaces.\n");
+    }
+    for (i = 0; i < equatorcasinglist->len(); i++) {
+      testtet = *(triface*)(*equatorcasinglist)[i];
+      tspivot(testtet, testsh);
+      // For keep the same enext() direction.
+      findversion(&testsh, org(testtet), dest(testtet), 0);
+      for (j = 0; j < 3; j++) {
+        tsspivot(&testtet, &testseg);
+        if (testseg.sh != dummysh) {
+          ssbond(testsh, testseg);
+        }
+        enextself(testtet);
+        senextself(testsh);
+      }
+      // Check quality if need.
+      if (shflaws && success) {
+        uncheckedshlist->append(&testsh);
+      }
+      if (bdry2count == 0) {
+        // Remove and replacing fake tet at equator with 'dummytet'.
+        sym(testtet, neighbortet);
+        dissolve(neighbortet);
+        tspivot(testtet, testsh);
+        if (testsh.sh != dummysh) {
+          stdissolve(testsh);
+        }
+        tetrahedrondealloc(testtet.tet);
+        testtet = neighbortet;
+      }
+      if (tetflaws && success) {
+        uncheckedtetlist->append(&testtet);
+        if (bdry2count > 0) {
+          symself(testtet);
+          uncheckedtetlist->append(&testtet);
+        }
+      }
+    }
+  }
+
+  if (!success && docheck) {
+    checkmesh();
+    checkshells();
+  }
+
+  delete [] giftfaces;
+  delete [] giftpoints;
+  delete incitetlist;
+  delete incishlist;
+  delete northpointlist;
+  delete northcasinglist;
+  delete northbacktracelist;
+  if ((bdrycount > 0) || (bdry2count > 0)) {
+    delete equatorpointlist;
+    delete equatoredgelist;
+    delete equatorcasinglist;
+    if (bdry2count > 0) {
+      delete sourthpointlist;
+      delete sourthcasinglist;
+      delete sourthbacktracelist;
+    }
+  }
+  if (eextras) {
+    delete [] northattribs;
+    if (bdry2count > 0) {
+      delete [] sourthattribs;
+    }
+  }
+  return success;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// Insert/Delete point routines                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// Giftwrapping Algorithm Implementation                                     //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Using gift-wrapping algorithm to construct a constrained Delaunay         //
+// triangulation for input triangular faces bounded polyhedras.              //
+//                                                                           //
+//   Gift-wrapping (also called pivoting or incremental search) algorithm    //
+// can be used to solve Convex Hull(CH) problem, construct Delaunay Triangu- //
+// lation(DT) and Constrained Delaunay Triangulation(CDT) in d-dimension.    //
+//                                                                           //
+//   To construct three-dimensional CDT, gift-wrapping begins by finding a   //
+// single constrained Delaunay tetrahedron, upon which the remaining         //
+// Delaunay tetrahedras crystallize one by one. Say that a constraining      //
+// triangluar face of a Delaunay tetrahedron is UNFINISHED if the algorithm  //
+// has not yet identified the other Delaunay tetrahedron that shares the     //
+// face. To finish a face is to find the other tetrahedron, one must test    //
+// the visibility of each vertex from that face, If the face lies in the     //
+// boundary of the input, the face becomes finished when the algorithm       //
+// recognizes that there is no other adjoining tetrahedron.                  //
+//                                                                           //
+//   Generally, the running time for constructing a CDT using gift-wrapping  //
+// is O(nv*nf*ns), where nv is the number of input vertexs, nf is the number //
+// of constraining triangluar face and ns is the number of final tetrahedra. //
+// There have many variant implementations of this algorithm to improve the  //
+// poor time complexity of general gift-wrapping. Although in practice, gift //
+// -wrapping is not very suitable for constructing CDT. But if the vertexs'  //
+// and constraining faces number are tipically small, the performance of the //
+// algorithm used is not critical, our improved implementation of gift-      //
+// wrapping will suffice.                                                    //
+//                                                                           //
+//   The main idea in achieving an optimal result of gift-wrapping algorithm //
+// is that of eliminating redundant computations. Observe for each           //
+// UNFINISHED face, we must find a best visible vertex that can form a       //
+// constrained Delaunay tetrahedron with this face. For each visible vertex,  //
+// we need check all other constraining faces to see if they are obstructed  //
+// the visibility of vertex from the face. If we have known some of these    //
+// constraining faces can not obstructed the visibility of vertex in advance,//
+// we could have same time not to compute them.                              //
+//                                                                           //
+//   For this purpose, I use a Weighted-Vertex approach, which is widely     //
+// used in variety of graph algorithms, to help us determine whether a face  //
+// can be safely skipped. At first each vertex's weight is the number of     //
+// edges connected at this vertex. So all vertex's weight must great or      //
+// equal than 3. During the procedure of gift-wrapping, the weight of vertex //
+// will decrease 1 when an UNFINISHED face(contains this vertex) becaomes    //
+// finished, and increase 1 when a new UNFINISHED face(contains this vertex) //
+// be generated. Then, if a face contains a vertex with Zero-weight, it      //
+// means the face has already been finished, so it has no chance to obstruct //
+// other vertex(Remember the meaning of CDT), we can saftly skip this face   //
+// in later computing. The weight of vertex also can help us in chossing a   //
+// best face to start and chossing a best vertex when there exist more than  //
+// one visible vertexs. Please see the functions getgiftface() and           //
+// getgiftpoint() for a detail description.                                  //
+//                                                                           //
+//   At last, there need do a lot of triangle-triangle intersection tests in //
+// finding a best vertex to finish a face. I use the codes of Tomas Moller   //
+// directly to do the tests, see below.                                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// Triangle/triangle intersection test routine, by Tomas Moller.             //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Triangle/triangle intersection test routine,                              //
+// by Tomas Moller, 1997.                                                    //
+// See article "A Fast Triangle-Triangle Intersection Test",                 //
+// Journal of Graphics Tools, 2(2), 1997                                     //
+//                                                                           //
+// int tri_tri_intersect(REAL V0[3], REAL V1[3], REAL V2[3],                 //
+//                       REAL U0[3], REAL U1[3], REAL U2[3])                 //
+//                                                                           //
+// parameters: vertices of triangle 1: V0,V1,V2                              //
+//             vertices of triangle 2: U0,U1,U2                              //
+// result    : returns 1 if the triangles intersect, otherwise 0             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// fuzzycomp_interval()    Compare two floating-point values dx and dy.      //
+//                                                                           //
+// Return +1 if dx > dy; Return -1 if dx < dy; Return  0 if dx == dy.        //
+//                                                                           //
+// Si hang added this function for compare intervals. July, 2001.            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int fuzzycomp_interval(REAL dA, REAL dB)
+{
+  REAL dSum, dDiff;
+  REAL dTol = 5.e-9;
+  REAL dFloor = 1.e-6;
+
+  dSum  = fabs(dA) + fabs(dB);
+  dDiff = dA - dB;
+  dSum = (dSum > dFloor) ? dSum : dFloor;
+  if (dDiff > dTol * dSum) return 1;
+  else if (dDiff < - dTol * dSum) return -1;
+  else return 0;
+}
+
+// if USE_EPSILON_TEST is true then we do a check:
+//   if |dv|<EPSILON then dv=0.0;
+// else no check is done (which is less robust)
+
+#define USE_EPSILON_TEST TRUE
+#define EPSILON 1e-7
+
+// some macros
+#define CROSS(dest,v1,v2)                                                  \
+  dest[0]=v1[1]*v2[2]-v1[2]*v2[1];                                         \
+  dest[1]=v1[2]*v2[0]-v1[0]*v2[2];                                         \
+  dest[2]=v1[0]*v2[1]-v1[1]*v2[0];
+
+#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
+
+#define SUB(dest,v1,v2)                                                    \
+  dest[0]=v1[0]-v2[0];                                                     \
+  dest[1]=v1[1]-v2[1];                                                     \
+  dest[2]=v1[2]-v2[2];
+
+// sort so that a<=b
+#define SORT(a,b)                                                          \
+  if(a>b) {                                                                \
+    REAL c;                                                                \
+    c=a; a=b; b=c;                                                         \
+  }
+
+#define ISECT(VV0,VV1,VV2,D0,D1,D2,isect0,isect1)                          \
+  isect0=VV0+(VV1-VV0)*D0/(D0-D1);                                         \
+  isect1=VV0+(VV2-VV0)*D0/(D0-D2);
+
+#define COMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,isect0,isect1)    \
+  if(D0D1>0.0f)                                                            \
+  {                                                                        \
+    /* here we know that D0D2<=0.0 */                                      \
+/* that is D0, D1 are on the same side, D2 on the other or on the plane */ \
+    ISECT(VV2,VV0,VV1,D2,D0,D1,isect0,isect1);                             \
+  }                                                                        \
+  else if(D0D2>0.0f)                                                       \
+  {                                                                        \
+    /* here we know that d0d1<=0.0 */                                      \
+    ISECT(VV1,VV0,VV2,D1,D0,D2,isect0,isect1);                             \
+  }                                                                        \
+  else if(D1*D2>0.0f || D0!=0.0f)                                          \
+  {                                                                        \
+    /* here we know that d0d1<=0.0 or that D0!=0.0 */                      \
+    ISECT(VV0,VV1,VV2,D0,D1,D2,isect0,isect1);                             \
+  }                                                                        \
+  else if(D1!=0.0f)                                                        \
+  {                                                                        \
+    ISECT(VV1,VV0,VV2,D1,D0,D2,isect0,isect1);                             \
+  }                                                                        \
+  else if(D2!=0.0f)                                                        \
+  {                                                                        \
+    ISECT(VV2,VV0,VV1,D2,D0,D1,isect0,isect1);                             \
+  }                                                                        \
+  else                                                                     \
+  {                                                                        \
+    /* triangles are coplanar */                                           \
+    return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2);                         \
+  }
+
+// this edge to edge test is based on Franlin Antonio's gem:
+//   "Faster Line Segment Intersection", in Graphics Gems III,
+//   pp. 199-202
+#define EDGE_EDGE_TEST(V0,U0,U1)                                           \
+  Bx=U0[i0]-U1[i0];                                                        \
+  By=U0[i1]-U1[i1];                                                        \
+  Cx=V0[i0]-U0[i0];                                                        \
+  Cy=V0[i1]-U0[i1];                                                        \
+  f=Ay*Bx-Ax*By;                                                           \
+  d=By*Cx-Bx*Cy;                                                           \
+  if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f))                       \
+  {                                                                        \
+    e=Ax*Cy-Ay*Cx;                                                         \
+    if(f>0)                                                                \
+    {                                                                      \
+      if(e>=0 && e<=f) return 1;                                           \
+    }                                                                      \
+    else                                                                   \
+    {                                                                      \
+      if(e<=0 && e>=f) return 1;                                           \
+    }                                                                      \
+  }
+
+#define EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2)                             \
+{                                                                          \
+  REAL Ax,Ay,Bx,By,Cx,Cy,e,d,f;                                            \
+  Ax=V1[i0]-V0[i0];                                                        \
+  Ay=V1[i1]-V0[i1];                                                        \
+  /* test edge U0,U1 against V0,V1 */                                      \
+  EDGE_EDGE_TEST(V0,U0,U1);                                                \
+  /* test edge U1,U2 against V0,V1 */                                      \
+  EDGE_EDGE_TEST(V0,U1,U2);                                                \
+  /* test edge U2,U1 against V0,V1 */                                      \
+  EDGE_EDGE_TEST(V0,U2,U0);                                                \
+}
+
+#define POINT_IN_TRI(V0,U0,U1,U2)                                          \
+{                                                                          \
+  REAL a,b,c,d0,d1,d2;                                                     \
+  /* is T1 completly inside T2? */                                         \
+  /* check if V0 is inside tri(U0,U1,U2) */                                \
+  a=U1[i1]-U0[i1];                                                         \
+  b=-(U1[i0]-U0[i0]);                                                      \
+  c=-a*U0[i0]-b*U0[i1];                                                    \
+  d0=a*V0[i0]+b*V0[i1]+c;                                                  \
+                                                                           \
+  a=U2[i1]-U1[i1];                                                         \
+  b=-(U2[i0]-U1[i0]);                                                      \
+  c=-a*U1[i0]-b*U1[i1];                                                    \
+  d1=a*V0[i0]+b*V0[i1]+c;                                                  \
+                                                                           \
+  a=U0[i1]-U2[i1];                                                         \
+  b=-(U0[i0]-U2[i0]);                                                      \
+  c=-a*U2[i0]-b*U2[i1];                                                    \
+  d2=a*V0[i0]+b*V0[i1]+c;                                                  \
+  if(d0*d1>0.0)                                                            \
+  {                                                                        \
+    if(d0*d2>0.0) return 1;                                                \
+  }                                                                        \
+}
+
+int coplanar_tri_tri(const REAL N[3],
+                     const REAL V0[3],const REAL V1[3],const REAL V2[3],
+                     const REAL U0[3],const REAL U1[3],const REAL U2[3])
+{
+   REAL A[3];
+   short i0,i1;
+   // first project onto an axis-aligned plane, that maximizes the area
+   //   of the triangles, compute indices: i0,i1.
+   A[0]=fabs(N[0]);
+   A[1]=fabs(N[1]);
+   A[2]=fabs(N[2]);
+   if(A[0]>A[1])
+   {
+      if(A[0]>A[2])
+      {
+          i0=1;      // A[0] is greatest
+          i1=2;
+      }
+      else
+      {
+          i0=0;      // A[2] is greatest
+          i1=1;
+      }
+   }
+   else   // A[0]<=A[1]
+   {
+      if(A[2]>A[1])
+      {
+          i0=0;      // A[2] is greatest
+          i1=1;
+      }
+      else
+      {
+          i0=0;      // A[1] is greatest
+          i1=2;
+      }
+    }
+
+    // test all edges of triangle 1 against the edges of triangle 2
+    EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2);
+    EDGE_AGAINST_TRI_EDGES(V1,V2,U0,U1,U2);
+    EDGE_AGAINST_TRI_EDGES(V2,V0,U0,U1,U2);
+
+    // finally, test if tri1 is totally contained in tri2 or vice versa
+    POINT_IN_TRI(V0,U0,U1,U2);
+    POINT_IN_TRI(U0,V0,V1,V2);
+
+    return 0;
+}
+
+
+int tri_tri_intersect(const REAL V0[3], const REAL V1[3], const REAL V2[3],
+                      const REAL U0[3], const REAL U1[3], const REAL U2[3])
+{
+  REAL E1[3],E2[3];
+  REAL N1[3],N2[3],d1,d2;
+  REAL du0,du1,du2,dv0,dv1,dv2;
+  REAL D[3];
+  REAL isect1[2], isect2[2];
+  REAL du0du1,du0du2,dv0dv1,dv0dv2;
+  short index;
+  REAL vp0,vp1,vp2;
+  REAL up0,up1,up2;
+  REAL b,c,max;
+
+  // compute plane equation of triangle(V0,V1,V2)
+  SUB(E1,V1,V0);
+  SUB(E2,V2,V0);
+  CROSS(N1,E1,E2);
+  d1=-DOT(N1,V0);
+  // plane equation 1: N1.X+d1=0
+
+  // put U0,U1,U2 into plane equation 1 to compute signed distances to
+  //   the plane
+  du0=DOT(N1,U0)+d1;
+  du1=DOT(N1,U1)+d1;
+  du2=DOT(N1,U2)+d1;
+
+  // coplanarity robustness check
+#if USE_EPSILON_TEST==TRUE
+  if(fabs(du0)<EPSILON) du0=0.0;
+  if(fabs(du1)<EPSILON) du1=0.0;
+  if(fabs(du2)<EPSILON) du2=0.0;
+#endif
+  du0du1=du0*du1;
+  du0du2=du0*du2;
+
+  if(du0du1>0.0f && du0du2>0.0f) // same sign on all of them + not equal 0 ?
+    return 0;                    // no intersection occurs
+
+  // compute plane of triangle (U0,U1,U2)
+  SUB(E1,U1,U0);
+  SUB(E2,U2,U0);
+  CROSS(N2,E1,E2);
+  d2=-DOT(N2,U0);
+  // plane equation 2: N2.X+d2=0
+
+  // put V0,V1,V2 into plane equation 2
+  dv0=DOT(N2,V0)+d2;
+  dv1=DOT(N2,V1)+d2;
+  dv2=DOT(N2,V2)+d2;
+
+#if USE_EPSILON_TEST==TRUE
+  if(fabs(dv0)<EPSILON) dv0=0.0;
+  if(fabs(dv1)<EPSILON) dv1=0.0;
+  if(fabs(dv2)<EPSILON) dv2=0.0;
+#endif
+
+  dv0dv1=dv0*dv1;
+  dv0dv2=dv0*dv2;
+
+  if(dv0dv1>0.0f && dv0dv2>0.0f) // same sign on all of them + not equal 0 ?
+    return 0;                    // no intersection occurs
+
+  // compute direction of intersection line
+  CROSS(D,N1,N2);
+
+  // compute and index to the largest component of D
+  max=fabs(D[0]);
+  index=0;
+  b=fabs(D[1]);
+  c=fabs(D[2]);
+  if(b>max) max=b,index=1;
+  if(c>max) max=c,index=2;
+
+  // this is the simplified projection onto L
+  vp0=V0[index];
+  vp1=V1[index];
+  vp2=V2[index];
+
+  up0=U0[index];
+  up1=U1[index];
+  up2=U2[index];
+
+  // compute interval for triangle 1
+  COMPUTE_INTERVALS(vp0,vp1,vp2,dv0,dv1,dv2,dv0dv1,dv0dv2,isect1[0],isect1[1]);
+
+  // compute interval for triangle 2
+  COMPUTE_INTERVALS(up0,up1,up2,du0,du1,du2,du0du1,du0du2,isect2[0],isect2[1]);
+
+  SORT(isect1[0],isect1[1]);
+  SORT(isect2[0],isect2[1]);
+
+  // Origin code,
+  // if(isect1[1]<isect2[0] || isect2[1]<isect1[0]) return 0;
+  // New code, changed by Si hang
+  if ((fuzzycomp_interval(isect1[1], isect2[0]) == -1) ||
+      (fuzzycomp_interval(isect2[1], isect1[0]) == -1)) return 0;
+  return 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Triangle/triangle intersection test routine, by Tomas Moller.             //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// struct giftface                                                           //
+//                                                                           //
+// A struct used to store a face for giftwrapping algorithm to construct     //
+// constrained Delaunay tetrahedralization. Where 'casing' is a handle of    //
+// unfinished face, and 'iorg', 'idest' and 'iapex' are vertex index in      //
+// pointweightlist. Use these values to get weights value for each vertices  //
+// of this giftface.                                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+typedef struct giftfacetype {
+  triface casing;
+  int iorg, idest, iapex;
+} giftface;
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dumpgifts()    Debug routine. Write current gift faces and gift points    //
+//                infomation to file.                                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::dumpgifts(char *gfile, list *giftfacelist, int numberofgiftpoints,
+                       point3d *giftpoints, int *pointweightlist)
+{
+  FILE *outfile;
+  giftface *gfaceptr;
+  int i;
+
+  outfile = fopen(gfile, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("  Error:  Cannot create file %s.\n", gfile);
+    return;
+  }
+  if (!quiet) {
+    printf("Writing %s.\n", gfile);
+  }
+  if (verbose < 1) {
+    numbernodes(1);
+  }
+  fprintf(outfile, "# Dumpping %d giftfaces.\n", giftfacelist->len());
+  for (i = 0; i < giftfacelist->len(); i++) {
+    gfaceptr = (giftface*)(*giftfacelist)[i];
+    fprintf(outfile, "%4d %4d %4d %4d  index %3d %3d %3d.\n", i,
+            pointmark(org(gfaceptr->casing)),
+            pointmark(dest(gfaceptr->casing)),
+            pointmark(apex(gfaceptr->casing)),
+            gfaceptr->iorg, gfaceptr->idest, gfaceptr->iapex);
+  }
+  fprintf(outfile, "# Dumpping %d giftpoints.\n", numberofgiftpoints);
+  for (i = 0; i < numberofgiftpoints; i++) {
+    fprintf(outfile, "%4d %4d %10.8g %10.8g %10.8g weight %4d.\n", i,
+            pointmark(giftpoints[i]), giftpoints[i][0], giftpoints[i][1],
+            giftpoints[i][2], pointweightlist[i]);
+  }
+  fclose(outfile);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// is_face_tet_inter_0()     Check if input face is intersecting with input  //
+//                           tetrahedron(given by its four vertexs). There   //
+//                           no shared points between face and tetrahedron.  //
+//                                                                           //
+// Take each faces of tetrahedron and do triangle-triangle intersection test //
+// with the input face. They are intersected if one of face pairs are inter- //
+// secting. If all face pairs are not intersecting, we still need to check   //
+// if the face is fully in the tetrahedron.                                  //
+//                                                                           //
+// Return 1 if they are intersecting each other. Otherwise, return zero.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::is_face_tet_inter_0(triface *checkface, point3d torg, point3d tdest,
+                                point3d tapex, point3d toppo)
+{
+  point3d forg, fdest, fapex;
+  int intersect;
+  int i;
+
+  org (*checkface, forg);
+  dest(*checkface, fdest);
+  apex(*checkface, fapex);
+
+  intersect = 0;
+  for (i = 0; i < 4; i++) {
+    if (i == 0) {
+      // 'checkface' must not intersect with base face. Remember, they are
+      //    both the input constraining faces.
+      // intersect = tri_tri_intersect(forg, fdest, fapex, torg, tdest, tapex);
+    } else if (i == 1) {
+      intersect = tri_tri_intersect(forg, fdest, fapex, torg, tdest, toppo);
+    } else if (i == 2) {
+      intersect = tri_tri_intersect(forg, fdest, fapex, tdest, tapex, toppo);
+    } else if (i == 3) {
+      intersect = tri_tri_intersect(forg, fdest, fapex, tapex, torg, toppo);
+    }
+    if (intersect) {
+      return 1;
+    }
+  }
+  // Check the face is located in the tetrahedron. That is to check each
+  //   vertex of face is located in tetrahedron. Because no face pair is
+  //   intersecting(above step guarantee this) and not exists share point.
+  //   We only need check one vertex, choose aribitarily.
+  enum locateresult loc = isintet(torg, tdest, tapex, toppo, forg);
+  // There only two cases (in or out) can be happened.
+  if ((intersect != OUTSIDE) && (intersect != INTETRAHEDRON)) {
+    printf("Internal error in is_face_tet_inter_0(): \n");
+    printf("  Invalid isintet() return value: %i. \n", intersect);
+    printf("  (0 = coplanar, 1 = on vertex, 2 = on edge, 3 = on face.)\n");
+    internalerror();
+  }
+  intersect = (loc == OUTSIDE) ? 0 : 1;
+  return intersect;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// is_face_tet_inter_1()     Check if input face is intersecting with input  //
+//                           tetrahedron(given by its four vertexs). There 1 //
+//                           share points between face and tetrahedron.      //
+//                                                                           //
+// Here we can reuse is_face_tet_inter_0(). But before use it we must detach //
+// the share point between face and tetrahedron.                             //
+//                                                                           //
+// Return 1 if they are intersecting each other. Otherwise, return zero.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::is_face_tet_inter_1(triface *checkface, point3d torg, point3d tdest,
+                                point3d tapex, point3d toppo)
+{
+  point3d forg, fdest, fapex;
+  REAL tmpforg[3], center[3];
+  int oldversion, intersect;
+  int i;
+
+  // We will change the checkface's version. So we must restore it after
+  //   checking, otherwise, the index fields in each giftface will invalid.
+  oldversion = checkface->ver;
+  // First set the share vertex be origin of checkface.
+  for (i = 0; i < 3; i++) {
+    org(*checkface, forg);
+    if ((forg == torg) || (forg == tdest) ||
+        (forg == tapex) || (forg == toppo)) {
+      dest(*checkface, fdest);
+      apex(*checkface, fapex);
+      break;
+    }
+    enextself(*checkface);
+  }
+  assert(i < 3);
+
+  center[0] = 0.5 * (fdest[0] + fapex[0]);
+  center[1] = 0.5 * (fdest[1] + fapex[1]);
+  center[2] = 0.5 * (fdest[2] + fapex[2]);
+
+  tmpforg[0] = 0.5 * (forg[0] + center[0]);
+  tmpforg[1] = 0.5 * (forg[1] + center[1]);
+  tmpforg[2] = 0.5 * (forg[2] + center[2]);
+
+  setorg(*checkface, tmpforg);
+  intersect = is_face_tet_inter_0(checkface, torg, tdest, tapex, toppo);
+  setorg(*checkface, forg);
+  checkface->ver = oldversion;
+
+  return intersect;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// is_face_tet_inter_2()     Check if input face is intersecting with input  //
+//                           tetrahedron(given by its four vertexs). There 2 //
+//                           share points between face and tetrahedron.      //
+//                                                                           //
+// The algorithm:                                                            //
+//                                                                           //
+// Set the face be f, two share point be org, dest. The other point in face  //
+//   be apex, The other two points in tetrahedron be v0, v1.                 //
+// Take f as reference plane. Check spatial relation between f and v0, v1.   //
+// IF (v0 and v1 are locating at the same side to f) THEN                    //
+//   return No intersecyion;                                                 //
+// ELSE IF (v0 and v1 are locating at diffrent side to f) THEN               //
+//   Take a face f' in tetrahedron which contain v0 but not contain v1 as    //
+//     reference plane. Check spatial relation between f' and apex, v1.      //
+//   IF (apex and v1 are loacting at the same side of f') THEN               //
+//     return Intersection;                                                  //
+//   ELSE                                                                    //
+//     return No intersection;                                               //
+//   END                                                                     //
+// ELSE IF (v0 or v1 is coplanar with f) THEN                                //
+//   IF (v0 is coplanar with f) THEN                                         //
+//     Take apex face f' in tetrahedron which contain v1 but not conatin v0  //
+//       as reference plane. Check spatial relation between f' and apex, v0. //
+//     IF (apex and v0 are loacting at the same side of f') THEN             //
+//       return Intersection;                                                //
+//     ELSE                                                                  //
+//       return No intersection;                                             //
+//     END                                                                   //
+//   ELSE                                                                    //
+//     (v1 is coplanar with f)                                               //
+//     Take apex face f' in tetrahedron which contain v0 but not conatin v1  //
+//       as reference plane. Check spatial relation between f' and apex, v1. //
+//     IF (apex and v1 are loacting at the same side of f') THEN             //
+//       return Intersection;                                                //
+//     ELSE                                                                  //
+//       return No intersection;                                             //
+//     END                                                                   //
+//   END                                                                     //
+// ELSE                                                                      //
+//   (both v0 and v1 are coplanar with f)                                    //
+//   Impossible case. Throw;                                                 //
+// END                                                                       //
+//                                                                           //
+// Return 1 if they are intersecting each other. Otherwise, return zero.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::is_face_tet_inter_2(triface *checkface, point3d torg, point3d tdest,
+                                point3d tapex, point3d toppo)
+{
+  point3d forg, fdest, fapex, v0, v1;
+  int iori1, iori2, iori3, iori4;
+  int oldversion, intersect;
+  int i;
+
+  // We will change the checkface's version. So we must restore it after
+  //   checking, otherwise, the index fields in each giftface will invalid.
+  oldversion = checkface->ver;
+  // Get forg, fdest, fapex.
+  for (i = 0; i < 3; i++) {
+    org(*checkface, forg);
+    dest(*checkface, fdest);
+    if (((forg == torg) || (forg == tdest) ||
+         (forg == tapex) || (forg == toppo)) &&
+        ((fdest == torg) || (fdest == tdest) ||
+         (fdest == tapex) || (fdest == toppo))) {
+      apex(*checkface, fapex);
+      break;
+    }
+    enextself(*checkface);
+  }
+  assert(i < 3);
+
+  // Get v0, v1.
+  if ((torg == forg) || (torg == fdest)) {
+    if ((tdest == forg) || (tdest == fdest)) {
+      v0 = tapex; v1 = toppo;
+    } else if ((tapex == forg) || (tapex == fdest)) {
+      v0 = tdest; v1 = toppo;
+    } else {
+      assert((toppo == forg) || (toppo == fdest));
+      v0 = tdest; v1 = tapex;
+    }
+  } else {
+    v0 = torg;
+    if ((tdest == forg) || (tdest == fdest)) {
+      if ((tapex == forg) || (tapex == fdest)) {
+        v1 = toppo;
+      } else {
+        assert((toppo == forg) || (toppo == fdest));
+        v1 = tapex;
+      }
+    } else {
+      assert((tapex == forg) || (tapex == fdest));
+      assert((toppo == forg) || (toppo == fdest));
+      v1 = tdest;
+    }
+  }
+  assert((v0 != forg) && (v0 != fdest));
+  assert((v1 != forg) && (v1 != fdest));
+
+  iori1 = iorient3d(forg, fdest, fapex, v0);
+  iori2 = iorient3d(forg, fdest, fapex, v1);
+  if (iori1 * iori2 != 0) {
+    // No coplanar case.
+    if (iori1 == iori2) {
+      intersect = 0;  // No intersection.
+    } else {
+      iori3 = iorient3d(forg, fdest, v0, fapex);
+      iori4 = iorient3d(forg, fdest, v0, v1);
+      assert(iori3 * iori4 != 0);
+      if (iori3 != iori4) {
+        intersect = 0;  // No intersection.
+      } else {
+        intersect = 1;  // Intersection.
+      }
+    }
+  } else {
+    // v0, or v1 is coplanar with face.
+    if (iori1 == 0) {
+      assert(iori2 != 0);
+      // v0 is coplanar with face, choose v1.
+      iori3 = iorient3d(forg, fdest, v1, v0);
+      iori4 = iorient3d(forg, fdest, v1, fapex);
+    } else {
+      assert(iori1 != 0);
+      // v1 is coplanar with face, choose v0.
+      iori3 = iorient3d(forg, fdest, v0, v1);
+      iori4 = iorient3d(forg, fdest, v0, fapex);
+    }
+    assert(iori3 * iori4 != 0);
+    if (iori3 != iori4) {
+      intersect = 0;  // No intersection.
+    } else {
+      intersect = 1;  // Intersection.
+    }
+  }
+
+  checkface->ver = oldversion;
+  return intersect;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// getgiftface()    Search for a face that most suitable for finishing.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::getgiftface(list *giftfacelist, int numberofgiftpoints,
+                        int *pointweightlist, list *smallweightlist)
+{
+  giftface *gfaceptr;
+  int smallestweight, smallestindex;
+  int gpointindex, giftfaceweight;
+  int i, j, index;
+
+  // First find the smallest weight and index in giftpoint array.
+  smallestweight = 1000;
+  smallestindex = -1;
+  for (i = 0; i < numberofgiftpoints; i++) {
+    // We only need consider the unfinished giftpoint.
+    if (pointweightlist[i] == 0) continue;
+    if (pointweightlist[i] < smallestweight) {
+      smallestweight = pointweightlist[i];
+      smallestindex = i;
+    }
+  }
+  assert(smallestindex != -1);
+
+  if (smallestweight == 3) {
+    for (i = 0; i < giftfacelist->len(); i++) {
+      gfaceptr = (giftface*) (*giftfacelist)[i];
+      if ((pointweightlist[gfaceptr->iorg] == 3)
+          || (pointweightlist[gfaceptr->idest] == 3)
+          || (pointweightlist[gfaceptr->iapex] == 3)) {
+        break;
+      }
+    }
+    assert(i < giftfacelist->len());
+    return i;
+  } else {
+    // For there might exist more than one points have the same smallest
+    //   weight, I use a list to keep all these points.
+    smallweightlist = new list("int");
+    smallweightlist->append(&smallestindex);
+    for (i = smallestindex + 1; i < numberofgiftpoints; i++) {
+      if (pointweightlist[i] == smallestweight) {
+        smallweightlist->append(&i);
+      }
+    }
+    // Find the most suit giftface. Get each point index from
+    //   'smallweightlist', then find in giftface array. If a giftface
+    //   contain this point, then sum its weight of three point. Get a
+    //   giftface which have the smallest sum of weight.
+    smallestweight = 1000;
+    smallestindex = -1;
+    for (i = 0; i < smallweightlist->len(); i++) {
+      gpointindex = *(int*)(*smallweightlist)[i];
+      for (j = 0; j < giftfacelist->len(); j++) {
+        gfaceptr = (giftface*) (*giftfacelist)[j];
+        if ((gfaceptr->iorg == gpointindex) ||
+            (gfaceptr->idest == gpointindex) ||
+            (gfaceptr->iapex == gpointindex)) {
+          giftfaceweight = pointweightlist[gfaceptr->iorg]
+                         + pointweightlist[gfaceptr->idest]
+                         + pointweightlist[gfaceptr->iapex];
+          if (smallestweight > giftfaceweight) {
+            smallestweight = giftfaceweight;
+            smallestindex = j;
+          }
+        }
+      }
+    }
+    assert(smallestindex != -1);
+    return smallestindex;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// getgiftpoint()    Search for a point that finished input face.            //
+//                                                                           //
+// To get a visible giftpoint for input giftface, we need:                   //
+//   (1) First find all points which visible from input face.                //
+//   (2) Choose a best (gift)point among these points.                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::getgiftpoint(triface *gface, list *giftfacelist,
+                         int numberofgiftpoints, point3d *giftpoints,
+                         int *pointweightlist, list *candpointindexlist,
+                         list *bestpointindexlist)
+{
+  giftface *gfaceptr;
+  point3d forg, fdest, fapex;
+  point3d testpoint1, testpoint2;
+  int intersect, sharecount;
+  int inspheretest, findflag;
+  int gpointindex1, gpointindex2;
+  int largerweight;
+  int i, j, index;
+
+  // Get the vertexs of input (gift)face.
+  dest(*gface, forg);
+  org(*gface, fdest);
+  apex(*gface, fapex);
+  if (verbose > 2) {
+    printf("    Finding a point for finishing face (%d, %d, %d).\n",
+           pointmark(forg), pointmark(fdest), pointmark(fapex));
+  }
+
+  candpointindexlist->clear();
+
+  // Step (1):
+  for (i = 0; i < numberofgiftpoints; i++) {
+    if (pointweightlist[i] == 0) {
+      // All faces which contain this point were finished.
+      continue;
+    }
+    testpoint1 = giftpoints[i];
+    if ((testpoint1 == forg) || (testpoint1 == fdest) ||
+        (testpoint1 == fapex)) {
+      continue; // Skip the vertex of face.
+    }
+    if (!isaboveplane(forg, fdest, fapex, testpoint1)) {
+      // This point is below or coplanar or coincident with this face.
+      continue;
+    }
+    if (verbose > 2) {
+      printf("    Checking point %d.\n", pointmark(testpoint1));
+    }
+    // Now, we found that this point is vivible form face, we still need
+    //   to check if there exist any constraining face that will cause
+    //   this point unvisible form face.
+    intersect = 0;
+    for (j = 0; j < giftfacelist->len(); j++) {
+      gfaceptr = (giftface*) (*giftfacelist)[j];
+      if ((pointweightlist[gfaceptr->iorg] == 0) ||
+          (pointweightlist[gfaceptr->idest] == 0) ||
+          (pointweightlist[gfaceptr->iapex] == 0)) {
+        // This face contain a zero-weight point, skip it.
+        continue;
+      }
+      if (verbose > 2) {
+        printf("    Checking face (%d, %d, %d).\n",
+               pointmark(org(gfaceptr->casing)),
+               pointmark(dest(gfaceptr->casing)),
+               pointmark(apex(gfaceptr->casing)));
+      }
+      // Check if this face's vertexs are share with the new tet.
+      sharecount = 0;
+      if (isfacehaspoint(&gfaceptr->casing, forg)) sharecount++;
+      if (isfacehaspoint(&gfaceptr->casing, fdest)) sharecount++;
+      if (isfacehaspoint(&gfaceptr->casing, fapex)) sharecount++;
+      if (isfacehaspoint(&gfaceptr->casing, testpoint1)) sharecount++;
+      // assert(sharecount < 4);
+      if (sharecount == 0) {
+        intersect = is_face_tet_inter_0(&gfaceptr->casing, forg, fdest, fapex,
+                                        testpoint1);
+      } else if (sharecount == 1) {
+        intersect = is_face_tet_inter_1(&gfaceptr->casing, forg, fdest, fapex,
+                                        testpoint1);
+      } else if (sharecount == 2) {
+        intersect = is_face_tet_inter_2(&gfaceptr->casing, forg, fdest, fapex,
+                                        testpoint1);
+      } else { // if (sharecount == 3)
+        intersect = 0;
+      }
+      if (intersect) {
+        // If exist intersection face. break find face loop.
+        if (verbose > 2) {
+          printf("    Skipped.\n");
+        }
+        break;
+      }
+    }
+    if (!intersect) {
+      if (verbose > 2) {
+        printf("    Visible from face.\n");
+      }
+      candpointindexlist->append(&i);
+    }
+  }
+  if (candpointindexlist->len() == 0) {
+    return -1; // Cannot find a point that can finish input face.
+  }
+
+  // Setp (2):
+  if (verbose > 2) {
+    printf("    Find %d candidating points.\n", candpointindexlist->len());
+  }
+
+  // Find a best point index from 'candpointindexlist'. A best point
+  //   should be satisfied following rules:
+  //   (1) It must satisfy the empty circumsphere criteria with the input
+  //       face. If there exist more than one such point, choose the point
+  //       which has the largest weight.
+  //   (2) The degenerate case is there exist cosphere points. If so, we
+  //       should choose a point which has the largest weight (This will
+  //       helpfully avoid form a tetrahedron that cause later giftwrapping
+  //       failed).
+  //   (3) If no satisfied point be found. This mean we can't form a constr-
+  //       ained Delaunay tetrahedralization from this faces and points(In
+  //       my case, it should not happen.) For complete the job, we choose
+  //       the point which has the maximized minimum-dihedral angle (not
+  //       done yet).
+
+  bestpointindexlist->clear();
+
+  for (i = 0; i < candpointindexlist->len(); i++) {
+    findflag = 1;
+    gpointindex1 = *(int*)(*candpointindexlist)[i];
+    testpoint1 = giftpoints[gpointindex1];
+    for (j = 0; j < candpointindexlist->len(); j++) {
+      if (j == i) continue; // Skip the same point.
+      gpointindex2 = *(int*)(*candpointindexlist)[j];
+      testpoint2 = giftpoints[gpointindex2];
+      inspheretest = iinsphere(fdest, forg, fapex, testpoint1, testpoint2);
+      if (inspheretest > 0) {
+        findflag = 0;
+        break;
+      } else if (inspheretest == 0) {
+        if (pointweightlist[gpointindex1] < pointweightlist[gpointindex2]) {
+          findflag = 0;
+          break;
+        }
+      }
+    }
+    if (findflag) {
+      bestpointindexlist->append(&gpointindex1);
+    }
+  }
+
+  if (verbose > 2) {
+    printf("    Find %d best points.\n", bestpointindexlist->len());
+  }
+  if (bestpointindexlist->len() == 1) {
+    gpointindex1 = *(int*)(*bestpointindexlist)[0];
+  } else if (bestpointindexlist->len() > 1) {
+    for (i = 0; i < bestpointindexlist->len(); i++) {
+      gpointindex2 = *(int*)(*bestpointindexlist)[i];
+      if (verbose > 2) {
+        printf("     Checking point %d, weight = %d.\n",
+               pointmark(giftpoints[gpointindex2]),
+               pointweightlist[gpointindex2]);
+      }
+      if (i == 0) {
+        largerweight = pointweightlist[gpointindex2];
+        gpointindex1 = gpointindex2;
+      } else {
+        if (largerweight < pointweightlist[gpointindex2]) {
+          largerweight = pointweightlist[gpointindex2];
+          gpointindex1 = gpointindex2;
+        }
+      }
+    }
+  } else {
+    // No constrained Delaunay tetrahedralization can be formed.
+    printf("Internal error in getgiftpoint(): \n");
+    printf("  Cannot find a best point from %i points",
+           candpointindexlist->len());
+    internalerror();
+  }
+
+  return gpointindex1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// giftwrapping()    Generate a constrained Delaunay tetrahedralization from //
+//                   input faces and points use Giftwrapping algorithm.      //
+//                                                                           //
+// The Giftwrapping algorithm:                                               //
+//   The gift-wrapping algorithm maintains a dictionary of unfinished faces, //
+// which initially contains the d+1 faces of the first Delaunay d-simplex.   //
+// Repeat the following step: remove an arbitrary unfinished face f from the //
+// dictionary and search for a vertex that finishes f. This vertex must be   //
+// above f, and have the property that the new d-simplex that results has an //
+// empty circumsphere. Na��vely, this search takes O(n) time. If no vertex   //
+// is above f, then f lies on the boundary of the convex hull. Otherwise, s  //
+// becomes part of the growing triangulation. Check each (d-1)-face of s,    //
+// except f against the dictionary. If a face is already present in the dic- //
+// tionary, then the face is now finished, so remove it from the dictionary. //
+// Otherwise, the face is new, so insert it into the dictionary.             //
+//                                                                           //
+// 'backtracelist' is a list to keep all new tets be created during gift-    //
+// wrapping stage, so we can delete them if gift-wrapping failed.            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::giftwrapping(int numberofgiftfaces, triface *giftfaces,
+                         int numberofgiftpoints, point3d *giftpoints,
+                         REAL *tetattribs, REAL volumevar, list *backtracelist)
+{
+  list *giftfacelist;
+  list *smallweightlist;
+  list *candpointindexlist, *bestpointindexlist;
+  giftface gface, *gfaceptr;
+  triface newtetra, checkface;
+  face checksh;
+  point3d gpoint, checkorg, checkdest;
+  int *pointweightlist;
+  int gfaceindex, gpointindex;
+  int success, facefinished;
+  int i, j;
+
+  if (verbose > 1) {
+    printf("  Gift-wrapping begin with %d faces, %d points.\n",
+           numberofgiftfaces, numberofgiftpoints);
+  }
+  giftfacelist = new list(sizeof(giftface));
+  pointweightlist = new int[numberofgiftpoints];
+  // Init giftfacelist. At init all giftfaces are unfinished.
+  for (i = 0; i < numberofgiftfaces; i++) {
+    gfaceptr = (giftface*) giftfacelist->alloc();
+    gfaceptr->casing = giftfaces[i];
+    gfaceptr->iorg = gfaceptr->idest = gfaceptr->iapex = 0;
+  }
+  // Generate weights for every giftpoint. At the same time, store all
+  //   vertexs's index in giftpoints array of each giftface. This will
+  //   avoid to search index every time when a giftface is finfished.
+  for (i = 0; i < numberofgiftpoints; i++) {
+    pointweightlist[i] = 0;
+    for (j = 0; j < giftfacelist->len(); j++) {
+      gfaceptr = (giftface*) (*giftfacelist)[j];
+      if (org(gfaceptr->casing) == giftpoints[i]) {
+        pointweightlist[i]++;
+        gfaceptr->iorg = i;
+      } else if (dest(gfaceptr->casing) == giftpoints[i]) {
+        pointweightlist[i]++;
+        gfaceptr->idest = i;
+      } else if (apex(gfaceptr->casing) == giftpoints[i]) {
+        pointweightlist[i]++;
+        gfaceptr->iapex = i;
+      }
+    }
+    assert(pointweightlist[i] > 0);
+  }
+  if (verbose > 3) {
+    dumpgifts("gifts.txt", giftfacelist, numberofgiftpoints,
+              giftpoints, pointweightlist);
+  }
+
+  success = 1;
+  // For there might exist more than one points have the same smallest
+  //   weight, I use a list to keep all these points.
+  smallweightlist = new list("int");
+  // A list to keep all indexs of points which visible from the input
+  //   giftface(*gface) in giftpoints array.
+  candpointindexlist = new list("int");
+  // A list to keep the best point(s) for finishing a giftface.
+  bestpointindexlist = new list("int");
+  // These three lists are created here to avoid create and delete every
+  //   time when finishing each giftface.
+
+  // Do giftwrapping from 'giftfacelist' and 'giftpoints'.
+  while (giftfacelist->len()) {
+    // Get a most suit giftface to start.
+    gfaceindex = getgiftface(giftfacelist, numberofgiftpoints, pointweightlist,
+                             smallweightlist);
+    gface = *(giftface*)(*giftfacelist)[gfaceindex];
+    if (verbose > 2) {
+      printf("    Choosing face (%d, %d, %d).\n", pointmark(org(gface.casing)),
+             pointmark(dest(gface.casing)), pointmark(apex(gface.casing)));
+    }
+    // Decrease corresponding point's weight.
+    pointweightlist[gface.iorg]--;
+    pointweightlist[gface.idest]--;
+    pointweightlist[gface.iapex]--;
+    // Remove this giftface from unfinished list.
+    giftfacelist->del(gfaceindex);
+    // Get a giftpoint that can be formed a constrained Delaunay tetrahedron
+    //   with this giftface.
+    gpointindex = getgiftpoint(&gface.casing, giftfacelist, numberofgiftpoints,
+                               giftpoints, pointweightlist, candpointindexlist,
+                               bestpointindexlist);
+    if (gpointindex == -1) {
+      success = 0;
+      break; // Giftwrapping failed.
+    }
+    gpoint = giftpoints[gpointindex];
+    if (verbose > 2) {
+      printf("    Choosing point %d.\n", pointmark(gpoint));
+    }
+    // Form a new tetrahedron from gface.casing and gpoint.
+    maketetrahedron(&newtetra);
+    backtracelist->append(&newtetra);
+    setorg (newtetra, dest(gface.casing));
+    setdest(newtetra, org(gface.casing));
+    setapex(newtetra, apex(gface.casing));
+    setoppo(newtetra, gpoint);
+    // Bond the new tetra with gift face.
+    bond(gface.casing, newtetra);
+    tspivot(gface.casing, checksh);
+    if (checksh.sh != dummysh) {
+      sesymself(checksh);
+      tsbond(newtetra, checksh);
+    }
+    if (tetattribs != NULL) {
+      // Set the element attributes of the new tetrahedron.
+      for (i = 0; i < eextras; i++) {
+        setelemattribute(newtetra.tet, i, tetattribs[i]);
+      }
+    }
+    if (varvolume) {
+      // Set the area constraint of a new tetrahedron.
+      setvolumebound(newtetra.tet, volumevar);
+    }
+    // Check three new faces of newtetra to see if they are finished by
+    //   other gift faces. If find such gift face, its being finished,
+    //   remove it from giftfaces(set face finished flag be 1). If not
+    //   find such gift face, add this face to giftfaces.
+    adjustedgering(newtetra, CCW);
+    for (i = 0; i < 3; i++) {
+      fnext(newtetra, checkface);
+      checkorg = org(checkface);
+      checkdest = dest(checkface);
+      // Find in giftfacelist to see if any face be finished. If a face
+      //   has both three points(checkorg, checkdest and gpoint). It must
+      //   be finished.
+      facefinished = 0;
+      for (j = 0; j < giftfacelist->len(); j++) {
+        gfaceptr = (giftface*)(*giftfacelist)[j];
+        if (isfacehaspoint(&(gfaceptr->casing), checkorg) &&
+            isfacehaspoint(&(gfaceptr->casing), checkdest) &&
+            isfacehaspoint(&(gfaceptr->casing), gpoint)) {
+          // Find such face, now it is finished.
+          if (verbose > 2) {
+            printf("    Finishing face (%d, %d, %d).\n",
+                   pointmark(org(gfaceptr->casing)),
+                   pointmark(dest(gfaceptr->casing)),
+                   pointmark(apex(gfaceptr->casing)));
+          }
+          //   Decrease corresponding point's weight.
+          pointweightlist[gfaceptr->iorg]--;
+          pointweightlist[gfaceptr->idest]--;
+          pointweightlist[gfaceptr->iapex]--;
+          //   Bond these two tets.
+          bond(gfaceptr->casing, checkface);
+          tspivot(gfaceptr->casing, checksh);
+          if (checksh.sh != dummysh) {
+            sesymself(checksh);
+            tsbond(checkface, checksh);
+          }
+          // Remove this giftface from unfinished list.
+          giftfacelist->del(j);
+          facefinished = 1;
+          break;
+        }
+      }
+      if (!facefinished) {
+        // This is an unfinished face, add it to giftfacelist.
+        gfaceptr = (giftface*) giftfacelist->alloc();
+        adjustedgering(checkface, CCW);
+        gfaceptr->casing = checkface;
+        if (verbose > 2) {
+          printf("    Adding an unfinished face (%d, %d, %d).\n",
+                 pointmark(org(gfaceptr->casing)),
+                 pointmark(dest(gfaceptr->casing)),
+                 pointmark(apex(gfaceptr->casing)));
+        }
+        // Decide the index of point from gface. Note: here gface's enext()
+        //   sequence is: (idest, iorg)->(iorg, iapex)->(iapex, idest) that
+        //   corresponding to checkface's enext() sequence. But after do
+        //   checkface.adjustedgering(0) it becomes inversed in each term:
+        //   that is: (iorg, idest)->(iapex, iorg)->(idest, iapex).
+        if (i == 0) {
+          gfaceptr->iorg = gface.iorg;
+          gfaceptr->idest = gface.idest;
+        } else if (i == 1) {
+          gfaceptr->iorg = gface.iapex;
+          gfaceptr->idest = gface.iorg;
+        } else { // i == 2
+          gfaceptr->iorg = gface.idest;
+          gfaceptr->idest = gface.iapex;
+        }
+        gfaceptr->iapex = gpointindex;
+        // Increase each vertex's weight.
+        pointweightlist[gfaceptr->iorg]++;
+        pointweightlist[gfaceptr->idest]++;
+        pointweightlist[gfaceptr->iapex]++;
+      }
+      enextself(newtetra);
+    }
+    if (verbose > 2) {
+      printf("    Create new: ");
+      dump(&newtetra);
+    }
+  }
+
+  if (verbose > 1) {
+    printf("  Gift-wrapping end: %s.\n", success ? "Success" : "Failed");
+  }
+  delete [] pointweightlist;
+  delete giftfacelist;
+  delete smallweightlist;
+  delete bestpointindexlist;
+  delete candpointindexlist;
+  return success;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// Giftwrapping Algorithm Implementation                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// Randomized Incremental Flip Delaunay Tetrahedrization                     //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+//   Incremental insertion algorithm is the simplest and the most commonly   //
+// used algorithm for constructing Delaunay triangulations. It extends in    //
+// a straightforward way to three (or more) dimensions. In three-dimension   //
+// there have several algorithms based on the incermental scheme, such as    //
+// the algorithms proposed by Boywer/Watson[1], Joe[2] and Edelsbrunner and  //
+// Shah[3], etc.                                                             //
+//                                                                           //
+//   Joe[2] provided an Incremental Flip algorithm to construct Delaunay     //
+// tetrahedralization with time complexity of O(n ^ 2) in the worst case, n  //
+// is the size of input point set. Edelsbrunner and Shah[3] extended Joe's   //
+// algorithm to a Randomized Incremental Flip algorithm with time complexity //
+// of O(n ^ (d+1)/2) in the worst case and O(n log n + n ^ ceiling(d/2)) in  //
+// the expected case.  Empirical results with an existing implementation     //
+// (Detri[4]) shows the Edelsbrunner and Shah[3]'s algorithm behaved well    //
+// for both randomly and regular distributed point sets.                     //
+//                                                                           //
+//   Tetgen uses the Randomized Incremental Flip algorithm of Edelsbrunner   //
+// and Shah[3] to construct Delaunay tetrahedralizations of 3D point sets.   //
+// The implementation is robust and fast. It used the fast randomized point  //
+// location algorithm of Mucke, Issac and Zhu's to perform point location.   //
+// and optionally used the adaptive exact geometric predicates package of    //
+// Shewchuk to perform exact orientation and insphere tests, Mucke's share-  //
+// ware Detri[4] also implemented the same algorithm, but lack of speed. My  //
+// implementation of this algorithm is faster than Detri[4].                 //
+//                                                                           //
+// Please see predicate.cpp, ptloc.cpp and flips.cpp for more infomation.    //
+//                                                                           //
+// Refernces:                                                                //
+//                                                                           //
+// [1] Adrian Bowyer. Computing Dirichlet Tessellations. Computer Journal    //
+//     24(2):162-166, 1981.  David F. Watson. Computing the three-dimens-    //
+//     ional Delaunay Tessellation with Application to Voronoi Polytopes.    //
+//     Computer Journal 24(2):167-172, 1981.                                 //
+// [2] Barry Joe. Construction of Three-Dimensional Triangulations using     //
+//     Local Transformations. Computer Aided Geometric Design 8:123-142,     //
+//     1991.                                                                 //
+// [3] Herbert Edelsbrunner and Nimish Shah. Incremental topological         //
+//     flipping works for regular triangulations. Algorithmica, 15:223-241,  //
+//     1996.                                                                 //
+// [4] Detri, The Code Constructs the 3D Delaunay Triangulation of a Given   //
+//     Point Set Using a Variant of the Randomized Incremental-Flip          //
+//     Algorithm,                                                            //
+//     http://www.geom.umn.edu/software/cglist/GeomDir/Detri_2.6.a.tar.gz    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// construct_initial_tetra()    Create an initial triangulation by building  //
+//                              tetrahedron <a, b, c, o>; where the four     //
+//                              points are not coplanar, and no three points //
+//                              are colinear.                                //
+//                                                                           //
+// To construct the first tetrahedron, we should detect and avoid degenerate //
+// cases. They are two duplicated points, three colinear points and four     //
+// coplanar points. At two duplicated points case, we just ignored one of    //
+// them; at colinear and coplanar points cases, we must skip current point   //
+// and get next point, keep testing until a good point be found, all skipped //
+// points will consider later, store them in 'skippointlist'.                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::construct_initial_tetra(queue* skippointlist)
+{
+  triface newtet, ghosttet;
+  point3d pointloop;
+  point3d pa, pb, pc, pd;
+  int pointnumber;
+  int i, j;
+
+  if (verbose > 1) {
+    printf("  Construct an initial tetrahedron.\n");
+  }
+  // Set a 'ghosttet' handle the Outer space.
+  ghosttet.tet = dummytet;
+  pointnumber = points.items;
+  points.traversalinit();
+  pa = pointtraverse();
+  i = 0;
+  while (i < pointnumber) {
+    pointloop = pointtraverse();
+    i++;
+    if(compare2points(&pa, &pointloop) == 0) {
+      if (!quiet) {
+        printf("Warning:  A duplicate point at (%.12g, %.12g, %.12g)",
+               pointloop[0], pointloop[1], pointloop[2]);
+        printf(" appeared and was ignored.\n");
+      }
+      // This will cause change from input points set.
+      // pointdealloc(pointloop);
+      continue;
+    }
+    break;
+  }
+  if (i >= pointnumber) {
+    printf("\nAll points are duplicate, no tetrahedralization be");
+    printf(" constructed.\n");
+    exit(1);
+  }
+  pb = pointloop;
+  while (i < pointnumber) {
+    pointloop = pointtraverse();
+    i++;
+    if (iscoline(pa, pb, pointloop)) {
+      if (verbose > 2) {
+        printf("    A colinear point at (%.12g, %.12g, %.12g) %d",
+          pointloop[0], pointloop[1], pointloop[2]);
+        printf(" appeared and queued to process later.\n");
+      }
+      skippointlist->push(&pointloop);
+      continue;
+    }
+    break;
+  }
+  if (i >= pointnumber) {
+    printf("\nAll points are colinear, no tetrahedralization be");
+    printf(" constructed.\n");
+    exit(1);
+  }
+  pc = pointloop;
+  while (i < pointnumber) {
+    pointloop = pointtraverse();
+    i++;
+    if (iscoplane(pa, pb, pc, pointloop)) {
+      if (verbose > 2) {
+        printf("    A coplanar point at (%.12g, %.12g, %.12g)",
+          pointloop[0], pointloop[1], pointloop[2]);
+        printf(" appeared and queued to process later.\n");
+      }
+      skippointlist->push(&pointloop);
+      continue;
+    }
+    break;
+  }
+  if (i >= pointnumber) {
+    printf("All points are coplanar, no tetrahedrization be constructed.\n");
+    exit(1);
+  }
+  pd = pointloop;
+
+  if (!isaboveplane(pa, pb, pc, pd)) {
+    pointloop = pa; pa = pb; pb = pointloop;
+  }
+  maketetrahedron(&newtet);
+  setorg(newtet, pa);
+  setdest(newtet, pb);
+  setapex(newtet, pc);
+  setoppo(newtet, pd);
+  bond(newtet, ghosttet);
+  if (verbose > 2) {
+    printf("    Creating tetra ");
+    dump(&newtet);
+  }
+  // At init, all faces of this tet are hull faces.
+  hullsize = 4;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// collect_visibles()    Collects all CH facets visible from insertpoint and //
+//                       stores them in fliplist. At the same time,construct //
+//                       tetrahedra from insertpoint to all visible facets.  //
+//                                                                           //
+// The 'insertpoint' locate outside CH. And 'horiz' is a init hull facet ha- //
+// ndle that visible from 'insertpoint'. ( We assume that an oracle provided //
+// the initial facet which is on CH )   'fliplist' is a queue for return all //
+// visible facets from 'insertpoint', which will check doflip later.         //
+//                                                                           //
+// 'ghosttet' is a handle that hold the 'Outer Space' of current mesh. Use   //
+// this handle to bond new generated tetrahedron on current boundary, so     //
+// later point location routines will work correctlly.                       //
+//                                                                           //
+// 'unfinfacelist' is a link to keep all unfinished faces for 'insertpoint'. //
+// It is created in routine rand_incr_flip_delaunay() to avoid create it and //
+// delete it every time when call this routine. At the beginning and end of  //
+// this routine, 'unfinfacelist' should be empty.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::collect_visibles(point3d insertpoint, triface *horiz,
+                              triface *ghosttet, link *unfinfacelist)
+{
+  triface newtet, otherface, horizface;
+  point3d torg, tdest, tapex;
+  int findex;
+
+  if (verbose > 1) {
+    printf("  Collect visible facets for inserting point: \n");
+  }
+
+  enqueuefliplist(*horiz);
+  adjustedgering(*horiz, CCW);
+  org (*horiz, torg);
+  dest(*horiz, tdest);
+  apex(*horiz, tapex);
+  // Mount the initial tetrahedron to mesh.  That is a tetrahedron consists
+  //   of facet horiz and insertpoint.
+  maketetrahedron(&newtet); // default newtet.ver = 0.
+  setorg (newtet, tdest);
+  setdest(newtet, torg);
+  setapex(newtet, tapex);
+  setoppo(newtet, insertpoint);
+  // Make the connection of two tets.
+  bond(newtet, *horiz);
+  // Add the new tetrahedron's three faces to unfinished faces list.
+  //   Keep 'insertpoint' be apex of each faces.
+  fnext(newtet, otherface);
+  unfinfacelist->add(&otherface);
+  enextfnext(newtet, otherface);
+  unfinfacelist->add(&otherface);
+  enext2fnext(newtet, otherface);
+  bond(otherface, *ghosttet);
+  unfinfacelist->add(&otherface);
+  if (verbose > 2) {
+    printf("    Creating newtet ");
+    dump(&newtet);
+  }
+  // Hull face number decreased caused by face bond() operation.
+  hullsize --;
+
+  // Loop untill unfinfacelist is empty.
+  while (unfinfacelist->len() > 0) {
+    horizface = * (triface *) unfinfacelist->getnitem(1);
+    unfinfacelist->del(1);  // Remove it.
+    otherface = horizface;
+    adjustedgering(otherface, CCW);
+    // Spin otherface around the edge of otherface. Stop when encounter
+    //   Outer space.
+    while (fnextself(otherface)) ;
+    adjustedgering(horizface, CW);
+    apex(otherface, tapex);
+    if (isaboveplane(&horizface, tapex)) {
+      // otherface is visible form insertpoint.
+      enqueuefliplist(otherface);
+      org (otherface, torg);
+      dest(otherface, tdest);
+      // Mount a tetrahedron to mesh.  This tetrahedron is consists of
+      //   otherface's vertexs and insertpoint.
+      maketetrahedron(&newtet);          // default newtet.ver = 0.
+      setorg (newtet, torg);
+      setdest(newtet, tdest);
+      setapex(newtet, tapex);
+      setoppo(newtet, insertpoint);
+      // Make the connection of three tets.  Note:  The other two faces of
+      //   new tet default bond to 'dummytet',  here need check if they are
+      //   finished.
+      bond(newtet, otherface);
+      // Hull face number decrease caused by bond().
+      hullsize --;
+      fnext(newtet, otherface);
+      bond(otherface, horizface);
+      // Check other two face if they already exist in list Unfinshed.If so
+      //   They are finished now and can be removed from list, then bond.
+      enextfnext(newtet, otherface);
+      findex = unfinfacelist->hasitem(&otherface);
+      if ((findex > 0) && (findex <= unfinfacelist->len())) {
+        horizface = * (triface *) unfinfacelist->getnitem(findex);
+        unfinfacelist->del(findex);  // Remove it.
+        bond(otherface, horizface);
+      } else {
+        bond(otherface, *ghosttet);
+        unfinfacelist->add(&otherface);
+      }
+      enext2fnext(newtet, otherface);
+      findex = unfinfacelist->hasitem(&otherface);
+      if ((findex > 0) && (findex <= unfinfacelist->len())) {
+        horizface = * (triface *) unfinfacelist->getnitem(findex);
+        unfinfacelist->del(findex);  // Remove it.
+        bond(otherface, horizface);
+      } else {
+        bond(otherface, *ghosttet);
+        unfinfacelist->add(&otherface);
+      }
+      if (verbose > 2) {
+        printf("    Createing newtet ");
+        dump(&newtet);
+      }
+    } else {
+      // This is a hull face.
+      hullsize ++;
+    }
+  } // End of while.
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dofliplist()    Flips non-Delaunay triangular facets in given 'fliplist'  //
+//                 until all triangular facets are locally Delaunay.         //
+//                                                                           //
+// ASSUMPTION: Current tetrahedrization is non-Delaunay after inserting      //
+// point v, AND: all possibly non-Delaunay link-facets after are on 'flip-   //
+// list. Upon success (which should always happen, by now) dofliplist()      //
+// returns the number of necessary flips. As a side effect,'fliplist' will   //
+// be cleared, and current tetrahedrization updated accordingly.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int mesh3d::dofliplist()
+{
+  triface flipface;
+  enum facecategory fc;
+  int flipcount;
+
+  flipcount = flip_t23s + flip_t32s + flip_t22s + flip_t44s;
+  // Start flip.
+  if (verbose > 1) {
+    printf("  Start do flip list: %d faces in list.", fliplist->len());
+    if (verbose > 1) printf("\n");
+  }
+  while (dequeuefliplist(flipface)) {
+    fc = categorizeface(flipface);
+    // Determine the preferable configuration and swap if necessary.
+    switch (fc) {
+      // These cases are handled by edge swapping.
+      case N44:
+      case N32:
+        break;
+      // These cases are definitely unswappable
+      case N40:
+      case N30:
+      case N20:
+      case LOCKED:
+        break;
+      case T44:
+        if (querydoswap(flipface)) {
+          flip44(flipface);
+        }
+        break;
+      case T22:
+        if (querydoswap(flipface)) {
+          flip22(flipface);
+        }
+        break;
+      case T23:
+        if (querydoswap(flipface)) {
+          flip23(flipface);
+        }
+        break;
+      case T32:
+        if (querydoswap(flipface)) {
+          flip32(flipface);
+        }
+        break;
+      // Catch-all for bad cases
+      default:
+        break;
+    }
+  }
+  flipcount = flip_t23s + flip_t32s + flip_t22s + flip_t44s - flipcount;
+  if (verbose > 1) {
+    printf("  Total %d flips.\n", flipcount);
+  }
+  return flipcount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// rand_incr_flip_delaunay()   Construction delaunay tetrahedrization for a  //
+//                             given three-dimensional point set use Random- //
+//                             ize Incremental Flip algorithm.               //
+//                                                                           //
+// The basic idea of the incremental flip algorithm is the folloeing. S be a //
+// set of points in IR{3}, Let 4 <= i <= n and assume that the Delaunay tri- //
+// angulation of the first i-1 points in S is already constructed; call it   //
+// D(i-1). Add the i-th point pi (belong to S) to the triangulation,and res- //
+// tore Delaunayhood by flipping; this result in D(i). Repeat this procedure //
+// until i = n. If implemented correctly, this strategy always leads to the  //
+// Ddelaunay triangulation of S.                                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+long mesh3d::rand_incr_flip_delaunay()
+{
+  queue *skippointlist;
+  link *unfinfacelist;
+  triface starttet, ghosttet;
+  point3d pointloop;
+  enum insertsiteresult insres;
+  long max_flips, flipcount;
+  int max_flips_overflow;
+
+  // max_flips is the upper bound on total number of flips.
+  //   see Herbert's Triangulation notes, p95.
+  max_flips = points.items * (points.items + 3) + 1;
+  if (max_flips <= 0) {
+    // The long number Overflow!
+    max_flips_overflow = 1;
+  } else {
+    max_flips_overflow = 0;
+  }
+
+  usefliplist = 1;
+  if (fliplist) {
+    fliplist->clear();
+  } else {
+    fliplist = new queue(sizeof(badface3d));
+  }
+
+  // Set a queue for keeping all skipped points in routine
+  //   construct_initial_tetra();
+  skippointlist = new queue("point");
+
+  // Set a 'ghosttet' handle the Outer space.
+  //   This variable only used in routine collect_visible().
+  ghosttet.tet = dummytet;
+  // Setup a list for keeping all unfinished faces.
+  //   This list only used in routine collect_visible(). It is created here
+  //   to avoid create it and delete it every time when call this routine.
+  unfinfacelist = new link(sizeof(triface));
+  // Set user-defined compare function for comparing faces.
+  unfinfacelist->setcomp((compfunc) &issameface);
+
+  flip_t23s = flip_t32s = flip_t22s = flip_t44s = 0;
+  cospherecount = 0;
+
+  // Build a initial tetrahedron.
+  construct_initial_tetra(skippointlist);
+
+  // Delaunay tetrahedrization construction.
+  //   Continue get points after above routine, need not do traverseinit().
+  pointloop = pointtraverse();
+  while (pointloop != (point3d) NULL) {
+    starttet.tet = (tetrahedron *) NULL;
+    insres = insertsite(pointloop, &starttet, NULL, NULL);
+    if (insres == FAILED) {
+      // Point is outside current mesh.
+      collect_visibles(pointloop, &starttet, &ghosttet, unfinfacelist);
+      assert(unfinfacelist->len() == 0);
+    } else if (insres == DUPLICATE) {
+      if (!quiet) {
+        printf("Warning:  A duplicate point at (%.12g, %.12g, %.12g)",
+               pointloop[0], pointloop[1], pointloop[2]);
+        printf(" appeared and was ignored.\n");
+      }
+    }
+    if (!fliplist->empty()) {
+      flipcount = dofliplist();
+      if (!max_flips_overflow) {
+        max_flips -= flipcount;
+      }
+    }
+    pointloop = pointtraverse();
+  }
+  if (!max_flips_overflow && (max_flips <= 0)) {
+    printf("Error: Randomize Incremental Flip algorithm crashed!\n");
+    internalerror();
+  }
+
+  if (skippointlist->len() > 0) {
+    while (skippointlist->get(&pointloop)) {
+      starttet.tet = (tetrahedron *) NULL;
+      insres = insertsite(pointloop, &starttet, NULL, NULL);
+      if (insres == FAILED) {
+        // Point is outside current mesh.
+        collect_visibles(pointloop, &starttet, &ghosttet, unfinfacelist);
+        assert(unfinfacelist->len() == 0);
+      } else if (insres == DUPLICATE) {
+        if (!quiet) {
+          printf("Warning:  A duplicate point at (%.12g, %.12g, %.12g)",
+                 pointloop[0], pointloop[1], pointloop[2]);
+          printf(" appeared and was ignored.\n");
+        }
+      }
+      if (!fliplist->empty()) {
+        flipcount = dofliplist();
+        if (!max_flips_overflow) {
+          max_flips -= flipcount;
+        }
+      }
+    }
+    if (!max_flips_overflow && (max_flips <= 0)) {
+      printf("Error: Randomize Incremental Flip algorithm crashed!\n");
+      internalerror();
+    }
+  }
+
+  if (verbose) {
+    printf("  Total flips: %d  Where T23: %d  T32: %d  T22: %d  T44: %d\n",
+           flip_t23s + flip_t32s + flip_t22s + flip_t44s,
+           flip_t23s, flip_t32s, flip_t22s, flip_t44s);
+    printf("  Cosphere count: %d\n", cospherecount);
+  }
+  assert(fliplist->empty());
+  usefliplist = 0;
+  delete skippointlist;
+  delete unfinfacelist;
+  return hullsize;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// delaunay()   Form a Delaunay triangulation.                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+long mesh3d::delaunay()
+{
+  eextras = 0;
+  initializetetshpools();
+
+  if (!quiet) {
+    if (noexact) {
+      printf("Using approximate floating-point arthmetic ");
+    } else {
+      printf("Using adaptive exact floating-point arthmetic ");
+    }
+    if (noroundoff) {
+      printf("without tolerance.\n");
+    } else {
+      printf("with tolerance %g.\n", usertolerance);
+    }
+    printf("Constructing Delaunay triangulation ");
+    printf("by Randomized Incremental-Flip algorithm.\n");
+  }
+
+  return rand_incr_flip_delaunay();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// Randomized Incremental Flip Delaunay Tetrahedrization                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// File I/O Routines                                                         //
+// BEGIN                                                                     //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// readline()    Read a nonempty line from a file.                           //
+//                                                                           //
+// A line is considered "nonempty" if it contains something that looks like  //
+// a number.                                                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+char* mesh3d::readline(char *string, FILE *infile, char *infilename)
+{
+  char *result;
+
+  // Search for something that looks like a number.
+  do {
+    result = fgets(string, INPUTLINESIZE, infile);
+    if (result == (char *) NULL) {
+      printf("File I/O Error:  Unexpected end of file in %s.\n", infilename);
+      exit(1);
+    }
+    // Skip anything that doesn't look like a number, a comment,
+    //   or the end of a line.
+    while ((*result != '\0') && (*result != '#')
+           && (*result != '.') && (*result != '+') && (*result != '-')
+           && ((*result < '0') || (*result > '9'))) {
+      result++;
+    }
+  // If it's a comment or end of line, read another line and try again.
+  } while ((*result == '#') || (*result == '\0'));
+  return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// findfield()    Find the next field of a string.                           //
+//                                                                           //
+// Jumps past the current field by searching for whitespace, then jumps past //
+// the whitespace to find the next field.                                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+char* mesh3d::findfield(char *string)
+{
+  char *result;
+
+  result = string;
+  // Skip the current field.  Stop upon reaching whitespace.
+  while ((*result != '\0') && (*result != '#')
+         && (*result != ' ') && (*result != '\t')) {
+    result++;
+  }
+  // Now skip the whitespace and anything else that doesn't look like a
+  //   number, a comment, or the end of a line.
+  while ((*result != '\0') && (*result != '#')
+         && (*result != '.') && (*result != '+') && (*result != '-')
+         && ((*result < '0') || (*result > '9'))) {
+    result++;
+  }
+  // Check for a comment (prefixed with `#').
+  if (*result == '#') {
+    *result = '\0';
+  }
+  return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// readnodes()    Read the points from a file, which may be a .node or .poly //
+//                file.                                                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::readnodes(FILE **polyfile)
+{
+  FILE *infile;
+  point3d pointloop;
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  char *infilename;
+  REAL x, y, z;
+  int firstnode;
+  int nodemarkers;
+  int currentmarker;
+  int i, j;
+
+  if (poly || smesh) {
+    // Read the points from a .poly or .smesh file.
+    if (poly) {
+      if (!quiet) {
+        printf("Opening %s.\n", inpolyfilename);
+      }
+      *polyfile = fopen(inpolyfilename, "r");
+      if (*polyfile == (FILE *) NULL) {
+        printf("File I/O Error:  Cannot access file %s.\n", inpolyfilename);
+        exit(1);
+      }
+      stringptr = readline(inputline, *polyfile, inpolyfilename);
+    } else {
+      if (!quiet) {
+        printf("Opening %s.\n", insmeshfilename);
+      }
+      *polyfile = fopen(insmeshfilename, "r");
+      if (*polyfile == (FILE *) NULL) {
+        printf("File I/O Error:  Cannot access file %s.\n", insmeshfilename);
+        exit(1);
+      }
+      stringptr = readline(inputline, *polyfile, insmeshfilename);
+    }
+    // Read number of points, number of dimensions, number of point
+    //   attributes, and number of boundary markers.
+    inpoints = (int) strtol (stringptr, &stringptr, 0);
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      mesh_dim = 3;
+    } else {
+      mesh_dim = (int) strtol (stringptr, &stringptr, 0);
+    }
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      nextras = 0;
+    } else {
+      nextras = (int) strtol (stringptr, &stringptr, 0);
+    }
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      nodemarkers = 0;
+    } else {
+      nodemarkers = (int) strtol (stringptr, &stringptr, 0);
+    }
+    if (inpoints > 0) {
+      readnodefile = 0;
+      infilename = inpolyfilename;
+      infile = *polyfile;
+    } else {
+      // If the .poly file claims there are zero points, that means that
+      //   the points should be read from a separate .node file.
+      readnodefile = 1;
+      infilename = innodefilename;
+    }
+  } else {
+    readnodefile = 1;
+    infilename = innodefilename;
+    *polyfile = (FILE *) NULL;
+  }
+
+  if (readnodefile) {
+    // Read the points from a .node file.
+    if (!quiet) {
+      printf("Opening %s.\n", innodefilename);
+    }
+    infile = fopen(innodefilename, "r");
+    if (infile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot access file %s.\n", innodefilename);
+      exit(1);
+    }
+    // Read number of points, number of dimensions, number of point
+    //   attributes, and number of boundary markers.
+    stringptr = readline(inputline, infile, innodefilename);
+    inpoints = (int) strtol (stringptr, &stringptr, 0);
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      mesh_dim = 3;
+    } else {
+      mesh_dim = (int) strtol (stringptr, &stringptr, 0);
+    }
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      nextras = 0;
+    } else {
+      nextras = (int) strtol (stringptr, &stringptr, 0);
+    }
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      nodemarkers = 0;
+    } else {
+      nodemarkers = (int) strtol (stringptr, &stringptr, 0);
+    }
+  }
+
+  if (inpoints < 4) {
+    printf("Error:  Input must have at least four input points.\n");
+    exit(1);
+  }
+  if (mesh_dim != 3) {
+    printf("Error:  This program only works with three-dimensional meshes.\n");
+    exit(1);
+  }
+
+  initializepointpool();
+
+  // Read the points.
+  for (i = 0; i < inpoints; i++) {
+    pointloop = (point3d) points.alloc();
+    stringptr = readline(inputline, infile, infilename);
+    if (i == 0) {
+      firstnode = (int) strtol (stringptr, &stringptr, 0);
+      if ((firstnode == 0) || (firstnode == 1)) {
+        firstnumber = firstnode;
+      }
+    }
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      printf("File I/O Error:  Point %d has no x coordinate.\n",
+             firstnumber + i);
+      exit(1);
+    }
+    x = (REAL) strtod(stringptr, &stringptr);
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      printf("File I/O Error:  Point %d has no y coordinate.\n",
+             firstnumber + i);
+      exit(1);
+    }
+    y = (REAL) strtod(stringptr, &stringptr);
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      printf("File I/O Error:  Point %d has no z coordinate.\n",
+             firstnumber + i);
+      exit(1);
+    }
+    z = (REAL) strtod(stringptr, &stringptr);
+    pointloop[0] = x;
+    pointloop[1] = y;
+    pointloop[2] = z;
+    // Read the point attributes.
+    for (j = 3; j < 3 + nextras; j++) {
+      stringptr = findfield(stringptr);
+      if (*stringptr == '\0') {
+        pointloop[j] = 0.0;
+      } else {
+        pointloop[j] = (REAL) strtod(stringptr, &stringptr);
+      }
+    }
+    if (nodemarkers) {
+      // Read a point marker.
+      stringptr = findfield(stringptr);
+      if (*stringptr == '\0') {
+        setpointmark(pointloop, 0);
+      } else {
+        currentmarker = (int) strtol (stringptr, &stringptr, 0);
+        setpointmark(pointloop, currentmarker);
+      }
+    } else {
+      // If no markers are specified in the file, they default to zero.
+      setpointmark(pointloop, 0);
+    }
+    // Determine the smallest and largest x and y coordinates.
+    if (i == 0) {
+      xmin = xmax = x;
+      ymin = ymax = y;
+      zmin = zmax = z;
+    } else {
+      xmin = (x < xmin) ? x : xmin;
+      xmax = (x > xmax) ? x : xmax;
+      ymin = (y < ymin) ? y : ymin;
+      ymax = (y > ymax) ? y : ymax;
+      zmin = (z < ymin) ? z : zmin;
+      zmax = (z > zmax) ? z : zmax;
+    }
+  }
+  if (readnodefile) {
+    fclose(infile);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// readholes()   Read the holes, and possibly regional attributes and volume //
+//               constraints, from a .poly file.                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::readholes(FILE *polyfile, REAL **hlist, int *holes, REAL **rlist,
+                       int *regions)
+{
+  REAL *holelist;
+  REAL *regionlist;
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  int index;
+  int i;
+
+  // Read the holes.
+  if (poly || smesh) {
+    stringptr = readline(inputline, polyfile, inpolyfilename);
+    *holes = (int) strtol (stringptr, &stringptr, 0);
+  } else {
+    // There need not hole section in smesh file format.
+    *holes = 0;
+  }
+  if (*holes > 0) {
+    holelist = (REAL *) new REAL[3 * *holes];
+    *hlist = holelist;
+    for (i = 0; i < 3 * *holes; i += 3) {
+      stringptr = readline(inputline, polyfile, inpolyfilename);
+      stringptr = findfield(stringptr);
+      if (*stringptr == '\0') {
+        printf("File I/O Error:  Hole %d has no x coordinate.\n",
+               firstnumber + (i / 3));
+        exit(1);
+      } else {
+        holelist[i] = (REAL) strtod(stringptr, &stringptr);
+      }
+      stringptr = findfield(stringptr);
+      if (*stringptr == '\0') {
+        printf("File I/O Error:  Hole %d has no y coordinate.\n",
+               firstnumber + (i / 3));
+        exit(1);
+      } else {
+        holelist[i + 1] = (REAL) strtod(stringptr, &stringptr);
+      }
+      stringptr = findfield(stringptr);
+      if (*stringptr == '\0') {
+        printf("File I/O Error:  Hole %d has no z coordinate.\n",
+               firstnumber + (i / 3));
+        exit(1);
+      } else {
+        holelist[i + 2] = (REAL) strtod(stringptr, &stringptr);
+      }
+    }
+  } else {
+    *hlist = (REAL *) NULL;
+  }
+
+  if ((regionattrib || varvolume) && !refine) {
+    // Read the volume constraints.
+    stringptr = readline(inputline, polyfile, inpolyfilename);
+    *regions = (int) strtol (stringptr, &stringptr, 0);
+    if (*regions > 0) {
+      regionlist = (REAL *) new REAL[5 * *regions];
+      *rlist = regionlist;
+      index = 0;
+      for (i = 0; i < *regions; i++) {
+        stringptr = readline(inputline, polyfile, inpolyfilename);
+        stringptr = findfield(stringptr);
+        if (*stringptr == '\0') {
+          printf("File I/O Error:  Region %d has no x coordinate.\n",
+                 firstnumber + i);
+          exit(1);
+        } else {
+          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findfield(stringptr);
+        if (*stringptr == '\0') {
+          printf("File I/O Error:  Region %d has no y coordinate.\n",
+                 firstnumber + i);
+          exit(1);
+        } else {
+          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findfield(stringptr);
+        if (*stringptr == '\0') {
+          printf("File I/O Error:  Region %d has no z coordinate.\n",
+                 firstnumber + i);
+          exit(1);
+        } else {
+          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findfield(stringptr);
+        if (*stringptr == '\0') {
+          printf("File I/O Error:  Region %d has no region attribute or",
+                 firstnumber + i);
+          printf(" volume constraint.\n");
+          exit(1);
+        } else {
+          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findfield(stringptr);
+        if (*stringptr == '\0') {
+          regionlist[index] = regionlist[index - 1];
+        } else {
+          regionlist[index] = (REAL) strtod(stringptr, &stringptr);
+        }
+        index++;
+      }
+    }
+  } else {
+    // Set `*regions' to zero to avoid an accidental free() later.
+    *regions = 0;
+    *rlist = (REAL *) NULL;
+  }
+
+  fclose(polyfile);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outnodes()    Number the points and write them to a .node file.           //
+//                                                                           //
+// To save memory, the point numbers are written over the shell markers      //
+// after the points are written to a file.                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::outnodes()
+{
+  FILE *outfile;
+  point3d pointloop;
+  int pointnumber;
+  int i;
+
+  if (!quiet) {
+    printf("Writing %s.\n", outnodefilename);
+  }
+  outfile = fopen(outnodefilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot create file %s.\n", outnodefilename);
+    exit(1);
+  }
+  // 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, mesh_dim, nextras,
+          1 - nobound);
+
+  points.traversalinit();
+  pointloop = pointtraverse();
+  pointnumber = firstnumber;
+  while (pointloop != (point3d) 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[i + 3]);
+    }
+    if (nobound) {
+      fprintf(outfile, "\n");
+    } else {
+      // Write the boundary marker.
+      fprintf(outfile, "    %d\n", pointmark(pointloop));
+    }
+    setpointmark(pointloop, pointnumber);
+    pointloop = pointtraverse();
+    pointnumber++;
+  }
+
+  fprintf(outfile, "# Generated by %s\n", commandline);
+  fclose(outfile);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// numbernodes()    Number the points.                                       //
+//                                                                           //
+// Each point is assigned a marker equal to its number.                      //
+//                                                                           //
+// Used when outnodes() is not called because no .node file is written.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::numbernodes(int myfirstnumber)
+{
+  point3d pointloop;
+  int pointnumber;
+
+  points.traversalinit();
+  pointloop = pointtraverse();
+  if (!myfirstnumber) {
+    pointnumber = firstnumber;
+  } else {
+    pointnumber = myfirstnumber;
+  }
+  while (pointloop != (point3d) NULL) {
+    setpointmark(pointloop, pointnumber);
+    pointloop = pointtraverse();
+    pointnumber++;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outelems()     Write the tetrahedra to an .ele file.                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::outelems()
+{
+  FILE *outfile;
+  tetrahedron* tptr;
+  point3d p1, p2, p3, p4;
+  int elementnumber;
+  int i;
+
+  if (!quiet) {
+    printf("Writing %s.\n", outelefilename);
+  }
+  outfile = fopen(outelefilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot create file %s.\n", outelefilename);
+    exit(1);
+  }
+  // Number of tetras, points per tetra, attributes per tetra.
+  fprintf(outfile, "%ld  %d  %d\n", tetrahedrons.items, 4, eextras);
+
+  tetrahedrons.traversalinit();
+  tptr = tetrahedrontraverse();
+  elementnumber = firstnumber;
+  while (tptr != (tetrahedron *) NULL) {
+    p1 = (point3d) tptr[4];
+    p2 = (point3d) tptr[5];
+    p3 = (point3d) tptr[6];
+    p4 = (point3d) tptr[7];
+    // Triangle number, indices for three points.
+    fprintf(outfile, "%5d   %5d %5d %5d %5d", elementnumber,
+            pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4));
+    for (i = 0; i < eextras; i++) {
+      fprintf(outfile, "    %.17g", elemattribute(tptr, i));
+    }
+    fprintf(outfile, "\n");
+    tptr = tetrahedrontraverse();
+    elementnumber++;
+  }
+
+  fprintf(outfile, "# Generated by %s\n", commandline);
+  fclose(outfile);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outelems2gid()    Generate mesh files for viewing by Gid.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::outelems2gid()
+{
+  FILE *outfile;
+  char gidfilename[FILENAMESIZE];
+  tetrahedron* tetptr;
+  point3d pointloop, p1, p2, p3, p4;;
+  int pointnumber, elementnumber;
+  int i;
+
+  strcpy(gidfilename, outelefilename);
+  strcat(gidfilename, ".gid");
+
+  if (!quiet) {
+    printf("Writing %s.\n", gidfilename);
+  }
+  outfile = fopen(gidfilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot create file %s.\n", gidfilename);
+    return;
+  }
+
+  fprintf(outfile, "mesh dimension = 3 elemtype tetrahedron nnode = 4\n");
+  fprintf(outfile, "coordinates\n");
+
+  points.traversalinit();
+  pointloop = pointtraverse();
+  pointnumber = 1;  // Gid mesh reader must need first number be '1'.
+  while (pointloop != (point3d) 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[i + 3]);
+    }
+    if (nobound) {
+      fprintf(outfile, "\n");
+    } else {
+      // Write the boundary marker.
+      fprintf(outfile, "    %d\n", pointmark(pointloop));
+    }
+    setpointmark(pointloop, pointnumber);
+    pointloop = pointtraverse();
+    pointnumber++;
+  }
+
+  fprintf(outfile, "end coordinates\n");
+  fprintf(outfile, "elements\n");
+
+  tetrahedrons.traversalinit();
+  tetptr = tetrahedrontraverse();
+  elementnumber = 1;
+  while (tetptr != (tetrahedron *) NULL) {
+    p1 = (point3d) tetptr[4];
+    p2 = (point3d) tetptr[5];
+    p3 = (point3d) tetptr[6];
+    p4 = (point3d) tetptr[7];
+    // tetrahedron number, indices for four points.
+    fprintf(outfile, "%5d  %5d %5d %5d %5d", elementnumber,
+            pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4));
+
+    for (i = 0; i < eextras; i++) {
+      fprintf(outfile, "  %.17g", elemattribute(tetptr, i));
+    }
+    fprintf(outfile, "\n");
+
+    tetptr = tetrahedrontraverse();
+    elementnumber++;
+  }
+
+  fprintf(outfile, "end elements\n");
+  fclose(outfile);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outelems2fa()    Generate mesh files for viewing by FA.                   //
+//                                                                           //
+// There need three files: .prj, .cor and .elm for FA.                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::outelems2fa()
+{
+  FILE *outfile;
+  char fafilename[FILENAMESIZE];
+  tetrahedron* tetptr;
+  point3d pointloop, p1, p2, p3, p4;;
+  int pointnumber, elementnumber;
+  int i;
+
+  strcpy(fafilename, outelefilename);
+  strcat(fafilename, ".prj");
+
+  if (!quiet) {
+    printf("Writing %s.\n", fafilename);
+  }
+  outfile = fopen(fafilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot create file %s.\n", fafilename);
+    return;
+  }
+  fprintf(outfile, "%s\n", outelefilename);
+  fprintf(outfile, "0\n0\n0\n");
+  fclose(outfile);
+
+  strcpy(fafilename, outelefilename);
+  strcat(fafilename, ".cor");
+
+  if (!quiet) {
+    printf("Writing %s.\n", fafilename);
+  }
+  outfile = fopen(fafilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot create file %s.\n", fafilename);
+    return;
+  }
+  fprintf(outfile, "%d    3\n", points.items);
+
+  points.traversalinit();
+  pointloop = pointtraverse();
+  pointnumber = 1;  // FA mesh reader must need first number be '1'.
+  while (pointloop != (point3d) NULL) {
+    // Point number, x , y and z coordinates.
+    fprintf(outfile, "%.17g %.17g %.17g\n", pointloop[0],
+            pointloop[1], pointloop[2]);
+    setpointmark(pointloop, pointnumber);
+    pointloop = pointtraverse();
+    pointnumber++;
+  }
+  fclose(outfile);
+
+  strcpy(fafilename, outelefilename);
+  strcat(fafilename, ".elm");
+
+  if (!quiet) {
+    printf("Writing %s.\n", fafilename);
+  }
+  outfile = fopen(fafilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot create file %s.\n", fafilename);
+    return;
+  }
+  fprintf(outfile, "%d    5\n", tetrahedrons.items);
+
+  tetrahedrons.traversalinit();
+  tetptr = tetrahedrontraverse();
+  elementnumber = 1;
+  while (tetptr != (tetrahedron *) NULL) {
+    p1 = (point3d) tetptr[4];
+    p2 = (point3d) tetptr[5];
+    p3 = (point3d) tetptr[6];
+    p4 = (point3d) tetptr[7];
+    // tetrahedron number, indices for four points.
+    fprintf(outfile, "%5d %5d %5d %5d",
+            pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4));
+    if (eextras > 0) {
+      fprintf(outfile, "  %.17g", elemattribute(tetptr, 0) + 1);
+    } else {
+      fprintf(outfile, "  1");
+    }
+    fprintf(outfile, "\n");
+
+    tetptr = tetrahedrontraverse();
+    elementnumber++;
+  }
+  fclose(outfile);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outfaces()    Write the faces to a .face file.                            //
+//                                                                           //
+// Also use this routine to output hull faces(when hull = 1).                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::outfaces(int hull)
+{
+  FILE *outfile;
+  triface tface, tsymface;
+  face checkmark;
+  point3d torg, tdest, tapex;
+  int facenumber;
+
+  if (!quiet) {
+    printf("Writing %s.\n", facefilename);
+  }
+  outfile = fopen(facefilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot create file %s.\n", facefilename);
+    exit(1);
+  }
+  // Number of faces, number of boundary markers (zero or one).
+  if (hull) {
+    fprintf(outfile, "%ld  %d\n", hullsize, 1 - nobound);
+  } else {
+    fprintf(outfile, "%ld  %d\n", faces, 1 - nobound);
+  }
+
+  tetrahedrons.traversalinit();
+  tface.tet = tetrahedrontraverse();
+  facenumber = firstnumber;
+  // To loop over the set of faces, loop over all tetrahedrons, and look at
+  //   the four faces of each tetrahedron. If there isn't another
+  //   tetrahedron adjacent to the face, operate on the face.  If there is
+  //   another adjacent tetrahedron, operate on the face only if the current
+  //   tetrahedron has a smaller pointer than its neighbor.  This way, each
+  //   face is considered only once.
+  // If the 'hull' flag is set, only operate on faces which neighbour is
+  //   'dummytet'. This will only output hull faces.
+  while (tface.tet != (tetrahedron *) NULL) {
+    for (tface.loc = 0; tface.loc < 4; tface.loc ++) {
+      sym(tface, tsymface);
+      if ((tface.tet < tsymface.tet) || (tsymface.tet == dummytet)) {
+        org (tface, torg);
+        dest(tface, tdest);
+        apex(tface, tapex);
+        if (hull) {
+          if (tsymface.tet == dummytet) {
+            // Only output hull faces.
+            fprintf(outfile, "%5d   %4d  %4d  %4d\n", facenumber,
+                    pointmark(torg), pointmark(tdest), pointmark(tapex));
+            facenumber++;
+          }
+        } else {
+          if (nobound) {
+            // Face number, indices of three vertexs.
+            fprintf(outfile, "%5d   %4d  %4d  %4d\n", facenumber,
+                    pointmark(torg), pointmark(tdest), pointmark(tapex));
+          } else {
+            // Face number, indices of three vertexs, and a boundary marker.
+            //   If there's no shell face, the boundary marker is zero.
+            if (useshelles) {
+              tspivot(tface, checkmark);
+              if ((checkmark.sh == dummysh) || isnonsolid(checkmark)) {
+                fprintf(outfile, "%5d   %4d  %4d  %4d  %4d\n", facenumber,
+                        pointmark(torg), pointmark(tdest), pointmark(tapex), 0);
+              } else {
+                fprintf(outfile, "%5d   %4d  %4d  %4d  %4d\n", facenumber,
+                        pointmark(torg), pointmark(tdest), pointmark(tapex),
+                        mark(checkmark));
+              }
+            } else {
+              fprintf(outfile, "%5d   %4d  %4d  %4d  %4d\n", facenumber,
+                      pointmark(torg), pointmark(tdest), pointmark(tapex),
+                      tsymface.tet == dummytet);
+            }
+          }
+          facenumber++;
+        }
+      }
+    }
+    tface.tet = tetrahedrontraverse();
+  }
+
+  fprintf(outfile, "# Generated by %s\n", commandline);
+  fclose(outfile);
+}
+
+void mesh3d::outfaces2gid(int hull)
+{
+  FILE *outfile;
+  char gidfilename[FILENAMESIZE];
+  triface tface, tsymface;
+  face checkmark;
+  point3d pointloop, torg, tdest, tapex;
+  int pointnumber, facenumber, i;
+
+  strcpy(gidfilename, facefilename);
+  strcat(gidfilename, ".gid");
+
+  if (!quiet) {
+    printf("Writing %s.\n", gidfilename);
+  }
+  outfile = fopen(gidfilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot create file %s.\n", gidfilename);
+    return;
+  }
+
+  fprintf(outfile, "mesh dimension = 3 elemtype triangle nnode = 3\n");
+  fprintf(outfile, "coordinates\n");
+
+  points.traversalinit();
+  pointloop = pointtraverse();
+  pointnumber = 1;  // Gid mesh reader must need first number be '1'.
+  while (pointloop != (point3d) 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[i + 3]);
+    }
+    if (nobound) {
+      fprintf(outfile, "\n");
+    } else {
+      // Write the boundary marker.
+      fprintf(outfile, "    %d\n", pointmark(pointloop));
+    }
+    setpointmark(pointloop, pointnumber);
+    pointloop = pointtraverse();
+    pointnumber++;
+  }
+
+  fprintf(outfile, "end coordinates\n");
+  fprintf(outfile, "elements\n");
+
+  tetrahedrons.traversalinit();
+  tface.tet = tetrahedrontraverse();
+  facenumber = 1;
+  // To loop over the set of faces, loop over all tetrahedra, and look at
+  //   the four faces of each tetrahedron. If there isn't another tetrahedron
+  //   adjacent to the face, operate on the face.  If there is another adj-
+  //   acent tetrahedron, operate on the face only if the current tetrahedron
+  //   has a smaller pointer than its neighbor.  This way, each face is
+  //   considered only once.
+  // If the 'hull' flag is set, only operate on faces which neighbour is
+  //   'dummytet'. This will only output hull faces.
+  while (tface.tet != (tetrahedron *) NULL) {
+    for (tface.loc = 0; tface.loc < 4; tface.loc ++) {
+      sym(tface, tsymface);
+      if ((tface.tet < tsymface.tet) || (tsymface.tet == dummytet)) {
+        org (tface, torg);
+        dest(tface, tdest);
+        apex(tface, tapex);
+        if (hull) {
+          if (tsymface.tet == dummytet) {
+            // Only output hull faces.
+            fprintf(outfile, "%5d   %d  %d  %d\n", facenumber,
+                    pointmark(torg), pointmark(tdest), pointmark(tapex));
+            facenumber++;
+          }
+        } else {
+          if (nobound) {
+            // Face number, indices of three vertexs.
+            fprintf(outfile, "%5d   %d  %d  %d\n", facenumber,
+                    pointmark(torg), pointmark(tdest), pointmark(tapex));
+          } else {
+            // Face number, indices of three vertexs, and a boundary marker.
+            //   If there's no shell face, the boundary marker is zero.
+            if (useshelles) {
+              tspivot(tface, checkmark);
+              if (checkmark.sh == dummysh) {
+                fprintf(outfile, "%5d   %d  %d  %d  %d\n", facenumber,
+                        pointmark(torg), pointmark(tdest), pointmark(tapex), 0);
+              } else {
+                fprintf(outfile, "%5d   %d  %d  %d  %d\n", facenumber,
+                        pointmark(torg), pointmark(tdest), pointmark(tapex),
+                        mark(checkmark));
+              }
+            } else {
+              fprintf(outfile, "%5d   %d  %d  %d  %d\n", facenumber,
+                      pointmark(torg), pointmark(tdest), pointmark(tapex),
+                      tsymface.tet == dummytet);
+            }
+          }
+          facenumber++;
+        }
+      }
+    }
+    tface.tet = tetrahedrontraverse();
+  }
+
+  fprintf(outfile, "end elements\n");
+  fclose(outfile);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outedges()    Write the edges (segments) to a .edge file.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::outedges()
+{
+  FILE *outfile;
+  face segloop;
+  point3d torg, tdest;
+  int edgenumber;
+
+  if (!quiet) {
+    printf("Writing %s.\n", edgefilename);
+  }
+  outfile = fopen(edgefilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot create file %s.\n", edgefilename);
+    exit(1);
+  }
+  // Number of edges.
+  fprintf(outfile, "%ld\n", subsegs.items);
+
+  subsegs.traversalinit();
+  segloop.sh = shellfacetraverse(&subsegs);
+  edgenumber = firstnumber;
+  while (segloop.sh != (shellface*) NULL) {
+    torg = sorg(segloop);
+    tdest = sdest(segloop);
+    fprintf(outfile, "%5d   %4d  %4d\n", edgenumber,
+            pointmark(torg), pointmark(tdest));
+    edgenumber++;
+    segloop.sh = shellfacetraverse(&subsegs);
+  }
+
+  fprintf(outfile, "# Generated by %s\n", commandline);
+  fclose(outfile);
+}
+
+void mesh3d::outedges2gid()
+{
+  FILE *outfile;
+  char gidfilename[FILENAMESIZE];
+  face segloop;
+  point3d pointloop, torg, tdest;
+  int pointnumber, edgenumber, i;
+
+  strcpy(gidfilename, edgefilename);
+  strcat(gidfilename, ".gid");
+
+  if (!quiet) {
+    printf("Writing %s.\n", gidfilename);
+  }
+  outfile = fopen(gidfilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot create file %s.\n", gidfilename);
+    return;
+  }
+
+  fprintf(outfile, "MESH    dimension 3 ElemType Linear  Nnode 2\n");
+  fprintf(outfile, "Coordinates\n");
+
+  points.traversalinit();
+  pointloop = pointtraverse();
+  pointnumber = 1;  // Gid mesh reader must need first number be '1'.
+  while (pointloop != (point3d) 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[i + 3]);
+    }
+    if (nobound) {
+      fprintf(outfile, "\n");
+    } else {
+      // Write the boundary marker.
+      fprintf(outfile, "    %d\n", pointmark(pointloop));
+    }
+    setpointmark(pointloop, pointnumber);
+    pointloop = pointtraverse();
+    pointnumber++;
+  }
+
+  fprintf(outfile, "end coordinates\n");
+  fprintf(outfile, "Elements\n");
+
+  subsegs.traversalinit();
+  segloop.sh = shellfacetraverse(&subsegs);
+  edgenumber = firstnumber;
+  while (segloop.sh != (shellface*) NULL) {
+    torg = sorg(segloop);
+    tdest = sdest(segloop);
+    fprintf(outfile, "%5d   %4d  %4d\n", edgenumber,
+            pointmark(torg), pointmark(tdest));
+    edgenumber++;
+    segloop.sh = shellfacetraverse(&subsegs);
+  }
+
+  fprintf(outfile, "end elements\n");
+  fclose(outfile);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outneighbors()    Write neighbor elems to file *.neigh                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::outneighbors()
+{
+  FILE *outfile;
+  tetrahedron *tptr;
+  triface tetloop, tetsym;
+  int elementnumber;
+  int neighbor1, neighbor2, neighbor3, neighbor4;
+
+  if (!quiet) {
+    printf("Writing %s.\n", neighborfilename);
+  }
+  outfile = fopen(neighborfilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot create file %s.\n", neighborfilename);
+    exit(1);
+  }
+  // Number of tetrahedra, four faces per tetrahedron.
+  fprintf(outfile, "%ld  %d\n", tetrahedrons.items, 4);
+
+  tetrahedrons.traversalinit();
+  tptr = tetrahedrontraverse();
+  elementnumber = firstnumber;
+  while (tptr != (tetrahedron *) NULL) {
+    * (int *) (tptr + 8) = elementnumber;
+    tptr = tetrahedrontraverse();
+    elementnumber++;
+  }
+  * (int *) (dummytet + 8) = -1;
+
+  tetrahedrons.traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  elementnumber = firstnumber;
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    tetloop.loc = 0;
+    sym(tetloop, tetsym);
+    neighbor1 = * (int *) (tetsym.tet + 8);
+    tetloop.loc = 1;
+    sym(tetloop, tetsym);
+    neighbor2 = * (int *) (tetsym.tet + 8);
+    tetloop.loc = 2;
+    sym(tetloop, tetsym);
+    neighbor3 = * (int *) (tetsym.tet + 8);
+    tetloop.loc = 3;
+    sym(tetloop, tetsym);
+    neighbor4 = * (int *) (tetsym.tet + 8);
+    // Tetrahedra number, neighboring tetrahedron numbers.
+    fprintf(outfile, "%4d    %4d  %4d  %4d  %4d\n", elementnumber,
+            neighbor1, neighbor2, neighbor3, neighbor4);
+    tptr = tetrahedrontraverse();
+    elementnumber++;
+  }
+
+  fprintf(outfile, "# Generated by %s\n", commandline);
+  fclose(outfile);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+//  outoff()    Write the triangulation to an .off file.                     //
+//                                                                           //
+//  OFF stands for the Object File Format, a format used by the Geometry     //
+//  Center's Geomview package.                                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::outoff()
+{
+  FILE *outfile;
+  triface tface, tsymface;
+  point3d pointloop;
+  point3d torg, tdest, tapex;
+
+  if (!quiet) {
+    printf("Writing %s.\n", offfilename);
+  }
+  outfile = fopen(offfilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot create file %s.\n", offfilename);
+    exit(1);
+  }
+  // Number of points, faces, and edges(not used, here show hullsize).
+  fprintf(outfile, "OFF\n%ld  %ld  %ld\n", points.items, faces, hullsize);
+
+  // Write the points.
+  points.traversalinit();
+  pointloop = pointtraverse();
+  while (pointloop != (point3d) NULL) {
+    fprintf(outfile, " %.17g  %.17g  %.17g\n", pointloop[0],
+            pointloop[1], pointloop[2]);
+    pointloop = pointtraverse();
+  }
+
+  tetrahedrons.traversalinit();
+  tface.tet = tetrahedrontraverse();
+  // To loop over the set of faces, loop over all tetrahedra, and look at
+  //   the four faces of each tetrahedron. If there isn't another tetrahedron
+  //   adjacent to the face, operate on the face.  If there is another adj-
+  //   acent tetrahedron, operate on the face only if the current tetrahedron
+  //   has a smaller pointer than its neighbor.  This way, each face is
+  //   considered only once.
+  // If the 'hull' flag is set, only operate on faces which neighbour is
+  //   'dummytet'. This will only output hull faces.
+  while (tface.tet != (tetrahedron *) NULL) {
+    for (tface.loc = 0; tface.loc < 4; tface.loc ++) {
+      sym(tface, tsymface);
+      if ((tface.tet < tsymface.tet) || (tsymface.tet == dummytet)) {
+        org (tface, torg);
+        dest(tface, tdest);
+        apex(tface, tapex);
+        // Face number, indices of three vertexs.
+        fprintf(outfile, "3   %4d  %4d  %4d\n", pointmark(torg) - 1,
+                pointmark(tdest) - 1, pointmark(tapex) - 1);
+      }
+    }
+    tface.tet = tetrahedrontraverse();
+  }
+
+  fprintf(outfile, "# Generated by %s\n", commandline);
+  fclose(outfile);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dumpallbadelems()    Output all bad elements.                             //
+//                                                                           //
+// Bad elements include Sliver, Cap, Wedge, Spindle, Needle.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::dumpallbadelems(char* badelemfilename)
+{
+  FILE *outfile;
+  tetrahedron* tetptr;
+  point3d pointloop, p1, p2, p3, p4;
+  REAL alldihed[6], allsolid[4];
+  REAL smallsolid, largesolid;
+  REAL smalldihed, largedihed;
+  REAL smallestdiangle, biggestdiangle;
+  int pointnumber, elementnumber;
+  int smalldihedcount, largedihedcount;
+  int smallsolidcount, largesolidcount;
+  int elemtype;
+  int i;
+
+  if (!quiet) {
+    printf("Writing %s.\n", badelemfilename);
+  }
+  outfile = fopen(badelemfilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot create file %s.\n", badelemfilename);
+    return;
+  }
+  smallsolid = 3.;
+  largesolid = 300.;
+  smalldihed = 20.;
+  largedihed = 160.;
+
+  fprintf(outfile, "mesh dimension = 3 elemtype tetrahedron nnode = 4\n");
+  fprintf(outfile, "coordinates\n");
+
+  points.traversalinit();
+  pointloop = pointtraverse();
+  pointnumber = 1;  // Gid mesh reader must need first number be '1'.
+  while (pointloop != (point3d) 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[i + 3]);
+    }
+    if (nobound) {
+      fprintf(outfile, "\n");
+    } else {
+      // Write the boundary marker.
+      fprintf(outfile, "    %d\n", pointmark(pointloop));
+    }
+    setpointmark(pointloop, pointnumber);
+    pointloop = pointtraverse();
+    pointnumber++;
+  }
+
+  fprintf(outfile, "end coordinates\n");
+  fprintf(outfile, "elements\n");
+
+  tetrahedrons.traversalinit();
+  tetptr = tetrahedrontraverse();
+  elementnumber = 1;
+  while (tetptr != (tetrahedron *) NULL) {
+    p1 = (point3d) tetptr[4];
+    p2 = (point3d) tetptr[5];
+    p3 = (point3d) tetptr[6];
+    p4 = (point3d) tetptr[7];
+
+    tetalldihedral(p1, p2, p3, p4, alldihed);
+    smalldihedcount = largedihedcount = 0;
+    smallestdiangle = 180;
+    biggestdiangle = 0;
+    for (i = 0; i < 6; i++) {
+      if (alldihed[i] < smallestdiangle) {
+        smallestdiangle = alldihed[i];
+      } else if (alldihed[i] > biggestdiangle) {
+        biggestdiangle = alldihed[i];
+      }
+      if (alldihed[i] < smalldihed) {
+        smalldihedcount++;
+      } else if (alldihed[i] > largedihed) {
+        largedihedcount++;
+      }
+    }
+    allsolid[0] = alldihed[0] + alldihed[1] + alldihed[2] - 180;
+    allsolid[1] = alldihed[0] + alldihed[3] + alldihed[4] - 180;
+    allsolid[2] = alldihed[1] + alldihed[3] + alldihed[5] - 180;
+    allsolid[3] = alldihed[2] + alldihed[4] + alldihed[5] - 180;
+    smallsolidcount = largesolidcount = 0;
+    for (i = 0; i < 4; i++) {
+      if (allsolid[i] < smallsolid) {
+        smallsolidcount++;
+      } else if (allsolid[i] > largesolid) {
+        largesolidcount++;
+      }
+    }
+    if (largesolidcount >= 1) {
+      elemtype = 1; // capcount++;
+    } else if ((largedihedcount > 0) && (smalldihedcount > 0)) {
+      elemtype = 2; // slivercount++;
+    } else if (largedihedcount > 0) {
+      elemtype = 3; // spindlecount++;
+    } else if (smalldihedcount > 0) {
+      elemtype = 4; // wedgecount++;
+    } else if (smallsolidcount > 0) {
+      elemtype = 5; // needlecount++;
+    } else {
+      elemtype = 0; // roundcount++;
+    }
+
+    if (elemtype) {
+      // tetrahedron number, indices for four points.
+      fprintf(outfile, "%5d  %5d %5d %5d %5d  %10.6g %10.6g", elementnumber,
+              pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4),
+              smallestdiangle, biggestdiangle);
+      if (elemtype == 1) {
+        fprintf(outfile, "      Cap");
+      } else if (elemtype == 2) {
+        fprintf(outfile, "      Sliver");
+      } else if (elemtype == 3) {
+        fprintf(outfile, "      Spindle");
+      } else if (elemtype == 4) {
+        fprintf(outfile, "      Wedge");
+      } else if (elemtype == 5) {
+        fprintf(outfile, "      Needle");
+      }
+      fprintf(outfile, "\n");
+    }
+
+    tetptr = tetrahedrontraverse();
+    elementnumber++;
+  }
+
+  fprintf(outfile, "end elements\n");
+  fclose(outfile);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// END                                                                       //
+// File I/O Routines                                                         //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// internalerror()    Ask the user to send me the defective product.  Exit.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::internalerror()
+{
+  printf("  Please report this bug to sihang@weboo.com. 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);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// precisionerror()    Print an error message for precision problems.        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::precisionerror()
+{
+  if (noexact) {
+    printf("  This problem maybe caused by the approximate floating-point\n");
+    printf("    arthmetic. Try use -X switch in commandline and try again.\n");
+  } else {
+    printf("  Try increasing the volume criterion and/or increasing the\n");
+    printf("    minimum allowable radius-edge ratio so that tiny tetrahedra\n");
+    printf("    are not created.\n");
+  }
+#ifdef SINGLE
+  printf("  Alternatively, try recompiling me with double precision\n");
+  printf("    arithmetic (by removing \"#define SINGLE\" from the\n");
+  printf("    source file or \"-DSINGLE\" from the makefile).\n");
+#endif // SINGLE
+  exit(1);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// recovererror()      Print an error message for recover problems.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::recovererror()
+{
+  printf("  You met a recover problem in your model. Please check your\n");
+  printf("    input PLC facet data, make sure that all coplanar segments,\n");
+  printf("    polygons and isolated points are list in this facet.\n");
+  printf("  If there still has problem, please report this bug to \n");
+  printf("    sihang@weboo.com. Include the message above, your input data\n");
+  printf("    set, and the exact command line you used to run this program,\n");
+  printf("    thank you.\n");
+  exit(1);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkmesh()    Test the mesh for topological consistency.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::checkmesh()
+{
+  triface tetraloop;
+  triface oppotet, oppooppotet;
+  point3d tetorg, tetdest, tetapex, tetoppo;
+  point3d oppoorg, oppodest, oppoapex;
+  int horrors;
+  int saveexact;
+
+  // Temporarily turn on exact arithmetic if it's off.
+  saveexact = noexact;
+  noexact = 0;
+  if (!quiet) {
+    printf("  Checking consistency of mesh...\n");
+  }
+  if (verbose < 1) {
+    numbernodes(1);
+  }
+  horrors = 0;
+  // Run through the list of tetrahedra, checking each one.
+  tetrahedrons.traversalinit();
+  tetraloop.tet = tetrahedrontraverse();
+  while (tetraloop.tet != (tetrahedron *) NULL) {
+    // Check all four faces of the tetrahedron.
+    for (tetraloop.loc = 0; tetraloop.loc < 4; tetraloop.loc++) {
+      org (tetraloop, tetorg);
+      dest(tetraloop, tetdest);
+      apex(tetraloop, tetapex);
+      oppo(tetraloop, tetoppo);
+      if (tetraloop.loc == 0) {             // Only test for inversion once.
+        if (orient3d(tetorg, tetdest, tetapex, tetoppo) >= 0.0) {
+          printf("  !! !! Inverted ");
+          dump(&tetraloop);
+          horrors++;
+        }
+      }
+      // Find the neighboring tetrahedron on this face.
+      sym(tetraloop, oppotet);
+      if (oppotet.tet != dummytet) {
+        // Check that the tetrahedron's neighbor knows it's a neighbor.
+        sym(oppotet, oppooppotet);
+        if ((tetraloop.tet != oppooppotet.tet)
+            || (tetraloop.loc != oppooppotet.loc)) {
+          printf("  !! !! Asymmetric tetra-tetra bond:\n");
+          if (tetraloop.tet == oppooppotet.tet) {
+            printf("   (Right tetrahedron, wrong orientation)\n");
+          }
+          printf("    First ");
+          dump(&tetraloop);
+          printf("    Second (nonreciprocating) ");
+          dump(&oppotet);
+          horrors++;
+        }
+        // Check that both tetrahedra agree on the identities
+        //   of their shared vertices.
+        if (findorg(&oppotet, tetorg)) {
+          dest(oppotet, oppodest);
+          apex(oppotet, oppoapex);
+        } else {
+          oppodest = (point3d) NULL;
+        }
+        if ((tetdest != oppoapex) || (tetapex != oppodest)) {
+          printf("  !! !! Mismatched face coordinates between two tetras:\n");
+          printf("    First mismatched ");
+          dump(&tetraloop);
+          printf("    Second mismatched ");
+          dump(&oppotet);
+          horrors++;
+        }
+      }
+    }
+    tetraloop.tet = tetrahedrontraverse();
+  }
+  if (horrors == 0) {
+    if (!quiet) {
+      printf("  In my studied opinion, the mesh appears to be consistent.\n");
+    }
+  } else if (horrors == 1) {
+    printf("  !! !! !! !! Precisely one festering wound discovered.\n");
+  } else {
+    printf("  !! !! !! !! %d abominations witnessed.\n", horrors);
+  }
+  // Restore the status of exact arithmetic.
+  noexact = saveexact;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkdelaunay()    Ensure that the mesh is (constrained or conforming)    //
+//                    Delaunay.                                              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::checkdelaunay()
+{
+  triface tetraloop;
+  triface oppotet;
+  face opposhelle;
+  point3d tetorg, tetdest, tetapex, tetoppo;
+  point3d oppooppo;
+  int shouldbedelaunay;
+  int horrors;
+  int saveexact;
+
+  // Temporarily turn on exact arithmetic if it's off.
+  saveexact = noexact;
+  noexact = 0;
+  if (!quiet) {
+    printf("  Checking Delaunay property of mesh...\n");
+  }
+  if (verbose < 1) {
+    numbernodes(1);
+  }
+  horrors = 0;
+  // Run through the list of triangles, checking each one.
+  tetrahedrons.traversalinit();
+  tetraloop.tet = tetrahedrontraverse();
+  while (tetraloop.tet != (tetrahedron *) NULL) {
+    // Check all three edges of the triangle.
+    for (tetraloop.loc = 0; tetraloop.loc < 4; tetraloop.loc++) {
+      org(tetraloop, tetorg);
+      dest(tetraloop, tetdest);
+      apex(tetraloop, tetapex);
+      oppo(tetraloop, tetoppo);
+      sym(tetraloop, oppotet);
+      oppo(oppotet, oppooppo);
+      // Only test that the face is locally Delaunay if there is an
+      //   adjoining tetrahedron whose pointer is larger (to ensure that
+      //   each pair isn't tested twice).
+      shouldbedelaunay = (oppotet.tet != dummytet)
+                          && (tetoppo != (point3d) NULL)
+                          && (oppooppo != (point3d) NULL)
+                          && (tetraloop.tet < oppotet.tet);
+      if (checksegments && shouldbedelaunay) {
+        // If a shell edge separates the triangles, then the edge is
+        //   constrained, so no local Delaunay test should be done.
+        tspivot(tetraloop, opposhelle);
+        if (opposhelle.sh != dummysh){
+          if (!isnonsolid(opposhelle)) {
+            shouldbedelaunay = 0;
+          }
+        }
+      }
+      if (shouldbedelaunay) {
+        if (iinsphere(tetdest, tetorg, tetapex, tetoppo, oppooppo) > 0) {
+          printf("  !! !! Non-Delaunay pair of triangles:\n");
+          printf("    First non-Delaunay ");
+          dump(&tetraloop);
+          printf("    Second non-Delaunay ");
+          dump(&oppotet);
+          horrors++;
+        }
+      }
+    }
+    tetraloop.tet = tetrahedrontraverse();
+  }
+  if (horrors == 0) {
+    if (!quiet) {
+      printf(
+  "  By virtue of my perceptive intelligence, I declare the mesh Delaunay.\n");
+    }
+  } else if (horrors == 1) {
+    printf(
+         "  !! !! !! !! Precisely one terrifying transgression identified.\n");
+  } else {
+    printf("  !! !! !! !! %d obscenities viewed with horror.\n", horrors);
+  }
+  // Restore the status of exact arithmetic.
+  noexact = saveexact;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkshells()       Test the shells of mesh for topological consistency.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::checkshells()
+{
+  triface oppotet, oppooppotet;
+  triface testtet, spintet;
+  face shloop, testsh;
+  face segloop, testseg;
+  point3d tapex, spapex;
+  int hitbdry, edgecount;
+  int horrors;
+
+  if (!quiet) {
+    printf("  Checking subfaces-tetrahedra connection...\n");
+  }
+  if (verbose < 1) {
+    numbernodes(1);
+  }
+  horrors = 0;
+  subfaces.traversalinit();
+  shloop.sh = shellfacetraverse(&subfaces);
+  while (shloop.sh != (shellface *) NULL) {
+    shloop.shver = 0;
+    stpivot(shloop, oppotet);
+    if (oppotet.tet != dummytet) {
+      tspivot(oppotet, testsh);
+      if (testsh.sh != shloop.sh) {
+        printf("  !! !! Wrong tetra-subface connection.\n");
+        printf("    Tetra: ");
+        dump(&oppotet);
+        printf("    Subface: ");
+        dump(&shloop);
+        horrors++;
+      }
+    }
+    sesymself(shloop);
+    stpivot(shloop, oppooppotet);
+    if (oppooppotet.tet != dummytet) {
+      tspivot(oppooppotet, testsh);
+      if (testsh.sh != shloop.sh) {
+        printf("  !! !! Wrong tetra-subface connection.\n");
+        printf("    Tetra: ");
+        dump(&oppooppotet);
+        printf("    Subface: ");
+        dump(&shloop);
+        horrors++;
+      }
+      if (oppotet.tet != dummytet) {
+        sym(oppotet, testtet);
+        if (testtet.tet != oppooppotet.tet) {
+          printf("  !! !! Wrong tetra-subface-tetra connection.\n");
+          printf("    Tetra 1: ");
+          dump(&oppotet);
+          printf("    Subface: ");
+          dump(&shloop);
+          printf("    Tetra 2: ");
+          dump(&oppooppotet);
+          horrors++;
+        }
+      }
+    }
+    shloop.sh = shellfacetraverse(&subfaces);
+  }
+  if (horrors == 0) {
+    if (!quiet) {
+      printf("  Subfaces-tetrahedra connected correctly.\n");
+    }
+  } else if (horrors == 1) {
+    printf(
+    "  !! !! !! !! Precisely one terrifying subface-tetrahedron identified.\n");
+  } else {
+    printf("  !! !! !! !! %d subface-tetrahedron viewed with horror.\n",
+           horrors);
+    return;
+  }
+
+  if (!quiet) {
+    printf("  Checking Subfaces-subsegments connection...\n");
+  }
+  horrors = 0;
+  horrors = 0;
+  subfaces.traversalinit();
+  shloop.sh = shellfacetraverse(&subfaces);
+  while (shloop.sh != (shellface *) NULL) {
+    shloop.shver = 0;
+    for (edgecount = 0; edgecount < 3; edgecount++) {
+      senextself(shloop);
+      sspivot(shloop, testseg);
+      if (testseg.sh != dummysh) {
+        if (!((sorg(shloop) == sorg(testseg))
+              && (sdest(shloop) == sdest(testseg)))
+            && !((sorg(shloop) == sdest(testseg))
+                 && (sdest(shloop) == sorg(testseg)))) {
+          printf("  !! !! Wrong subface-subsegment connection.\n");
+          printf("    Subface: ");
+          dump(&shloop);
+          printf("    Subsegment: ");
+          dump(&testseg);
+          horrors++;
+        }
+      }
+    }
+    shloop.sh = shellfacetraverse(&subfaces);
+  }
+  if (horrors == 0) {
+    if (!quiet) {
+      printf("  Subfaces-subsegments connected correctly.\n");
+    }
+  } else if (horrors == 1) {
+    printf(
+    "  !! !! !! !! Precisely one terrifying subface-subsegments identified.\n");
+  } else {
+    printf("  !! !! !! !! %d subface-subsegments viewed with horror.\n",
+           horrors);
+    return;
+  }
+
+  if (!quiet) {
+    printf("  Checking Subsegments connection...\n");
+  }
+  horrors = 0;
+  subsegs.traversalinit();
+  segloop.sh = shellfacetraverse(&subsegs);
+  while (segloop.sh != (shellface *) NULL) {
+    segloop.shver = 0;
+    sapex(segloop, spapex);
+    if (spapex != (point3d) NULL) {
+      printf("  !! !! Detect a subface in subsegs pool(apex() != NULL).\n");
+      printf("    Wrong : ");
+      dump(&segloop);
+      horrors++;
+      segloop.sh = shellfacetraverse(&subsegs);
+      continue;
+    }
+    spivot(segloop, testsh);
+    if (testsh.sh == dummysh) {
+      printf("  !! !! A subsegment missing its parent subface.\n ");
+      printf("    Wrong : ");
+      dump(&segloop);
+      horrors++;
+      segloop.sh = shellfacetraverse(&subsegs);
+      continue;
+    }
+    sspivot(testsh, testseg);
+    if (testseg.sh != segloop.sh) {
+      printf("  !! !! Wrong subface-subsegment connection.\n ");
+      printf("    Wrong : ");
+      dump(&testsh);
+      printf("    Wrong : ");
+      dump(&segloop);
+      horrors++;
+      segloop.sh = shellfacetraverse(&subsegs);
+      continue;
+    }
+    stpivot(testsh, testtet);
+    if (testtet.tet == dummytet) {
+      sesymself(testsh);
+      stpivot(testsh, testtet);
+      if (testtet.tet == dummytet) {
+        printf("  !! !! Parent subface not bonded to a valid tetrahedron.\n ");
+        printf("    Wrong : ");
+        dump(&testsh);
+        horrors++;
+        segloop.sh = shellfacetraverse(&subsegs);
+        continue;
+      }
+    }
+    findversion(&testtet, &testseg);
+    spintet = testtet;
+    apex(testtet, tapex);
+    hitbdry = 0;
+    while (true) {
+      if (fnextself(spintet)) {
+        apex(spintet, spapex);
+        if (spapex == tapex) {
+          break; // Rewind, can leave now.
+        }
+        tspivot(spintet, testsh);
+        if (testsh.sh != dummysh) {
+          findversion(&testsh, &spintet);
+          sspivot(testsh, testseg);
+          if (testseg.sh == dummysh) {
+            printf("  !! !! Subface miss bond a subsegment.\n");
+            printf("    Miss bond : ");
+            dump(&testsh);
+            printf("    Miss : ");
+            dump(&segloop);
+            horrors++;
+          } else if (testseg.sh != segloop.sh) {
+            printf("  !! !! Wrong subface-subsegment bond.\n");
+            printf("    Wrong : ");
+            dump(&testsh);
+            printf("    Wrong : ");
+            dump(&segloop);
+            horrors++;
+          }
+        }
+      } else {
+        hitbdry ++;
+        if(hitbdry >= 2) {
+          break;
+        } else {
+          esym(testtet, spintet);
+        }
+      }
+    }
+    segloop.sh = shellfacetraverse(&subsegs);
+  }
+  if (horrors == 0) {
+    if (!quiet) {
+      printf("  Subsegments connected correctly.\n");
+    }
+  } else if (horrors == 1) {
+    printf(
+    "  !! !! !! !! Precisely one terrifying subsegment identified.\n");
+  } else {
+    printf("  !! !! !! !! %d subsegments viewed with horror.\n", horrors);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// quality_statistics()    Print statistics about the quality of the mesh.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::quality_statistics()
+{
+  triface tetloop;
+  point3d p[4];
+  REAL ratiotable[16];
+  REAL dx[6], dy[6], dz[6];
+  REAL edgelength[6];
+  REAL alldihed[6], allsolid[4];
+  REAL tetvol;
+  REAL tetlongest2;
+  REAL shortest, longest;
+  REAL smallestvolume, biggestvolume;
+  REAL tetminaltitude2;
+  REAL minaltitude;
+  REAL tetaspect2;
+  REAL worstaspect;
+  REAL smallestdiangle, biggestdiangle;
+  REAL smallsolid, largesolid;
+  REAL smalldihed, largedihed;
+  unsigned long roundcount, slivercount, capcount;
+  unsigned long needlecount, wedgecount, spindlecount;
+  int dihedangletable[18];
+  int aspecttable[16];
+  int aspectindex;
+  int tendegree;
+  int smallsolidcount, largesolidcount;
+  int smalldihedcount, largedihedcount;
+  int i, ii, j, k;
+
+  printf("Mesh quality statistics:\n\n");
+
+  ratiotable[0]  =      1.5;      ratiotable[1]  =     2.0;
+  ratiotable[2]  =      2.5;      ratiotable[3]  =     3.0;
+  ratiotable[4]  =      4.0;      ratiotable[5]  =     6.0;
+  ratiotable[6]  =     10.0;      ratiotable[7]  =    15.0;
+  ratiotable[8]  =     25.0;      ratiotable[9]  =    50.0;
+  ratiotable[10] =    100.0;      ratiotable[11] =   300.0;
+  ratiotable[12] =   1000.0;      ratiotable[13] = 10000.0;
+  ratiotable[14] = 100000.0;      ratiotable[15] =     0.0;
+  for (i = 0; i < 16; i++) {
+    aspecttable[i] = 0;
+  }
+  for (i = 0; i < 18; i++) {
+    dihedangletable[i] = 0;
+  }
+
+  worstaspect = 0.0;
+  minaltitude = xmax - xmin + ymax - ymin + zmax - zmin;
+  minaltitude = minaltitude * minaltitude;
+  shortest = minaltitude;
+  longest = 0.0;
+  smallestvolume = minaltitude;
+  biggestvolume = 0.0;
+  worstaspect = 0.0;
+  smallestdiangle = 180.0;
+  biggestdiangle = 0.0;
+  smallsolid = 3.;
+  largesolid = 300.;
+  smalldihed = 18.;
+  largedihed = 162.;
+  roundcount = slivercount = 0l;
+  capcount = spindlecount = wedgecount = needlecount = 0;
+
+  tetrahedrons.traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    org (tetloop, p[0]);
+    dest(tetloop, p[1]);
+    apex(tetloop, p[2]);
+    oppo(tetloop, p[3]);
+    tetlongest2 = 0.0;
+
+    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];
+      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];
+      if (edgelength[i] > tetlongest2) {
+        tetlongest2 = edgelength[i];
+      }
+      if (edgelength[i] > longest) {
+        longest = edgelength[i];
+      }
+      if (edgelength[i] < shortest) {
+        shortest = edgelength[i];
+      }
+    }
+
+    tetvol = tetvolume(p[0], p[1], p[2], p[3]);
+    if (tetvol < 0) tetvol = -tetvol;
+    if (tetvol < smallestvolume) {
+      smallestvolume = tetvol;
+    }
+    if (tetvol > biggestvolume) {
+      biggestvolume = tetvol;
+    }
+
+    tetalldihedral(p[0], p[1], p[2], p[3], alldihed);
+    smalldihedcount = largedihedcount = 0;
+    for (i = 0; i < 6; i++) {
+      if (alldihed[i] < smallestdiangle) {
+        smallestdiangle = alldihed[i];
+      } else if (alldihed[i] > biggestdiangle) {
+        biggestdiangle = alldihed[i];
+      }
+      if (alldihed[i] < smalldihed) {
+        smalldihedcount++;
+      } else if (alldihed[i] > largedihed) {
+        largedihedcount++;
+      }
+      tendegree = (int) (alldihed[i] / 10.);
+      dihedangletable[tendegree]++;
+    }
+    allsolid[0] = alldihed[0] + alldihed[1] + alldihed[2] - 180;
+    allsolid[1] = alldihed[0] + alldihed[3] + alldihed[4] - 180;
+    allsolid[2] = alldihed[1] + alldihed[3] + alldihed[5] - 180;
+    allsolid[3] = alldihed[2] + alldihed[4] + alldihed[5] - 180;
+    smallsolidcount = largesolidcount = 0;
+    for (i = 0; i < 4; i++) {
+      if (allsolid[i] < smallsolid) {
+        smallsolidcount++;
+      } else if (allsolid[i] > largesolid) {
+        largesolidcount++;
+      }
+    }
+    if (largesolidcount >= 1) {
+      capcount++;
+    } else if ((largedihedcount > 0) && (smalldihedcount > 0)) {
+      slivercount++;
+    } else if (largedihedcount > 0) {
+      spindlecount++;
+    } else if (smalldihedcount > 0) {
+      wedgecount++;
+    } else if (smallsolidcount > 0) {
+      needlecount++;
+    } else {
+      roundcount++;
+    }
+
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  shortest = sqrt(shortest);
+  longest = sqrt(longest);
+  minaltitude = sqrt(minaltitude);
+  worstaspect = sqrt(worstaspect);
+
+  printf("  Smallest volume: %16.5g   |  Largest volume: %16.5g\n",
+         smallestvolume, biggestvolume);
+  printf("  Shortest edge:   %16.5g   |  Longest edge:   %16.5g\n",
+         shortest, longest);
+  printf("\n");
+  printf("  Smallest dihedral: %14.5g   |  Largest dihedral: %14.5g\n\n",
+         smallestdiangle, biggestdiangle);
+  printf("  Dihedral Angle histogram:\n");
+  for (i = 0; i < 9; i++) {
+    printf("      %3d - %3d degrees:  %8d    |    %3d - %3d degrees:  %8d\n",
+           i * 10, i * 10 + 10, dihedangletable[i],
+           i * 10 + 90, i * 10 + 100, dihedangletable[i + 9]);
+  }
+  printf("\n");
+
+  printf("  Shape histogram:\n\n");
+  printf("    Sliver:  %d\n", slivercount);
+  printf("    Needle:  %d\n", needlecount);
+  printf("    Spindle: %d\n", spindlecount);
+  printf("    Wedge:   %d\n", wedgecount);
+  printf("    Cap:     %d\n\n", capcount);
+  printf("  There are %d bad elements among %d elements.\n",
+         slivercount + needlecount + spindlecount + wedgecount + capcount,
+         tetrahedrons.items);
+
+  printf("\n");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// statistics()    Print all sorts of cool facts.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::statistics()
+{
+  printf("\nStatistics:\n\n");
+  printf("  Input points: %d\n", inpoints);
+  if (refine) {
+    printf("  Input tetrahedra: %d\n", inelements);
+  }
+  if (poly) {
+    printf("  Input facets: %d\n", infacets);
+    if (!refine) {
+      printf("  Input holes: %d\n", holes);
+    }
+  }
+
+  printf("\n  Mesh points: %ld\n", points.items);
+  printf("  Mesh tetrahedra: %ld\n", tetrahedrons.items);
+  printf("  Mesh faces: %ld\n", faces);
+  if (poly || refine) {
+    printf("  Mesh boundary faces: %ld\n", hullsize);
+    printf("  Mesh subfaces: %ld (include nonsolids)\n", subfaces.items);
+    printf("  Mesh subsegments: %ld\n\n", subsegs.items);
+  } else {
+    printf("  Mesh convex hull faces: %ld\n\n", hullsize);
+  }
+  if (verbose) {
+    if (quality) {
+      quality_statistics();
+    }
+    printf("Memory allocation statistics:\n\n");
+    printf("  Maximum number of points: %ld\n", points.maxitems);
+    printf("  Maximum number of tetrahedra: %ld\n", tetrahedrons.maxitems);
+    if (subfaces.maxitems > 0) {
+      printf("  Maximum number of subfaces: %ld\n", subfaces.maxitems);
+    }
+    if (subsegs.maxitems > 0) {
+      printf("  Maximum number of segments: %ld\n", subsegs.maxitems);
+    }
+    if (viri.maxitems > 0) {
+      printf("  Maximum number of viri: %ld\n", viri.maxitems);
+    }
+    if (badfaces.maxitems > 0) {
+      printf("  Maximum number of encroached subfaces: %ld\n",
+             badfaces.maxitems);
+    }
+    if (badsegments.maxitems > 0) {
+      printf("  Maximum number of encroached segments: %ld\n",
+             badsegments.maxitems);
+    }
+    if (badtets.maxitems > 0) {
+      printf("  Maximum number of bad tetrahedra: %ld\n", badtets.maxitems);
+    }
+    printf("  Approximate heap memory use (bytes): %ld\n\n",
+           points.maxitems * points.itembytes
+           + tetrahedrons.maxitems * tetrahedrons.itembytes
+           + subfaces.maxitems * subfaces.itembytes
+           + subsegs.maxitems * subsegs.itembytes
+           + viri.maxitems * viri.itembytes
+           + badfaces.maxitems * badfaces.itembytes
+           + badsegments.maxitems * badsegments.itembytes
+           + badtets.maxitems * badtets.itembytes);
+
+    printf("Algorithmic statistics:\n\n");
+    printf("  Number of insphere tests: %ld\n", inspherecount);
+    printf("  Number of orientation tests: %ld\n", orient3dcount);
+    if (segmentintersectioncount > 0) {
+      printf("  Number of segment intersections: %ld\n",
+             segmentintersectioncount);
+    }
+    printf("\n");
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// syntax()    Print list of command line switches.                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::syntax()
+{
+  printf("tetgen [-pq__a__AnfcgBPNEIOXzS__T__CQVh] input_file\n");
+  printf("    -p  Triangulates a Piecewise Linear Complex (.poly file).\n");
+  printf("    -q  Quality mesh generation. Use Shewchuk's Delaunay Refinement\n");
+  printf("        Algorithm. A minimum radius-edge ratio may be specified.\n");
+  printf("    -a  Applies a maximum tetrahedron volume constraint.\n");
+  printf("    -A  Applies attributes to identify elements in certain regions.\n");
+  printf("    -f  Generates a list of tetrahedron faces.\n");
+  printf("    -e  Generates a list of edges (segments).\n");
+  printf("    -c  Generates a list of convex hull faces.\n");
+  printf("    -n  Generates a list of tetrahedron neighbors.\n");
+  printf("    -g  Generates file for viewing mesh by Geomview(*.off) or Gid.\n");
+  printf("    -B  Suppresses output of boundary information.\n");
+  printf("    -P  Suppresses output of .poly file.\n");
+  printf("    -N  Suppresses output of .node file.\n");
+  printf("    -E  Suppresses output of .ele file.\n");
+  printf("    -I  Suppresses mesh iteration numbers.\n");
+  printf("    -O  Ignores holes in .poly file.\n");
+  printf("    -X  Use exact arithmetic to perform geometric predicates.\n");
+  printf("    -z  Numbers all items starting from zero (rather than one).\n");
+  printf("    -S  Specifies maximum number of added Steiner points.\n");
+  printf("    -T  Specifies the tolerance for round-to-zero.\n");
+  printf("    -C  Check consistency of final mesh.\n");
+  printf("    -Q  Quiet:  No terminal output except errors.\n");
+  printf("    -V  Verbose:  Detailed information on what I'm doing.\n");
+  printf("    -h  Help:  Detailed instructions for Tetgen.\n");
+  exit(0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// meshinit()     Initialize some variables.                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::meshinit()
+{
+  recenttet.tet = (tetrahedron*) NULL;     // No tetra has been visited yet.
+  samples = 1;            // Point location should take at least one sample.
+  checksegments = 0;      // There are no segments in the triangulation yet.
+  randomseed = 1;
+  usefliplist = 0;
+  shflaws = shsegflaws = tetflaws = 0;
+  fliplist = NULL;
+  dummytetbase = dummyshbase = NULL;
+  surfmesh = NULL;
+
+  // Init statistic variables.
+  flip_t23s = flip_t32s = flip_t22s = flip_t44s = 0;
+  cospherecount = segmentintersectioncount = 0l;
+  inspherecount = orient3dcount = 0l;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// meshdeinit()     Free all remaining allocated memory.                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::meshdeinit()
+{
+  tetrahedrons.deinit();
+  if (dummytetbase) {
+    delete [] dummytetbase;
+  }
+  if (useshelles) {
+    subfaces.deinit();
+    subsegs.deinit();
+    if (dummyshbase) {
+      delete [] dummyshbase;
+    }
+  }
+  points.deinit();
+  if (poly && faces) {
+    badsegments.deinit();
+  }
+  if (quality) {
+    badfaces.deinit();
+    if ((minratio > 0.0) || varvolume || fixedvolume) {
+      badtets.deinit();
+    }
+  }
+  if (fliplist) {
+    delete fliplist;
+  }
+  if (surfmesh) {
+    delete surfmesh;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// parsecommandline()    Read the command line, identify switches, and set   //
+//                       up options and file names.                          //
+//                                                                           //
+// The effects of this routine are felt entirely through global variables.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::parsecommandline(int argc, char **argv)
+{
+  int startindex;
+  int increment;
+  int meshnumber;
+  int i, j, k;
+  char workstring[FILENAMESIZE];
+
+  poly = smesh = 0;
+  refine = quality = varvolume = fixedvolume = regionattrib = convex = 0;
+  firstnumber = 1;
+  facesout = edgesout = voronoi = neighbors = geomview = 0;
+  nobound = nopolywritten = nonodewritten = noelewritten = noiterationnum = 0;
+  noholes = nobisect = 0;
+  noexact = 1;   // default vaule, not use exact arithmetic.
+  splitseg = 1;  // default value in 3D case.
+  docheck = 0;
+  steiner = -1;
+  minratio = 2.0;  // Default radius-edge ratio.
+  maxvolume = -1.0;
+  noroundoff = 0;
+  usertolerance = 1e-12;    // default tolerance.
+  userubtolerance = 1e-10;
+  badelemreport = 0;
+  quiet = verbose = 0;
+  innodefilename[0] = '\0';
+  commandline[0] = '\0';
+
+  startindex = 1;
+  strcpy(commandline, argv[0]);
+  strcat(commandline, " ");
+  for (i = startindex; i < argc; i++) {
+    if (argv[i][0] == '-') {
+      for (j = startindex; argv[i][j] != '\0'; j++) {
+        if (argv[i][j] == 'p') {
+          poly = 1;
+        }
+        if (argv[i][j] == 'r') {
+          refine = 1;
+        }
+        if (argv[i][j] == 'q') {
+          quality = 1;
+          if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+              (argv[i][j + 1] == '.')) {
+            k = 0;
+            while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+                   (argv[i][j + 1] == '.')) {
+              j++;
+              workstring[k] = argv[i][j];
+              k++;
+            }
+            workstring[k] = '\0';
+            minratio = (REAL) strtod(workstring, (char **) NULL);
+            if (minratio <= 0.0) {
+              printf("Command line Error:  After -q switch, the minimum");
+              printf(" radius-edge ratio must greater than Zero.\n");
+              exit(1);
+            }
+          } else {
+            minratio = 2; // Default radius-edge ratio.
+          }
+        }
+        if (argv[i][j] == 'a') {
+          quality = 1;
+          if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+              (argv[i][j + 1] == '.')) {
+            fixedvolume = 1;
+            k = 0;
+            while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+                   (argv[i][j + 1] == '.')) {
+              j++;
+              workstring[k] = argv[i][j];
+              k++;
+            }
+            workstring[k] = '\0';
+            maxvolume = (REAL) strtod(workstring, (char **) NULL);
+            if (maxvolume <= 0.0) {
+              printf("Command line Error:  After -a switch, the maximum");
+              printf(" volume constraints must greater than Zero.\n");
+              exit(1);
+            }
+          } else {
+            varvolume = 1;
+          }
+        }
+        if (argv[i][j] == 'A') {
+          regionattrib = 1;
+        }
+        if (argv[i][j] == 'c') {
+          convex = 1;
+        }
+        if (argv[i][j] == 's') {
+          splitseg = 0;
+        }
+        if (argv[i][j] == 'z') {
+          firstnumber = 0;
+        }
+        if (argv[i][j] == 'f') {
+          facesout = 1;
+        }
+        if (argv[i][j] == 'e') {
+          edgesout = 1;
+        }
+        if (argv[i][j] == 'v') {
+          voronoi = 1;
+        }
+        if (argv[i][j] == 'n') {
+          neighbors = 1;
+        }
+        if (argv[i][j] == 'g') {
+          geomview = 1;
+        }
+        if (argv[i][j] == 'B') {
+          nobound = 1;
+        }
+        if (argv[i][j] == 'P') {
+          nopolywritten = 1;
+        }
+        if (argv[i][j] == 'N') {
+          nonodewritten = 1;
+        }
+        if (argv[i][j] == 'E') {
+          noelewritten = 1;
+        }
+        if (argv[i][j] == 'I') {
+          noiterationnum = 1;
+        }
+        if (argv[i][j] == 'O') {
+          noholes = 1;
+        }
+        if (argv[i][j] == 'X') {
+          noexact = 0; // Use exact arithmetic.
+        }
+        if (argv[i][j] == 'Y') {
+          nobisect++;
+        }
+        if (argv[i][j] == 'S') {
+          steiner = 0;
+          while ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
+            j++;
+            steiner = steiner * 10 + (int) (argv[i][j] - '0');
+          }
+        }
+        if (argv[i][j] == 'T') {
+          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';
+            usertolerance = (REAL) strtod(workstring, (char **) NULL);
+            if (usertolerance <= 0.0) {
+              printf("Command line Error:  After -T switch, tolerance");
+              printf(" must greater than Zero.\n");
+              exit(1);
+            }
+            userubtolerance = usertolerance * 1e+2;
+          }
+        }
+        if (argv[i][j] == 'F') {
+          noroundoff = 1;
+        }
+        if (argv[i][j] == 'b') {
+          badelemreport = 1;
+        }
+        if (argv[i][j] == 'C') {
+          docheck = 1;
+        }
+        if (argv[i][j] == 'Q') {
+          quiet = 1;
+        }
+        if (argv[i][j] == 'V') {
+          verbose++;
+        }
+        if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
+            (argv[i][j] == '?')) {
+          syntax();
+        }
+      }
+    } else {
+      strncpy(innodefilename, argv[i], FILENAMESIZE - 1);
+      innodefilename[FILENAMESIZE - 1] = '\0';
+    }
+    strcat(commandline, argv[i]);
+    strcat(commandline, " ");
+  }
+  commandline[FILENAMESIZE - 1] = '\0';
+  if (innodefilename[0] == '\0') {
+    syntax();
+  }
+  if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".node")) {
+    innodefilename[strlen(innodefilename) - 5] = '\0';
+  }
+  if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".poly")) {
+    innodefilename[strlen(innodefilename) - 5] = '\0';
+    poly = 1;
+    smesh = 0;
+  }
+  if (!strcmp(&innodefilename[strlen(innodefilename) - 6], ".smesh")) {
+    innodefilename[strlen(innodefilename) - 6] = '\0';
+    smesh = 1;
+    poly = 0;
+  }
+  if (!strcmp(&innodefilename[strlen(innodefilename) - 4], ".ele")) {
+    innodefilename[strlen(innodefilename) - 4] = '\0';
+    refine = 1;
+  }
+  if (!strcmp(&innodefilename[strlen(innodefilename) - 7], ".volume")) {
+    innodefilename[strlen(innodefilename) - 5] = '\0';
+    refine = 1;
+    quality = 1;
+    varvolume = 1;
+  }
+  steinerleft = steiner;
+  useshelles = poly || smesh || refine || quality || convex;
+  goodratio = minratio;
+  goodratio *= goodratio;
+  if (refine && noiterationnum) {
+    printf("Command line Error:  You cannot use the -I switch when");
+    printf(" refining a triangulation.\n");
+    exit(1);
+  }
+  // Be careful not to allocate space for element volume constraints that
+  //   will never be assigned any value (other than the default -1.0).
+  if (!refine && !poly && !smesh) {
+    varvolume = 0;
+  }
+  // Be careful not to add an extra attribute to each element unless the
+  //   input supports it (PLC in, but not refining a preexisting mesh).
+  if (refine || (!poly && !smesh)) {
+    regionattrib = 0;
+  }
+
+  strcpy(inpolyfilename, innodefilename);
+  strcpy(insmeshfilename, innodefilename);
+  strcpy(inelefilename, innodefilename);
+  strcpy(volumefilename, innodefilename);
+  increment = 0;
+  strcpy(workstring, innodefilename);
+  j = 1;
+  while (workstring[j] != '\0') {
+    if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) {
+      increment = j + 1;
+    }
+    j++;
+  }
+  meshnumber = 0;
+  if (increment > 0) {
+    j = increment;
+    do {
+      if ((workstring[j] >= '0') && (workstring[j] <= '9')) {
+        meshnumber = meshnumber * 10 + (int) (workstring[j] - '0');
+      } else {
+        increment = 0;
+      }
+      j++;
+    } while (workstring[j] != '\0');
+  }
+  if (noiterationnum) {
+    strcpy(outnodefilename, innodefilename);
+    strcpy(outelefilename, innodefilename);
+    strcpy(facefilename, innodefilename);
+    strcpy(edgefilename, innodefilename);
+    strcpy(neighborfilename, innodefilename);
+    strcpy(offfilename, innodefilename);
+    strcat(outnodefilename, ".node");
+    strcat(outelefilename, ".ele");
+    strcat(facefilename, ".face");
+    strcat(edgefilename, ".edge");
+    strcat(neighborfilename, ".neigh");
+    strcat(offfilename, ".off");
+  } else if (increment == 0) {
+    strcpy(outnodefilename, innodefilename);
+    strcpy(outpolyfilename, innodefilename);
+    strcpy(outelefilename, innodefilename);
+    strcpy(facefilename, innodefilename);
+    strcpy(edgefilename, innodefilename);
+    strcpy(neighborfilename, innodefilename);
+    strcpy(offfilename, innodefilename);
+    strcat(outnodefilename, ".1.node");
+    strcat(outpolyfilename, ".1.poly");
+    strcat(outelefilename, ".1.ele");
+    strcat(facefilename, ".1.face");
+    strcat(edgefilename, ".1.edge");
+    strcat(neighborfilename, ".1.neigh");
+    strcat(offfilename, ".1.off");
+  } else {
+    workstring[increment] = '%';
+    workstring[increment + 1] = 'd';
+    workstring[increment + 2] = '\0';
+    sprintf(outnodefilename, workstring, meshnumber + 1);
+    strcpy(outpolyfilename, outnodefilename);
+    strcpy(outelefilename, outnodefilename);
+    strcpy(facefilename, outnodefilename);
+    strcpy(edgefilename, outnodefilename);
+    strcpy(neighborfilename, outnodefilename);
+    strcpy(offfilename, outnodefilename);
+    strcat(outnodefilename, ".node");
+    strcat(outpolyfilename, ".poly");
+    strcat(outelefilename, ".ele");
+    strcat(facefilename, ".face");
+    strcat(edgefilename, ".edge");
+    strcat(neighborfilename, ".neigh");
+    strcat(offfilename, ".off");
+  }
+  strcat(innodefilename, ".node");
+  strcat(inpolyfilename, ".poly");
+  strcat(insmeshfilename, ".smesh");
+  strcat(inelefilename, ".ele");
+  strcat(volumefilename, ".volume");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// triangulate()   Gosh, do everything.                                      //
+//                                                                           //
+// The sequence is roughly as follows.  Many of these steps can be skipped,  //
+// depending on the command line switches.                                   //
+//                                                                           //
+// - Initialize constants and parse the command line.                        //
+// - Read the points from a file and either                                  //
+//   - triangulate them                                                      //
+// - Insert the PLC segments and subfaces (-p).                              //
+// - Read the holes (-p), regional attributes (-pA), and regional area       //
+//     constraints (-pa).  Carve the holes and concavities, and spread the   //
+//     regional attributes and area constraints.                             //
+// - Enforce the constraints on minimum angle (-q) and maximum area (-a).    //
+//     Also enforce the conforming Delaunay property (-q and -a).            //
+// - Compute the number of edges in the resulting mesh.                      //
+// - Write the output files and print the statistics.                        //
+// - Check the consistency and Delaunay property of the mesh (-C).           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void mesh3d::triangulate(int argc, char **argv)
+{
+  REAL *holearray;                                        // Array of holes.
+  REAL *regionarray;   // Array of regional attributes and area constraints.
+  FILE *polyfile;
+  // Variables for timing the performance of Tetrahedra.
+#ifndef NO_TIMER
+  // The types are defined in sys/time.h.
+  struct timeval tv0, tv1, tv2, tv3, tv4, tv5, tv6;
+  struct timezone tz;
+#else  // NO_TIMER
+  // The types are defined in time.h.
+  clock_t tv0, tv1, tv2, tv3, tv4, tv5, tv6;
+#endif // NO_TIMER
+
+#ifndef NO_TIMER
+  gettimeofday(&tv0, &tz);
+#else  // NO_TIMER
+  tv0 = clock();
+#endif // NO_TIMER
+
+  exactinit();                     // Initialize exact arithmetic constants.
+  parsecommandline(argc, argv);
+  readnodes(&polyfile);
+
+  if (verbose > 1) {
+    // Number the points first when "-VV" or "-VVV" switch be set, so that
+    //   the debug functions can output point indices for you.
+    numbernodes(1);
+  }
+
+  if (!quiet) {
+#ifndef NO_TIMER
+    gettimeofday(&tv1, &tz);
+#else  // NO_TIMER
+    tv1 = clock();
+#endif // NO_TIMER
+  }
+
+  if (refine) {
+    // Read and reconstruct a mesh.
+    printf("Sorry, the -r switch has not been implemented now.\n");
+    exit(1);
+  } else {
+    hullsize = delaunay();                        // Triangulate the points.
+  }
+
+  if (!quiet) {
+    if (refine) {
+      printf("Mesh reconstruction");
+    } else {
+      printf("Delaunay");
+    }
+#ifndef NO_TIMER
+    gettimeofday(&tv2, &tz);
+    printf(" milliseconds:  %ld\n", 1000l * (tv2.tv_sec - tv1.tv_sec)
+           + (tv2.tv_usec - tv1.tv_usec) / 1000l);
+#else  // NO_TIMER
+    tv2 = clock();
+    printf(" milliseconds:  %g\n", 1000l * (tv2 - tv1) / (REAL) CLK_TCK);
+#endif // NO_TIMER
+  }
+
+  if (useshelles) {
+    checksegments = 1;                  // Segments will be introduced next.
+    if (!refine) {
+      // Insert PLC segments/facets and/or convex hull segments/facets.
+      infacets = formskeleton(polyfile);
+      if (docheck) {
+        checkshells();
+      }
+    }
+  }
+
+  if (!quiet) {
+#ifndef NO_TIMER
+    gettimeofday(&tv3, &tz);
+    if (useshelles && !refine) {
+      printf("Segment and facet milliseconds:  %ld\n",
+             1000l * (tv3.tv_sec - tv2.tv_sec)
+             + (tv3.tv_usec - tv2.tv_usec) / 1000l);
+    }
+#else  // NO_TIMER
+    tv3 = clock();
+    if (useshelles && !refine) {
+      printf("Segment and facet milliseconds:  %g\n",
+             1000l * (tv3 - tv2) / (REAL) CLK_TCK);
+    }
+#endif // NO_TIMER
+  }
+
+  if (poly || smesh) {
+    readholes(polyfile, &holearray, &holes, &regionarray, &regions);
+    if (!refine) {
+      // Carve out holes and concavities.
+      carveholes(holearray, holes, regionarray, regions);
+    }
+  } else {
+    // Without a PLC, there can be no holes or regional attributes
+    //   or area constraints.  The following are set to zero to avoid
+    //   an accidental free later.
+    holes = 0;
+    regions = 0;
+  }
+
+  if (!quiet) {
+#ifndef NO_TIMER
+    gettimeofday(&tv4, &tz);
+    if (poly && !refine) {
+      printf("Hole milliseconds:  %ld\n", 1000l * (tv4.tv_sec - tv3.tv_sec)
+             + (tv4.tv_usec - tv3.tv_usec) / 1000l);
+    }
+#else  // NO_TIMER
+    tv4 = clock();
+    if (poly && !refine) {
+      printf("Hole milliseconds:  %g\n", 1000l * (tv4 - tv3) / (REAL) CLK_TCK);
+    }
+#endif // NO_TIMER
+  }
+
+  if (quality) {
+    enforcequality();                 // Enforce angle and area constraints.
+  }
+
+  if (!quiet) {
+#ifndef NO_TIMER
+    gettimeofday(&tv5, &tz);
+    if (quality) {
+      printf("Quality milliseconds:  %ld\n",
+             1000l * (tv5.tv_sec - tv4.tv_sec)
+             + (tv5.tv_usec - tv4.tv_usec) / 1000l);
+    }
+#else  // NO_TIMER
+    tv5 = clock();
+    if (quality) {
+      printf("Quality milliseconds:  %g\n",
+             1000l * (tv5 - tv4) / (REAL) CLK_TCK);
+    }
+#endif // NO_TIMER
+  }
+
+  // Compute the number of edges.
+  faces = (4l * tetrahedrons.items + hullsize) / 2l;
+
+  if (!quiet) {
+    printf("\n");
+  }
+
+  // If not using iteration numbers, don't write a .node file if one was
+  //   read, because the original one would be overwritten!
+  if (nonodewritten || (noiterationnum && readnodefile)) {
+    if (!quiet) {
+      printf("NOT writing a .node file.\n");
+    }
+    numbernodes();                 // We must remember to number the points.
+  } else {
+    outnodes();                                   // Numbers the points too.
+  }
+
+  if (noelewritten) {
+    if (!quiet) {
+      printf("NOT writing an .ele file.\n");
+    }
+  } else {
+    outelems();
+  }
+
+  if (regions > 0) {
+    delete [] regionarray;
+  }
+  if (holes > 0) {
+    delete [] holearray;
+  }
+  if (geomview) {
+    outelems2gid();   // for gid mesh reader.
+    outfaces2gid(1);  // only output hull faces.
+    outoff();         // off file of geomview.
+    // outelems2fa();    // Fa files.
+  }
+  if (facesout || convex) {
+    outfaces(convex);
+  }
+  if (edgesout) {
+    outedges();
+  }
+  if (neighbors) {
+    outneighbors();
+  }
+  if (badelemreport) {
+    dumpallbadelems("badelems.gid");
+  }
+
+  if (!quiet) {
+#ifndef NO_TIMER
+    gettimeofday(&tv6, &tz);
+    printf("\nOutput milliseconds:  %ld\n",
+           1000l * (tv6.tv_sec - tv5.tv_sec)
+           + (tv6.tv_usec - tv5.tv_usec) / 1000l);
+    printf("Total running milliseconds:  %ld\n",
+           1000l * (tv6.tv_sec - tv0.tv_sec)
+           + (tv6.tv_usec - tv0.tv_usec) / 1000l);
+#else  // NO_TIMER
+    tv6 = clock();
+    printf("\nOutput milliseconds:  %g\n",
+           1000l * (tv6 - tv5) / (REAL) CLK_TCK);
+    printf("Total running milliseconds:  %g\n",
+           1000l * (tv6 - tv0) / (REAL) CLK_TCK);
+#endif // NO_TIMER
+    statistics();
+  }
+
+  // If the "-C" swith be set.
+  if (docheck) {
+    checkmesh();
+    if (checksegments) {
+      checkshells();
+    }
+    checkdelaunay();
+  }
+}
diff --git a/Tetgen/tetlib.h b/Tetgen/tetlib.h
new file mode 100644
index 0000000000..3c860cb03e
--- /dev/null
+++ b/Tetgen/tetlib.h
@@ -0,0 +1,1301 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetlib.h    Head file for the mesh data structures and mesh3d class       //
+//             declaration.                                                  //
+//                                                                           //
+// Tetgen Version 1.0 beta                                                   //
+// Oct. 2001                                                                 //
+//                                                                           //
+// Si hang                                                                   //
+// Email: sihang@weboo.com                                                   //
+// http://www.weboo.com/sh/tetgen.htm                                        //
+//                                                                           //
+// You are free to use, copy and modify the sources under certain            //
+// circumstances, provided this copyright notice remains intact.             //
+// See the file LICENSE for details.                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+//   Tetgen is based on the Delaunay method and incorporates face-swapping   //
+// techniques. It generates meshes composed of tetrahedral elements. Tetgen  //
+// generates exact Delaunay tetrahedralization for three-dimensional point   //
+// sets, generates boundary constrained Delaunay tetrahedralization and      //
+// quality (conforming) Delaunay tetrahedralizations for three-dimensional   //
+// Piecewise Linear Complex(PLC).                                            //
+//                                                                           //
+//   The Tetgen mesh generator is based on:                                  //
+//                                                                           //
+// [*] Integrating two relative mesh data structures: The tetrahedron-based  //
+//     mesh data structure and triangle-edge mesh data structure.            //
+//                                                                           //
+// [*] Using the randomized incremental flip algorithm to construct Delaunay //
+//     tetrahedralization for 3D point sets.                                 //
+//                                                                           //
+// [*] Using simple face/edge swapping method and local re-meshing method to //
+//     construct boundary-constrained Delaunay tetrahedralization.           //
+//                                                                           //
+// [*] Using the Delaunay refinement algorithm and the radius-edge ratio     //
+//     quality measure to incrementally insert (steiner) points into the     //
+//     mesh to eliminate bad quality tetrahedra and generate an almost good  //
+//     mesh with good grading.                                               //
+//                                                                           //
+// [*] Other algorithms involve fast randomized point location algorithm to  //
+//     perform fast point location and using gift-wrapping algorithm to      //
+//     construct a constrained Delaunay triangulation for triangular faces   //
+//     bounded polyhedras.                                                   //
+//                                                                           //
+// [*] Embedding the 2D mesh generator Triangle to generate planar surface   //
+//     mesh, Optionally using the adaptive exact arithmetic package to       //
+//     improve the robustness of the implementation.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef tetlibH
+#define tetlibH
+
+#include "defines.h"
+#include "linklist.h"
+#include "trilib.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh data structures                                                      //
+//                                                                           //
+//   The efficiency of a tetrahedral mesh generator is rests on its          //
+// algorithms and data structures. It was important to begin with a robust   //
+// data structure that was flexible and encompassing enough to serve as the  //
+// basis for a wide variety of applications. In Tetgen, the data structure   //
+// was so designed make it suitable for both Delaunay and Advancing-Front    //
+// methods.                                                                  //
+//                                                                           //
+//   Tetgen integrates two relative mesh data structures: The tetrahedron-   //
+// based data structure of Shewchuk[1] and the triangle-edge data structure  //
+// of Mucke[2]. Where the tetrahedron-based data structure is convenient for //
+// storing tetrahedral mesh and is deeply discussed in [1]. The triangle-    //
+// edge data structure is convenient for face classification and mesh        //
+// manipulation, it was mainly described in [2].                             //
+//                                                                           //
+//   Please refer to Dobkin and Laszlo[3], Guibas and Stolfi[4], and Owen[5] //
+// for more general discussions about mesh data structures.                  //
+//                                                                           //
+// Refernces:                                                                //
+//                                                                           //
+// [1] Jonathan Richard Shewchuk, Delaunay Refinement Mesh Generation. Ph.D. //
+//     thesis, School of Computer Science, Carnegie Mellon University, Pitt- //
+//     sburgh, Pennsylvania. May 1997. Available as Technical Rreport CMU-CS //
+//     -97-137.                                                              //
+// [2] Ernst P. Mucke, Shapes and Implementations in Three-Dimensional Geom- //
+//     etry. Ph.D. thesis, Technical Report UIUCDCS-R-93-1836. Department of //
+//     Computer Science, University of Illinois at Urbana-Champaign, Urbana, //
+//     Illinois, 1993.                                                       //
+// [3] David P. Dobkin and Michael J. Laszlo. Primitives for the Manipulati- //
+//     on of Three-Dimensional Subdivisions. Algorithmica 4:3-32, 1989.      //
+// [4] Leonidas J. Guibas and Jorge Stolfi, Primitives for the Manipulation  //
+//     of General Subdivisions and the Computation of Voronoi Diagrams, ACM  //
+//     Transactions on Graphics 4(2):74-123, April 1985.                     //
+// [5] Steven J. Owen, Non-Simplicial Unstructured Mesh Generation, Ph.D.    //
+//     Dissertation, Carnegie Mellon University, 1999.                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Basic data structure: tetrahedron                                         //
+//                                                                           //
+//   Each tetrahedron contain four pointers to its vertices, and four        //
+// pointers to the adjoining tetrahedra. Plus four pointers to subfaces      //
+// (define below, these pointers are usually 'dummysh'). It may or may not   //
+// also contain user-defined attributes and/or a floating-point volume       //
+// constraint.                                                               //
+//   Because the size and structure of a 'tetrahedron' is not decided until  //
+// runtime,  It is not simply defined to be a structure or a class.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+typedef REAL **tetrahedron;
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Basic data structure: shellface                                           //
+//                                                                           //
+//   The shell (triangular) face data structure. Both subface and subsegment //
+// are represented by shellface(see[1]).                                     //
+//   Each subface contains three pointers to its vertices, three pointers to //
+// adjoining subfaces, and two pointers to adjoining tetrahedron,  plus one  //
+// boundary marker.  Three pointer to adjoining subfaces are only used for   //
+// coplanar neighbours in a common facet, or used for applications of gener- //
+// ating surface meshes. Each subface also has three pointers to adjoining   //
+// subsegments. To save space, there are no pointers directly connecting     //
+// tetrahedra and adjoining subsegments;  connections between tetrahedra and //
+// subsegments are entirely mediated through subfaces.                       //
+//   Because a subsegment may be shared by any number of subfaces and        //
+// tetrahedra, each subsegment has a pointer to only one adjoining subface //
+// (chosen arbitrarily);  the others must be found through the connectivity  //
+// of the mesh.                                                              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+typedef REAL **shellface;
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Basic data structure: point3d                                             //
+//                                                                           //
+//   The point data structure.  Each point is actually an array of REALs.    //
+// The number of REALs is unknown until runtime. An integer boundary marker, //
+// and sometimes a pointer to a tetrahedron, is appended after the REALs.    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+typedef REAL *point3d;
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Handle                                                                    //
+//                                                                           //
+//   The oriented triangular face 'triface' and oriented shell face 'face'   //
+// data structures defined below do not themselves store any part of the     //
+// mesh. The mesh itself is made of 'tetrahedron's, 'shellface's, and        //
+// 'point3d's.                                                               //
+//                                                                           //
+//   Oriented triangular faces and oriented shell faces will usually be      //
+// referred to as "handles".  A handle is essentially a pointer into the     //
+// mesh; it allows you to "hold" one particular part of the mesh.  Handles   //
+// are used to specify the regions in which one is traversing and modifying  //
+// the mesh.                                                                 //
+//                                                                           //
+//    A 'triface' is a handle that holds a tetrahedron. It holds a specific  //
+// side of the tetrahedron. An 'face' is a handle that holds a shell face.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// The handle data structure: triface                                        //
+//                                                                           //
+//   triface is an oriented triangluar face of tetrahedron in 3D. The        //
+// orientation is determined by face vertices. A triface includes a pointer  //
+// to a tetrahedron, a face location and a face version. where face location //
+// is an integer number varies from 0 to 3. It was used to indicate a face   //
+// of tetrahedron. Face version is an integer number varies from 0 to 5. It  //
+// was used to represent an oriented edge of face.                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+class triface {
+
+  public:
+
+    tetrahedron* tet;
+    int loc;                                           // Range from 0 to 3.
+    int ver;                                           // Range from 0 to 5.
+
+    // Constructors;
+    triface() : tet(0), loc(0), ver(0) {}
+    triface(const triface& tface) {
+      tet = tface.tet; loc = tface.loc; ver = tface.ver;
+    }
+
+    // Operators;
+    triface& operator=(const triface& tface) {
+      tet = tface.tet; loc = tface.loc; ver = tface.ver;
+      return *this;
+    }
+    bool operator==(triface& tface) {
+      return (tet == tface.tet) && (loc == tface.loc) && (ver == tface.ver);
+    }
+    bool operator!=(triface& tface) {
+      return (tet != tface.tet) || (loc != tface.loc) || (ver != tface.ver);
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// The handle data structure: face                                           //
+//                                                                           //
+//   face is an oriented subface in 3D. The orientation is determined by its //
+// vertices. A face includes a pointer to a shell face, and a face version.  //
+// where face version is an integer number varies from 0 to 5. It was used   //
+// to represent an oriented edge of face.                                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+class face {
+
+  public:
+
+    shellface *sh;
+    int shver;                                        // Ranges from 0 to 5.
+
+    // Constructors;
+    face() : sh(0), shver(0) {}
+    face(const face& sface) {
+      sh = sface.sh; shver = sface.shver;
+    }
+
+    // Operators;
+    face& operator=(const face& sface) {
+      sh = sface.sh; shver = sface.shver;
+      return *this;
+    }
+    bool operator==(face& sface) {
+      return (sh == sface.sh) && (shver == sface.shver);
+    }
+    bool operator!=(face& sface) {
+      return (sh != sface.sh) || (shver != sface.shver);
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh data type linar-order functions used in list and link data types.    //
+// See linklist.h for detail description about linar-order functions.        //
+//                                                                           //
+// compare2points()    Compare two point3ds by their x-coordinate, using the //
+//                     y-coordinate as a secondary key, and the z-coordinate //
+//                     if their need.                                        //
+// compare2tets()      Compare two handles of tetrahedra by thire address.   //
+// compare2shfaces()   Compare two handles of subfaces/subsegments by thire  //
+//                     address.                                              //
+//                                                                           //
+// Return 0 if they are the same. Return 1 or -1 if they are not the same.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int compare2points(point3d*, point3d*);
+int compare2tets(triface*, triface*);
+int compare2shfaces(face*, face*);
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// struct badface3d                                                          //
+//                                                                           //
+//   A queue used to store bad triangular faces.  Each face's vertices are   //
+// stored so that one can check whether a face is still the same.            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+typedef struct badface3dtype {
+  triface badfacetet;                    // A tetrahedron hold the bad face.
+  face shface;                                                // A bad face.
+  REAL cent[3];                           // The circumcenters' coordinates.
+  point3d faceorg, facedest, faceapex;                // The three vertices.
+  struct badface3dtype *nextface;               // Pointer to next bad face.
+} badface3d;
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// struct badtet                                                             //
+//                                                                           //
+//   A queue used to store bad tetrahedra. Each tetrahedron's vertices are   //
+// stored so that one can check whether a tetrahedron is still the same.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+typedef struct badtettype {
+  triface btet;                                                // A bad tet.
+  REAL key;                                          // radius-edge ratio^2.
+  REAL cent[3];                           // The circumcenters' coordinates.
+  point3d tetorg, tetdest, tetapex, tetoppo;           // The four vertices.
+  struct badtettype *nexttet;                    // Pointer to next bad tet.
+} badtet;
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// class mesh3d    The quality Tetrahedral mesh Generator and Delaunay       //
+//                 triangulator implementation class.                        //
+//                                                                           //
+//   Tetgen is based on the Delaunay method and incorporates face-swapping   //
+// techniques. It generates meshed composed of tetrahedral elements. Tetgen  //
+// generates exact Delaunay tetrahedralization for three-dimensional point   //
+// sets, generates boundary constrained Delaunay tetrahedralization and      //
+// quality (conforming) Delaunay tetrahedralizations for three-dimensional   //
+// Piecewise Linear Complex(PLC).                                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+class mesh3d {
+
+  public:
+
+    // Labels that signify the result of point location.  The result of a
+    //   search indicates that the point falls in the interior of a tetra-
+    //   hedra, on a face, on an edge, on a vertex, or outside the mesh.
+    enum locateresult {INTETRAHEDRON, ONFACE, ONEDGE, ONVERTEX, OUTSIDE};
+
+    // Labels that signify the result of site insertion.  The result indica-
+    //   tes that the point was inserted with complete success, was inserted
+    //   but encroaches on a segment or a subface, was not inserted because
+    //   it lies on a segment or a subface, or was not inserted because
+    //   another point occupies the same location.
+    enum insertsiteresult {SUCCESSFUL, FAILED, VIOLATINGEDGE, VIOLATINGFACE,
+                           DUPLICATE};
+
+    // Labels that signify the result of direction finding.  The result
+    //   indicates that a segment connecting the two query points falls
+    //   within the tetrahedron's face, along the left edge of the face
+    //   along the right edge of the face, along the top edge of the face
+    //   or cross the opposite face of the query point.
+    enum finddirectionresult {LEFTCOLLINEAR, RIGHTCOLLINEAR, TOPCOLLINEAR,
+                              WITHIN, ACROSS};
+
+    // Labels that signify the result of subface matching.  The result of a
+    //   match indicates that the match face is existing in mesh, one edge
+    //   of the match face is missing, or two edge of the match face is mis-
+    //   sing.
+    enum matchfaceresult {FACEMATCHING, EDGEMISSING, APEXMISSING};
+
+    // Labels that signify the result of tetrahedral face category. The
+    //   result of face category are used for purposes of face and edge
+    //   swapping. 'T' indicates that the face is transformable, 'N'
+    //   indicates non-transformable. For 'T' faces, the digits are the
+    //   number of tets before and after the transformation.  For 'N' faces,
+    //   the digits are the number of tets that would be present for a
+    //   transformable case; a zero as the second digit indicates that the
+    //   case is irrevocably unswappable.
+    enum facecategory {T23, T32, T22, T44, N32, N44, N40, N30, N20, LOCKED};
+
+    // Labels that signify two edge ring of a triangle, one(CCW) traversing
+    //   edges in counterclockwise direction and one(CW) travesing edges in
+    //   clockwise direction.
+    enum {CCW = 0, CW = 1};
+
+  public:
+
+    // Variables used to allocate and access memory.
+    memorypool tetrahedrons;
+    memorypool subfaces;
+    memorypool subsegs;
+    memorypool points;
+    memorypool viri;
+    memorypool badsegments;
+    memorypool badfaces;
+    memorypool badtets;
+
+    // Variables for global used.
+    REAL xmin, xmax, ymin, ymax, zmin, zmax;
+    int inpoints, inelements, infacets, holes, regions;
+    int mesh_dim, nextras, eextras;
+    long faces, hullsize;
+    int tetwords, shwords;
+    int pointmarkindex, point2tetindex;
+    int highorderindex, elemattribindex, volumeboundindex;
+    int checksegments;
+    int readnodefile;
+    long samples;
+    unsigned long randomseed;
+
+    // Vraiables for switches.
+    int poly, smesh;
+    int refine, quality, varvolume, fixedvolume, regionattrib, convex;
+    int firstnumber;
+    int facesout, edgesout, voronoi, neighbors, geomview;
+    int nopolywritten, nonodewritten, noelewritten, noiterationnum;
+    int nobound, noholes, nobisect, noexact, noroundoff;
+    int splitseg, steiner, steinerleft;
+    int docheck;
+    int quiet, verbose;
+    int useshelles, usefliplist;
+    int shflaws, shsegflaws, tetflaws;
+    int badelemreport;
+    REAL minratio, goodratio;
+    REAL maxvolume;
+    REAL usertolerance, userubtolerance;
+
+    // A queue used to keep all uncategorized tetrahedra's face, which
+    //   maybe non local optimal.
+    queue *fliplist;
+
+    // Pointer to the two-dimensional mesh generator. Used in surface
+    //   recover process.
+    mesh2d *surfmesh;
+
+    // Pointer to a recently visited tetrahedron. Improves point location
+    //   if proximate points are inserted sequentially.
+    triface recenttet;
+
+    // Pointer to the 'tetrahedron' that occupies all of "outer space".
+    tetrahedron *dummytet;
+    tetrahedron *dummytetbase; // Keep base address so we can free it later.
+
+    // Pointer to the omnipresent shell face.  Referenced by any tetrahedron,
+    //   or subface that isn't really connected to a shell face at that
+    //   location.
+    shellface *dummysh;
+    shellface *dummyshbase;  // Keep base address so we can free() it later.
+
+    // Variables used to quality mesh generation.
+    badface3d *facequefront[2];
+    badface3d **facequetail[2];
+    badtet *tetquefront[64];
+    badtet **tetquetail[64];
+    list *uncheckedshseglist;
+    list *uncheckedshlist;
+    list *uncheckedtetlist;
+    // Three lists used for Boywer-Watson point insertion scheme.
+    list *cavetetlist;
+    list *caveshlist;
+    list *cavebdfacelist;
+
+    long inspherecount;               // Number of insphere tests performed.
+    long orient3dcount;               // Number of orient3d tests performed.
+    long cospherecount;                        // Number of cosphere tested.
+    long segmentintersectioncount; // Number segment intersection performed.
+    // Number of flips performed.
+    long flip_t23s, flip_t32s, flip_t22s, flip_t44s;
+
+    // Vraiables for filenames.
+    char innodefilename[FILENAMESIZE];
+    char inelefilename[FILENAMESIZE];
+    char inpolyfilename[FILENAMESIZE];
+    char insmeshfilename[FILENAMESIZE];
+    char volumefilename[FILENAMESIZE];
+    char outnodefilename[FILENAMESIZE];
+    char outelefilename[FILENAMESIZE];
+    char outpolyfilename[FILENAMESIZE];
+    char facefilename[FILENAMESIZE];
+    char edgefilename[FILENAMESIZE];
+    char neighborfilename[FILENAMESIZE];
+    char offfilename[FILENAMESIZE];
+    char commandline[FILENAMESIZE];
+
+  public:
+
+    ////////////////////////////////////////////////////////////////////////
+    //                                                                    //
+    // Mesh manipulation primitives.                                      //
+    //                                                                    //
+    //   Each tetrahedron contains four pointers to other tetrahedra,     //
+    // with face locations. Each pointer  points not to the first pointer //
+    // of a tetrahedron, but to one of the first four pointers of a       //
+    // tetrahedron. It is necessary to extract both the tetrahedron       //
+    // itself and the face location. To save memory,  We keep both pieces //
+    // (a tet pointer, a face loction) of information in one pointer, and //
+    // do not allocate space for face version.  To make this possible,  I //
+    // assume that all tetrahedra are aligned to eight-byte boundaries.   //
+    // The three least significant bits (two for face locations, one for  //
+    // viral infection) are masked out to produce the real pointer. The   //
+    // 'decode' primitive below decodes a pointer, extracting a face      //
+    // location, and a pointer to the a tetrahedron. The 'encode'         //
+    // primitive compresses a pointer to a tetrahedron and a face         //
+    // location into a single pointer.                                    //
+    //                                                                    //
+    ////////////////////////////////////////////////////////////////////////
+
+    // Fast lookup tables for mesh manipulation primitives. These tables are
+    //   just like global variables that used by all objects of the class.
+
+    // For enext() primitive, use 'ver' as index.
+    static int ve[6];
+
+    // For org(), dest() and apex() primitives, use 'ver' as index.
+    static int vo[6], vd[6], va[6];
+
+    // For org(), dest() and apex() primitives, use 'loc' as first index
+    //   and 'ver' as second index.
+    static int locver2org[4][6];
+    static int locver2dest[4][6];
+    static int locver2apex[4][6];
+    // For oppo() primitives, use 'loc' as index.
+    static int loc2oppo[4];
+
+    // For fnext() primitives, use 'loc' as first index and 'ver' as second
+    //   index, return a new 'loc' and new 'ver' in an int array.
+    // Note: Only valid for face version = 0, 2, 4.
+    static int locver2nextf[4][6][2];
+
+    static int plus1mod3[3];
+    static int minus1mod3[3];
+
+    // Some macros for convenience
+    #define Div2  >> 1
+    #define Mod2  & 01
+    // NOTE: These bit operators should only be used in macros below.
+
+    // Get orient(Range from 0 to 2) from face version(Range from 0 to 5).
+    #define Orient(V)   ((V) Div2)
+
+    // Determine edge ring(0 or 1) from face version(Range from 0 to 5).
+    #define EdgeRing(V) ((V) Mod2)
+
+    ////////////////////////////////////////////////////////////////////////
+    // Primitives for tetrahedron                                         //
+    ////////////////////////////////////////////////////////////////////////
+
+    // decode() converts a pointer to a triface.  The location is
+    //   extracted from the two least significant bits of the pointer.
+    static void decode(tetrahedron ptr, triface& tface) {
+      tface.loc = (int) ((unsigned long) (ptr) & (unsigned long) 3l);
+      tface.tet = (tetrahedron *)
+                  ((unsigned long) (ptr) & ~(unsigned long) 7l);
+    }
+
+    // encode() compresses a triface into a single pointer.  It relies on
+    //   the assumption that all tetrahedra are aligned to four-byte
+    //   boundaries, so the two least significant bits of (triface).tet are
+    //   zero.
+    static tetrahedron encode(triface& tface) {
+      return (tetrahedron)
+             ((unsigned long) tface.tet | (unsigned long) tface.loc);
+    }
+
+    // sym() finds the abutting tetrahedron on the same face.
+    static void sym(triface& tface1, triface& tface2) {
+      tetrahedron ptr = tface1.tet[tface1.loc];
+      decode(ptr, tface2);
+    }
+
+    static void symself(triface& tface) {
+      tetrahedron ptr = tface.tet[tface.loc];
+      decode(ptr, tface);
+    }
+
+    // The bond() and dissolve() primitives are just like the splice()
+    //   primitive of Mucke[2]'s.
+
+    // Bond two tetrahedra together at their faces.
+    static void bond(triface& tface1, triface& tface2) {
+      tface1.tet[tface1.loc] = encode(tface2);
+      tface2.tet[tface2.loc] = encode(tface1);
+    }
+
+    // Dissolve a bond (from one side).  Note that the other tetrahedron
+    //   will still think it's connected to this tetrahedron.  Usually,
+    //   however, the other tetrahedron is being deleted entirely, or bonded
+    //   to another tetrahedron, so it doesn't matter.
+    // Note: 'dummytet' isn't a static member variable of class, that's
+    //   the reason why dissolve() can not be declared with 'static'.
+    void dissolve(triface& tface) {
+      tface.tet[tface.loc] = (tetrahedron) dummytet;
+    }
+
+    // These primitives determine or set the origin, destination, apex or
+    //   opposition of a tetrahedron with respect to 'loc' and 'ver'.
+
+    static void org(triface& tface, point3d& pointptr) {
+      pointptr = (point3d) tface.tet[locver2org[tface.loc][tface.ver] + 4];
+    }
+
+    static point3d org(triface& tface) {
+      return (point3d) tface.tet[locver2org[tface.loc][tface.ver] + 4];
+    }
+
+    static void dest(triface& tface, point3d& pointptr) {
+      pointptr = (point3d) tface.tet[locver2dest[tface.loc][tface.ver] + 4];
+    }
+
+    static point3d dest(triface& tface) {
+      return (point3d) tface.tet[locver2dest[tface.loc][tface.ver] + 4];
+    }
+
+    static void apex(triface& tface, point3d& pointptr) {
+      pointptr = (point3d) tface.tet[locver2apex[tface.loc][tface.ver] + 4];
+    }
+
+    static point3d apex(triface& tface) {
+      return (point3d) tface.tet[locver2apex[tface.loc][tface.ver] + 4];
+    }
+
+    static void oppo(triface& tface, point3d& pointptr) {
+      pointptr = (point3d) tface.tet[loc2oppo[tface.loc] + 4];
+    }
+
+    static point3d oppo(triface& tface) {
+      return (point3d) tface.tet[loc2oppo[tface.loc] + 4];
+    }
+
+    static void setorg(triface& tface, point3d pointptr) {
+      tface.tet[locver2org[tface.loc][tface.ver] + 4] = (tetrahedron) pointptr;
+    }
+
+    static void setdest(triface& tface, point3d pointptr) {
+      tface.tet[locver2dest[tface.loc][tface.ver] + 4] = (tetrahedron) pointptr;
+    }
+
+    static void setapex(triface& tface, point3d pointptr) {
+      tface.tet[locver2apex[tface.loc][tface.ver] + 4] = (tetrahedron) pointptr;
+    }
+
+    static void setoppo(triface& tface, point3d pointptr) {
+      tface.tet[loc2oppo[tface.loc] + 4] = (tetrahedron) pointptr;
+    }
+
+    static void setvertices2null(triface& tface) {
+      tface.tet[4] = (tetrahedron) NULL;
+      tface.tet[5] = (tetrahedron) NULL;
+      tface.tet[6] = (tetrahedron) NULL;
+      tface.tet[7] = (tetrahedron) NULL;
+    }
+
+    // These primitives were drived from Mucke[2]'s triangle-based data
+    //   structure to change face-edge relation in a tetrahedron (esym,
+    //   enext and enext2) or between two tetrahedra (fnext).
+
+    // If e0 = e(i, j), e1 = e(j, i), that is e0 and e1 are the two
+    //   direction of the same undirected edge of a triangular face.
+    //   e0.sym() = e1 and vice versa.
+    static void esym(triface& tface1, triface& tface2) {
+      tface2.tet = tface1.tet;
+      tface2.loc = tface1.loc;
+      tface2.ver = tface1.ver + (EdgeRing(tface1.ver) ? -1 : 1);
+    }
+
+    static void esymself(triface& tface) {
+      tface.ver += (EdgeRing(tface.ver) ? -1 : 1);
+    }
+
+    // If e0 and e1 are both in the same edge ring of a triangular face,
+    //   e1 = e0.enext(). Then e1 is the successor of e0.
+    static void enext(triface& tface1, triface& tface2) {
+      tface2.tet = tface1.tet;
+      tface2.loc = tface1.loc;
+      tface2.ver = ve[tface1.ver];
+    }
+
+    static void enextself(triface& tface) {
+      tface.ver = ve[tface.ver];
+    }
+
+    // enext2() is equal to e2 = e0.enext().enext()
+    static void enext2(triface& tface1, triface& tface2) {
+      tface2.tet = tface1.tet;
+      tface2.loc = tface1.loc;
+      tface2.ver = ve[ve[tface1.ver]];
+    }
+
+    static void enext2self(triface& tface) {
+      tface.ver = ve[ve[tface.ver]];
+    }
+
+    // If f0 and f1 are both in the same triangle ring of a triangular face,
+    //   f1 = f0.fnext(), Then f1 is the successor of f0. Return true if f1
+    //   exist. Return false if f1 not exist(f0 is a boundary face).
+    #define fnext(triface1, triface2)                                      \
+      getnextface(&(triface1), &(triface2))
+
+    #define fnextself(triface)                                             \
+      getnextface(&(triface), NULL)
+
+    // enextfnext() and enext2fnext() are combination primitives of enext()
+    //   and fnext().
+    #define enextfnext(triface1, triface2)                                 \
+      enext(triface1, triface2);                                           \
+      fnextself(triface2)
+
+    #define enextfnextself(triface)                                        \
+      enextself(triface);                                                  \
+      fnextself(triface)
+
+    #define enext2fnext(triface1, triface2)                                \
+      enext2(triface1, triface2);                                          \
+      fnextself(triface2)
+
+    #define enext2fnextself(triface)                                       \
+      enext2self(triface);                                                 \
+      fnextself(triface)
+
+    // Primitives to infect or cure a tetrahedron with the virus. These rely
+    //   on the assumption that all tetrahedron are aligned to eight-byte
+    //   boundaries.
+    static void infect(triface& tface) {
+      tface.tet[0] = (tetrahedron)
+                    ((unsigned long) tface.tet[0] | (unsigned long) 4l);
+    }
+
+    static void uninfect(triface& tface) {
+      tface.tet[0] = (tetrahedron)
+                  ((unsigned long) tface.tet[0] & ~ (unsigned long) 4l);
+    }
+
+    // Test a tetrahedron for viral infection.
+    static bool infected(triface& tface) {
+      return (((unsigned long) tface.tet[0] & (unsigned long) 4l) != 0);
+    }
+
+    // Check or set a tetrahedron's attributes.
+    REAL elemattribute(tetrahedron* ptr, int attnum) {
+      return ((REAL *) (ptr))[elemattribindex + attnum];
+    }
+
+    void setelemattribute(tetrahedron* ptr, int attnum, REAL value) {
+      ((REAL *) (ptr))[elemattribindex + attnum] = value;
+    }
+
+    // Check or set a tetrahedron's maximum volume bound.
+    REAL volumebound(tetrahedron* ptr) {
+      return ((REAL *) (ptr))[volumeboundindex];
+    }
+
+    void setvolumebound(tetrahedron* ptr, REAL value) {
+      ((REAL *) (ptr))[volumeboundindex] = value;
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    // Primitives for shellface                                           //
+    ////////////////////////////////////////////////////////////////////////
+
+    // sdecode() converts a pointer to an oriented shell face.  The face
+    //   version is extracted from the least three significant bit of the
+    //   pointer.  The three least significant bits are masked out to
+    //   produce the real pointer.
+    static void sdecode(shellface sptr, face& sface) {
+      sface.shver = (int) ((unsigned long) (sptr) & (unsigned long) 7l);
+      sface.sh = (shellface *)
+             ((unsigned long) (sptr) & ~ (unsigned long) 7l);
+    }
+
+    // sencode() compresses an oriented shell face into a single pointer.
+    //   It relies on the assumption that all shell faces are aligned to
+    //   eight-byte boundaries, so the least three significant bit of
+    //   (face).sh is zero.
+    static shellface sencode(face& sface) {
+      return (shellface)
+             ((unsigned long) sface.sh | (unsigned long) sface.shver);
+    }
+
+    // spivot() finds the other shell face (from the same face) that shares
+    //   the same edge.
+    static void spivot(face& sface1, face& sface2) {
+      shellface sptr = sface1.sh[Orient(sface1.shver)];
+      sdecode(sptr, sface2);
+    }
+
+    static void spivotself(face& sface) {
+      shellface sptr = sface.sh[Orient(sface.shver)];
+      sdecode(sptr, sface);
+    }
+
+    // Bond two shell faces together.
+    static void sbond(face& sface1, face& sface2) {
+      sface1.sh[Orient(sface1.shver)] = sencode(sface2);
+      sface2.sh[Orient(sface2.shver)] = sencode(sface1);
+    }
+
+    // Dissolve a shell face bond (from one side).  Note that the other
+    //   shell face will still think it's connected to this shell face.
+    // Note: 'dummysh' isn't a static member variable of class, that's
+    //   the reason why sdissolve() can not be declared with 'static'.
+    void sdissolve(face& sface) {
+      sface.sh[Orient(sface.shver)] = (shellface) dummysh;
+    }
+
+    // These primitives determine or set the origin, destination, or apex
+    //   of a shell face with respect to current face version.
+
+    static void sorg(face& sface, point3d& pointptr) {
+      pointptr = (point3d) sface.sh[3 + vo[sface.shver]];
+    }
+
+    static point3d sorg(face& sface) {
+      return (point3d) sface.sh[3 + vo[sface.shver]];
+    }
+
+    static void sdest(face& sface, point3d& pointptr) {
+      pointptr = (point3d) sface.sh[3 + vd[sface.shver]];
+    }
+
+    static point3d sdest(face& sface) {
+      return (point3d) sface.sh[3 + vd[sface.shver]];
+    }
+
+    static void sapex(face& sface, point3d& pointptr) {
+      pointptr = (point3d) sface.sh[3 + va[sface.shver]];
+    }
+
+    static point3d sapex(face& sface) {
+      return (point3d) sface.sh[3 + va[sface.shver]];
+    }
+
+    static void setsorg(face& sface, point3d pointptr) {
+      sface.sh[3 + vo[sface.shver]] = (shellface) pointptr;
+    }
+
+    static void setsdest(face& sface, point3d pointptr) {
+      sface.sh[3 + vd[sface.shver]] = (shellface) pointptr;
+    }
+
+    static void setsapex(face& sface, point3d pointptr) {
+      sface.sh[3 + va[sface.shver]] = (shellface) pointptr;
+    }
+
+    // These primitives were drived from Mucke[2]'s triangle-based data
+    //   structure to change face-edge relation in a tetrahedron (sesym,
+    //   senext and senext2).
+
+    static void sesym(face& sface1, face& sface2) {
+      sface2.sh = sface1.sh;
+      sface2.shver = sface1.shver + (EdgeRing(sface1.shver) ? -1 : 1);
+    }
+
+    static void sesymself(face& sface) {
+      sface.shver += (EdgeRing(sface.shver) ? -1 : 1);
+    }
+
+    static void senext(face& sface1, face& sface2) {
+      sface2.sh = sface1.sh;
+      sface2.shver = ve[sface1.shver];
+    }
+
+    static void senextself(face& sface) { sface.shver = ve[sface.shver]; }
+
+    static void senext2(face& sface1, face& sface2) {
+      sface2.sh = sface1.sh;
+      sface2.shver = ve[ve[sface1.shver]];
+    }
+
+    static void senext2self(face& sface) {
+      sface.shver = ve[ve[sface.shver]];
+    }
+
+    // These primitives read or set a shell marker.  Shell markers are used
+    //   to hold user boundary information.
+
+    static int mark(face& sface) { return (* (int *) (sface.sh + 11)); }
+
+    static void setmark(face& sface, int value) {
+      * (int *) (sface.sh + 11) = value;
+    }
+
+    // Primitives to infect or cure a shell face with the virus. These rely
+    //   on the assumption that all shell face are aligned to eight-byte
+    //   boundaries.
+    static void sinfect(face& sface) {
+      sface.sh[10] = (shellface)
+                     ((unsigned long) sface.sh[10] | (unsigned long) 4l);
+    }
+
+    static void suninfect(face& sface) {
+      sface.sh[10] = (shellface)
+                     ((unsigned long) sface.sh[10] & ~ (unsigned long) 4l);
+    }
+
+    // Test a shell face for viral infection.
+    static bool sinfected(face& sface) {
+      return (((unsigned long) sface.sh[10] & (unsigned long) 4l) != 0);
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    // Primitives for interacting tetrahedra and subfaces                 //
+    ////////////////////////////////////////////////////////////////////////
+
+    // tspivot() finds a subface abutting on this tetrahdera.
+    static void tspivot(triface& tface, face& sface) {
+      shellface sptr = (shellface) tface.tet[8 + tface.loc];
+      sdecode(sptr, sface);
+    }
+
+    // stpivot() finds a tetrahedron abutting a subface.
+    static void stpivot(face& sface, triface& tface) {
+      tetrahedron ptr = (tetrahedron) sface.sh[6 + EdgeRing(sface.shver)];
+      decode(ptr, tface);
+    }
+
+    // tsbond() bond a tetrahedron to a subface.
+    static void tsbond(triface& tface, face& sface) {
+      tface.tet[8 + tface.loc] = (tetrahedron) sencode(sface);
+      sface.sh[6 + EdgeRing(sface.shver)] = (shellface) encode(tface);
+    }
+
+    // tsdissolve() dissolve a bond (from the tetrahedron side).
+    void tsdissolve(triface& tface) {
+      tface.tet[8 + tface.loc] = (tetrahedron) dummysh;
+    }
+
+    // stdissolve() dissolve a bond (from the subface side).
+    void stdissolve(face& sface) {
+      sface.sh[6 + EdgeRing(sface.shver)] = (shellface) dummytet;
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    // Primitives for interacting subfaces and subsegments                //
+    ////////////////////////////////////////////////////////////////////////
+
+    // sspivot() finds a subsegment abutting a subface.
+    static void sspivot(face& sface, face& edge) {
+      shellface sptr = (shellface) sface.sh[8 + Orient(sface.shver)];
+      sdecode(sptr, edge);
+    }
+
+    // ssbond() bond a subface to a subsegment.
+    static void ssbond(face& sface, face& edge) {
+      sface.sh[8 + Orient(sface.shver)] = sencode(edge);
+      edge.sh[0] = sencode(sface);
+    }
+
+    // ssdisolve() dissolve a bond (from the subface side)
+    void ssdissolve(face& sface) {
+      sface.sh[8 + Orient(sface.shver)] = (shellface) dummysh;
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    // Primitives for point3d                                             //
+    ////////////////////////////////////////////////////////////////////////
+
+    int pointmark(point3d pt) { return ((int *) (pt))[pointmarkindex]; }
+
+    void setpointmark(point3d pt, int value) {
+      ((int *) (pt))[pointmarkindex] = value;
+    }
+
+    tetrahedron point2tet(point3d pt) {
+      return ((tetrahedron *) (pt))[point2tetindex];
+    }
+
+    void setpoint2tet(point3d pt, tetrahedron value) {
+      ((tetrahedron *) (pt))[point2tetindex] = value;
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    // Advanced primitives                                                //
+    ////////////////////////////////////////////////////////////////////////
+
+    // Implement the fnext(), fnextself() primitives of tetrahedron.
+    bool getnextface(triface*, triface*);
+
+    // Finds a subsegment abutting on this tetrahdera.
+    void tsspivot(triface*, face*);
+
+    // Finds a tetrahedron abutting a subsegment.
+    void sstpivot(face*, triface*);
+
+    ////////////////////////////////////////////////////////////////////////
+    // Useful auxiliary primitives                                        //
+    ////////////////////////////////////////////////////////////////////////
+
+    // Find and set version to indicate the directed edge.
+    static void findversion(triface*, point3d, point3d, int symflag = 1);
+    static void findversion(triface*, triface*, int symflag = 1);
+    static void findversion(triface*, face*, int symflag = 1);
+    static void findversion(face*, point3d, point3d, int symflag = 1);
+    static void findversion(face*, triface*, int symflag = 1);
+    static void findversion(face*, face*, int symflag = 1);
+
+    // Find and set the version to indicate the desired point.
+    bool findorg(triface*, point3d);
+    bool findorg(face*, point3d);
+
+    // Adjusts edge version(ver) to corresponding edge ring if necessary.
+    //   Here direction is only valid for 0(CCW) or 1(CW).
+    static void adjustedgering(triface& tface, int direction) {
+      if (EdgeRing(tface.ver) != direction) {
+        esymself(tface);
+      }
+    }
+
+    // Returns true if adjoining tetrahedron exist.
+    // Note: 'dummytet' is not a static member variable.
+    bool issymexist(triface* tface) {
+      tetrahedron *ptr = (tetrahedron *)
+        ((unsigned long)(tface->tet[tface->loc]) & ~(unsigned long)3l);
+      return ptr != dummytet;
+    }
+
+    // Returns true if this tetrahedron is dealloced.
+    static bool isdead(triface* tface) {
+      if (tface->tet == (tetrahedron*) NULL) {
+        return true;
+      } else {
+        return tface->tet[4] == (tetrahedron) NULL;
+      }
+    }
+
+    // Returns true if this shellface is dealloced.
+    static bool isdead(face* sface) {
+      if (sface->sh == (shellface*) NULL) {
+        return true;
+      } else {
+        return sface->sh[3] == (shellface) NULL;
+      }
+    }
+
+    // Test if the subface is a non-solid subface. Every non-solid subface
+    //   is marked with a special flag NONSOLIDFLAG.
+    static bool isnonsolid(face& sface) {
+      return mark(sface) == NONSOLIDFLAG;
+    }
+
+    // Return true if the point is one of vertices of input triangular face.
+    static bool isfacehaspoint(triface* tface, point3d testpoint) {
+      return  ((org(*tface) == testpoint)
+               || (dest(*tface) == testpoint)
+               || (apex(*tface) == testpoint));
+    }
+
+    // Compare the coordinates of two points to see if they are coincident.
+    //   Return true if they are coincident, otherwise return false;
+    bool issamepoint(point3d p1, point3d p2) {
+      return (fabs(p1[0] - p2[0]) <= usertolerance)
+              && (fabs(p1[1] - p2[1]) <= usertolerance)
+              && (fabs(p1[2] - p2[2]) <= usertolerance);
+    }
+
+    // Returns true if the edge of tetrahedron(specified by loc and ver)
+    //   is a ridge in the mesh.
+    bool isridge(triface*);
+
+    // Test if there exist any segment shars with input segment's origin.
+    //   Return true if exist such segment, otherwise return false.
+    bool isexistincidentseg(face*);
+
+    // Compare the vertices of two faces/edges to see if they are the same
+    //   face/edge. The inputs are handles of two tetrahedra. Only return
+    //   0 (same) or 1 (diffrent). The two primitives mainly used as list
+    //   or link's linear order functions.
+    static int issameface(triface*, triface*);
+    static int issameedge(triface*, triface*);
+
+    // For debuging, print out the details of a tetrahedron/shellfacet
+    //   handle to standard output.
+    void dump(triface*);
+    void dump(face*);
+
+    ////////////////////////////////////////////////////////////////////////
+    // End of mesh manipulation primitives                                //
+    ////////////////////////////////////////////////////////////////////////
+
+    ////////////////////////////////////////////////////////////////////////
+    // Commonly used vector operations                                    //
+    ////////////////////////////////////////////////////////////////////////
+
+    // Assign3D(), Return: vres = va.
+    static void Assign3D(REAL* va, REAL* vres) {
+      vres[0] = va[0]; vres[1] = va[1]; vres[2] = va[2];
+    }
+
+    // Sub3D(), Return: vres = va - vb.
+    static void Sub3D(REAL* va, REAL* vb, REAL* vres) {
+      vres[0] = va[0] - vb[0];
+      vres[1] = va[1] - vb[1];
+      vres[2] = va[2] - vb[2];
+    }
+
+    // Scale3D(), Return: vres = vres * scale.
+    static void Scale3D(REAL* vres, REAL scale) {
+      vres[0] *= scale; vres[1] *= scale; vres[2] *= scale;
+    }
+
+    // Dot3D(), Return: va dot vb.
+    static REAL Dot3D(REAL* va, REAL* vb) {
+      return (va[0] * vb[0] + va[1] * vb[1] + va[2] * vb[2]);
+    }
+
+    // Cross3D(), Return: vres = va cross vb.
+    static void Cross3D(REAL* va, REAL* vb, REAL* vres) {
+      vres[0] = va[1] * vb[2] - va[2] * vb[1];
+      vres[1] = va[2] * vb[0] - va[0] * vb[2];
+      vres[2] = va[0] * vb[1] - va[1] * vb[0];
+    }
+
+    // Mag3D(), Return: Mod of va.
+    static REAL Mag3D(REAL* va) {
+      return sqrt(va[0] * va[0] + va[1] * va[1] + va[2] * va[2]);
+    }
+
+    // Dist3D(), Return the Euler distance of va and vb.
+    static REAL Dist3D(REAL* va, REAL* vb) {
+      return sqrt((va[0] - vb[0]) * (va[0] - vb[0])
+                  + (va[1] - vb[1]) * (va[1] - vb[1])
+                  + (va[2] - vb[2]) * (va[2] - vb[2]));
+    }
+
+    // Normal3D(), Compute the vector normal for a set of three points.
+    static void Normal3D(REAL* va, REAL* vb, REAL* vc, REAL* vnormal) {
+      REAL tempb[3], tempc[3];
+      Sub3D(vb, va, tempb);
+      Sub3D(vc, va, tempc);
+      Cross3D(tempb, tempc, vnormal);
+    }
+
+    // Normalize3D(), Return: Unit vector of va.
+    static void Normalize3D(REAL* va) {
+      REAL invmag = 1. / Mag3D(va);
+      Scale3D(va, invmag);
+    }
+
+    static void Swap3D(REAL* va, REAL* vb) {
+      REAL temp;
+      temp = vb[0]; vb[0] = va[0]; va[0] = temp;
+      temp = vb[1]; vb[1] = va[1]; va[1] = temp;
+      temp = vb[2]; vb[2] = va[2]; va[2] = temp;
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    // End of commonly used vector operations                             //
+    ////////////////////////////////////////////////////////////////////////
+
+    // Memory management routines
+    void dummyinit(int, int);
+    void initializepointpool();
+    void initializetetshpools();
+    void tetrahedrondealloc(tetrahedron*);
+    tetrahedron *tetrahedrontraverse();
+    void shellfacedealloc(memorypool*, shellface*);
+    shellface *shellfacetraverse(memorypool*);
+    void badsegmentdealloc(badface3d*);
+    badface3d *badsegmenttraverse();
+    void pointdealloc(point3d);
+    point3d pointtraverse();
+    point3d getpoint(int number);
+    // tetrahedron, subface and subsegment construct routines
+    void maketetrahedron(triface*);
+    void makeshellface(memorypool*, face*);
+
+    // Geometric primitives.
+    inline bool iszero(const REAL);
+    int iorient3d(point3d, point3d, point3d, point3d);
+    int iinsphere(point3d, point3d, point3d, point3d, point3d);
+    int iinsphere(triface*, point3d);
+    bool isbelowplane(point3d, point3d, point3d, point3d);
+    bool isbelowplane(triface*, point3d);
+    bool isaboveplane(point3d, point3d, point3d, point3d);
+    bool isaboveplane(triface*, point3d);
+    bool iscoplane(point3d, point3d, point3d, point3d);
+    bool iscoplane(triface*, point3d);
+    bool iscoline(point3d, point3d, point3d);
+
+    // Geometric functions.
+    void projontoface(point3d, point3d, point3d, point3d);
+    void circumcenter(point3d, point3d, point3d, point3d);
+    void circumcenter(point3d, point3d, point3d, point3d, point3d);
+    REAL tetvolume(point3d, point3d, point3d, point3d);
+    REAL facedihedral(point3d, point3d, point3d, point3d, point3d, point3d);
+    void tetalldihedral(point3d, point3d, point3d, point3d, REAL[6]);
+
+    // Point location routines.
+    // (Fast Randomized Point Location Algorithm of Mucke, Issac and Zhu.)
+    unsigned long randomnation(unsigned int);
+    void makepointmap();
+    REAL distance(triface*, point3d);
+    enum locateresult isintet(point3d, point3d, point3d, point3d, point3d);
+    enum locateresult iscoplanarintri(point3d, triface*);
+    enum locateresult preciselocate(point3d, triface*);
+    enum locateresult locate(point3d, triface*);
+
+    // Mesh transformation routines.
+    enum facecategory categorizeface(triface&);
+    bool querydoswap(triface&);
+    // bool querydoswap(triface&, enum facecategory);
+    void preservesubsegments(face&, triface&);
+    void enqueuefliplist(triface&);
+    bool dequeuefliplist(triface&);
+    int flip23(triface&);
+    int flip32(triface&);
+    int flip22(triface&);
+    int flip44(triface&);
+    int flip(triface&);
+
+    // Insert/Delete point routines.
+    enum insertsiteresult insertsite(point3d, triface*, face*, face*);
+    int insertonedge(point3d, triface*, face*);
+    int insertonface(point3d, triface*, face*);
+    int insertininterior(point3d, triface*);
+    void insertsubface(triface*, int, int);
+    void insertsubsegment(triface*, int);
+    int deletesite(triface*);
+
+    // Giftwrapping Algorithm
+    int is_face_tet_inter_0(triface*, point3d, point3d, point3d, point3d);
+    int is_face_tet_inter_1(triface*, point3d, point3d, point3d, point3d);
+    int is_face_tet_inter_2(triface*, point3d, point3d, point3d, point3d);
+    int getgiftface(list*, int, int*, list*);
+    int getgiftpoint(triface*, list*, int, point3d*, int*, list*, list*);
+    int giftwrapping(int, triface*, int, point3d*, REAL*, REAL, list*);
+
+    // Delaunay tetrahedrization construct routines.
+    // (Randomized Incremental Flip Algorithm.)
+    void construct_initial_tetra(queue*);
+    void collect_visibles(point3d, triface*, triface*, link*);
+    int dofliplist();
+    long rand_incr_flip_delaunay();
+    long delaunay();
+
+    // Segment/facet (boundary) constrained routines.
+    enum finddirectionresult finddirection(triface*, point3d);
+    void segmentintersection(triface*, face*, point3d);
+    int scoutsegment(triface*, point3d, int);
+    void conformingedge(point3d, point3d, int);
+    void insertsegment(point3d, point3d, int);
+    void getsteinersinseg(point3d, point3d, list*);
+    int getdiagonalapexindex(struct triangulateio*, int, int);
+    int getneighbourtriedge(struct triangulateio*, int, int, int*, int*);
+    int swapdiagonal(struct triangulateio*, int, int, int);
+    enum matchfaceresult matchface(point3d, point3d, point3d, triface*, int);
+    int insertfieldpoint(int, triface*, int, point3d*, list*);
+    int recoverface(list*, triangulateio*, int, int);
+    void insertfacet(list*, list*, int, int);
+    int formskeleton(FILE*);
+
+    // Carving out holes and concavities routines.
+    void infecthull();
+    void plague();
+    void regionplague(REAL, REAL);
+    void carveholes(REAL*, int, REAL*, int);
+
+    // Mesh quality testing routines.
+    void checkquality(triface*);
+    int checkedge4encroach(face*, point3d testpoint = NULL);
+    int checkface4encroach(face*, point3d testpoint = NULL);
+    void testtetrahedron(triface*);
+    void enqueuebadface(face*, point3d, int);
+    badface3d *dequeuebadface();
+    void enqueuebadtet(triface*, REAL, point3d, point3d, point3d, point3d,
+                       point3d);
+    badtet *dequeuebadtet();
+    // Mesh quality maintenance routines.
+    void tallyencsegs();
+    void tallyencfaces();
+    void tallytets();
+    void repairencsegs();
+    void repairencfaces();
+    void splittet(badtet*);
+    void enforcequality();
+
+    // File I/O routines.
+    char *readline(char*, FILE*, char*);
+    char *findfield(char*);
+    void readnodes(FILE**);
+    void readholes(FILE*, REAL**, int*, REAL**, int*);
+    void numbernodes(int myfirstnumber = 0);
+    void outnodes();
+    void outelems();
+    void outfaces(int hull = 0);
+    void outedges();
+    void outneighbors();
+    void outoff();
+    void outelems2gid();
+    void outfaces2gid(int hull = 0);
+    void outedges2gid();
+    void outelems2fa();
+
+    // Debug routines.
+    void dumpgifts(char*, list*, int, point3d*, int*);
+    void dumplist(char*, list*, int, int);
+    void dumpallbadelems(char*);
+
+    void internalerror();
+    void precisionerror();
+    void recovererror();
+
+    void checkmesh();
+    void checkdelaunay();
+    void checkshells();
+    void statistics();
+    void quality_statistics();
+    void syntax();
+
+    void meshinit();
+    void meshdeinit();
+    void parsecommandline(int, char**);
+
+  public:
+
+    mesh3d() { meshinit(); }
+    ~mesh3d() { meshdeinit(); }
+
+    // General mesh construction.
+    void triangulate(int, char**);
+};
+
+#endif // #ifndef tetlibH
diff --git a/Tetgen/tetmain.cpp b/Tetgen/tetmain.cpp
new file mode 100644
index 0000000000..ded9d1649a
--- /dev/null
+++ b/Tetgen/tetmain.cpp
@@ -0,0 +1,11 @@
+
+#include "tetlib.h"
+
+int main(int argc, char* argv[])
+{
+  mesh3d mymesh;
+
+  mymesh.triangulate(argc, argv);
+
+  return 0;
+}
diff --git a/Tetgen/trilib.cpp b/Tetgen/trilib.cpp
new file mode 100644
index 0000000000..b4cab2f132
--- /dev/null
+++ b/Tetgen/trilib.cpp
@@ -0,0 +1,5602 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// trilib.cpp    Implementation file for two-dimensional mesh generator.     //
+//                                                                           //
+// Tetgen Version 1.0 beta                                                   //
+// July, 2001                                                                //
+//                                                                           //
+// Si hang                                                                   //
+// Email: sihang@weboo.com                                                   //
+// http://www.weboo.com/sh/tetgen.htm                                        //
+//                                                                           //
+// You are free to use, copy and modify the sources under certain            //
+// circumstances, provided this copyright notice remains intact.             //
+// See the file LICENSE for details.                                         //
+//                                                                           //
+// This file with it's couple file trilib.h are modified version of the      //
+// triangle program of Jonathan Richard Shewchuk, which is public available  //
+// from the following Web page with its license(see trilib.h):               //
+//                                                                           //
+//              http://www.cs.cmu.edu/~quake/triangle.html                   //
+//                                                                           //
+// Please see trilib.h for description of how to use this modified codes     //
+// of triangle.                                                              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+/*****************************************************************************/
+/*                                                                           */
+/*  Traingle program license:                                                */
+/*                                                                           */
+/*  Triangle                                                                 */
+/*  A Two-Dimensional Quality Mesh Generator                                 */
+/*  and Delaunay Triangulator.                                               */
+/*  Version 1.3                                                              */
+/*                                                                           */
+/*  Copyright 1996                                                           */
+/*  Jonathan Richard Shewchuk                                                */
+/*  School of Computer Science                                               */
+/*  Carnegie Mellon University                                               */
+/*  5000 Forbes Avenue                                                       */
+/*  Pittsburgh, Pennsylvania  15213-3891                                     */
+/*  jrs@cs.cmu.edu                                                           */
+/*                                                                           */
+/*  This program may be freely redistributed under the condition that the    */
+/*    copyright notices (including this entire header and the copyright      */
+/*    notice printed when the `-h' switch is selected) are not removed, and  */
+/*    no compensation is received.  Private, research, and institutional     */
+/*    use is free.  You may distribute modified versions of this code UNDER  */
+/*    THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE   */
+/*    SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE   */
+/*    AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR    */
+/*    NOTICE IS GIVEN OF THE MODIFICATIONS.  Distribution of this code as    */
+/*    part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT  */
+/*    WITH THE AUTHOR.  (If you are not directly supplying this code to a    */
+/*    customer, and you are instead telling them how they can obtain it for  */
+/*    free, then you are not required to make any arrangement with me.)      */
+/*                                                                           */
+/*  Disclaimer:  Neither I nor Carnegie Mellon warrant this code in any way  */
+/*    whatsoever.  This code is provided "as-is".  Use at your own risk.     */
+/*                                                                           */
+/*****************************************************************************/
+
+#include "trilib.h"
+
+/********* struct triangulateio routines begin here                  *********/
+/**                                                                         **/
+/**                                                                         **/
+
+void triangulateioinit(struct triangulateio* io)
+{
+  io->pointlist = NULL;
+  io->pointattributelist = NULL;
+  io->pointmarkerlist = NULL;
+  io->numberofpoints = 0;
+  io->numberofpointattributes = 0;
+
+  io->trianglelist = NULL;
+  io->triangleattributelist = NULL;
+  io->trianglearealist = NULL;
+  io->neighborlist = NULL;
+  io->numberoftriangles = 0;
+  io->numberofcorners = 0;
+  io->numberoftriangleattributes = 0;
+
+  io->segmentlist = NULL;
+  io->segmentmarkerlist = NULL;
+  io->numberofsegments = 0;
+
+  io->holelist = NULL;
+  io->numberofholes = 0;
+
+  io->regionlist = NULL;
+  io->numberofregions = 0;
+
+  io->edgelist = NULL;
+  io->edgemarkerlist = NULL;
+  io->normlist = NULL;
+  io->numberofedges = 0;
+}
+
+void triangulateiodeinit(struct triangulateio* io)
+{
+  if (io->numberofpoints && io->pointlist) {
+    delete [] io->pointlist;
+    io->pointlist = NULL;
+    io->numberofpoints = 0;
+  }
+  if (io->numberofpointattributes && io->pointattributelist) {
+    delete [] io->pointattributelist;
+    io->pointattributelist = NULL;
+    io->numberofpointattributes = 0;
+  }
+  if (io->pointmarkerlist) {
+    delete [] io->pointmarkerlist;
+    io->pointmarkerlist = NULL;
+  }
+
+  if (io->numberoftriangles && io->trianglelist) {
+    delete [] io->trianglelist;
+    io->trianglelist = NULL;
+    io->numberoftriangles = 0;
+    io->numberofcorners = 0;
+  }
+  if (io->numberoftriangleattributes && io->triangleattributelist) {
+    delete [] io->triangleattributelist;
+    io->triangleattributelist = NULL;
+    io->numberoftriangleattributes = 0;
+  }
+  if (io->trianglearealist) {
+    delete [] io->trianglearealist;
+    io->trianglearealist = NULL;
+  }
+  if (io->neighborlist) {
+    delete [] io->neighborlist;
+    io->neighborlist = NULL;
+  }
+
+  if (io->numberofsegments && io->segmentlist) {
+    delete [] io->segmentlist;
+    io->segmentlist = NULL;
+    io->numberofsegments = 0;
+  }
+  if (io->segmentmarkerlist) {
+    delete [] io->segmentmarkerlist;
+    io->segmentmarkerlist = NULL;
+  }
+
+  if (io->numberofholes && io->holelist) {
+    delete [] io->holelist;
+    io->holelist = NULL;
+    io->numberofholes = 0;
+  }
+
+  if (io->numberofregions && io->regionlist) {
+    delete [] io->regionlist;
+    io->regionlist = NULL;
+    io->numberofregions = 0;
+  }
+
+  if (io->numberofedges && io->edgelist) {
+    delete [] io->edgelist;
+    io->edgelist = NULL;
+    io->numberofedges = 0;
+  }
+  if (io->edgemarkerlist) {
+    delete [] io->edgemarkerlist;
+    io->edgemarkerlist = NULL;
+  }
+  if (io->normlist) {
+    delete [] io->normlist;
+    io->normlist = NULL;
+  }
+}
+
+void triangulateioreport(struct triangulateio *io, int markers,
+  int reporttriangles, int reportneighbors, int reportsegments,
+  int reportedges, int reportnorms)
+{
+  int i, j;
+
+  if (io->numberofpoints && io->pointlist)  {
+    for (i = 0; i < io->numberofpoints; i++) {
+      printf("Point %4d:", i + 1);
+      for (j = 0; j < 2; j++) {
+        printf("  %.6g", io->pointlist[i * 2 + j]);
+      }
+      if (io->numberofpointattributes > 0) {
+        printf("   attributes");
+      }
+      for (j = 0; j < io->numberofpointattributes; j++) {
+        printf("  %.6g",
+               io->pointattributelist[i * io->numberofpointattributes + j]);
+      }
+      if (markers) {
+        printf("   marker %d\n", io->pointmarkerlist[i]);
+      } else {
+        printf("\n");
+      }
+    }
+    printf("\n");
+  }
+
+  if (reporttriangles || reportneighbors) {
+    for (i = 0; i < io->numberoftriangles; i++) {
+      if (reporttriangles) {
+        printf("Triangle %4d points:", i + 1);
+        for (j = 0; j < io->numberofcorners; j++) {
+          printf("  %4d", io->trianglelist[i * io->numberofcorners + j] + 1);
+        }
+        if (io->numberoftriangleattributes > 0) {
+          printf("   attributes");
+        }
+        for (j = 0; j < io->numberoftriangleattributes; j++) {
+          printf("  %.6g", io->triangleattributelist[i *
+                                         io->numberoftriangleattributes + j]);
+        }
+        printf("\n");
+      }
+      if (reportneighbors) {
+        printf("Triangle %4d neighbors:", i + 1);
+        for (j = 0; j < 3; j++) {
+          if (io->neighborlist[i * 3 + j] < 0) {
+            printf("  %4d", io->neighborlist[i * 3 + j]);
+          } else {
+            printf("  %4d", io->neighborlist[i * 3 + j] + 1);
+          }
+        }
+        printf("\n");
+      }
+    }
+    printf("\n");
+  }
+
+  if (reportsegments) {
+    for (i = 0; i < io->numberofsegments; i++) {
+      printf("Segment %4d points:", i + 1);
+      for (j = 0; j < 2; j++) {
+        printf("  %4d", io->segmentlist[i * 2 + j] + 1);
+      }
+      if (markers) {
+        printf("   marker %d\n", io->segmentmarkerlist[i]);
+      } else {
+        printf("\n");
+      }
+    }
+    printf("\n");
+  }
+
+  if (reportedges) {
+    for (i = 0; i < io->numberofedges; i++) {
+      printf("Edge %4d points:", i + 1);
+      for (j = 0; j < 2; j++) {
+        printf("  %4d", io->edgelist[i * 2 + j] + 1);
+      }
+      if (reportnorms && (io->edgelist[i * 2 + 1] == -1)) {
+        for (j = 0; j < 2; j++) {
+          printf("  %.6g", io->normlist[i * 2 + j]);
+        }
+      }
+      if (markers) {
+        printf("   marker %d\n", io->edgemarkerlist[i]);
+      } else {
+        printf("\n");
+      }
+    }
+    printf("\n");
+  }
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* struct triangulateio routines end here                    *********/
+
+/********* Mesh manipulation primitives begin here                   *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/* Fast lookup arrays to speed some of the mesh manipulation primitives.     */
+
+int mesh2d::plus1mod3[3] = {1, 2, 0};
+int mesh2d::minus1mod3[3] = {2, 0, 1};
+
+/********* Primitives for triangles                                  *********/
+/*                                                                           */
+/*                                                                           */
+
+/* decode() converts a pointer to an oriented triangle.  The orientation is  */
+/*   extracted from the two least significant bits of the pointer.           */
+
+#define decode(ptr, triedge)                                                  \
+  (triedge).orient = (int) ((unsigned long) (ptr) & (unsigned long) 3l);      \
+  (triedge).tri = (triangle *)                                                \
+                  ((unsigned long) (ptr) ^ (unsigned long) (triedge).orient)
+
+/* encode() compresses an oriented triangle into a single pointer.  It       */
+/*   relies on the assumption that all triangles are aligned to four-byte    */
+/*   boundaries, so the two least significant bits of (triedge).tri are zero.*/
+
+#define encode(triedge)                                                       \
+  (triangle) ((unsigned long) (triedge).tri | (unsigned long) (triedge).orient)
+
+/* The following edge manipulation primitives are all described by Guibas    */
+/*   and Stolfi.  However, they use an edge-based data structure, whereas I  */
+/*   am using a triangle-based data structure.                               */
+
+/* sym() finds the abutting triangle, on the same edge.  Note that the       */
+/*   edge direction is necessarily reversed, because triangle/edge handles   */
+/*   are always directed counterclockwise around the triangle.               */
+
+#define sym(triedge1, triedge2)                                               \
+  ptr = (triedge1).tri[(triedge1).orient];                                    \
+  decode(ptr, triedge2);
+
+#define symself(triedge)                                                      \
+  ptr = (triedge).tri[(triedge).orient];                                      \
+  decode(ptr, triedge);
+
+/* lnext() finds the next edge (counterclockwise) of a triangle.             */
+
+#define lnext(triedge1, triedge2)                                             \
+  (triedge2).tri = (triedge1).tri;                                            \
+  (triedge2).orient = plus1mod3[(triedge1).orient]
+
+#define lnextself(triedge)                                                    \
+  (triedge).orient = plus1mod3[(triedge).orient]
+
+/* lprev() finds the previous edge (clockwise) of a triangle.                */
+
+#define lprev(triedge1, triedge2)                                             \
+  (triedge2).tri = (triedge1).tri;                                            \
+  (triedge2).orient = minus1mod3[(triedge1).orient]
+
+#define lprevself(triedge)                                                    \
+  (triedge).orient = minus1mod3[(triedge).orient]
+
+/* onext() spins counterclockwise around a point; that is, it finds the next */
+/*   edge with the same origin in the counterclockwise direction.  This edge */
+/*   will be part of a different triangle.                                   */
+
+#define onext(triedge1, triedge2)                                             \
+  lprev(triedge1, triedge2);                                                  \
+  symself(triedge2);
+
+#define onextself(triedge)                                                    \
+  lprevself(triedge);                                                         \
+  symself(triedge);
+
+/* oprev() spins clockwise around a point; that is, it finds the next edge   */
+/*   with the same origin in the clockwise direction.  This edge will be     */
+/*   part of a different triangle.                                           */
+
+#define oprev(triedge1, triedge2)                                             \
+  sym(triedge1, triedge2);                                                    \
+  lnextself(triedge2);
+
+#define oprevself(triedge)                                                    \
+  symself(triedge);                                                           \
+  lnextself(triedge);
+
+/* dnext() spins counterclockwise around a point; that is, it finds the next */
+/*   edge with the same destination in the counterclockwise direction.  This */
+/*   edge will be part of a different triangle.                              */
+
+#define dnext(triedge1, triedge2)                                             \
+  sym(triedge1, triedge2);                                                    \
+  lprevself(triedge2);
+
+#define dnextself(triedge)                                                    \
+  symself(triedge);                                                           \
+  lprevself(triedge);
+
+/* dprev() spins clockwise around a point; that is, it finds the next edge   */
+/*   with the same destination in the clockwise direction.  This edge will   */
+/*   be part of a different triangle.                                        */
+
+#define dprev(triedge1, triedge2)                                             \
+  lnext(triedge1, triedge2);                                                  \
+  symself(triedge2);
+
+#define dprevself(triedge)                                                    \
+  lnextself(triedge);                                                         \
+  symself(triedge);
+
+/* rnext() moves one edge counterclockwise about the adjacent triangle.      */
+/*   (It's best understood by reading Guibas and Stolfi.  It involves        */
+/*   changing triangles twice.)                                              */
+
+#define rnext(triedge1, triedge2)                                             \
+  sym(triedge1, triedge2);                                                    \
+  lnextself(triedge2);                                                        \
+  symself(triedge2);
+
+#define rnextself(triedge)                                                    \
+  symself(triedge);                                                           \
+  lnextself(triedge);                                                         \
+  symself(triedge);
+
+/* rnext() moves one edge clockwise about the adjacent triangle.             */
+/*   (It's best understood by reading Guibas and Stolfi.  It involves        */
+/*   changing triangles twice.)                                              */
+
+#define rprev(triedge1, triedge2)                                             \
+  sym(triedge1, triedge2);                                                    \
+  lprevself(triedge2);                                                        \
+  symself(triedge2);
+
+#define rprevself(triedge)                                                    \
+  symself(triedge);                                                           \
+  lprevself(triedge);                                                         \
+  symself(triedge);
+
+/* These primitives determine or set the origin, destination, or apex of a   */
+/* triangle.                                                                 */
+
+#define org(triedge, pointptr)                                                \
+  pointptr = (point) (triedge).tri[plus1mod3[(triedge).orient] + 3]
+
+#define dest(triedge, pointptr)                                               \
+  pointptr = (point) (triedge).tri[minus1mod3[(triedge).orient] + 3]
+
+#define apex(triedge, pointptr)                                               \
+  pointptr = (point) (triedge).tri[(triedge).orient + 3]
+
+#define setorg(triedge, pointptr)                                             \
+  (triedge).tri[plus1mod3[(triedge).orient] + 3] = (triangle) pointptr
+
+#define setdest(triedge, pointptr)                                            \
+  (triedge).tri[minus1mod3[(triedge).orient] + 3] = (triangle) pointptr
+
+#define setapex(triedge, pointptr)                                            \
+  (triedge).tri[(triedge).orient + 3] = (triangle) pointptr
+
+#define setvertices2null(triedge)                                             \
+  (triedge).tri[3] = (triangle) NULL;                                         \
+  (triedge).tri[4] = (triangle) NULL;                                         \
+  (triedge).tri[5] = (triangle) NULL;
+
+/* Bond two triangles together.                                              */
+
+#define bond(triedge1, triedge2)                                              \
+  (triedge1).tri[(triedge1).orient] = encode(triedge2);                       \
+  (triedge2).tri[(triedge2).orient] = encode(triedge1)
+
+/* Dissolve a bond (from one side).  Note that the other triangle will still */
+/*   think it's connected to this triangle.  Usually, however, the other     */
+/*   triangle is being deleted entirely, or bonded to another triangle, so   */
+/*   it doesn't matter.                                                      */
+
+#define dissolve(triedge)                                                     \
+  (triedge).tri[(triedge).orient] = (triangle) dummytri
+
+/* Copy a triangle/edge handle.                                              */
+
+#define triedgecopy(triedge1, triedge2)                                       \
+  (triedge2).tri = (triedge1).tri;                                            \
+  (triedge2).orient = (triedge1).orient
+
+/* Test for equality of triangle/edge handles.                               */
+
+#define triedgeequal(triedge1, triedge2)                                      \
+  (((triedge1).tri == (triedge2).tri) &&                                      \
+   ((triedge1).orient == (triedge2).orient))
+
+/* Primitives to infect or cure a triangle with the virus.  These rely on    */
+/*   the assumption that all shell edges are aligned to four-byte boundaries.*/
+
+#define infect(triedge)                                                       \
+  (triedge).tri[6] = (triangle)                                               \
+                     ((unsigned long) (triedge).tri[6] | (unsigned long) 2l)
+
+#define uninfect(triedge)                                                     \
+  (triedge).tri[6] = (triangle)                                               \
+                     ((unsigned long) (triedge).tri[6] & ~ (unsigned long) 2l)
+
+/* Test a triangle for viral infection.                                      */
+
+#define infected(triedge)                                                     \
+  (((unsigned long) (triedge).tri[6] & (unsigned long) 2l) != 0)
+
+/* Check or set a triangle's attributes.                                     */
+
+#define elemattribute(triedge, attnum)                                        \
+  ((REAL *) (triedge).tri)[elemattribindex + (attnum)]
+
+#define setelemattribute(triedge, attnum, value)                              \
+  ((REAL *) (triedge).tri)[elemattribindex + (attnum)] = value
+
+/* Check or set a triangle's maximum area bound.                             */
+
+#define areabound(triedge)  ((REAL *) (triedge).tri)[areaboundindex]
+
+#define setareabound(triedge, value)                                          \
+  ((REAL *) (triedge).tri)[areaboundindex] = value
+
+/********* Primitives for shell edges                                *********/
+/*                                                                           */
+/*                                                                           */
+
+/* sdecode() converts a pointer to an oriented shell edge.  The orientation  */
+/*   is extracted from the least significant bit of the pointer.  The two    */
+/*   least significant bits (one for orientation, one for viral infection)   */
+/*   are masked out to produce the real pointer.                             */
+
+#define sdecode(sptr, edge)                                                   \
+  (edge).shorient = (int) ((unsigned long) (sptr) & (unsigned long) 1l);      \
+  (edge).sh = (shelle *)                                                      \
+              ((unsigned long) (sptr) & ~ (unsigned long) 3l)
+
+/* sencode() compresses an oriented shell edge into a single pointer.  It    */
+/*   relies on the assumption that all shell edges are aligned to two-byte   */
+/*   boundaries, so the least significant bit of (edge).sh is zero.          */
+
+#define sencode(edge)                                                         \
+  (shelle) ((unsigned long) (edge).sh | (unsigned long) (edge).shorient)
+
+/* ssym() toggles the orientation of a shell edge.                           */
+
+#define ssym(edge1, edge2)                                                    \
+  (edge2).sh = (edge1).sh;                                                    \
+  (edge2).shorient = 1 - (edge1).shorient
+
+#define ssymself(edge)                                                        \
+  (edge).shorient = 1 - (edge).shorient
+
+/* spivot() finds the other shell edge (from the same segment) that shares   */
+/*   the same origin.                                                        */
+
+#define spivot(edge1, edge2)                                                  \
+  sptr = (edge1).sh[(edge1).shorient];                                        \
+  sdecode(sptr, edge2)
+
+#define spivotself(edge)                                                      \
+  sptr = (edge).sh[(edge).shorient];                                          \
+  sdecode(sptr, edge)
+
+/* snext() finds the next shell edge (from the same segment) in sequence;    */
+/*   one whose origin is the input shell edge's destination.                 */
+
+#define snext(edge1, edge2)                                                   \
+  sptr = (edge1).sh[1 - (edge1).shorient];                                    \
+  sdecode(sptr, edge2)
+
+#define snextself(edge)                                                       \
+  sptr = (edge).sh[1 - (edge).shorient];                                      \
+  sdecode(sptr, edge)
+
+/* These primitives determine or set the origin or destination of a shell    */
+/*   edge.                                                                   */
+
+#define sorg(edge, pointptr)                                                  \
+  pointptr = (point) (edge).sh[2 + (edge).shorient]
+
+#define sdest(edge, pointptr)                                                 \
+  pointptr = (point) (edge).sh[3 - (edge).shorient]
+
+#define setsorg(edge, pointptr)                                               \
+  (edge).sh[2 + (edge).shorient] = (shelle) pointptr
+
+#define setsdest(edge, pointptr)                                              \
+  (edge).sh[3 - (edge).shorient] = (shelle) pointptr
+
+/* These primitives read or set a shell marker.  Shell markers are used to   */
+/*   hold user boundary information.                                         */
+
+#define mark(edge)  (* (int *) ((edge).sh + 6))
+
+#define setmark(edge, value)                                                  \
+  * (int *) ((edge).sh + 6) = value
+
+/* Bond two shell edges together.                                            */
+
+#define sbond(edge1, edge2)                                                   \
+  (edge1).sh[(edge1).shorient] = sencode(edge2);                              \
+  (edge2).sh[(edge2).shorient] = sencode(edge1)
+
+/* Dissolve a shell edge bond (from one side).  Note that the other shell    */
+/*   edge will still think it's connected to this shell edge.                */
+
+#define sdissolve(edge)                                                       \
+  (edge).sh[(edge).shorient] = (shelle) dummysh
+
+/* Copy a shell edge.                                                        */
+
+#define shellecopy(edge1, edge2)                                              \
+  (edge2).sh = (edge1).sh;                                                    \
+  (edge2).shorient = (edge1).shorient
+
+/* Test for equality of shell edges.                                         */
+
+#define shelleequal(edge1, edge2)                                             \
+  (((edge1).sh == (edge2).sh) &&                                              \
+   ((edge1).shorient == (edge2).shorient))
+
+/********* Primitives for interacting triangles and shell edges      *********/
+/*                                                                           */
+/*                                                                           */
+
+/* tspivot() finds a shell edge abutting a triangle.                         */
+
+#define tspivot(triedge, edge)                                                \
+  sptr = (shelle) (triedge).tri[6 + (triedge).orient];                        \
+  sdecode(sptr, edge)
+
+/* stpivot() finds a triangle abutting a shell edge.  It requires that the   */
+/*   variable `ptr' of type `triangle' be defined.                           */
+
+#define stpivot(edge, triedge)                                                \
+  ptr = (triangle) (edge).sh[4 + (edge).shorient];                            \
+  decode(ptr, triedge)
+
+/* Bond a triangle to a shell edge.                                          */
+
+#define tsbond(triedge, edge)                                                 \
+  (triedge).tri[6 + (triedge).orient] = (triangle) sencode(edge);             \
+  (edge).sh[4 + (edge).shorient] = (shelle) encode(triedge)
+
+/* Dissolve a bond (from the triangle side).                                 */
+
+#define tsdissolve(triedge)                                                   \
+  (triedge).tri[6 + (triedge).orient] = (triangle) dummysh
+
+/* Dissolve a bond (from the shell edge side).                               */
+
+#define stdissolve(edge)                                                      \
+  (edge).sh[4 + (edge).shorient] = (shelle) dummytri
+
+/********* Primitives for points                                     *********/
+/*                                                                           */
+/*                                                                           */
+
+#define pointmark(pt)  ((int *) (pt))[pointmarkindex]
+
+#define setpointmark(pt, value)                                               \
+  ((int *) (pt))[pointmarkindex] = value
+
+#define point2tri(pt)  ((triangle *) (pt))[point2triindex]
+
+#define setpoint2tri(pt, value)                                               \
+  ((triangle *) (pt))[point2triindex] = value
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Mesh manipulation primitives end here                     *********/
+
+/********* User interaction routines begin here                      *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  syntax()   Print list of command line switches.                          */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::syntax()
+{
+  printf("triangle [-paAcevngBPNEIOXzo_YS__iFlsCQVh] input_file\n");
+  exit(0);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  info()   Print out complete instructions.                                */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::info()
+{
+  printf("Triangle\n");
+  printf(
+"A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.\n");
+  printf("Version 1.3\n\n");
+  printf(
+"Copyright 1996 Jonathan Richard Shewchuk  (bugs/comments to jrs@cs.cmu.edu)\n"
+);
+  printf("School of Computer Science / Carnegie Mellon University\n");
+  printf("5000 Forbes Avenue / Pittsburgh, Pennsylvania  15213-3891\n");
+  printf(
+"Created as part of the Archimedes project (tools for parallel FEM).\n");
+  printf(
+"Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.\n");
+  printf("There is no warranty whatsoever.  Use at your own risk.\n");
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  internalerror()   Ask the user to send me the defective product.  Exit.  */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::internalerror()
+{
+  printf("  Please report this bug to sihang@weboo.com\n");
+  printf("  Include the message above, your input data set, and the exact\n");
+  printf("    command line you used to run Triangle.\n");
+  exit(1);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  parsecommandline()   Read the command line, identify switches, and set   */
+/*                       up options and file names.                          */
+/*                                                                           */
+/*  The effects of this routine are felt entirely through global variables.  */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::parsecommandline(int argc, char **argv, int libflag)
+{
+  int startindex;
+  char startchar;
+  int increment;
+  int meshnumber;
+  int i, j, k;
+  char workstring[FILENAMESIZE];
+
+  poly = refine = quality = vararea = fixedarea = regionattrib = convex = 0;
+  firstnumber = 1;
+  edgesout = voronoi = neighbors = geomview = 0;
+  nobound = nopolywritten = nonodewritten = noelewritten = noiterationnum = 0;
+  noholes = noexact = 0;
+  incremental = sweepline = 0;
+  dwyer = 1;
+  splitseg = 0;
+  docheck = 0;
+  nobisect = 0;
+  steiner = -1;
+  order = 1;
+  minangle = 0.0;
+  maxarea = -1.0;
+  quiet = verbose = 0;
+
+  if (libflag) {
+    startindex = 0;
+  } else {
+    startindex = 1;
+  }
+
+  for (i = startindex; i < argc; i++) {
+    if (libflag) {
+      startchar = '-';
+    } else {
+      startchar = argv[i][0];
+    }
+    if (startchar == '-') {
+      for (j = startindex; argv[i][j] != '\0'; j++) {
+        if (argv[i][j] == 'p') {
+          poly = 1;
+        }
+        if (argv[i][j] == 'r') {
+          refine = 1;
+	      }
+        if (argv[i][j] == 'q') {
+          quality = 1;
+          if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+              (argv[i][j + 1] == '.')) {
+            k = 0;
+            while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+                   (argv[i][j + 1] == '.')) {
+              j++;
+              workstring[k] = argv[i][j];
+              k++;
+            }
+            workstring[k] = '\0';
+            minangle = (REAL) strtod(workstring, (char **) NULL);
+          } else {
+            minangle = 20.0;
+          }
+        }
+        if (argv[i][j] == 'a') {
+          quality = 1;
+          if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+              (argv[i][j + 1] == '.')) {
+            fixedarea = 1;
+            k = 0;
+            while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+                   (argv[i][j + 1] == '.')) {
+              j++;
+              workstring[k] = argv[i][j];
+              k++;
+            }
+            workstring[k] = '\0';
+            maxarea = (REAL) strtod(workstring, (char **) NULL);
+            if (maxarea <= 0.0) {
+              printf("Error:  Maximum area must be greater than zero.\n");
+              exit(1);
+            }
+          } else {
+            vararea = 1;
+          }
+        }
+        if (argv[i][j] == 'A') {
+          regionattrib = 1;
+        }
+        if (argv[i][j] == 'c') {
+          convex = 1;
+        }
+        if (argv[i][j] == 'z') {
+          firstnumber = 0;
+        }
+        if (argv[i][j] == 'e') {
+          edgesout = 1;
+        }
+        if (argv[i][j] == 'v') {
+          voronoi = 1;
+        }
+        if (argv[i][j] == 'n') {
+          neighbors = 1;
+        }
+        if (argv[i][j] == 'g') {
+          geomview = 1;
+        }
+        if (argv[i][j] == 'B') {
+          nobound = 1;
+        }
+        if (argv[i][j] == 'P') {
+          nopolywritten = 1;
+        }
+        if (argv[i][j] == 'N') {
+          nonodewritten = 1;
+        }
+        if (argv[i][j] == 'E') {
+          noelewritten = 1;
+        }
+        if (argv[i][j] == 'I') {
+          noiterationnum = 1;
+        }
+        if (argv[i][j] == 'O') {
+          noholes = 1;
+        }
+        if (argv[i][j] == 'X') {
+          noexact = 1;
+        }
+        if (argv[i][j] == 'o') {
+          if (argv[i][j + 1] == '2') {
+            j++;
+            order = 2;
+          }
+        }
+        if (argv[i][j] == 'Y') {
+          nobisect++;
+        }
+        if (argv[i][j] == 'S') {
+          steiner = 0;
+          while ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
+            j++;
+            steiner = steiner * 10 + (int) (argv[i][j] - '0');
+          }
+        }
+        if (argv[i][j] == 'i') {
+          incremental = 1;
+        }
+        if (argv[i][j] == 'F') {
+          sweepline = 1;
+        }
+        if (argv[i][j] == 'l') {
+          dwyer = 0;
+        }
+        if (argv[i][j] == 's') {
+          splitseg = 1;
+        }
+        if (argv[i][j] == 'C') {
+          docheck = 1;
+        }
+        if (argv[i][j] == 'Q') {
+          quiet = 1;
+        }
+        if (argv[i][j] == 'V') {
+          verbose++;
+        }
+        if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
+            (argv[i][j] == '?')) {
+          info();
+        }
+      }
+    }
+  }
+
+  steinerleft = steiner;
+  useshelles = poly || refine || quality || convex;
+  // Be careful not to add an extra attribute to each element unless the
+  //   input supports it (PSLG in, but not refining a preexisting mesh).
+  if (refine || !poly) {
+    regionattrib = 0;
+  }
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* User interaction routines begin here                      *********/
+
+/********* Debugging routines begin here                             *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  printtriangle()   Print out the details of a triangle/edge handle.       */
+/*                                                                           */
+/*  I originally wrote this procedure to simplify debugging; it can be       */
+/*  called directly from the debugger, and presents information about a      */
+/*  triangle/edge handle in digestible form.  It's also used when the        */
+/*  highest level of verbosity (`-VVV') is specified.                        */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::printtriangle(struct triedge *t)
+{
+  struct triedge printtri;
+  struct edge printsh;
+  point printpoint;
+
+  printf("triangle x%lx with orientation %d:\n", (unsigned long) t->tri,
+         t->orient);
+  decode(t->tri[0], printtri);
+  if (printtri.tri == dummytri) {
+    printf("    [0] = Outer space\n");
+  } else {
+    printf("    [0] = x%lx  %d\n", (unsigned long) printtri.tri,
+           printtri.orient);
+  }
+  decode(t->tri[1], printtri);
+  if (printtri.tri == dummytri) {
+    printf("    [1] = Outer space\n");
+  } else {
+    printf("    [1] = x%lx  %d\n", (unsigned long) printtri.tri,
+           printtri.orient);
+  }
+  decode(t->tri[2], printtri);
+  if (printtri.tri == dummytri) {
+    printf("    [2] = Outer space\n");
+  } else {
+    printf("    [2] = x%lx  %d\n", (unsigned long) printtri.tri,
+           printtri.orient);
+  }
+  org(*t, printpoint);
+  if (printpoint == (point) NULL)
+    printf("    Origin[%d] = NULL\n", (t->orient + 1) % 3 + 3);
+  else
+    printf("    Origin[%d] = x%lx  (%.12g, %.12g)\n",
+           (t->orient + 1) % 3 + 3, (unsigned long) printpoint,
+           printpoint[0], printpoint[1]);
+  dest(*t, printpoint);
+  if (printpoint == (point) NULL)
+    printf("    Dest  [%d] = NULL\n", (t->orient + 2) % 3 + 3);
+  else
+    printf("    Dest  [%d] = x%lx  (%.12g, %.12g)\n",
+           (t->orient + 2) % 3 + 3, (unsigned long) printpoint,
+           printpoint[0], printpoint[1]);
+  apex(*t, printpoint);
+  if (printpoint == (point) NULL)
+    printf("    Apex  [%d] = NULL\n", t->orient + 3);
+  else
+    printf("    Apex  [%d] = x%lx  (%.12g, %.12g)\n",
+           t->orient + 3, (unsigned long) printpoint,
+           printpoint[0], printpoint[1]);
+  if (useshelles) {
+    sdecode(t->tri[6], printsh);
+    if (printsh.sh != dummysh) {
+      printf("    [6] = x%lx  %d\n", (unsigned long) printsh.sh,
+             printsh.shorient);
+    }
+    sdecode(t->tri[7], printsh);
+    if (printsh.sh != dummysh) {
+      printf("    [7] = x%lx  %d\n", (unsigned long) printsh.sh,
+             printsh.shorient);
+    }
+    sdecode(t->tri[8], printsh);
+    if (printsh.sh != dummysh) {
+      printf("    [8] = x%lx  %d\n", (unsigned long) printsh.sh,
+             printsh.shorient);
+    }
+  }
+  if (vararea) {
+    printf("    Area constraint:  %.4g\n", areabound(*t));
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  printshelle()   Print out the details of a shell edge handle.            */
+/*                                                                           */
+/*  I originally wrote this procedure to simplify debugging; it can be       */
+/*  called directly from the debugger, and presents information about a      */
+/*  shell edge handle in digestible form.  It's also used when the highest   */
+/*  level of verbosity (`-VVV') is specified.                                */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::printshelle(struct edge *s)
+{
+  struct edge printsh;
+  struct triedge printtri;
+  point printpoint;
+
+  printf("shell edge x%lx with orientation %d and mark %d:\n",
+         (unsigned long) s->sh, s->shorient, mark(*s));
+  sdecode(s->sh[0], printsh);
+  if (printsh.sh == dummysh) {
+    printf("    [0] = No shell\n");
+  } else {
+    printf("    [0] = x%lx  %d\n", (unsigned long) printsh.sh,
+           printsh.shorient);
+  }
+  sdecode(s->sh[1], printsh);
+  if (printsh.sh == dummysh) {
+    printf("    [1] = No shell\n");
+  } else {
+    printf("    [1] = x%lx  %d\n", (unsigned long) printsh.sh,
+           printsh.shorient);
+  }
+  sorg(*s, printpoint);
+  if (printpoint == (point) NULL)
+    printf("    Origin[%d] = NULL\n", 2 + s->shorient);
+  else
+    printf("    Origin[%d] = x%lx  (%.12g, %.12g)\n",
+           2 + s->shorient, (unsigned long) printpoint,
+           printpoint[0], printpoint[1]);
+  sdest(*s, printpoint);
+  if (printpoint == (point) NULL)
+    printf("    Dest  [%d] = NULL\n", 3 - s->shorient);
+  else
+    printf("    Dest  [%d] = x%lx  (%.12g, %.12g)\n",
+           3 - s->shorient, (unsigned long) printpoint,
+           printpoint[0], printpoint[1]);
+  decode(s->sh[4], printtri);
+  if (printtri.tri == dummytri) {
+    printf("    [4] = Outer space\n");
+  } else {
+    printf("    [4] = x%lx  %d\n", (unsigned long) printtri.tri,
+           printtri.orient);
+  }
+  decode(s->sh[5], printtri);
+  if (printtri.tri == dummytri) {
+    printf("    [5] = Outer space\n");
+  } else {
+    printf("    [5] = x%lx  %d\n", (unsigned long) printtri.tri,
+           printtri.orient);
+  }
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Debugging routines end here                               *********/
+
+/********* Memory management routines begin here                     *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  dummyinit()   Initialize the triangle that fills "outer space" and the   */
+/*                omnipresent shell edge.                                    */
+/*                                                                           */
+/*  The triangle that fills "outer space", called `dummytri', is pointed to  */
+/*  by every triangle and shell edge on a boundary (be it outer or inner) of */
+/*  the triangulation.  Also, `dummytri' points to one of the triangles on   */
+/*  the convex hull (until the holes and concavities are carved), making it  */
+/*  possible to find a starting triangle for point location.                 */
+/*                                                                           */
+/*  The omnipresent shell edge, `dummysh', is pointed to by every triangle   */
+/*  or shell edge that doesn't have a full complement of real shell edges    */
+/*  to point to.                                                             */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::dummyinit(int trianglewords, int shellewords)
+{
+  unsigned long alignptr;
+
+  /* `triwords' and `shwords' are used by the mesh manipulation primitives */
+  /*   to extract orientations of triangles and shell edges from pointers. */
+  triwords = trianglewords;       /* Initialize `triwords' once and for all. */
+  shwords = shellewords;           /* Initialize `shwords' once and for all. */
+
+  /* Set up `dummytri', the `triangle' that occupies "outer space". */
+  dummytribase = (triangle *) new BYTE[triwords * sizeof(triangle)
+                                       + triangles.alignbytes];
+  if (dummytribase == (triangle *) NULL) {
+    printf("Error:  Out of memory.\n");
+    exit(1);
+  }
+  /* Align `dummytri' on a `triangles.alignbytes'-byte boundary. */
+  alignptr = (unsigned long) dummytribase;
+  dummytri = (triangle *)
+    (alignptr + (unsigned long) triangles.alignbytes
+     - (alignptr % (unsigned long) triangles.alignbytes));
+  /* Initialize the three adjoining triangles to be "outer space".  These  */
+  /*   will eventually be changed by various bonding operations, but their */
+  /*   values don't really matter, as long as they can legally be          */
+  /*   dereferenced.                                                       */
+  dummytri[0] = (triangle) dummytri;
+  dummytri[1] = (triangle) dummytri;
+  dummytri[2] = (triangle) dummytri;
+  /* Three NULL vertex points. */
+  dummytri[3] = (triangle) NULL;
+  dummytri[4] = (triangle) NULL;
+  dummytri[5] = (triangle) NULL;
+
+  if (useshelles) {
+    /* Set up `dummysh', the omnipresent "shell edge" pointed to by any      */
+    /*   triangle side or shell edge end that isn't attached to a real shell */
+    /*   edge.                                                               */
+    dummyshbase = (shelle *) new BYTE[shwords * sizeof(shelle)
+                                      + shelles.alignbytes];
+    if (dummyshbase == (shelle *) NULL) {
+      printf("Error:  Out of memory.\n");
+      exit(1);
+    }
+    /* Align `dummysh' on a `shelles.alignbytes'-byte boundary. */
+    alignptr = (unsigned long) dummyshbase;
+    dummysh = (shelle *)
+      (alignptr + (unsigned long) shelles.alignbytes
+       - (alignptr % (unsigned long) shelles.alignbytes));
+    /* Initialize the two adjoining shell edges to be the omnipresent shell */
+    /*   edge.  These will eventually be changed by various bonding         */
+    /*   operations, but their values don't really matter, as long as they  */
+    /*   can legally be dereferenced.                                       */
+    dummysh[0] = (shelle) dummysh;
+    dummysh[1] = (shelle) dummysh;
+    /* Two NULL vertex points. */
+    dummysh[2] = (shelle) NULL;
+    dummysh[3] = (shelle) NULL;
+    /* Initialize the two adjoining triangles to be "outer space". */
+    dummysh[4] = (shelle) dummytri;
+    dummysh[5] = (shelle) dummytri;
+    /* Set the boundary marker to zero. */
+    * (int *) (dummysh + 6) = 0;
+
+    /* Initialize the three adjoining shell edges of `dummytri' to be */
+    /*   the omnipresent shell edge.                                  */
+    dummytri[6] = (triangle) dummysh;
+    dummytri[7] = (triangle) dummysh;
+    dummytri[8] = (triangle) dummysh;
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  initializepointpool()   Calculate the size of the point data structure   */
+/*                          and initialize its memory pool.                  */
+/*                                                                           */
+/*  This routine also computes the `pointmarkindex' and `point2triindex'     */
+/*  indices used to find values within each point.                           */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::initializepointpool()
+{
+  int pointsize;
+
+  /* The index within each point at which the boundary marker is found.  */
+  /*   Ensure the point marker is aligned to a sizeof(int)-byte address. */
+  pointmarkindex = ((mesh_dim + nextras) * sizeof(REAL) + sizeof(int) - 1)
+                 / sizeof(int);
+  pointsize = (pointmarkindex + 1) * sizeof(int);
+  if (poly) {
+    /* The index within each point at which a triangle pointer is found.   */
+    /*   Ensure the pointer is aligned to a sizeof(triangle)-byte address. */
+    point2triindex = (pointsize + sizeof(triangle) - 1) / sizeof(triangle);
+    pointsize = (point2triindex + 1) * sizeof(triangle);
+  }
+  /* Initialize the pool of points. */
+  points.init(pointsize, POINTPERBLOCK,
+           (sizeof(REAL) >= sizeof(triangle)) ? FLOATINGPOINT : POINTER, 0);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  initializetrisegpools()   Calculate the sizes of the triangle and shell  */
+/*                            edge data structures and initialize their      */
+/*                            memory pools.                                  */
+/*                                                                           */
+/*  This routine also computes the `highorderindex', `elemattribindex', and  */
+/*  `areaboundindex' indices used to find values within each triangle.       */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::initializetrisegpools()
+{
+  int trisize;
+
+  /* The index within each triangle at which the extra nodes (above three)  */
+  /*   associated with high order elements are found.  There are three      */
+  /*   pointers to other triangles, three pointers to corners, and possibly */
+  /*   three pointers to shell edges before the extra nodes.                */
+  highorderindex = 6 + (useshelles * 3);
+  /* The number of bytes occupied by a triangle. */
+  trisize = ((order + 1) * (order + 2) / 2 + (highorderindex - 3)) *
+            sizeof(triangle);
+  /* The index within each triangle at which its attributes are found, */
+  /*   where the index is measured in REALs.                           */
+  elemattribindex = (trisize + sizeof(REAL) - 1) / sizeof(REAL);
+  /* The index within each triangle at which the maximum area constraint  */
+  /*   is found, where the index is measured in REALs.  Note that if the  */
+  /*   `regionattrib' flag is set, an additional attribute will be added. */
+  areaboundindex = elemattribindex + eextras + regionattrib;
+  /* If triangle attributes or an area bound are needed, increase the number */
+  /*   of bytes occupied by a triangle.                                      */
+  if (vararea) {
+    trisize = (areaboundindex + 1) * sizeof(REAL);
+  } else if (eextras + regionattrib > 0) {
+    trisize = areaboundindex * sizeof(REAL);
+  }
+  /* If a Voronoi diagram or triangle neighbor graph is requested, make    */
+  /*   sure there's room to store an integer index in each triangle.  This */
+  /*   integer index can occupy the same space as the shell edges or       */
+  /*   attributes or area constraint or extra nodes.                       */
+  if ((voronoi || neighbors) &&
+      (trisize < 6 * sizeof(triangle) + sizeof(int))) {
+    trisize = 6 * sizeof(triangle) + sizeof(int);
+  }
+  /* Having determined the memory size of a triangle, initialize the pool. */
+  triangles.init(trisize, TRIPERBLOCK, POINTER, 4);
+
+  if (useshelles) {
+    /* Initialize the pool of shell edges. */
+    shelles.init(6 * sizeof(triangle) + sizeof(int), SHELLEPERBLOCK,
+                 POINTER, 4);
+
+    /* Initialize the "outer space" triangle and omnipresent shell edge. */
+    dummyinit(triangles.itemwords, shelles.itemwords);
+  } else {
+    /* Initialize the "outer space" triangle. */
+    dummyinit(triangles.itemwords, 0);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  triangledealloc()   Deallocate space for a triangle, marking it dead.    */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::triangledealloc(triangle *dyingtriangle)
+{
+  /* Set triangle's vertices to NULL.  This makes it possible to        */
+  /*   detect dead triangles when traversing the list of all triangles. */
+  dyingtriangle[3] = (triangle) NULL;
+  dyingtriangle[4] = (triangle) NULL;
+  dyingtriangle[5] = (triangle) NULL;
+  triangles.dealloc(dyingtriangle);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  triangletraverse()   Traverse the triangles, skipping dead ones.         */
+/*                                                                           */
+/*****************************************************************************/
+
+triangle* mesh2d::triangletraverse()
+{
+  triangle *newtriangle;
+
+  do {
+    newtriangle = (triangle *) triangles.traverse();
+    if (newtriangle == (triangle *) NULL) {
+      return (triangle *) NULL;
+    }
+  } while (newtriangle[3] == (triangle) NULL);            /* Skip dead ones. */
+  return newtriangle;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  shelledealloc()   Deallocate space for a shell edge, marking it dead.    */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::shelledealloc(shelle *dyingshelle)
+{
+  /* Set shell edge's vertices to NULL.  This makes it possible to */
+  /*   detect dead shells when traversing the list of all shells.  */
+  dyingshelle[2] = (shelle) NULL;
+  dyingshelle[3] = (shelle) NULL;
+  shelles.dealloc(dyingshelle);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  shelletraverse()   Traverse the shell edges, skipping dead ones.         */
+/*                                                                           */
+/*****************************************************************************/
+
+shelle* mesh2d::shelletraverse()
+{
+  shelle *newshelle;
+
+  do {
+    newshelle = (shelle *) shelles.traverse();
+    if (newshelle == (shelle *) NULL) {
+      return (shelle *) NULL;
+    }
+  } while (newshelle[2] == (shelle) NULL);                /* Skip dead ones. */
+  return newshelle;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  pointdealloc()   Deallocate space for a point, marking it dead.          */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::pointdealloc(point dyingpoint)
+{
+  /* Mark the point as dead.  This makes it possible to detect dead points */
+  /*   when traversing the list of all points.                             */
+  setpointmark(dyingpoint, DEADPOINT);
+  points.dealloc(dyingpoint);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  pointtraverse()   Traverse the points, skipping dead ones.               */
+/*                                                                           */
+/*****************************************************************************/
+
+point mesh2d::pointtraverse()
+{
+  point newpoint;
+
+  do {
+    newpoint = (point) points.traverse();
+    if (newpoint == (point) NULL) {
+      return (point) NULL;
+    }
+  } while (pointmark(newpoint) == DEADPOINT);             /* Skip dead ones. */
+  return newpoint;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  getpoint()   Get a specific point, by number, from the list.             */
+/*                                                                           */
+/*  The first point is number 'firstnumber'.                                 */
+/*                                                                           */
+/*  Note that this takes O(n) time (with a small constant, if POINTPERBLOCK  */
+/*  is large).  I don't care to take the trouble to make it work in constant */
+/*  time.                                                                    */
+/*                                                                           */
+/*****************************************************************************/
+
+point mesh2d::getpoint(int number)
+{
+  void **getblock;
+  point foundpoint;
+  unsigned long alignptr;
+  int current;
+
+  getblock = points.firstblock;
+  current = firstnumber;
+  /* Find the right block. */
+  while (current + points.itemsperblock <= number) {
+    getblock = (void **) *getblock;
+    current += points.itemsperblock;
+  }
+  /* Now find the right point. */
+  alignptr = (unsigned long) (getblock + 1);
+  foundpoint = (point) (alignptr + (unsigned long) points.alignbytes
+                        - (alignptr % (unsigned long) points.alignbytes));
+  while (current < number) {
+    foundpoint += points.itemwords;
+    current++;
+  }
+  return foundpoint;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  triangledeinit()   Free all remaining allocated memory.                  */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::triangledeinit()
+{
+  triangles.deinit();
+  if (dummytribase) delete [] dummytribase;
+  if (useshelles) {
+    shelles.deinit();
+    if (dummyshbase) delete [] dummyshbase;
+  }
+  points.deinit();
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Memory management routines end here                       *********/
+
+/********* Constructors begin here                                   *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  maketriangle()   Create a new triangle with orientation zero.            */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::maketriangle(struct triedge *newtriedge)
+{
+  int i;
+
+  newtriedge->tri = (triangle *) triangles.alloc();
+  /* Initialize the three adjoining triangles to be "outer space". */
+  newtriedge->tri[0] = (triangle) dummytri;
+  newtriedge->tri[1] = (triangle) dummytri;
+  newtriedge->tri[2] = (triangle) dummytri;
+  /* Three NULL vertex points. */
+  newtriedge->tri[3] = (triangle) NULL;
+  newtriedge->tri[4] = (triangle) NULL;
+  newtriedge->tri[5] = (triangle) NULL;
+  /* Initialize the three adjoining shell edges to be the omnipresent */
+  /*   shell edge.                                                    */
+  if (useshelles) {
+    newtriedge->tri[6] = (triangle) dummysh;
+    newtriedge->tri[7] = (triangle) dummysh;
+    newtriedge->tri[8] = (triangle) dummysh;
+  }
+  for (i = 0; i < eextras; i++) {
+    setelemattribute(*newtriedge, i, 0.0);
+  }
+  if (vararea) {
+    setareabound(*newtriedge, -1.0);
+  }
+
+  newtriedge->orient = 0;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  makeshelle()   Create a new shell edge with orientation zero.            */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::makeshelle(struct edge *newedge)
+{
+  newedge->sh = (shelle *) shelles.alloc();
+  /* Initialize the two adjoining shell edges to be the omnipresent */
+  /*   shell edge.                                                  */
+  newedge->sh[0] = (shelle) dummysh;
+  newedge->sh[1] = (shelle) dummysh;
+  /* Two NULL vertex points. */
+  newedge->sh[2] = (shelle) NULL;
+  newedge->sh[3] = (shelle) NULL;
+  /* Initialize the two adjoining triangles to be "outer space". */
+  newedge->sh[4] = (shelle) dummytri;
+  newedge->sh[5] = (shelle) dummytri;
+  /* Set the boundary marker to zero. */
+  setmark(*newedge, 0);
+
+  newedge->shorient = 0;
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Constructors end here                                     *********/
+
+/********* Determinant evaluation routines begin here                *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/* This routines were move to "predicate.cpp" file                           */
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Determinant evaluation routines end here                  *********/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  triangleinit()   Initialize some variables.                              */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::triangleinit()
+{
+  points.maxitems = triangles.maxitems = shelles.maxitems = viri.maxitems = 0l;
+  points.itembytes = triangles.itembytes = shelles.itembytes =
+    viri.itembytes = 0;
+  recenttri.tri = (triangle *) NULL;    /* No triangle has been visited yet. */
+  samples = 1;            /* Point location should take at least one sample. */
+  checksegments = 0;      /* There are no segments in the triangulation yet. */
+  circumcentercount = 0;
+  randomseed = 1;
+  incirclecount = counterclockcount = 0;
+  dummytribase = NULL;
+  dummyshbase = NULL;
+  restartsymbol = 0;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/* trianglerestart()    Clear all remaining allocated memory, not free them. */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::trianglerestart()
+{
+  triangles.restart();
+  if (useshelles) {
+    shelles.restart();
+  }
+  points.restart();
+
+  recenttri.tri = (triangle *) NULL;    // No triangle has been visited yet.
+  samples = 1;            // Point location should take at least one sample.
+  checksegments = 0;      // There are no segments in the triangulation yet.
+  randomseed = 1;
+  circumcentercount = 0;
+  restartsymbol = 1;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  counterclockwise()   Return a positive value if the points pa, pb, and   */
+/*                       pc occur in counterclockwise order; a negative      */
+/*                       value if they occur in clockwise order; and zero    */
+/*                       if they are collinear.  The result is also a rough  */
+/*                       approximation of twice the signed area of the       */
+/*                       triangle defined by the three points.               */
+/*                                                                           */
+/*  Uses exact arithmetic if necessary to ensure a correct answer.  The      */
+/*  result returned is the determinant of a matrix.  This determinant is     */
+/*  computed adaptively, in the sense that exact arithmetic is used only to  */
+/*  the degree it is needed to ensure that the returned value has the        */
+/*  correct sign.  Hence, this function is usually quite fast, but will run  */
+/*  more slowly when the input points are collinear or nearly so.            */
+/*                                                                           */
+/*  See my Robust Predicates paper for details.                              */
+/*                                                                           */
+/*****************************************************************************/
+
+#define dDIST2D(a, b) sqrt((a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]))
+
+REAL mesh2d::counterclockwise(point pa, point pb, point pc)
+{
+  counterclockcount++;
+  if (noexact) {
+    REAL xa = pa[0], ya = pa[1];
+    REAL xb = pb[0], yb = pb[1];
+    REAL xc = pc[0], yc = pc[1];
+
+    // Currently no exact arithmetic
+    REAL dDet = ((xb - xa) * (yc - ya) - (xc - xa) * (yb - ya));
+    // Scale the determinant by the mean of the magnitudes of vectors:
+    REAL dScale = (dDIST2D (pa, pb)
+                   + dDIST2D (pb, pc)
+		               + dDIST2D (pc, pa)) / 3;
+    REAL dScaleDet = dDet / (dScale * dScale);
+    if (fabs(dScaleDet) <= 1.e-10) {
+      dDet = 0.;
+    }
+    return dDet;
+  } else {
+    REAL dDet = orient2d(pa, pb, pc);
+    return dDet;
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  incircle()   Return a positive value if the point pd lies inside the     */
+/*               circle passing through pa, pb, and pc; a negative value if  */
+/*               it lies outside; and zero if the four points are cocircular.*/
+/*               The points pa, pb, and pc must be in counterclockwise       */
+/*               order, or the sign of the result will be reversed.          */
+/*                                                                           */
+/*  Uses exact arithmetic if necessary to ensure a correct answer.  The      */
+/*  result returned is the determinant of a matrix.  This determinant is     */
+/*  computed adaptively, in the sense that exact arithmetic is used only to  */
+/*  the degree it is needed to ensure that the returned value has the        */
+/*  correct sign.  Hence, this function is usually quite fast, but will run  */
+/*  more slowly when the input points are cocircular or nearly so.           */
+/*                                                                           */
+/*  See my Robust Predicates paper for details.                              */
+/*                                                                           */
+/*****************************************************************************/
+
+REAL mesh2d::iincircle(point pa, point pb, point pc, point pd)
+{
+  incirclecount++;
+  return incircle(pa, pb, pc, pd);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  randomnation()   Generate a random number between 0 and `choices' - 1.   */
+/*                                                                           */
+/*  This is a simple linear congruential random number generator.  Hence, it */
+/*  is a bad random number generator, but good enough for most randomized    */
+/*  geometric algorithms.                                                    */
+/*                                                                           */
+/*****************************************************************************/
+
+unsigned long mesh2d::randomnation(unsigned int choices)
+{
+  randomseed = (randomseed * 1366l + 150889l) % 714025l;
+  return randomseed / (714025l / choices + 1);
+}
+
+/********* Point location routines begin here                        *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  makepointmap()   Construct a mapping from points to triangles to improve  */
+/*                  the speed of point location for segment insertion.       */
+/*                                                                           */
+/*  Traverses all the triangles, and provides each corner of each triangle   */
+/*  with a pointer to that triangle.  Of course, pointers will be            */
+/*  overwritten by other pointers because (almost) each point is a corner    */
+/*  of several triangles, but in the end every point will point to some      */
+/*  triangle that contains it.                                               */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::makepointmap()
+{
+  struct triedge triangleloop;
+  point triorg;
+
+  if (verbose) {
+    printf("    Constructing mapping from points to triangles.\n");
+  }
+  triangles.traversalinit();
+  triangleloop.tri = triangletraverse();
+  while (triangleloop.tri != (triangle *) NULL) {
+    /* Check all three points of the triangle. */
+    for (triangleloop.orient = 0; triangleloop.orient < 3;
+         triangleloop.orient++) {
+      org(triangleloop, triorg);
+      setpoint2tri(triorg, encode(triangleloop));
+    }
+    triangleloop.tri = triangletraverse();
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  preciselocate()   Find a triangle or edge containing a given point.      */
+/*                                                                           */
+/*  Begins its search from `searchtri'.  It is important that `searchtri'    */
+/*  be a handle with the property that `searchpoint' is strictly to the left */
+/*  of the edge denoted by `searchtri', or is collinear with that edge and   */
+/*  does not intersect that edge.  (In particular, `searchpoint' should not  */
+/*  be the origin or destination of that edge.)                              */
+/*                                                                           */
+/*  These conditions are imposed because preciselocate() is normally used in */
+/*  one of two situations:                                                   */
+/*                                                                           */
+/*  (1)  To try to find the location to insert a new point.  Normally, we    */
+/*       know an edge that the point is strictly to the left of.  In the     */
+/*       incremental Delaunay algorithm, that edge is a bounding box edge.   */
+/*       In Ruppert's Delaunay refinement algorithm for quality meshing,     */
+/*       that edge is the shortest edge of the triangle whose circumcenter   */
+/*       is being inserted.                                                  */
+/*                                                                           */
+/*  (2)  To try to find an existing point.  In this case, any edge on the    */
+/*       convex hull is a good starting edge.  The possibility that the      */
+/*       vertex one seeks is an endpoint of the starting edge must be        */
+/*       screened out before preciselocate() is called.                      */
+/*                                                                           */
+/*  On completion, `searchtri' is a triangle that contains `searchpoint'.    */
+/*                                                                           */
+/*  This implementation differs from that given by Guibas and Stolfi.  It    */
+/*  walks from triangle to triangle, crossing an edge only if `searchpoint'  */
+/*  is on the other side of the line containing that edge.  After entering   */
+/*  a triangle, there are two edges by which one can leave that triangle.    */
+/*  If both edges are valid (`searchpoint' is on the other side of both      */
+/*  edges), one of the two is chosen by drawing a line perpendicular to      */
+/*  the entry edge (whose endpoints are `forg' and `fdest') passing through  */
+/*  `fapex'.  Depending on which side of this perpendicular `searchpoint'    */
+/*  falls on, an exit edge is chosen.                                        */
+/*                                                                           */
+/*  This implementation is empirically faster than the Guibas and Stolfi     */
+/*  point location routine (which I originally used), which tends to spiral  */
+/*  in toward its target.                                                    */
+/*                                                                           */
+/*  Returns ONVERTEX if the point lies on an existing vertex.  `searchtri'   */
+/*  is a handle whose origin is the existing vertex.                         */
+/*                                                                           */
+/*  Returns ONEDGE if the point lies on a mesh edge.  `searchtri' is a       */
+/*  handle whose primary edge is the edge on which the point lies.           */
+/*                                                                           */
+/*  Returns INTRIANGLE if the point lies strictly within a triangle.         */
+/*  `searchtri' is a handle on the triangle that contains the point.         */
+/*                                                                           */
+/*  Returns OUTSIDE if the point lies outside the mesh.  `searchtri' is a    */
+/*  handle whose primary edge the point is to the right of.  This might      */
+/*  occur when the circumcenter of a triangle falls just slightly outside    */
+/*  the mesh due to floating-point roundoff error.  It also occurs when      */
+/*  seeking a hole or region point that a foolish user has placed outside    */
+/*  the mesh.                                                                */
+/*                                                                           */
+/*  WARNING:  This routine is designed for convex triangulations, and will   */
+/*  not generally work after the holes and concavities have been carved.     */
+/*  However, it can still be used to find the circumcenter of a triangle, as */
+/*  long as the search is begun from the triangle in question.               */
+/*                                                                           */
+/*****************************************************************************/
+
+enum mesh2d::locateresult
+mesh2d::preciselocate(point searchpoint, struct triedge *searchtri)
+{
+  struct triedge backtracktri;
+  point forg, fdest, fapex;
+  point swappoint;
+  REAL orgorient, destorient;
+  int moveleft;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+  if (verbose > 2) {
+    printf("  Searching for point (%.12g, %.12g).\n",
+           searchpoint[0], searchpoint[1]);
+  }
+  /* Where are we? */
+  org(*searchtri, forg);
+  dest(*searchtri, fdest);
+  apex(*searchtri, fapex);
+  while (1) {
+    if (verbose > 2) {
+      printf("    At (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
+             forg[0], forg[1], fdest[0], fdest[1], fapex[0], fapex[1]);
+    }
+    /* Check whether the apex is the point we seek. */
+    if ((fapex[0] == searchpoint[0]) && (fapex[1] == searchpoint[1])) {
+      lprevself(*searchtri);
+      return ONVERTEX;
+    }
+    /* Does the point lie on the other side of the line defined by the */
+    /*   triangle edge opposite the triangle's destination?            */
+    destorient = counterclockwise(forg, fapex, searchpoint);
+    /* Does the point lie on the other side of the line defined by the */
+    /*   triangle edge opposite the triangle's origin?                 */
+    orgorient = counterclockwise(fapex, fdest, searchpoint);
+    if (destorient > 0.0) {
+      if (orgorient > 0.0) {
+        /* Move left if the inner product of (fapex - searchpoint) and  */
+        /*   (fdest - forg) is positive.  This is equivalent to drawing */
+        /*   a line perpendicular to the line (forg, fdest) passing     */
+        /*   through `fapex', and determining which side of this line   */
+        /*   `searchpoint' falls on.                                    */
+        moveleft = (fapex[0] - searchpoint[0]) * (fdest[0] - forg[0]) +
+                   (fapex[1] - searchpoint[1]) * (fdest[1] - forg[1]) > 0.0;
+      } else {
+        moveleft = 1;
+      }
+    } else {
+      if (orgorient > 0.0) {
+        moveleft = 0;
+      } else {
+        /* The point we seek must be on the boundary of or inside this */
+        /*   triangle.                                                 */
+        if (destorient == 0.0) {
+          lprevself(*searchtri);
+          return ONEDGE;
+        }
+        if (orgorient == 0.0) {
+          lnextself(*searchtri);
+          return ONEDGE;
+        }
+        return INTRIANGLE;
+      }
+    }
+
+    /* Move to another triangle.  Leave a trace `backtracktri' in case */
+    /*   floating-point roundoff or some such bogey causes us to walk  */
+    /*   off a boundary of the triangulation.  We can just bounce off  */
+    /*   the boundary as if it were an elastic band.                   */
+    if (moveleft) {
+      lprev(*searchtri, backtracktri);
+      fdest = fapex;
+    } else {
+      lnext(*searchtri, backtracktri);
+      forg = fapex;
+    }
+    sym(backtracktri, *searchtri);
+
+    /* Check for walking off the edge. */
+    if (searchtri->tri == dummytri) {
+      /* Turn around. */
+      triedgecopy(backtracktri, *searchtri);
+      swappoint = forg;
+      forg = fdest;
+      fdest = swappoint;
+      apex(*searchtri, fapex);
+      /* Check if the point really is beyond the triangulation boundary. */
+      destorient = counterclockwise(forg, fapex, searchpoint);
+      orgorient = counterclockwise(fapex, fdest, searchpoint);
+      if ((orgorient < 0.0) && (destorient < 0.0)) {
+        return OUTSIDE;
+      }
+    } else {
+      apex(*searchtri, fapex);
+    }
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  locate()   Find a triangle or edge containing a given point.             */
+/*                                                                           */
+/*  Searching begins from one of:  the input `searchtri', a recently         */
+/*  encountered triangle `recenttri', or from a triangle chosen from a       */
+/*  random sample.  The choice is made by determining which triangle's       */
+/*  origin is closest to the point we are searcing for.  Normally,           */
+/*  `searchtri' should be a handle on the convex hull of the triangulation.  */
+/*                                                                           */
+/*  Details on the random sampling method can be found in the Mucke, Saias,  */
+/*  and Zhu paper cited in the header of this code.                          */
+/*                                                                           */
+/*  On completion, `searchtri' is a triangle that contains `searchpoint'.    */
+/*                                                                           */
+/*  Returns ONVERTEX if the point lies on an existing vertex.  `searchtri'   */
+/*  is a handle whose origin is the existing vertex.                         */
+/*                                                                           */
+/*  Returns ONEDGE if the point lies on a mesh edge.  `searchtri' is a       */
+/*  handle whose primary edge is the edge on which the point lies.           */
+/*                                                                           */
+/*  Returns INTRIANGLE if the point lies strictly within a triangle.         */
+/*  `searchtri' is a handle on the triangle that contains the point.         */
+/*                                                                           */
+/*  Returns OUTSIDE if the point lies outside the mesh.  `searchtri' is a    */
+/*  handle whose primary edge the point is to the right of.  This might      */
+/*  occur when the circumcenter of a triangle falls just slightly outside    */
+/*  the mesh due to floating-point roundoff error.  It also occurs when      */
+/*  seeking a hole or region point that a foolish user has placed outside    */
+/*  the mesh.                                                                */
+/*                                                                           */
+/*  WARNING:  This routine is designed for convex triangulations, and will   */
+/*  not generally work after the holes and concavities have been carved.     */
+/*                                                                           */
+/*****************************************************************************/
+
+enum mesh2d::locateresult
+mesh2d::locate(point searchpoint, struct triedge *searchtri)
+{
+  void **sampleblock;
+  triangle *firsttri;
+  struct triedge sampletri;
+  point torg, tdest;
+  unsigned long alignptr;
+  REAL searchdist, dist;
+  REAL ahead;
+  long sampleblocks, samplesperblock, samplenum;
+  long triblocks;
+  long i, j;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+  if (verbose > 2) {
+    printf("  Randomly sampling for a triangle near point (%.12g, %.12g).\n",
+           searchpoint[0], searchpoint[1]);
+  }
+  /* Record the distance from the suggested starting triangle to the */
+  /*   point we seek.                                                */
+  org(*searchtri, torg);
+  searchdist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0])
+             + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]);
+  if (verbose > 2) {
+    printf("    Boundary triangle has origin (%.12g, %.12g).\n",
+           torg[0], torg[1]);
+  }
+
+  /* If a recently encountered triangle has been recorded and has not been */
+  /*   deallocated, test it as a good starting point.                      */
+  if (recenttri.tri != (triangle *) NULL) {
+    if (recenttri.tri[3] != (triangle) NULL) {
+      org(recenttri, torg);
+      if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) {
+        triedgecopy(recenttri, *searchtri);
+        return ONVERTEX;
+      }
+      dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0])
+           + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]);
+      if (dist < searchdist) {
+        triedgecopy(recenttri, *searchtri);
+        searchdist = dist;
+        if (verbose > 2) {
+          printf("    Choosing recent triangle with origin (%.12g, %.12g).\n",
+                 torg[0], torg[1]);
+        }
+      }
+    }
+  }
+
+  /* The number of random samples taken is proportional to the cube root of */
+  /*   the number of triangles in the mesh.  The next bit of code assumes   */
+  /*   that the number of triangles increases monotonically.                */
+  while (SAMPLEFACTOR * samples * samples * samples < triangles.items) {
+    samples++;
+  }
+  triblocks = (triangles.maxitems + TRIPERBLOCK - 1) / TRIPERBLOCK;
+  samplesperblock = 1 + (samples / triblocks);
+  sampleblocks = samples / samplesperblock;
+  sampleblock = triangles.firstblock;
+  sampletri.orient = 0;
+  for (i = 0; i < sampleblocks; i++) {
+    alignptr = (unsigned long) (sampleblock + 1);
+    firsttri = (triangle *) (alignptr + (unsigned long) triangles.alignbytes
+                          - (alignptr % (unsigned long) triangles.alignbytes));
+    for (j = 0; j < samplesperblock; j++) {
+      if (i == triblocks - 1) {
+        samplenum = randomnation((int)
+                                 (triangles.maxitems - (i * TRIPERBLOCK)));
+      } else {
+        samplenum = randomnation(TRIPERBLOCK);
+      }
+      sampletri.tri = (triangle *)
+                      (firsttri + (samplenum * triangles.itemwords));
+      if (sampletri.tri[3] != (triangle) NULL) {
+        org(sampletri, torg);
+        dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0])
+             + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]);
+        if (dist < searchdist) {
+          triedgecopy(sampletri, *searchtri);
+          searchdist = dist;
+          if (verbose > 2) {
+            printf("    Choosing triangle with origin (%.12g, %.12g).\n",
+                   torg[0], torg[1]);
+          }
+        }
+      }
+    }
+    sampleblock = (void **) *sampleblock;
+  }
+  /* Where are we? */
+  org(*searchtri, torg);
+  dest(*searchtri, tdest);
+  /* Check the starting triangle's vertices. */
+  if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) {
+    return ONVERTEX;
+  }
+  if ((tdest[0] == searchpoint[0]) && (tdest[1] == searchpoint[1])) {
+    lnextself(*searchtri);
+    return ONVERTEX;
+  }
+  /* Orient `searchtri' to fit the preconditions of calling preciselocate(). */
+  ahead = counterclockwise(torg, tdest, searchpoint);
+  if (ahead < 0.0) {
+    /* Turn around so that `searchpoint' is to the left of the */
+    /*   edge specified by `searchtri'.                        */
+    symself(*searchtri);
+  } else if (ahead == 0.0) {
+    /* Check if `searchpoint' is between `torg' and `tdest'. */
+    if (((torg[0] < searchpoint[0]) == (searchpoint[0] < tdest[0]))
+        && ((torg[1] < searchpoint[1]) == (searchpoint[1] < tdest[1]))) {
+      return ONEDGE;
+    }
+  }
+  return preciselocate(searchpoint, searchtri);
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Point location routines end here                          *********/
+
+/********* Mesh transformation routines begin here                   *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  insertshelle()   Create a new shell edge and insert it between two       */
+/*                   triangles.                                              */
+/*                                                                           */
+/*  The new shell edge is inserted at the edge described by the handle       */
+/*  `tri'.  Its vertices are properly initialized.  The marker `shellemark'  */
+/*  is applied to the shell edge and, if appropriate, its vertices.          */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::insertshelle(struct triedge *tri, int shellemark)
+{
+  struct triedge oppotri;
+  struct edge newshelle;
+  point triorg, tridest;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  shelle sptr;                      /* Temporary variable used by tspivot(). */
+
+  /* Mark points if possible. */
+  org(*tri, triorg);
+  dest(*tri, tridest);
+  if (pointmark(triorg) == 0) {
+    setpointmark(triorg, shellemark);
+  }
+  if (pointmark(tridest) == 0) {
+    setpointmark(tridest, shellemark);
+  }
+  /* Check if there's already a shell edge here. */
+  tspivot(*tri, newshelle);
+  if (newshelle.sh == dummysh) {
+    /* Make new shell edge and initialize its vertices. */
+    makeshelle(&newshelle);
+    setsorg(newshelle, tridest);
+    setsdest(newshelle, triorg);
+    /* Bond new shell edge to the two triangles it is sandwiched between. */
+    /*   Note that the facing triangle `oppotri' might be equal to        */
+    /*   `dummytri' (outer space), but the new shell edge is bonded to it */
+    /*   all the same.                                                    */
+    tsbond(*tri, newshelle);
+    sym(*tri, oppotri);
+    ssymself(newshelle);
+    tsbond(oppotri, newshelle);
+    setmark(newshelle, shellemark);
+    if (verbose > 2) {
+      printf("  Inserting new ");
+      printshelle(&newshelle);
+    }
+  } else {
+    if (mark(newshelle) == 0) {
+      setmark(newshelle, shellemark);
+    }
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  Terminology                                                              */
+/*                                                                           */
+/*  A "local transformation" replaces a small set of triangles with another  */
+/*  set of triangles.  This may or may not involve inserting or deleting a   */
+/*  point.                                                                   */
+/*                                                                           */
+/*  The term "casing" is used to describe the set of triangles that are      */
+/*  attached to the triangles being transformed, but are not transformed     */
+/*  themselves.  Think of the casing as a fixed hollow structure inside      */
+/*  which all the action happens.  A "casing" is only defined relative to    */
+/*  a single transformation; each occurrence of a transformation will        */
+/*  involve a different casing.                                              */
+/*                                                                           */
+/*  A "shell" is similar to a "casing".  The term "shell" describes the set  */
+/*  of shell edges (if any) that are attached to the triangles being         */
+/*  transformed.  However, I sometimes use "shell" to refer to a single      */
+/*  shell edge, so don't get confused.                                       */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  flip()   Transform two triangles to two different triangles by flipping  */
+/*           an edge within a quadrilateral.                                 */
+/*                                                                           */
+/*  Imagine the original triangles, abc and bad, oriented so that the        */
+/*  shared edge ab lies in a horizontal plane, with the point b on the left  */
+/*  and the point a on the right.  The point c lies below the edge, and the  */
+/*  point d lies above the edge.  The `flipedge' handle holds the edge ab    */
+/*  of triangle abc, and is directed left, from vertex a to vertex b.        */
+/*                                                                           */
+/*  The triangles abc and bad are deleted and replaced by the triangles cdb  */
+/*  and dca.  The triangles that represent abc and bad are NOT deallocated;  */
+/*  they are reused for dca and cdb, respectively.  Hence, any handles that  */
+/*  may have held the original triangles are still valid, although not       */
+/*  directed as they were before.                                            */
+/*                                                                           */
+/*  Upon completion of this routine, the `flipedge' handle holds the edge    */
+/*  dc of triangle dca, and is directed down, from vertex d to vertex c.     */
+/*  (Hence, the two triangles have rotated counterclockwise.)                */
+/*                                                                           */
+/*  WARNING:  This transformation is geometrically valid only if the         */
+/*  quadrilateral adbc is convex.  Furthermore, this transformation is       */
+/*  valid only if there is not a shell edge between the triangles abc and    */
+/*  bad.  This routine does not check either of these preconditions, and     */
+/*  it is the responsibility of the calling routine to ensure that they are  */
+/*  met.  If they are not, the streets shall be filled with wailing and      */
+/*  gnashing of teeth.                                                       */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::flip(struct triedge *flipedge)
+{
+  struct triedge botleft, botright;
+  struct triedge topleft, topright;
+  struct triedge top;
+  struct triedge botlcasing, botrcasing;
+  struct triedge toplcasing, toprcasing;
+  struct edge botlshelle, botrshelle;
+  struct edge toplshelle, toprshelle;
+  point leftpoint, rightpoint, botpoint;
+  point farpoint;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  shelle sptr;                      /* Temporary variable used by tspivot(). */
+
+  /* Identify the vertices of the quadrilateral. */
+  org(*flipedge, rightpoint);
+  dest(*flipedge, leftpoint);
+  apex(*flipedge, botpoint);
+  sym(*flipedge, top);
+#ifdef SELF_CHECK
+  if (top.tri == dummytri) {
+    printf("Internal error in flip():  Attempt to flip on boundary.\n");
+    lnextself(*flipedge);
+    return;
+  }
+  if (checksegments) {
+    tspivot(*flipedge, toplshelle);
+    if (toplshelle.sh != dummysh) {
+      printf("Internal error in flip():  Attempt to flip a segment.\n");
+      lnextself(*flipedge);
+      return;
+    }
+  }
+#endif /* SELF_CHECK */
+  apex(top, farpoint);
+
+  /* Identify the casing of the quadrilateral. */
+  lprev(top, topleft);
+  sym(topleft, toplcasing);
+  lnext(top, topright);
+  sym(topright, toprcasing);
+  lnext(*flipedge, botleft);
+  sym(botleft, botlcasing);
+  lprev(*flipedge, botright);
+  sym(botright, botrcasing);
+  /* Rotate the quadrilateral one-quarter turn counterclockwise. */
+  bond(topleft, botlcasing);
+  bond(botleft, botrcasing);
+  bond(botright, toprcasing);
+  bond(topright, toplcasing);
+
+  if (checksegments) {
+    /* Check for shell edges and rebond them to the quadrilateral. */
+    tspivot(topleft, toplshelle);
+    tspivot(botleft, botlshelle);
+    tspivot(botright, botrshelle);
+    tspivot(topright, toprshelle);
+    if (toplshelle.sh == dummysh) {
+      tsdissolve(topright);
+    } else {
+      tsbond(topright, toplshelle);
+    }
+    if (botlshelle.sh == dummysh) {
+      tsdissolve(topleft);
+    } else {
+      tsbond(topleft, botlshelle);
+    }
+    if (botrshelle.sh == dummysh) {
+      tsdissolve(botleft);
+    } else {
+      tsbond(botleft, botrshelle);
+    }
+    if (toprshelle.sh == dummysh) {
+      tsdissolve(botright);
+    } else {
+      tsbond(botright, toprshelle);
+    }
+  }
+
+  /* New point assignments for the rotated quadrilateral. */
+  setorg(*flipedge, farpoint);
+  setdest(*flipedge, botpoint);
+  setapex(*flipedge, rightpoint);
+  setorg(top, botpoint);
+  setdest(top, farpoint);
+  setapex(top, leftpoint);
+  if (verbose > 2) {
+    printf("  Edge flip results in left ");
+    lnextself(topleft);
+    printtriangle(&topleft);
+    printf("  and right ");
+    printtriangle(flipedge);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  insertsite()   Insert a vertex into a Delaunay triangulation,            */
+/*                 performing flips as necessary to maintain the Delaunay    */
+/*                 property.                                                 */
+/*                                                                           */
+/*  The point `insertpoint' is located.  If `searchtri.tri' is not NULL,     */
+/*  the search for the containing triangle begins from `searchtri'.  If      */
+/*  `searchtri.tri' is NULL, a full point location procedure is called.      */
+/*  If `insertpoint' is found inside a triangle, the triangle is split into  */
+/*  three; if `insertpoint' lies on an edge, the edge is split in two,       */
+/*  thereby splitting the two adjacent triangles into four.  Edge flips are  */
+/*  used to restore the Delaunay property.  If `insertpoint' lies on an      */
+/*  existing vertex, no action is taken, and the value DUPLICATEPOINT is     */
+/*  returned.  On return, `searchtri' is set to a handle whose origin is the */
+/*  existing vertex.                                                         */
+/*                                                                           */
+/*  Normally, the parameter `splitedge' is set to NULL, implying that no     */
+/*  segment should be split.  In this case, if `insertpoint' is found to     */
+/*  lie on a segment, no action is taken, and the value VIOLATINGPOINT is    */
+/*  returned.  On return, `searchtri' is set to a handle whose primary edge  */
+/*  is the violated segment.                                                 */
+/*                                                                           */
+/*  If the calling routine wishes to split a segment by inserting a point in */
+/*  it, the parameter `splitedge' should be that segment.  In this case,     */
+/*  `searchtri' MUST be the triangle handle reached by pivoting from that    */
+/*  segment; no point location is done.                                      */
+/*                                                                           */
+/*  `segmentflaws' and `triflaws' are flags that indicate whether or not     */
+/*  there should be checks for the creation of encroached segments or bad    */
+/*  quality faces.  If a newly inserted point encroaches upon segments,      */
+/*  these segments are added to the list of segments to be split if          */
+/*  `segmentflaws' is set.  If bad triangles are created, these are added    */
+/*  to the queue if `triflaws' is set.                                       */
+/*                                                                           */
+/*  If a duplicate point or violated segment does not prevent the point      */
+/*  from being inserted, the return value will be ENCROACHINGPOINT if the    */
+/*  point encroaches upon a segment (and checking is enabled), or            */
+/*  SUCCESSFULPOINT otherwise.  In either case, `searchtri' is set to a      */
+/*  handle whose origin is the newly inserted vertex.                        */
+/*                                                                           */
+/*  insertsite() does not use flip() for reasons of speed; some              */
+/*  information can be reused from edge flip to edge flip, like the          */
+/*  locations of shell edges.                                                */
+/*                                                                           */
+/*****************************************************************************/
+
+enum mesh2d::insertsiteresult
+mesh2d::insertsite(point insertpoint, struct triedge *searchtri,
+                   struct edge *splitedge, int segmentflaws, int triflaws)
+{
+  struct triedge horiz;
+  struct triedge top;
+  struct triedge botleft, botright;
+  struct triedge topleft, topright;
+  struct triedge newbotleft, newbotright;
+  struct triedge newtopright;
+  struct triedge botlcasing, botrcasing;
+  struct triedge toplcasing, toprcasing;
+  struct triedge testtri;
+  struct edge botlshelle, botrshelle;
+  struct edge toplshelle, toprshelle;
+  struct edge brokenshelle;
+  struct edge checkshelle;
+  struct edge rightedge;
+  struct edge newedge;
+  struct edge *encroached;
+  point first;
+  point leftpoint, rightpoint, botpoint, toppoint, farpoint;
+  REAL attrib;
+  REAL area;
+  enum insertsiteresult success;
+  enum locateresult intersect;
+  int doflip;
+  int mirrorflag;
+  int i;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  shelle sptr;         /* Temporary variable used by spivot() and tspivot(). */
+
+  if (verbose > 1) {
+    printf("  Inserting (%.12g, %.12g).\n", insertpoint[0], insertpoint[1]);
+  }
+  if (splitedge == (struct edge *) NULL) {
+    /* Find the location of the point to be inserted.  Check if a good */
+    /*   starting triangle has already been provided by the caller.    */
+    if (searchtri->tri == (triangle *) NULL) {
+      /* Find a boundary triangle. */
+      horiz.tri = dummytri;
+      horiz.orient = 0;
+      symself(horiz);
+      /* Search for a triangle containing `insertpoint'. */
+      intersect = locate(insertpoint, &horiz);
+    } else {
+      /* Start searching from the triangle provided by the caller. */
+      triedgecopy(*searchtri, horiz);
+      intersect = preciselocate(insertpoint, &horiz);
+    }
+  } else {
+    /* The calling routine provides the edge in which the point is inserted. */
+    triedgecopy(*searchtri, horiz);
+    intersect = ONEDGE;
+  }
+  if (intersect == ONVERTEX) {
+    /* There's already a vertex there.  Return in `searchtri' a triangle */
+    /*   whose origin is the existing vertex.                            */
+    triedgecopy(horiz, *searchtri);
+    triedgecopy(horiz, recenttri);
+    return DUPLICATEPOINT;
+  }
+  if ((intersect == ONEDGE) || (intersect == OUTSIDE)) {
+    /* The vertex falls on an edge or boundary. */
+    if (checksegments && (splitedge == (struct edge *) NULL)) {
+      /* Check whether the vertex falls on a shell edge. */
+      tspivot(horiz, brokenshelle);
+      if (brokenshelle.sh != dummysh) {
+        /* The vertex falls on a shell edge. */
+        /* Return a handle whose primary edge contains the point, */
+        /*   which has not been inserted.                         */
+        triedgecopy(horiz, *searchtri);
+        triedgecopy(horiz, recenttri);
+        return VIOLATINGPOINT;
+      }
+    }
+    /* Insert the point on an edge, dividing one triangle into two (if */
+    /*   the edge lies on a boundary) or two triangles into four.      */
+    lprev(horiz, botright);
+    sym(botright, botrcasing);
+    sym(horiz, topright);
+    /* Is there a second triangle?  (Or does this edge lie on a boundary?) */
+    mirrorflag = topright.tri != dummytri;
+    if (mirrorflag) {
+      lnextself(topright);
+      sym(topright, toprcasing);
+      maketriangle(&newtopright);
+    } else {
+      /* Splitting the boundary edge increases the number of boundary edges. */
+      hullsize++;
+    }
+    maketriangle(&newbotright);
+
+    /* Set the vertices of changed and new triangles. */
+    org(horiz, rightpoint);
+    dest(horiz, leftpoint);
+    apex(horiz, botpoint);
+    setorg(newbotright, botpoint);
+    setdest(newbotright, rightpoint);
+    setapex(newbotright, insertpoint);
+    setorg(horiz, insertpoint);
+    for (i = 0; i < eextras; i++) {
+      /* Set the element attributes of a new triangle. */
+      setelemattribute(newbotright, i, elemattribute(botright, i));
+    }
+    if (vararea) {
+      /* Set the area constraint of a new triangle. */
+      setareabound(newbotright, areabound(botright));
+    }
+    if (mirrorflag) {
+      dest(topright, toppoint);
+      setorg(newtopright, rightpoint);
+      setdest(newtopright, toppoint);
+      setapex(newtopright, insertpoint);
+      setorg(topright, insertpoint);
+      for (i = 0; i < eextras; i++) {
+        /* Set the element attributes of another new triangle. */
+        setelemattribute(newtopright, i, elemattribute(topright, i));
+      }
+      if (vararea) {
+        /* Set the area constraint of another new triangle. */
+        setareabound(newtopright, areabound(topright));
+      }
+    }
+
+    /* There may be shell edges that need to be bonded */
+    /*   to the new triangle(s).                       */
+    if (checksegments) {
+      tspivot(botright, botrshelle);
+      if (botrshelle.sh != dummysh) {
+        tsdissolve(botright);
+        tsbond(newbotright, botrshelle);
+      }
+      if (mirrorflag) {
+        tspivot(topright, toprshelle);
+        if (toprshelle.sh != dummysh) {
+          tsdissolve(topright);
+          tsbond(newtopright, toprshelle);
+        }
+      }
+    }
+
+    /* Bond the new triangle(s) to the surrounding triangles. */
+    bond(newbotright, botrcasing);
+    lprevself(newbotright);
+    bond(newbotright, botright);
+    lprevself(newbotright);
+    if (mirrorflag) {
+      bond(newtopright, toprcasing);
+      lnextself(newtopright);
+      bond(newtopright, topright);
+      lnextself(newtopright);
+      bond(newtopright, newbotright);
+    }
+
+    if (splitedge != (struct edge *) NULL) {
+      /* Split the shell edge into two. */
+      setsdest(*splitedge, insertpoint);
+      ssymself(*splitedge);
+      spivot(*splitedge, rightedge);
+      insertshelle(&newbotright, mark(*splitedge));
+      tspivot(newbotright, newedge);
+      sbond(*splitedge, newedge);
+      ssymself(newedge);
+      sbond(newedge, rightedge);
+      ssymself(*splitedge);
+    }
+
+#ifdef SELF_CHECK
+    if (counterclockwise(rightpoint, leftpoint, botpoint) < 0.0) {
+      printf("Internal error in insertsite():\n");
+      printf("  Clockwise triangle prior to edge point insertion (bottom).\n");
+    }
+    if (mirrorflag) {
+      if (counterclockwise(leftpoint, rightpoint, toppoint) < 0.0) {
+        printf("Internal error in insertsite():\n");
+        printf("  Clockwise triangle prior to edge point insertion (top).\n");
+      }
+      if (counterclockwise(rightpoint, toppoint, insertpoint) < 0.0) {
+        printf("Internal error in insertsite():\n");
+        printf("  Clockwise triangle after edge point insertion (top right).\n"
+               );
+      }
+      if (counterclockwise(toppoint, leftpoint, insertpoint) < 0.0) {
+        printf("Internal error in insertsite():\n");
+        printf("  Clockwise triangle after edge point insertion (top left).\n"
+               );
+      }
+    }
+    if (counterclockwise(leftpoint, botpoint, insertpoint) < 0.0) {
+      printf("Internal error in insertsite():\n");
+      printf("  Clockwise triangle after edge point insertion (bottom left).\n"
+             );
+    }
+    if (counterclockwise(botpoint, rightpoint, insertpoint) < 0.0) {
+      printf("Internal error in insertsite():\n");
+      printf(
+        "  Clockwise triangle after edge point insertion (bottom right).\n");
+    }
+#endif /* SELF_CHECK */
+    if (verbose > 2) {
+      printf("  Updating bottom left ");
+      printtriangle(&botright);
+      if (mirrorflag) {
+        printf("  Updating top left ");
+        printtriangle(&topright);
+        printf("  Creating top right ");
+        printtriangle(&newtopright);
+      }
+      printf("  Creating bottom right ");
+      printtriangle(&newbotright);
+    }
+
+    /* Position `horiz' on the first edge to check for */
+    /*   the Delaunay property.                        */
+    lnextself(horiz);
+  } else {
+    /* Insert the point in a triangle, splitting it into three. */
+    lnext(horiz, botleft);
+    lprev(horiz, botright);
+    sym(botleft, botlcasing);
+    sym(botright, botrcasing);
+    maketriangle(&newbotleft);
+    maketriangle(&newbotright);
+
+    /* Set the vertices of changed and new triangles. */
+    org(horiz, rightpoint);
+    dest(horiz, leftpoint);
+    apex(horiz, botpoint);
+    setorg(newbotleft, leftpoint);
+    setdest(newbotleft, botpoint);
+    setapex(newbotleft, insertpoint);
+    setorg(newbotright, botpoint);
+    setdest(newbotright, rightpoint);
+    setapex(newbotright, insertpoint);
+    setapex(horiz, insertpoint);
+    for (i = 0; i < eextras; i++) {
+      /* Set the element attributes of the new triangles. */
+      attrib = elemattribute(horiz, i);
+      setelemattribute(newbotleft, i, attrib);
+      setelemattribute(newbotright, i, attrib);
+    }
+    if (vararea) {
+      /* Set the area constraint of the new triangles. */
+      area = areabound(horiz);
+      setareabound(newbotleft, area);
+      setareabound(newbotright, area);
+    }
+
+    /* There may be shell edges that need to be bonded */
+    /*   to the new triangles.                         */
+    if (checksegments) {
+      tspivot(botleft, botlshelle);
+      if (botlshelle.sh != dummysh) {
+        tsdissolve(botleft);
+        tsbond(newbotleft, botlshelle);
+      }
+      tspivot(botright, botrshelle);
+      if (botrshelle.sh != dummysh) {
+        tsdissolve(botright);
+        tsbond(newbotright, botrshelle);
+      }
+    }
+
+    /* Bond the new triangles to the surrounding triangles. */
+    bond(newbotleft, botlcasing);
+    bond(newbotright, botrcasing);
+    lnextself(newbotleft);
+    lprevself(newbotright);
+    bond(newbotleft, newbotright);
+    lnextself(newbotleft);
+    bond(botleft, newbotleft);
+    lprevself(newbotright);
+    bond(botright, newbotright);
+
+#ifdef SELF_CHECK
+    if (counterclockwise(rightpoint, leftpoint, botpoint) < 0.0) {
+      printf("Internal error in insertsite():\n");
+      printf("  Clockwise triangle prior to point insertion.\n");
+    }
+    if (counterclockwise(rightpoint, leftpoint, insertpoint) < 0.0) {
+      printf("Internal error in insertsite():\n");
+      printf("  Clockwise triangle after point insertion (top).\n");
+    }
+    if (counterclockwise(leftpoint, botpoint, insertpoint) < 0.0) {
+      printf("Internal error in insertsite():\n");
+      printf("  Clockwise triangle after point insertion (left).\n");
+    }
+    if (counterclockwise(botpoint, rightpoint, insertpoint) < 0.0) {
+      printf("Internal error in insertsite():\n");
+      printf("  Clockwise triangle after point insertion (right).\n");
+    }
+#endif /* SELF_CHECK */
+    if (verbose > 2) {
+      printf("  Updating top ");
+      printtriangle(&horiz);
+      printf("  Creating left ");
+      printtriangle(&newbotleft);
+      printf("  Creating right ");
+      printtriangle(&newbotright);
+    }
+  }
+
+  /* The insertion is successful by default, unless an encroached */
+  /*   edge is found.                                             */
+  success = SUCCESSFULPOINT;
+  /* Circle around the newly inserted vertex, checking each edge opposite */
+  /*   it for the Delaunay property.  Non-Delaunay edges are flipped.     */
+  /*   `horiz' is always the edge being checked.  `first' marks where to  */
+  /*   stop circling.                                                     */
+  org(horiz, first);
+  rightpoint = first;
+  dest(horiz, leftpoint);
+  /* Circle until finished. */
+  while (1) {
+    /* By default, the edge will be flipped. */
+    doflip = 1;
+    if (checksegments) {
+      /* Check for a segment, which cannot be flipped. */
+      tspivot(horiz, checkshelle);
+      if (checkshelle.sh != dummysh) {
+        /* The edge is a segment and cannot be flipped. */
+        doflip = 0;
+      }
+    }
+    if (doflip) {
+      /* Check if the edge is a boundary edge. */
+      sym(horiz, top);
+      if (top.tri == dummytri) {
+        /* The edge is a boundary edge and cannot be flipped. */
+        doflip = 0;
+      } else {
+        /* Find the point on the other side of the edge. */
+        apex(top, farpoint);
+        /* In the incremental Delaunay triangulation algorithm, any of    */
+        /*   `leftpoint', `rightpoint', and `farpoint' could be vertices  */
+        /*   of the triangular bounding box.  These vertices must be      */
+        /*   treated as if they are infinitely distant, even though their */
+        /*   "coordinates" are not.                                       */
+        if ((leftpoint == infpoint1) || (leftpoint == infpoint2)
+                   || (leftpoint == infpoint3)) {
+          /* `leftpoint' is infinitely distant.  Check the convexity of */
+          /*   the boundary of the triangulation.  'farpoint' might be  */
+          /*   infinite as well, but trust me, this same condition      */
+          /*   should be applied.                                       */
+          doflip = counterclockwise(insertpoint, rightpoint, farpoint) > 0.0;
+        } else if ((rightpoint == infpoint1) || (rightpoint == infpoint2)
+                   || (rightpoint == infpoint3)) {
+          /* `rightpoint' is infinitely distant.  Check the convexity of */
+          /*   the boundary of the triangulation.  'farpoint' might be  */
+          /*   infinite as well, but trust me, this same condition      */
+          /*   should be applied.                                       */
+          doflip = counterclockwise(farpoint, leftpoint, insertpoint) > 0.0;
+        } else if ((farpoint == infpoint1) || (farpoint == infpoint2)
+            || (farpoint == infpoint3)) {
+          /* `farpoint' is infinitely distant and cannot be inside */
+          /*   the circumcircle of the triangle `horiz'.           */
+          doflip = 0;
+        } else {
+          /* Test whether the edge is locally Delaunay. */
+          doflip = iincircle(leftpoint, insertpoint, rightpoint, farpoint)
+                   > 0.0;
+        }
+        if (doflip) {
+          /* We made it!  Flip the edge `horiz' by rotating its containing */
+          /*   quadrilateral (the two triangles adjacent to `horiz').      */
+          /* Identify the casing of the quadrilateral. */
+          lprev(top, topleft);
+          sym(topleft, toplcasing);
+          lnext(top, topright);
+          sym(topright, toprcasing);
+          lnext(horiz, botleft);
+          sym(botleft, botlcasing);
+          lprev(horiz, botright);
+          sym(botright, botrcasing);
+          /* Rotate the quadrilateral one-quarter turn counterclockwise. */
+          bond(topleft, botlcasing);
+          bond(botleft, botrcasing);
+          bond(botright, toprcasing);
+          bond(topright, toplcasing);
+          if (checksegments) {
+            /* Check for shell edges and rebond them to the quadrilateral. */
+            tspivot(topleft, toplshelle);
+            tspivot(botleft, botlshelle);
+            tspivot(botright, botrshelle);
+            tspivot(topright, toprshelle);
+            if (toplshelle.sh == dummysh) {
+              tsdissolve(topright);
+            } else {
+              tsbond(topright, toplshelle);
+            }
+            if (botlshelle.sh == dummysh) {
+              tsdissolve(topleft);
+            } else {
+              tsbond(topleft, botlshelle);
+            }
+            if (botrshelle.sh == dummysh) {
+              tsdissolve(botleft);
+            } else {
+              tsbond(botleft, botrshelle);
+            }
+            if (toprshelle.sh == dummysh) {
+              tsdissolve(botright);
+            } else {
+              tsbond(botright, toprshelle);
+            }
+          }
+          /* New point assignments for the rotated quadrilateral. */
+          setorg(horiz, farpoint);
+          setdest(horiz, insertpoint);
+          setapex(horiz, rightpoint);
+          setorg(top, insertpoint);
+          setdest(top, farpoint);
+          setapex(top, leftpoint);
+          for (i = 0; i < eextras; i++) {
+            /* Take the average of the two triangles' attributes. */
+            attrib = 0.5 * (elemattribute(top, i) + elemattribute(horiz, i));
+            setelemattribute(top, i, attrib);
+            setelemattribute(horiz, i, attrib);
+          }
+          if (vararea) {
+            if ((areabound(top) <= 0.0) || (areabound(horiz) <= 0.0)) {
+              area = -1.0;
+            } else {
+              /* Take the average of the two triangles' area constraints.    */
+              /*   This prevents small area constraints from migrating a     */
+              /*   long, long way from their original location due to flips. */
+              area = 0.5 * (areabound(top) + areabound(horiz));
+            }
+            setareabound(top, area);
+            setareabound(horiz, area);
+          }
+#ifdef SELF_CHECK
+          if (insertpoint != (point) NULL) {
+            if (counterclockwise(leftpoint, insertpoint, rightpoint) < 0.0) {
+              printf("Internal error in insertsite():\n");
+              printf("  Clockwise triangle prior to edge flip (bottom).\n");
+            }
+            /* The following test has been removed because constrainededge() */
+            /*   sometimes generates inverted triangles that insertsite()    */
+            /*   removes.                                                    */
+/*
+            if (counterclockwise(rightpoint, farpoint, leftpoint) < 0.0) {
+              printf("Internal error in insertsite():\n");
+              printf("  Clockwise triangle prior to edge flip (top).\n");
+            }
+*/
+            if (counterclockwise(farpoint, leftpoint, insertpoint) < 0.0) {
+              printf("Internal error in insertsite():\n");
+              printf("  Clockwise triangle after edge flip (left).\n");
+            }
+            if (counterclockwise(insertpoint, rightpoint, farpoint) < 0.0) {
+              printf("Internal error in insertsite():\n");
+              printf("  Clockwise triangle after edge flip (right).\n");
+            }
+          }
+#endif /* SELF_CHECK */
+          if (verbose > 2) {
+            printf("  Edge flip results in left ");
+            lnextself(topleft);
+            printtriangle(&topleft);
+            printf("  and right ");
+            printtriangle(&horiz);
+          }
+          /* On the next iterations, consider the two edges that were  */
+          /*   exposed (this is, are now visible to the newly inserted */
+          /*   point) by the edge flip.                                */
+          lprevself(horiz);
+          leftpoint = farpoint;
+        }
+      }
+    }
+    if (!doflip) {
+      /* The handle `horiz' is accepted as locally Delaunay. */
+      /* Look for the next edge around the newly inserted point. */
+      lnextself(horiz);
+      sym(horiz, testtri);
+      /* Check for finishing a complete revolution about the new point, or */
+      /*   falling off the edge of the triangulation.  The latter will     */
+      /*   happen when a point is inserted at a boundary.                  */
+      if ((leftpoint == first) || (testtri.tri == dummytri)) {
+        /* We're done.  Return a triangle whose origin is the new point. */
+        lnext(horiz, *searchtri);
+        lnext(horiz, recenttri);
+        return success;
+      }
+      /* Finish finding the next edge around the newly inserted point. */
+      lnext(testtri, horiz);
+      rightpoint = leftpoint;
+      dest(horiz, leftpoint);
+    }
+  }
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Mesh transformation routines end here                     *********/
+
+/********* Divide-and-conquer Delaunay triangulation begins here     *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  The divide-and-conquer bounding box                                      */
+/*                                                                           */
+/*  I originally implemented the divide-and-conquer and incremental Delaunay */
+/*  triangulations using the edge-based data structure presented by Guibas   */
+/*  and Stolfi.  Switching to a triangle-based data structure doubled the    */
+/*  speed.  However, I had to think of a few extra tricks to maintain the    */
+/*  elegance of the original algorithms.                                     */
+/*                                                                           */
+/*  The "bounding box" used by my variant of the divide-and-conquer          */
+/*  algorithm uses one triangle for each edge of the convex hull of the      */
+/*  triangulation.  These bounding triangles all share a common apical       */
+/*  vertex, which is represented by NULL and which represents nothing.       */
+/*  The bounding triangles are linked in a circular fan about this NULL      */
+/*  vertex, and the edges on the convex hull of the triangulation appear     */
+/*  opposite the NULL vertex.  You might find it easiest to imagine that     */
+/*  the NULL vertex is a point in 3D space behind the center of the          */
+/*  triangulation, and that the bounding triangles form a sort of cone.      */
+/*                                                                           */
+/*  This bounding box makes it easy to represent degenerate cases.  For      */
+/*  instance, the triangulation of two vertices is a single edge.  This edge */
+/*  is represented by two bounding box triangles, one on each "side" of the  */
+/*  edge.  These triangles are also linked together in a fan about the NULL  */
+/*  vertex.                                                                  */
+/*                                                                           */
+/*  The bounding box also makes it easy to traverse the convex hull, as the  */
+/*  divide-and-conquer algorithm needs to do.                                */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  pointsort()   Sort an array of points by x-coordinate, using the         */
+/*                y-coordinate as a secondary key.                           */
+/*                                                                           */
+/*  Uses quicksort.  Randomized O(n log n) time.  No, I did not make any of  */
+/*  the usual quicksort mistakes.                                            */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::pointsort(point *sortarray, int arraysize)
+{
+  int left, right;
+  int pivot;
+  REAL pivotx, pivoty;
+  point temp;
+
+  if (arraysize == 2) {
+    /* Recursive base case. */
+    if ((sortarray[0][0] > sortarray[1][0]) ||
+        ((sortarray[0][0] == sortarray[1][0]) &&
+         (sortarray[0][1] > sortarray[1][1]))) {
+      temp = sortarray[1];
+      sortarray[1] = sortarray[0];
+      sortarray[0] = temp;
+    }
+    return;
+  }
+  /* Choose a random pivot to split the array. */
+  pivot = (int) randomnation(arraysize);
+  pivotx = sortarray[pivot][0];
+  pivoty = sortarray[pivot][1];
+  /* Split the array. */
+  left = -1;
+  right = arraysize;
+  while (left < right) {
+    /* Search for a point whose x-coordinate is too large for the left. */
+    do {
+      left++;
+    } while ((left <= right) && ((sortarray[left][0] < pivotx) ||
+                                 ((sortarray[left][0] == pivotx) &&
+                                  (sortarray[left][1] < pivoty))));
+    /* Search for a point whose x-coordinate is too small for the right. */
+    do {
+      right--;
+    } while ((left <= right) && ((sortarray[right][0] > pivotx) ||
+                                 ((sortarray[right][0] == pivotx) &&
+                                  (sortarray[right][1] > pivoty))));
+    if (left < right) {
+      /* Swap the left and right points. */
+      temp = sortarray[left];
+      sortarray[left] = sortarray[right];
+      sortarray[right] = temp;
+    }
+  }
+  if (left > 1) {
+    /* Recursively sort the left subset. */
+    pointsort(sortarray, left);
+  }
+  if (right < arraysize - 2) {
+    /* Recursively sort the right subset. */
+    pointsort(&sortarray[right + 1], arraysize - right - 1);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  pointmedian()   An order statistic algorithm, almost.  Shuffles an array */
+/*                  of points so that the first `median' points occur        */
+/*                  lexicographically before the remaining points.           */
+/*                                                                           */
+/*  Uses the x-coordinate as the primary key if axis == 0; the y-coordinate  */
+/*  if axis == 1.  Very similar to the pointsort() procedure, but runs in    */
+/*  randomized linear time.                                                  */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::pointmedian(point *sortarray, int arraysize, int median, int axis)
+{
+  int left, right;
+  int pivot;
+  REAL pivot1, pivot2;
+  point temp;
+
+  if (arraysize == 2) {
+    /* Recursive base case. */
+    if ((sortarray[0][axis] > sortarray[1][axis]) ||
+        ((sortarray[0][axis] == sortarray[1][axis]) &&
+         (sortarray[0][1 - axis] > sortarray[1][1 - axis]))) {
+      temp = sortarray[1];
+      sortarray[1] = sortarray[0];
+      sortarray[0] = temp;
+    }
+    return;
+  }
+  /* Choose a random pivot to split the array. */
+  pivot = (int) randomnation(arraysize);
+  pivot1 = sortarray[pivot][axis];
+  pivot2 = sortarray[pivot][1 - axis];
+  /* Split the array. */
+  left = -1;
+  right = arraysize;
+  while (left < right) {
+    /* Search for a point whose x-coordinate is too large for the left. */
+    do {
+      left++;
+    } while ((left <= right) && ((sortarray[left][axis] < pivot1) ||
+                                 ((sortarray[left][axis] == pivot1) &&
+                                  (sortarray[left][1 - axis] < pivot2))));
+    /* Search for a point whose x-coordinate is too small for the right. */
+    do {
+      right--;
+    } while ((left <= right) && ((sortarray[right][axis] > pivot1) ||
+                                 ((sortarray[right][axis] == pivot1) &&
+                                  (sortarray[right][1 - axis] > pivot2))));
+    if (left < right) {
+      /* Swap the left and right points. */
+      temp = sortarray[left];
+      sortarray[left] = sortarray[right];
+      sortarray[right] = temp;
+    }
+  }
+  /* Unlike in pointsort(), at most one of the following */
+  /*   conditionals is true.                             */
+  if (left > median) {
+    /* Recursively shuffle the left subset. */
+    pointmedian(sortarray, left, median, axis);
+  }
+  if (right < median - 1) {
+    /* Recursively shuffle the right subset. */
+    pointmedian(&sortarray[right + 1], arraysize - right - 1,
+                median - right - 1, axis);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  alternateaxes()   Sorts the points as appropriate for the divide-and-    */
+/*                    conquer algorithm with alternating cuts.               */
+/*                                                                           */
+/*  Partitions by x-coordinate if axis == 0; by y-coordinate if axis == 1.   */
+/*  For the base case, subsets containing only two or three points are       */
+/*  always sorted by x-coordinate.                                           */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::alternateaxes(point *sortarray, int arraysize, int axis)
+{
+  int divider;
+
+  divider = arraysize >> 1;
+  if (arraysize <= 3) {
+    /* Recursive base case:  subsets of two or three points will be      */
+    /*   handled specially, and should always be sorted by x-coordinate. */
+    axis = 0;
+  }
+  /* Partition with a horizontal or vertical cut. */
+  pointmedian(sortarray, arraysize, divider, axis);
+  /* Recursively partition the subsets with a cross cut. */
+  if (arraysize - divider >= 2) {
+    if (divider >= 2) {
+      alternateaxes(sortarray, divider, 1 - axis);
+    }
+    alternateaxes(&sortarray[divider], arraysize - divider, 1 - axis);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  mergehulls()   Merge two adjacent Delaunay triangulations into a         */
+/*                 single Delaunay triangulation.                            */
+/*                                                                           */
+/*  This is similar to the algorithm given by Guibas and Stolfi, but uses    */
+/*  a triangle-based, rather than edge-based, data structure.                */
+/*                                                                           */
+/*  The algorithm walks up the gap between the two triangulations, knitting  */
+/*  them together.  As they are merged, some of their bounding triangles     */
+/*  are converted into real triangles of the triangulation.  The procedure   */
+/*  pulls each hull's bounding triangles apart, then knits them together     */
+/*  like the teeth of two gears.  The Delaunay property determines, at each  */
+/*  step, whether the next "tooth" is a bounding triangle of the left hull   */
+/*  or the right.  When a bounding triangle becomes real, its apex is        */
+/*  changed from NULL to a real point.                                       */
+/*                                                                           */
+/*  Only two new triangles need to be allocated.  These become new bounding  */
+/*  triangles at the top and bottom of the seam.  They are used to connect   */
+/*  the remaining bounding triangles (those that have not been converted     */
+/*  into real triangles) into a single fan.                                  */
+/*                                                                           */
+/*  On entry, `farleft' and `innerleft' are bounding triangles of the left   */
+/*  triangulation.  The origin of `farleft' is the leftmost vertex, and      */
+/*  the destination of `innerleft' is the rightmost vertex of the            */
+/*  triangulation.  Similarly, `innerright' and `farright' are bounding      */
+/*  triangles of the right triangulation.  The origin of `innerright' and    */
+/*  destination of `farright' are the leftmost and rightmost vertices.       */
+/*                                                                           */
+/*  On completion, the origin of `farleft' is the leftmost vertex of the     */
+/*  merged triangulation, and the destination of `farright' is the rightmost */
+/*  vertex.                                                                  */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::mergehulls(struct triedge *farleft, struct triedge *innerleft,
+                        struct triedge *innerright, struct triedge *farright,
+                        int axis)
+{
+  struct triedge leftcand, rightcand;
+  struct triedge baseedge;
+  struct triedge nextedge;
+  struct triedge sidecasing, topcasing, outercasing;
+  struct triedge checkedge;
+  point innerleftdest;
+  point innerrightorg;
+  point innerleftapex, innerrightapex;
+  point farleftpt, farrightpt;
+  point farleftapex, farrightapex;
+  point lowerleft, lowerright;
+  point upperleft, upperright;
+  point nextapex;
+  point checkvertex;
+  int changemade;
+  int badedge;
+  int leftfinished, rightfinished;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+  dest(*innerleft, innerleftdest);
+  apex(*innerleft, innerleftapex);
+  org(*innerright, innerrightorg);
+  apex(*innerright, innerrightapex);
+  /* Special treatment for horizontal cuts. */
+  if (dwyer && (axis == 1)) {
+    org(*farleft, farleftpt);
+    apex(*farleft, farleftapex);
+    dest(*farright, farrightpt);
+    apex(*farright, farrightapex);
+    /* The pointers to the extremal points are shifted to point to the */
+    /*   topmost and bottommost point of each hull, rather than the    */
+    /*   leftmost and rightmost points.                                */
+    while (farleftapex[1] < farleftpt[1]) {
+      lnextself(*farleft);
+      symself(*farleft);
+      farleftpt = farleftapex;
+      apex(*farleft, farleftapex);
+    }
+    sym(*innerleft, checkedge);
+    apex(checkedge, checkvertex);
+    while (checkvertex[1] > innerleftdest[1]) {
+      lnext(checkedge, *innerleft);
+      innerleftapex = innerleftdest;
+      innerleftdest = checkvertex;
+      sym(*innerleft, checkedge);
+      apex(checkedge, checkvertex);
+    }
+    while (innerrightapex[1] < innerrightorg[1]) {
+      lnextself(*innerright);
+      symself(*innerright);
+      innerrightorg = innerrightapex;
+      apex(*innerright, innerrightapex);
+    }
+    sym(*farright, checkedge);
+    apex(checkedge, checkvertex);
+    while (checkvertex[1] > farrightpt[1]) {
+      lnext(checkedge, *farright);
+      farrightapex = farrightpt;
+      farrightpt = checkvertex;
+      sym(*farright, checkedge);
+      apex(checkedge, checkvertex);
+    }
+  }
+  /* Find a line tangent to and below both hulls. */
+  do {
+    changemade = 0;
+    /* Make innerleftdest the "bottommost" point of the left hull. */
+    if (counterclockwise(innerleftdest, innerleftapex, innerrightorg) > 0.0) {
+      lprevself(*innerleft);
+      symself(*innerleft);
+      innerleftdest = innerleftapex;
+      apex(*innerleft, innerleftapex);
+      changemade = 1;
+    }
+    /* Make innerrightorg the "bottommost" point of the right hull. */
+    if (counterclockwise(innerrightapex, innerrightorg, innerleftdest) > 0.0) {
+      lnextself(*innerright);
+      symself(*innerright);
+      innerrightorg = innerrightapex;
+      apex(*innerright, innerrightapex);
+      changemade = 1;
+    }
+  } while (changemade);
+  /* Find the two candidates to be the next "gear tooth". */
+  sym(*innerleft, leftcand);
+  sym(*innerright, rightcand);
+  /* Create the bottom new bounding triangle. */
+  maketriangle(&baseedge);
+  /* Connect it to the bounding boxes of the left and right triangulations. */
+  bond(baseedge, *innerleft);
+  lnextself(baseedge);
+  bond(baseedge, *innerright);
+  lnextself(baseedge);
+  setorg(baseedge, innerrightorg);
+  setdest(baseedge, innerleftdest);
+  /* Apex is intentionally left NULL. */
+  if (verbose > 2) {
+    printf("  Creating base bounding ");
+    printtriangle(&baseedge);
+  }
+  /* Fix the extreme triangles if necessary. */
+  org(*farleft, farleftpt);
+  if (innerleftdest == farleftpt) {
+    lnext(baseedge, *farleft);
+  }
+  dest(*farright, farrightpt);
+  if (innerrightorg == farrightpt) {
+    lprev(baseedge, *farright);
+  }
+  /* The vertices of the current knitting edge. */
+  lowerleft = innerleftdest;
+  lowerright = innerrightorg;
+  /* The candidate vertices for knitting. */
+  apex(leftcand, upperleft);
+  apex(rightcand, upperright);
+  /* Walk up the gap between the two triangulations, knitting them together. */
+  while (1) {
+    /* Have we reached the top?  (This isn't quite the right question,       */
+    /*   because even though the left triangulation might seem finished now, */
+    /*   moving up on the right triangulation might reveal a new point of    */
+    /*   the left triangulation.  And vice-versa.)                           */
+    leftfinished = counterclockwise(upperleft, lowerleft, lowerright) <= 0.0;
+    rightfinished = counterclockwise(upperright, lowerleft, lowerright) <= 0.0;
+    if (leftfinished && rightfinished) {
+      /* Create the top new bounding triangle. */
+      maketriangle(&nextedge);
+      setorg(nextedge, lowerleft);
+      setdest(nextedge, lowerright);
+      /* Apex is intentionally left NULL. */
+      /* Connect it to the bounding boxes of the two triangulations. */
+      bond(nextedge, baseedge);
+      lnextself(nextedge);
+      bond(nextedge, rightcand);
+      lnextself(nextedge);
+      bond(nextedge, leftcand);
+      if (verbose > 2) {
+        printf("  Creating top bounding ");
+        printtriangle(&baseedge);
+      }
+      /* Special treatment for horizontal cuts. */
+      if (dwyer && (axis == 1)) {
+        org(*farleft, farleftpt);
+        apex(*farleft, farleftapex);
+        dest(*farright, farrightpt);
+        apex(*farright, farrightapex);
+        sym(*farleft, checkedge);
+        apex(checkedge, checkvertex);
+        /* The pointers to the extremal points are restored to the leftmost */
+        /*   and rightmost points (rather than topmost and bottommost).     */
+        while (checkvertex[0] < farleftpt[0]) {
+          lprev(checkedge, *farleft);
+          farleftapex = farleftpt;
+          farleftpt = checkvertex;
+          sym(*farleft, checkedge);
+          apex(checkedge, checkvertex);
+        }
+        while (farrightapex[0] > farrightpt[0]) {
+          lprevself(*farright);
+          symself(*farright);
+          farrightpt = farrightapex;
+          apex(*farright, farrightapex);
+        }
+      }
+      return;
+    }
+    /* Consider eliminating edges from the left triangulation. */
+    if (!leftfinished) {
+      /* What vertex would be exposed if an edge were deleted? */
+      lprev(leftcand, nextedge);
+      symself(nextedge);
+      apex(nextedge, nextapex);
+      /* If nextapex is NULL, then no vertex would be exposed; the */
+      /*   triangulation would have been eaten right through.      */
+      if (nextapex != (point) NULL) {
+        /* Check whether the edge is Delaunay. */
+        badedge = iincircle(lowerleft, lowerright, upperleft, nextapex) > 0.0;
+        while (badedge) {
+          /* Eliminate the edge with an edge flip.  As a result, the    */
+          /*   left triangulation will have one more boundary triangle. */
+          lnextself(nextedge);
+          sym(nextedge, topcasing);
+          lnextself(nextedge);
+          sym(nextedge, sidecasing);
+          bond(nextedge, topcasing);
+          bond(leftcand, sidecasing);
+          lnextself(leftcand);
+          sym(leftcand, outercasing);
+          lprevself(nextedge);
+          bond(nextedge, outercasing);
+          /* Correct the vertices to reflect the edge flip. */
+          setorg(leftcand, lowerleft);
+          setdest(leftcand, NULL);
+          setapex(leftcand, nextapex);
+          setorg(nextedge, NULL);
+          setdest(nextedge, upperleft);
+          setapex(nextedge, nextapex);
+          /* Consider the newly exposed vertex. */
+          upperleft = nextapex;
+          /* What vertex would be exposed if another edge were deleted? */
+          triedgecopy(sidecasing, nextedge);
+          apex(nextedge, nextapex);
+          if (nextapex != (point) NULL) {
+            /* Check whether the edge is Delaunay. */
+            badedge = iincircle(lowerleft, lowerright, upperleft, nextapex)
+                      > 0.0;
+          } else {
+            /* Avoid eating right through the triangulation. */
+            badedge = 0;
+          }
+        }
+      }
+    }
+    /* Consider eliminating edges from the right triangulation. */
+    if (!rightfinished) {
+      /* What vertex would be exposed if an edge were deleted? */
+      lnext(rightcand, nextedge);
+      symself(nextedge);
+      apex(nextedge, nextapex);
+      /* If nextapex is NULL, then no vertex would be exposed; the */
+      /*   triangulation would have been eaten right through.      */
+      if (nextapex != (point) NULL) {
+        /* Check whether the edge is Delaunay. */
+        badedge = iincircle(lowerleft, lowerright, upperright, nextapex) > 0.0;
+        while (badedge) {
+          /* Eliminate the edge with an edge flip.  As a result, the     */
+          /*   right triangulation will have one more boundary triangle. */
+          lprevself(nextedge);
+          sym(nextedge, topcasing);
+          lprevself(nextedge);
+          sym(nextedge, sidecasing);
+          bond(nextedge, topcasing);
+          bond(rightcand, sidecasing);
+          lprevself(rightcand);
+          sym(rightcand, outercasing);
+          lnextself(nextedge);
+          bond(nextedge, outercasing);
+          /* Correct the vertices to reflect the edge flip. */
+          setorg(rightcand, NULL);
+          setdest(rightcand, lowerright);
+          setapex(rightcand, nextapex);
+          setorg(nextedge, upperright);
+          setdest(nextedge, NULL);
+          setapex(nextedge, nextapex);
+          /* Consider the newly exposed vertex. */
+          upperright = nextapex;
+          /* What vertex would be exposed if another edge were deleted? */
+          triedgecopy(sidecasing, nextedge);
+          apex(nextedge, nextapex);
+          if (nextapex != (point) NULL) {
+            /* Check whether the edge is Delaunay. */
+            badedge = iincircle(lowerleft, lowerright, upperright, nextapex)
+                      > 0.0;
+          } else {
+            /* Avoid eating right through the triangulation. */
+            badedge = 0;
+          }
+        }
+      }
+    }
+    if (leftfinished || (!rightfinished &&
+           (iincircle(upperleft, lowerleft, lowerright, upperright) > 0.0))) {
+      /* Knit the triangulations, adding an edge from `lowerleft' */
+      /*   to `upperright'.                                       */
+      bond(baseedge, rightcand);
+      lprev(rightcand, baseedge);
+      setdest(baseedge, lowerleft);
+      lowerright = upperright;
+      sym(baseedge, rightcand);
+      apex(rightcand, upperright);
+    } else {
+      /* Knit the triangulations, adding an edge from `upperleft' */
+      /*   to `lowerright'.                                       */
+      bond(baseedge, leftcand);
+      lnext(leftcand, baseedge);
+      setorg(baseedge, lowerright);
+      lowerleft = upperleft;
+      sym(baseedge, leftcand);
+      apex(leftcand, upperleft);
+    }
+    if (verbose > 2) {
+      printf("  Connecting ");
+      printtriangle(&baseedge);
+    }
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  divconqrecurse()   Recursively form a Delaunay triangulation by the      */
+/*                     divide-and-conquer method.                            */
+/*                                                                           */
+/*  Recursively breaks down the problem into smaller pieces, which are       */
+/*  knitted together by mergehulls().  The base cases (problems of two or    */
+/*  three points) are handled specially here.                                */
+/*                                                                           */
+/*  On completion, `farleft' and `farright' are bounding triangles such that */
+/*  the origin of `farleft' is the leftmost vertex (breaking ties by         */
+/*  choosing the highest leftmost vertex), and the destination of            */
+/*  `farright' is the rightmost vertex (breaking ties by choosing the        */
+/*  lowest rightmost vertex).                                                */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::divconqrecurse(point *sortarray, int vertices, int axis,
+                            struct triedge *farleft, struct triedge *farright)
+{
+  struct triedge midtri, tri1, tri2, tri3;
+  struct triedge innerleft, innerright;
+  REAL area;
+  int divider;
+
+  if (verbose > 2) {
+    printf("  Triangulating %d points.\n", vertices);
+  }
+  if (vertices == 2) {
+    /* The triangulation of two vertices is an edge.  An edge is */
+    /*   represented by two bounding triangles.                  */
+    maketriangle(farleft);
+    setorg(*farleft, sortarray[0]);
+    setdest(*farleft, sortarray[1]);
+    /* The apex is intentionally left NULL. */
+    maketriangle(farright);
+    setorg(*farright, sortarray[1]);
+    setdest(*farright, sortarray[0]);
+    /* The apex is intentionally left NULL. */
+    bond(*farleft, *farright);
+    lprevself(*farleft);
+    lnextself(*farright);
+    bond(*farleft, *farright);
+    lprevself(*farleft);
+    lnextself(*farright);
+    bond(*farleft, *farright);
+    if (verbose > 2) {
+      printf("  Creating ");
+      printtriangle(farleft);
+      printf("  Creating ");
+      printtriangle(farright);
+    }
+    /* Ensure that the origin of `farleft' is sortarray[0]. */
+    lprev(*farright, *farleft);
+    return;
+  } else if (vertices == 3) {
+    /* The triangulation of three vertices is either a triangle (with */
+    /*   three bounding triangles) or two edges (with four bounding   */
+    /*   triangles).  In either case, four triangles are created.     */
+    maketriangle(&midtri);
+    maketriangle(&tri1);
+    maketriangle(&tri2);
+    maketriangle(&tri3);
+    area = counterclockwise(sortarray[0], sortarray[1], sortarray[2]);
+    if (area == 0.0) {
+      /* Three collinear points; the triangulation is two edges. */
+      setorg(midtri, sortarray[0]);
+      setdest(midtri, sortarray[1]);
+      setorg(tri1, sortarray[1]);
+      setdest(tri1, sortarray[0]);
+      setorg(tri2, sortarray[2]);
+      setdest(tri2, sortarray[1]);
+      setorg(tri3, sortarray[1]);
+      setdest(tri3, sortarray[2]);
+      /* All apices are intentionally left NULL. */
+      bond(midtri, tri1);
+      bond(tri2, tri3);
+      lnextself(midtri);
+      lprevself(tri1);
+      lnextself(tri2);
+      lprevself(tri3);
+      bond(midtri, tri3);
+      bond(tri1, tri2);
+      lnextself(midtri);
+      lprevself(tri1);
+      lnextself(tri2);
+      lprevself(tri3);
+      bond(midtri, tri1);
+      bond(tri2, tri3);
+      /* Ensure that the origin of `farleft' is sortarray[0]. */
+      triedgecopy(tri1, *farleft);
+      /* Ensure that the destination of `farright' is sortarray[2]. */
+      triedgecopy(tri2, *farright);
+    } else {
+      /* The three points are not collinear; the triangulation is one */
+      /*   triangle, namely `midtri'.                                 */
+      setorg(midtri, sortarray[0]);
+      setdest(tri1, sortarray[0]);
+      setorg(tri3, sortarray[0]);
+      /* Apices of tri1, tri2, and tri3 are left NULL. */
+      if (area > 0.0) {
+        /* The vertices are in counterclockwise order. */
+        setdest(midtri, sortarray[1]);
+        setorg(tri1, sortarray[1]);
+        setdest(tri2, sortarray[1]);
+        setapex(midtri, sortarray[2]);
+        setorg(tri2, sortarray[2]);
+        setdest(tri3, sortarray[2]);
+      } else {
+        /* The vertices are in clockwise order. */
+        setdest(midtri, sortarray[2]);
+        setorg(tri1, sortarray[2]);
+        setdest(tri2, sortarray[2]);
+        setapex(midtri, sortarray[1]);
+        setorg(tri2, sortarray[1]);
+        setdest(tri3, sortarray[1]);
+      }
+      /* The topology does not depend on how the vertices are ordered. */
+      bond(midtri, tri1);
+      lnextself(midtri);
+      bond(midtri, tri2);
+      lnextself(midtri);
+      bond(midtri, tri3);
+      lprevself(tri1);
+      lnextself(tri2);
+      bond(tri1, tri2);
+      lprevself(tri1);
+      lprevself(tri3);
+      bond(tri1, tri3);
+      lnextself(tri2);
+      lprevself(tri3);
+      bond(tri2, tri3);
+      /* Ensure that the origin of `farleft' is sortarray[0]. */
+      triedgecopy(tri1, *farleft);
+      /* Ensure that the destination of `farright' is sortarray[2]. */
+      if (area > 0.0) {
+        triedgecopy(tri2, *farright);
+      } else {
+        lnext(*farleft, *farright);
+      }
+    }
+    if (verbose > 2) {
+      printf("  Creating ");
+      printtriangle(&midtri);
+      printf("  Creating ");
+      printtriangle(&tri1);
+      printf("  Creating ");
+      printtriangle(&tri2);
+      printf("  Creating ");
+      printtriangle(&tri3);
+    }
+    return;
+  } else {
+    /* Split the vertices in half. */
+    divider = vertices >> 1;
+    /* Recursively triangulate each half. */
+    divconqrecurse(sortarray, divider, 1 - axis, farleft, &innerleft);
+    divconqrecurse(&sortarray[divider], vertices - divider, 1 - axis,
+                   &innerright, farright);
+    if (verbose > 1) {
+      printf("  Joining triangulations with %d and %d vertices.\n", divider,
+             vertices - divider);
+    }
+    /* Merge the two triangulations into one. */
+    mergehulls(farleft, &innerleft, &innerright, farright, axis);
+  }
+}
+
+long mesh2d::removeghosts(struct triedge *startghost)
+{
+  struct triedge searchedge;
+  struct triedge dissolveedge;
+  struct triedge deadtri;
+  point markorg;
+  long hullsize;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+  if (verbose) {
+    printf("  Removing ghost triangles.\n");
+  }
+  /* Find an edge on the convex hull to start point location from. */
+  lprev(*startghost, searchedge);
+  symself(searchedge);
+  dummytri[0] = encode(searchedge);
+  /* Remove the bounding box and count the convex hull edges. */
+  triedgecopy(*startghost, dissolveedge);
+  hullsize = 0;
+  do {
+    hullsize++;
+    lnext(dissolveedge, deadtri);
+    lprevself(dissolveedge);
+    symself(dissolveedge);
+    /* If no PSLG is involved, set the boundary markers of all the points */
+    /*   on the convex hull.  If a PSLG is used, this step is done later. */
+    if (!poly) {
+      /* Watch out for the case where all the input points are collinear. */
+      if (dissolveedge.tri != dummytri) {
+        org(dissolveedge, markorg);
+        if (pointmark(markorg) == 0) {
+          setpointmark(markorg, 1);
+        }
+      }
+    }
+    /* Remove a bounding triangle from a convex hull triangle. */
+    dissolve(dissolveedge);
+    /* Find the next bounding triangle. */
+    sym(deadtri, dissolveedge);
+    /* Delete the bounding triangle. */
+    triangledealloc(deadtri.tri);
+  } while (!triedgeequal(dissolveedge, *startghost));
+  return hullsize;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  divconqdelaunay()   Form a Delaunay triangulation by the divide-and-     */
+/*                      conquer method.                                      */
+/*                                                                           */
+/*  Sorts the points, calls a recursive procedure to triangulate them, and   */
+/*  removes the bounding box, setting boundary markers as appropriate.       */
+/*                                                                           */
+/*****************************************************************************/
+
+long mesh2d::divconqdelaunay()
+{
+  point *sortarray;
+  struct triedge hullleft, hullright;
+  int divider;
+  int i, j;
+
+  /* Allocate an array of pointers to points for sorting. */
+  sortarray = (point *) new point[inpoints];
+  if (sortarray == (point *) NULL) {
+    printf("Error:  Out of memory.\n");
+    exit(1);
+  }
+  points.traversalinit();
+  for (i = 0; i < inpoints; i++) {
+    sortarray[i] = pointtraverse();
+  }
+  if (verbose) {
+    printf("  Sorting points.\n");
+  }
+  /* Sort the points. */
+  pointsort(sortarray, inpoints);
+  /* Discard duplicate points, which can really mess up the algorithm. */
+  i = 0;
+  for (j = 1; j < inpoints; j++) {
+    if ((sortarray[i][0] == sortarray[j][0])
+        && (sortarray[i][1] == sortarray[j][1])) {
+      if (!quiet) {
+        printf(
+"Warning:  A duplicate point at (%.12g, %.12g) appeared and was ignored.\n",
+               sortarray[j][0], sortarray[j][1]);
+      }
+/*  Commented out - would eliminate point from output .node file, but causes
+    a failure if some segment has this point as an endpoint.
+      setpointmark(sortarray[j], DEADPOINT);
+*/
+    } else {
+      i++;
+      sortarray[i] = sortarray[j];
+    }
+  }
+  i++;
+  if (dwyer) {
+    /* Re-sort the array of points to accommodate alternating cuts. */
+    divider = i >> 1;
+    if (i - divider >= 2) {
+      if (divider >= 2) {
+        alternateaxes(sortarray, divider, 1);
+      }
+      alternateaxes(&sortarray[divider], i - divider, 1);
+    }
+  }
+  if (verbose) {
+    printf("  Forming triangulation.\n");
+  }
+  /* Form the Delaunay triangulation. */
+  divconqrecurse(sortarray, i, 0, &hullleft, &hullright);
+  delete [] sortarray;
+
+  return removeghosts(&hullleft);
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Divide-and-conquer Delaunay triangulation ends here       *********/
+
+/********* General mesh construction routines begin here             *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  delaunay()   Form a Delaunay triangulation.                              */
+/*                                                                           */
+/*****************************************************************************/
+
+long mesh2d::delaunay()
+{
+  eextras = 0;
+  if (!restartsymbol) {
+    initializetrisegpools();
+  }
+  if (!quiet) {
+    printf("Constructing Delaunay triangulation ");
+    if (incremental) {
+      printf("by incremental method.\n");
+    } else if (sweepline) {
+      printf("by sweepline method.\n");
+    } else {
+      printf("by divide-and-conquer method.\n");
+    }
+  }
+  if (incremental) {
+    // return incrementaldelaunay();
+    printf("Sorry, the incremental delaunay algorithm have not");
+    printf(" been transformed.\n");
+    exit(1);
+  } else if (sweepline) {
+    // return sweeplinedelaunay();
+    printf("Sorry, the sweepline delaunay algorithm have not");
+    printf(" been transformed.\n");
+    exit(1);
+  } else {
+    return divconqdelaunay();
+  }
+  return 0;
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* General mesh construction routines end here               *********/
+
+/********* Segment (shell edge) insertion begins here                *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  finddirection()   Find the first triangle on the path from one point     */
+/*                    to another.                                            */
+/*                                                                           */
+/*  Finds the triangle that intersects a line segment drawn from the         */
+/*  origin of `searchtri' to the point `endpoint', and returns the result    */
+/*  in `searchtri'.  The origin of `searchtri' does not change, even though  */
+/*  the triangle 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 whether the destination or apex of the found      */
+/*  triangle is collinear with the two points in question.                   */
+/*                                                                           */
+/*****************************************************************************/
+
+enum mesh2d::finddirectionresult
+mesh2d::finddirection(struct triedge *searchtri, point endpoint)
+{
+  struct triedge checktri;
+  point startpoint;
+  point leftpoint, rightpoint;
+  REAL leftccw, rightccw;
+  int leftflag, rightflag;
+  triangle ptr;           /* Temporary variable used by onext() and oprev(). */
+
+  org(*searchtri, startpoint);
+  dest(*searchtri, rightpoint);
+  apex(*searchtri, leftpoint);
+  /* Is `endpoint' to the left? */
+  leftccw = counterclockwise(endpoint, startpoint, leftpoint);
+  leftflag = leftccw > 0.0;
+  /* Is `endpoint' to the right? */
+  rightccw = counterclockwise(startpoint, endpoint, rightpoint);
+  rightflag = rightccw > 0.0;
+  if (leftflag && rightflag) {
+    /* `searchtri' faces directly away from `endpoint'.  We could go */
+    /*   left or right.  Ask whether it's a triangle or a boundary   */
+    /*   on the left.                                                */
+    onext(*searchtri, checktri);
+    if (checktri.tri == dummytri) {
+      leftflag = 0;
+    } else {
+      rightflag = 0;
+    }
+  }
+  while (leftflag) {
+    /* Turn left until satisfied. */
+    onextself(*searchtri);
+    if (searchtri->tri == dummytri) {
+      printf("Internal error in finddirection():  Unable to find a\n");
+      printf("  triangle leading from (%.12g, %.12g) to", startpoint[0],
+             startpoint[1]);
+      printf("  (%.12g, %.12g).\n", endpoint[0], endpoint[1]);
+      internalerror();
+    }
+    apex(*searchtri, leftpoint);
+    rightccw = leftccw;
+    leftccw = counterclockwise(endpoint, startpoint, leftpoint);
+    leftflag = leftccw > 0.0;
+  }
+  while (rightflag) {
+    /* Turn right until satisfied. */
+    oprevself(*searchtri);
+    if (searchtri->tri == dummytri) {
+      printf("Internal error in finddirection():  Unable to find a\n");
+      printf("  triangle leading from (%.12g, %.12g) to", startpoint[0],
+             startpoint[1]);
+      printf("  (%.12g, %.12g).\n", endpoint[0], endpoint[1]);
+      internalerror();
+    }
+    dest(*searchtri, rightpoint);
+    leftccw = rightccw;
+    rightccw = counterclockwise(startpoint, endpoint, rightpoint);
+    rightflag = rightccw > 0.0;
+  }
+  if (leftccw == 0.0) {
+    return LEFTCOLLINEAR;
+  } else if (rightccw == 0.0) {
+    return RIGHTCOLLINEAR;
+  } else {
+    return WITHIN;
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  segmentintersection()   Find the intersection of an existing segment     */
+/*                          and a segment that is being inserted.  Insert    */
+/*                          a point at the intersection, splitting an        */
+/*                          existing shell edge.                             */
+/*                                                                           */
+/*  The segment being inserted connects the apex of splittri to endpoint2.   */
+/*  splitshelle is the shell edge being split, and MUST be opposite          */
+/*  splittri.  Hence, the edge being split connects the origin and           */
+/*  destination of splittri.                                                 */
+/*                                                                           */
+/*  On completion, splittri is a handle having the newly inserted            */
+/*  intersection point as its origin, and endpoint1 as its destination.      */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::
+segmentintersection(struct triedge *splittri, struct edge *splitshelle,
+                    point endpoint2)
+{
+  point endpoint1;
+  point torg, tdest;
+  point leftpoint, rightpoint;
+  point newpoint;
+  enum insertsiteresult success;
+  enum finddirectionresult collinear;
+  REAL ex, ey;
+  REAL tx, ty;
+  REAL etx, ety;
+  REAL split, denom;
+  int i;
+  triangle ptr;                       /* Temporary variable used by onext(). */
+
+  /* Find the other three segment endpoints. */
+  apex(*splittri, endpoint1);
+  org(*splittri, torg);
+  dest(*splittri, tdest);
+  /* Segment intersection formulae; see the Antonio reference. */
+  tx = tdest[0] - torg[0];
+  ty = tdest[1] - torg[1];
+  ex = endpoint2[0] - endpoint1[0];
+  ey = endpoint2[1] - endpoint1[1];
+  etx = torg[0] - endpoint2[0];
+  ety = torg[1] - endpoint2[1];
+  denom = ty * ex - tx * ey;
+  if (denom == 0.0) {
+    printf("Internal error in segmentintersection():");
+    printf("  Attempt to find intersection of parallel segments.\n");
+    internalerror();
+  }
+  split = (ey * etx - ex * ety) / denom;
+  /* Create the new point. */
+  newpoint = (point) points.alloc();
+  /* Interpolate its coordinate and attributes. */
+  for (i = 0; i < 2 + nextras; i++) {
+    newpoint[i] = torg[i] + split * (tdest[i] - torg[i]);
+  }
+  setpointmark(newpoint, mark(*splitshelle));
+  if (verbose > 1) {
+    printf(
+    "  Splitting edge (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n",
+           torg[0], torg[1], tdest[0], tdest[1], newpoint[0], newpoint[1]);
+  }
+  /* Insert the intersection point.  This should always succeed. */
+  success = insertsite(newpoint, splittri, splitshelle, 0, 0);
+  if (success != SUCCESSFULPOINT) {
+    printf("Internal error in segmentintersection():\n");
+    printf("  Failure to split a segment.\n");
+    internalerror();
+  }
+  if (steinerleft > 0) {
+    steinerleft--;
+  }
+  /* Inserting the point may have caused edge flips.  We wish to rediscover */
+  /*   the edge connecting endpoint1 to the new intersection point.         */
+  collinear = finddirection(splittri, endpoint1);
+  dest(*splittri, rightpoint);
+  apex(*splittri, leftpoint);
+  if ((leftpoint[0] == endpoint1[0]) && (leftpoint[1] == endpoint1[1])) {
+    onextself(*splittri);
+  } else if ((rightpoint[0] != endpoint1[0]) ||
+             (rightpoint[1] != endpoint1[1])) {
+    printf("Internal error in segmentintersection():\n");
+    printf("  Topological inconsistency after splitting a segment.\n");
+    internalerror();
+  }
+  /* `splittri' should have destination endpoint1. */
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  scoutsegment()   Scout the first triangle on the path from one endpoint  */
+/*                   to another, and check for completion (reaching the      */
+/*                   second endpoint), a collinear point, and the            */
+/*                   intersection of two segments.                           */
+/*                                                                           */
+/*  Returns one if the entire segment is successfully inserted, and zero if  */
+/*  the job must be finished by conformingedge() or constrainededge().       */
+/*                                                                           */
+/*  If the first triangle on the path has the second endpoint as its         */
+/*  destination or apex, a shell edge is inserted and the job is done.       */
+/*                                                                           */
+/*  If the first triangle on the path has a destination or apex that lies on */
+/*  the segment, a shell edge is inserted connecting the first endpoint to   */
+/*  the collinear point, and the search is continued from the collinear      */
+/*  point.                                                                   */
+/*                                                                           */
+/*  If the first triangle on the path has a shell edge opposite its origin,  */
+/*  then there is a segment that intersects the segment being inserted.      */
+/*  Their intersection point is inserted, splitting the shell edge.          */
+/*                                                                           */
+/*  Otherwise, return zero.                                                  */
+/*                                                                           */
+/*****************************************************************************/
+
+int mesh2d::
+scoutsegment(struct triedge *searchtri, point endpoint2, int newmark)
+{
+  struct triedge crosstri;
+  struct edge crossedge;
+  point leftpoint, rightpoint;
+  point endpoint1;
+  enum finddirectionresult collinear;
+  shelle sptr;                      /* Temporary variable used by tspivot(). */
+
+  collinear = finddirection(searchtri, endpoint2);
+  dest(*searchtri, rightpoint);
+  apex(*searchtri, leftpoint);
+  if (((leftpoint[0] == endpoint2[0]) && (leftpoint[1] == endpoint2[1])) ||
+      ((rightpoint[0] == endpoint2[0]) && (rightpoint[1] == endpoint2[1]))) {
+    /* The segment is already an edge in the mesh. */
+    if ((leftpoint[0] == endpoint2[0]) && (leftpoint[1] == endpoint2[1])) {
+      lprevself(*searchtri);
+    }
+    /* Insert a shell edge, if there isn't already one there. */
+    insertshelle(searchtri, newmark);
+    return 1;
+  } else if (collinear == LEFTCOLLINEAR) {
+    /* We've collided with a point between the segment's endpoints. */
+    /* Make the collinear point be the triangle's origin. */
+    lprevself(*searchtri);
+    insertshelle(searchtri, newmark);
+    /* Insert the remainder of the segment. */
+    return scoutsegment(searchtri, endpoint2, newmark);
+  } else if (collinear == RIGHTCOLLINEAR) {
+    /* We've collided with a point between the segment's endpoints. */
+    insertshelle(searchtri, newmark);
+    /* Make the collinear point be the triangle's origin. */
+    lnextself(*searchtri);
+    /* Insert the remainder of the segment. */
+    return scoutsegment(searchtri, endpoint2, newmark);
+  } else {
+    lnext(*searchtri, crosstri);
+    tspivot(crosstri, crossedge);
+    /* Check for a crossing segment. */
+    if (crossedge.sh == dummysh) {
+      return 0;
+    } else {
+      org(*searchtri, endpoint1);
+      /* Insert a point at the intersection. */
+      segmentintersection(&crosstri, &crossedge, endpoint2);
+      triedgecopy(crosstri, *searchtri);
+      insertshelle(searchtri, newmark);
+      /* Insert the remainder of the segment. */
+      return scoutsegment(searchtri, endpoint2, newmark);
+    }
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  conformingedge()   Force a segment into a conforming Delaunay            */
+/*                     triangulation by inserting a point at its midpoint,   */
+/*                     and recursively forcing in the two half-segments if   */
+/*                     necessary.                                            */
+/*                                                                           */
+/*  Generates a sequence of edges connecting `endpoint1' to `endpoint2'.     */
+/*  `newmark' is the boundary marker of the segment, assigned to each new    */
+/*  splitting point and shell edge.                                          */
+/*                                                                           */
+/*  Note that conformingedge() does not always maintain the conforming       */
+/*  Delaunay property.  Once inserted, segments are locked into place;       */
+/*  points inserted later (to force other segments in) may render these      */
+/*  fixed segments non-Delaunay.  The conforming Delaunay property will be   */
+/*  restored by enforcequality() by splitting encroached segments.           */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::conformingedge(point endpoint1, point endpoint2, int newmark)
+{
+  struct triedge searchtri1, searchtri2;
+  struct edge brokenshelle;
+  point newpoint;
+  point midpoint1, midpoint2;
+  enum insertsiteresult success;
+  int result1, result2;
+  int i;
+  shelle sptr;                      /* Temporary variable used by tspivot(). */
+
+  if (verbose > 2) {
+    printf("Forcing segment into triangulation by recursive splitting:\n");
+    printf("  (%.12g, %.12g) (%.12g, %.12g)\n", endpoint1[0], endpoint1[1],
+           endpoint2[0], endpoint2[1]);
+  }
+  /* Create a new point to insert in the middle of the segment. */
+  newpoint = (point) points.alloc();
+  /* Interpolate coordinates and attributes. */
+  for (i = 0; i < 2 + nextras; i++) {
+    newpoint[i] = 0.5 * (endpoint1[i] + endpoint2[i]);
+  }
+  setpointmark(newpoint, newmark);
+  /* Find a boundary triangle to search from. */
+  searchtri1.tri = (triangle *) NULL;
+  /* Attempt to insert the new point. */
+  success = insertsite(newpoint, &searchtri1, (struct edge *) NULL, 0, 0);
+  if (success == DUPLICATEPOINT) {
+    if (verbose > 2) {
+      printf("  Segment intersects existing point (%.12g, %.12g).\n",
+             newpoint[0], newpoint[1]);
+    }
+    /* Use the point that's already there. */
+    pointdealloc(newpoint);
+    org(searchtri1, newpoint);
+  } else {
+    if (success == VIOLATINGPOINT) {
+      if (verbose > 2) {
+        printf("  Two segments intersect at (%.12g, %.12g).\n",
+               newpoint[0], newpoint[1]);
+      }
+      /* By fluke, we've landed right on another segment.  Split it. */
+      tspivot(searchtri1, brokenshelle);
+      success = insertsite(newpoint, &searchtri1, &brokenshelle, 0, 0);
+      if (success != SUCCESSFULPOINT) {
+        printf("Internal error in conformingedge():\n");
+        printf("  Failure to split a segment.\n");
+        internalerror();
+      }
+    }
+    /* The point has been inserted successfully. */
+    if (steinerleft > 0) {
+      steinerleft--;
+    }
+  }
+  triedgecopy(searchtri1, searchtri2);
+  result1 = scoutsegment(&searchtri1, endpoint1, newmark);
+  result2 = scoutsegment(&searchtri2, endpoint2, newmark);
+  if (!result1) {
+    /* The origin of searchtri1 may have changed if a collision with an */
+    /*   intervening vertex on the segment occurred.                    */
+    org(searchtri1, midpoint1);
+    conformingedge(midpoint1, endpoint1, newmark);
+  }
+  if (!result2) {
+    /* The origin of searchtri2 may have changed if a collision with an */
+    /*   intervening vertex on the segment occurred.                    */
+    org(searchtri2, midpoint2);
+    conformingedge(midpoint2, endpoint2, newmark);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  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 fixuptri 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          */
+/*  fixuptri.                                                                */
+/*                                                                           */
+/*  This routine also needs to make decisions regarding the "stacking" of    */
+/*  triangles.  (Read the description of constrainededge() below before      */
+/*  reading on here, so you understand the algorithm.)  If the position of   */
+/*  the new point (the origin of fixuptri) indicates that the vertex before  */
+/*  it on the polygon is a reflex vertex, then "stack" the triangle by       */
+/*  doing nothing.  (fixuptri is an inverted triangle, which is how stacked  */
+/*  triangles are identified.)                                               */
+/*                                                                           */
+/*  Otherwise, check whether the vertex before that was a reflex vertex.     */
+/*  If so, perform an edge flip, thereby eliminating an inverted triangle    */
+/*  (popping it off the stack).  The edge flip may result in the creation    */
+/*  of a new inverted triangle, depending on whether or not the new vertex   */
+/*  is visible to the vertex three edges behind on the polygon.              */
+/*                                                                           */
+/*  If neither of the two vertices behind the new vertex are reflex          */
+/*  vertices, fixuptri and fartri, the triangle opposite it, are not         */
+/*  inverted; hence, ensure that the edge between them is locally Delaunay.  */
+/*                                                                           */
+/*  `leftside' indicates whether or not fixuptri is to the left of the       */
+/*  segment being inserted.  (Imagine that the segment is pointing up from   */
+/*  endpoint1 to endpoint2.)                                                 */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::delaunayfixup(struct triedge *fixuptri, int leftside)
+{
+  struct triedge neartri;
+  struct triedge fartri;
+  struct edge faredge;
+  point nearpoint, leftpoint, rightpoint, farpoint;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  shelle sptr;                      /* Temporary variable used by tspivot(). */
+
+  lnext(*fixuptri, neartri);
+  sym(neartri, fartri);
+  /* Check if the edge opposite the origin of fixuptri can be flipped. */
+  if (fartri.tri == dummytri) {
+    return;
+  }
+  tspivot(neartri, faredge);
+  if (faredge.sh != dummysh) {
+    return;
+  }
+  /* Find all the relevant vertices. */
+  apex(neartri, nearpoint);
+  org(neartri, leftpoint);
+  dest(neartri, rightpoint);
+  apex(fartri, farpoint);
+  /* Check whether the previous polygon vertex is a reflex vertex. */
+  if (leftside) {
+    if (counterclockwise(nearpoint, leftpoint, farpoint) <= 0.0) {
+      /* leftpoint is a reflex vertex too.  Nothing can */
+      /*   be done until a convex section is found.     */
+      return;
+    }
+  } else {
+    if (counterclockwise(farpoint, rightpoint, nearpoint) <= 0.0) {
+      /* rightpoint is a reflex vertex too.  Nothing can */
+      /*   be done until a convex section is found.      */
+      return;
+    }
+  }
+  if (counterclockwise(rightpoint, leftpoint, farpoint) > 0.0) {
+    /* fartri is not an inverted triangle, and farpoint is not a reflex */
+    /*   vertex.  As there are no reflex vertices, fixuptri isn't an    */
+    /*   inverted triangle, either.  Hence, test the edge between the   */
+    /*   triangles to ensure it is locally Delaunay.                    */
+    if (iincircle(leftpoint, farpoint, rightpoint, nearpoint) <= 0.0) {
+      return;
+    }
+    /* Not locally Delaunay; go on to an edge flip. */
+  }        /* else fartri is inverted; remove it from the stack by flipping. */
+  flip(&neartri);
+  lprevself(*fixuptri);    /* Restore the origin of fixuptri after the flip. */
+  /* Recursively process the two triangles that result from the flip. */
+  delaunayfixup(fixuptri, leftside);
+  delaunayfixup(&fartri, leftside);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  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.                             */
+/*                                                                           */
+/*  Generates a single edge connecting `endpoint1' to `endpoint2'.  The      */
+/*  triangle `starttri' has `endpoint1' as its origin.  `newmark' is the     */
+/*  boundary marker of the segment.                                          */
+/*                                                                           */
+/*  To insert a segment, every triangle whose interior intersects the        */
+/*  segment is deleted.  The union of these deleted triangles is a polygon   */
+/*  (which is not necessarily monotone, but is close enough), which is       */
+/*  divided into two polygons by the new segment.  This routine's task is    */
+/*  to generate the Delaunay triangulation of these two polygons.            */
+/*                                                                           */
+/*  You might think of this routine's behavior as a two-step process.  The   */
+/*  first step is to walk from endpoint1 to endpoint2, flipping each edge    */
+/*  encountered.  This step creates a fan of edges connected to endpoint1,   */
+/*  including the desired edge to endpoint2.  The second step enforces the   */
+/*  Delaunay condition on each side of the segment in an incremental manner: */
+/*  proceeding along the polygon from endpoint1 to endpoint2 (this is done   */
+/*  independently on each side of the segment), each vertex is "enforced"    */
+/*  as if it had just been inserted, but affecting only the previous         */
+/*  vertices.  The result is the same as if the vertices had been inserted   */
+/*  in the order they appear on the polygon, so the result is Delaunay.      */
+/*                                                                           */
+/*  In truth, constrainededge() interleaves these two steps.  The procedure  */
+/*  walks from endpoint1 to endpoint2, and each time an edge is encountered  */
+/*  and flipped, the newly exposed vertex (at the far end of the flipped     */
+/*  edge) is "enforced" upon the previously flipped edges, usually affecting */
+/*  only one side of the polygon (depending upon which side of the segment   */
+/*  the vertex falls on).                                                    */
+/*                                                                           */
+/*  The algorithm is complicated by the need to handle polygons that are not */
+/*  convex.  Although the polygon is not necessarily monotone, it can be     */
+/*  triangulated in a manner similar to the stack-based algorithms for       */
+/*  monotone polygons.  For each reflex vertex (local concavity) of the      */
+/*  polygon, there will be an inverted triangle formed by one of the edge    */
+/*  flips.  (An inverted triangle is one with negative area - that is, its   */
+/*  vertices are arranged in clockwise order - and is best thought of as a   */
+/*  wrinkle in the fabric of the mesh.)  Each inverted triangle can be       */
+/*  thought of as a reflex vertex pushed on the stack, waiting to be fixed   */
+/*  later.                                                                   */
+/*                                                                           */
+/*  A reflex vertex is popped from the stack when a vertex is inserted that  */
+/*  is visible to the reflex vertex.  (However, if the vertex behind the     */
+/*  reflex vertex is not visible to the reflex vertex, a new inverted        */
+/*  triangle will take its place on the stack.)  These details are handled   */
+/*  by the delaunayfixup() routine above.                                    */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::
+constrainededge(struct triedge *starttri, point endpoint2, int newmark)
+{
+  struct triedge fixuptri, fixuptri2;
+  struct edge fixupedge;
+  point endpoint1;
+  point farpoint;
+  REAL area;
+  int collision;
+  int done;
+  triangle ptr;             /* Temporary variable used by sym() and oprev(). */
+  shelle sptr;                      /* Temporary variable used by tspivot(). */
+
+  org(*starttri, endpoint1);
+  lnext(*starttri, fixuptri);
+  flip(&fixuptri);
+  /* `collision' indicates whether we have found a point directly */
+  /*   between endpoint1 and endpoint2.                           */
+  collision = 0;
+  done = 0;
+  do {
+    org(fixuptri, farpoint);
+    /* `farpoint' is the extreme point of the polygon we are "digging" */
+    /*   to get from endpoint1 to endpoint2.                           */
+    if ((farpoint[0] == endpoint2[0]) && (farpoint[1] == endpoint2[1])) {
+      oprev(fixuptri, fixuptri2);
+      /* Enforce the Delaunay condition around endpoint2. */
+      delaunayfixup(&fixuptri, 0);
+      delaunayfixup(&fixuptri2, 1);
+      done = 1;
+    } else {
+      /* Check whether farpoint is to the left or right of the segment */
+      /*   being inserted, to decide which edge of fixuptri to dig     */
+      /*   through next.                                               */
+      area = counterclockwise(endpoint1, endpoint2, farpoint);
+      if (area == 0.0) {
+        /* We've collided with a point between endpoint1 and endpoint2. */
+        collision = 1;
+        oprev(fixuptri, fixuptri2);
+        /* Enforce the Delaunay condition around farpoint. */
+        delaunayfixup(&fixuptri, 0);
+        delaunayfixup(&fixuptri2, 1);
+        done = 1;
+      } else {
+        if (area > 0.0) {         /* farpoint is to the left of the segment. */
+          oprev(fixuptri, fixuptri2);
+          /* Enforce the Delaunay condition around farpoint, on the */
+          /*   left side of the segment only.                       */
+          delaunayfixup(&fixuptri2, 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 fixuptri is the fan vertex.               */
+          lprevself(fixuptri);
+        } else {                 /* farpoint is to the right of the segment. */
+          delaunayfixup(&fixuptri, 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 fixuptri is the fan vertex.               */
+          oprevself(fixuptri);
+        }
+        /* Check for two intersecting segments. */
+        tspivot(fixuptri, fixupedge);
+        if (fixupedge.sh == dummysh) {
+          flip(&fixuptri);   /* May create an inverted triangle on the left. */
+        } else {
+          /* We've collided with a segment between endpoint1 and endpoint2. */
+          collision = 1;
+          /* Insert a point at the intersection. */
+          segmentintersection(&fixuptri, &fixupedge, endpoint2);
+          done = 1;
+        }
+      }
+    }
+  } while (!done);
+  /* Insert a shell edge to make the segment permanent. */
+  insertshelle(&fixuptri, newmark);
+  /* 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 (!scoutsegment(&fixuptri, endpoint2, newmark)) {
+      constrainededge(&fixuptri, endpoint2, newmark);
+    }
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  insertsegment()   Insert a PSLG segment into a triangulation.            */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::insertsegment(point endpoint1, point endpoint2, int newmark)
+{
+  struct triedge searchtri1, searchtri2;
+  triangle encodedtri;
+  point checkpoint;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+  if (verbose > 1) {
+    printf("  Connecting (%.12g, %.12g) to (%.12g, %.12g).\n",
+           endpoint1[0], endpoint1[1], endpoint2[0], endpoint2[1]);
+  }
+
+  /* Find a triangle whose origin is the segment's first endpoint. */
+  checkpoint = (point) NULL;
+  encodedtri = point2tri(endpoint1);
+  if (encodedtri != (triangle) NULL) {
+    decode(encodedtri, searchtri1);
+    org(searchtri1, checkpoint);
+  }
+  if (checkpoint != endpoint1) {
+    /* Find a boundary triangle to search from. */
+    searchtri1.tri = dummytri;
+    searchtri1.orient = 0;
+    symself(searchtri1);
+    /* Search for the segment's first endpoint by point location. */
+    if (locate(endpoint1, &searchtri1) != ONVERTEX) {
+      printf(
+        "Internal error in insertsegment():  Unable to locate PSLG point\n");
+      printf("  (%.12g, %.12g) in triangulation.\n",
+             endpoint1[0], endpoint1[1]);
+      internalerror();
+    }
+  }
+  /* Remember this triangle to improve subsequent point location. */
+  triedgecopy(searchtri1, recenttri);
+  /* Scout the beginnings of a path from the first endpoint */
+  /*   toward the second.                                   */
+  if (scoutsegment(&searchtri1, endpoint2, newmark)) {
+    /* The segment was easily inserted. */
+    return;
+  }
+  /* The first endpoint may have changed if a collision with an intervening */
+  /*   vertex on the segment occurred.                                      */
+  org(searchtri1, endpoint1);
+
+  /* Find a triangle whose origin is the segment's second endpoint. */
+  checkpoint = (point) NULL;
+  encodedtri = point2tri(endpoint2);
+  if (encodedtri != (triangle) NULL) {
+    decode(encodedtri, searchtri2);
+    org(searchtri2, checkpoint);
+  }
+  if (checkpoint != endpoint2) {
+    /* Find a boundary triangle to search from. */
+    searchtri2.tri = dummytri;
+    searchtri2.orient = 0;
+    symself(searchtri2);
+    /* Search for the segment's second endpoint by point location. */
+    if (locate(endpoint2, &searchtri2) != ONVERTEX) {
+      printf(
+        "Internal error in insertsegment():  Unable to locate PSLG point\n");
+      printf("  (%.12g, %.12g) in triangulation.\n",
+             endpoint2[0], endpoint2[1]);
+      internalerror();
+    }
+  }
+  /* Remember this triangle to improve subsequent point location. */
+  triedgecopy(searchtri2, recenttri);
+  /* Scout the beginnings of a path from the second endpoint */
+  /*   toward the first.                                     */
+  if (scoutsegment(&searchtri2, endpoint1, newmark)) {
+    /* The segment was easily inserted. */
+    return;
+  }
+  /* The second endpoint may have changed if a collision with an intervening */
+  /*   vertex on the segment occurred.                                       */
+  org(searchtri2, endpoint2);
+
+  if (splitseg) {
+    /* Insert vertices to force the segment into the triangulation. */
+    conformingedge(endpoint1, endpoint2, newmark);
+  } else {
+    /* Insert the segment directly into the triangulation. */
+    constrainededge(&searchtri1, endpoint2, newmark);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  markhull()   Cover the convex hull of a triangulation with shell edges.  */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::markhull()
+{
+  struct triedge hulltri;
+  struct triedge nexttri;
+  struct triedge starttri;
+  triangle ptr;             /* Temporary variable used by sym() and oprev(). */
+
+  /* Find a triangle handle on the hull. */
+  hulltri.tri = dummytri;
+  hulltri.orient = 0;
+  symself(hulltri);
+  /* Remember where we started so we know when to stop. */
+  triedgecopy(hulltri, starttri);
+  /* Go once counterclockwise around the convex hull. */
+  do {
+    /* Create a shell edge if there isn't already one here. */
+    insertshelle(&hulltri, 1);
+    /* To find the next hull edge, go clockwise around the next vertex. */
+    lnextself(hulltri);
+    oprev(hulltri, nexttri);
+    while (nexttri.tri != dummytri) {
+      triedgecopy(nexttri, hulltri);
+      oprev(hulltri, nexttri);
+    }
+  } while (!triedgeequal(hulltri, starttri));
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  formskeleton()   Create the shell edges of a triangulation, including    */
+/*                   PSLG edges and edges on the convex hull.                */
+/*                                                                           */
+/*  The PSLG edges are read from a .poly file.  The return value is the      */
+/*  number of segments in the file.                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+int mesh2d::
+formskeleton(int *segmentlist, int *segmentmarkerlist, int numberofsegments)
+{
+  char polyfilename[6];
+  int index;
+  point endpoint1, endpoint2;
+  int segments;
+  int segmentmarkers;
+  int end1, end2;
+  int boundmarker;
+  int i;
+
+  if (poly) {
+    if (!quiet) {
+      printf("Inserting segments into Delaunay triangulation.\n");
+    }
+    strcpy(polyfilename, "input");
+    segments = numberofsegments;
+    segmentmarkers = segmentmarkerlist != (int *) NULL;
+    index = 0;
+    /* If segments are to be inserted, compute a mapping */
+    /*   from points to triangles.                       */
+    if (segments > 0) {
+      if (verbose) {
+        printf("  Inserting PSLG segments.\n");
+      }
+      makepointmap();
+    }
+
+    boundmarker = 0;
+    /* Read and insert the segments. */
+    for (i = 1; i <= segments; i++) {
+      end1 = segmentlist[index++];
+      end2 = segmentlist[index++];
+      if (segmentmarkers) {
+        boundmarker = segmentmarkerlist[i - 1];
+      }
+      if ((end1 < firstnumber) || (end1 >= firstnumber + inpoints)) {
+        if (!quiet) {
+          printf("Warning:  Invalid first endpoint of segment %d in %s.\n", i,
+                 polyfilename);
+        }
+      } else if ((end2 < firstnumber) || (end2 >= firstnumber + inpoints)) {
+        if (!quiet) {
+          printf("Warning:  Invalid second endpoint of segment %d in %s.\n", i,
+                 polyfilename);
+        }
+      } else {
+        endpoint1 = getpoint(end1);
+        endpoint2 = getpoint(end2);
+        if ((endpoint1[0] == endpoint2[0]) && (endpoint1[1] == endpoint2[1])) {
+          if (!quiet) {
+            printf("Warning:  Endpoints of segment %d are coincident in %s.\n",
+                   i, polyfilename);
+          }
+        } else {
+          insertsegment(endpoint1, endpoint2, boundmarker);
+        }
+      }
+    }
+  } else {
+    segments = 0;
+  }
+  if (convex || !poly) {
+    /* Enclose the convex hull with shell edges. */
+    if (verbose) {
+      printf("  Enclosing convex hull with segments.\n");
+    }
+    markhull();
+  }
+  return segments;
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Segment (shell edge) insertion ends here                  *********/
+
+/********* Carving out holes and concavities begins here             *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  infecthull()   Virally infect all of the triangles of the convex hull    */
+/*                 that are not protected by shell edges.  Where there are   */
+/*                 shell edges, set boundary markers as appropriate.         */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::infecthull()
+{
+  struct triedge hulltri;
+  struct triedge nexttri;
+  struct triedge starttri;
+  struct edge hulledge;
+  triangle **deadtri;
+  point horg, hdest;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  shelle sptr;                      /* Temporary variable used by tspivot(). */
+
+  if (verbose) {
+    printf("  Marking concavities (external triangles) for elimination.\n");
+  }
+  /* Find a triangle handle on the hull. */
+  hulltri.tri = dummytri;
+  hulltri.orient = 0;
+  symself(hulltri);
+  /* Remember where we started so we know when to stop. */
+  triedgecopy(hulltri, starttri);
+  /* Go once counterclockwise around the convex hull. */
+  do {
+    /* Ignore triangles that are already infected. */
+    if (!infected(hulltri)) {
+      /* Is the triangle protected by a shell edge? */
+      tspivot(hulltri, hulledge);
+      if (hulledge.sh == dummysh) {
+        /* The triangle is not protected; infect it. */
+        infect(hulltri);
+        deadtri = (triangle **) viri.alloc();
+        *deadtri = hulltri.tri;
+      } else {
+        /* The triangle is protected; set boundary markers if appropriate. */
+        if (mark(hulledge) == 0) {
+          setmark(hulledge, 1);
+          org(hulltri, horg);
+          dest(hulltri, hdest);
+          if (pointmark(horg) == 0) {
+            setpointmark(horg, 1);
+          }
+          if (pointmark(hdest) == 0) {
+            setpointmark(hdest, 1);
+          }
+        }
+      }
+    }
+    /* To find the next hull edge, go clockwise around the next vertex. */
+    lnextself(hulltri);
+    oprev(hulltri, nexttri);
+    while (nexttri.tri != dummytri) {
+      triedgecopy(nexttri, hulltri);
+      oprev(hulltri, nexttri);
+    }
+  } while (!triedgeequal(hulltri, starttri));
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  plague()   Spread the virus from all infected triangles to any neighbors */
+/*             not protected by shell edges.  Delete all infected triangles. */
+/*                                                                           */
+/*  This is the procedure that actually creates holes and concavities.       */
+/*                                                                           */
+/*  This procedure operates in two phases.  The first phase identifies all   */
+/*  the triangles that will die, and marks them as infected.  They are       */
+/*  marked to ensure that each triangle is added to the virus pool only      */
+/*  once, so the procedure will terminate.                                   */
+/*                                                                           */
+/*  The second phase actually eliminates the infected triangles.  It also    */
+/*  eliminates orphaned points.                                              */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::plague()
+{
+  struct triedge testtri;
+  struct triedge neighbor;
+  triangle **virusloop;
+  triangle **deadtri;
+  struct edge neighborshelle;
+  point testpoint;
+  point norg, ndest;
+  point deadorg, deaddest, deadapex;
+  int killorg;
+  triangle ptr;             /* Temporary variable used by sym() and onext(). */
+  shelle sptr;                      /* Temporary variable used by tspivot(). */
+
+  if (verbose) {
+    printf("  Marking neighbors of marked triangles.\n");
+  }
+  /* Loop through all the infected triangles, spreading the virus to */
+  /*   their neighbors, then to their neighbors' neighbors.          */
+  viri.traversalinit();
+  virusloop = (triangle **) viri.traverse();
+  while (virusloop != (triangle **) NULL) {
+    testtri.tri = *virusloop;
+    /* A triangle is marked as infected by messing with one of its shell */
+    /*   edges, setting it to an illegal value.  Hence, we have to       */
+    /*   temporarily uninfect this triangle so that we can examine its   */
+    /*   adjacent shell edges.                                           */
+    uninfect(testtri);
+    if (verbose > 2) {
+      /* Assign the triangle an orientation for convenience in */
+      /*   checking its points.                                */
+      testtri.orient = 0;
+      org(testtri, deadorg);
+      dest(testtri, deaddest);
+      apex(testtri, deadapex);
+      printf("    Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
+             deadorg[0], deadorg[1], deaddest[0], deaddest[1],
+             deadapex[0], deadapex[1]);
+    }
+    /* Check each of the triangle's three neighbors. */
+    for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
+      /* Find the neighbor. */
+      sym(testtri, neighbor);
+      /* Check for a shell between the triangle and its neighbor. */
+      tspivot(testtri, neighborshelle);
+      /* Check if the neighbor is nonexistent or already infected. */
+      if ((neighbor.tri == dummytri) || infected(neighbor)) {
+        if (neighborshelle.sh != dummysh) {
+          /* There is a shell edge separating the triangle from its */
+          /*   neighbor, but both triangles are dying, so the shell */
+          /*   edge dies too.                                       */
+          shelledealloc(neighborshelle.sh);
+          if (neighbor.tri != dummytri) {
+            /* Make sure the shell edge doesn't get deallocated again */
+            /*   later when the infected neighbor is visited.         */
+            uninfect(neighbor);
+            tsdissolve(neighbor);
+            infect(neighbor);
+          }
+        }
+      } else {                   /* The neighbor exists and is not infected. */
+        if (neighborshelle.sh == dummysh) {
+          /* There is no shell edge protecting the neighbor, so */
+          /*   the neighbor becomes infected.                   */
+          if (verbose > 2) {
+            org(neighbor, deadorg);
+            dest(neighbor, deaddest);
+            apex(neighbor, deadapex);
+            printf(
+              "    Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
+                   deadorg[0], deadorg[1], deaddest[0], deaddest[1],
+                   deadapex[0], deadapex[1]);
+          }
+          infect(neighbor);
+          /* Ensure that the neighbor's neighbors will be infected. */
+          deadtri = (triangle **) viri.alloc();
+          *deadtri = neighbor.tri;
+        } else {               /* The neighbor is protected by a shell edge. */
+          /* Remove this triangle from the shell edge. */
+          stdissolve(neighborshelle);
+          /* The shell edge becomes a boundary.  Set markers accordingly. */
+          if (mark(neighborshelle) == 0) {
+            setmark(neighborshelle, 1);
+          }
+          org(neighbor, norg);
+          dest(neighbor, ndest);
+          if (pointmark(norg) == 0) {
+            setpointmark(norg, 1);
+          }
+          if (pointmark(ndest) == 0) {
+            setpointmark(ndest, 1);
+          }
+        }
+      }
+    }
+    /* Remark the triangle as infected, so it doesn't get added to the */
+    /*   virus pool again.                                             */
+    infect(testtri);
+    virusloop = (triangle **) viri.traverse();
+  }
+
+  if (verbose) {
+    printf("  Deleting marked triangles.\n");
+  }
+  viri.traversalinit();
+  virusloop = (triangle **) viri.traverse();
+  while (virusloop != (triangle **) NULL) {
+    testtri.tri = *virusloop;
+
+    /* Check each of the three corners of the triangle for elimination. */
+    /*   This is done by walking around each point, checking if it is   */
+    /*   still connected to at least one live triangle.                 */
+    for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
+      org(testtri, testpoint);
+      /* Check if the point has already been tested. */
+      if (testpoint != (point) NULL) {
+        killorg = 1;
+        /* Mark the corner of the triangle as having been tested. */
+        setorg(testtri, NULL);
+        /* Walk counterclockwise about the point. */
+        onext(testtri, neighbor);
+        /* Stop upon reaching a boundary or the starting triangle. */
+        while ((neighbor.tri != dummytri)
+               && (!triedgeequal(neighbor, testtri))) {
+          if (infected(neighbor)) {
+            /* Mark the corner of this triangle as having been tested. */
+            setorg(neighbor, NULL);
+          } else {
+            /* A live triangle.  The point survives. */
+            killorg = 0;
+          }
+          /* Walk counterclockwise about the point. */
+          onextself(neighbor);
+        }
+        /* If we reached a boundary, we must walk clockwise as well. */
+        if (neighbor.tri == dummytri) {
+          /* Walk clockwise about the point. */
+          oprev(testtri, neighbor);
+          /* Stop upon reaching a boundary. */
+          while (neighbor.tri != dummytri) {
+            if (infected(neighbor)) {
+            /* Mark the corner of this triangle as having been tested. */
+              setorg(neighbor, NULL);
+            } else {
+              /* A live triangle.  The point survives. */
+              killorg = 0;
+            }
+            /* Walk clockwise about the point. */
+            oprevself(neighbor);
+          }
+        }
+        if (killorg) {
+          if (verbose > 1) {
+            printf("    Deleting point (%.12g, %.12g)\n",
+                   testpoint[0], testpoint[1]);
+          }
+          pointdealloc(testpoint);
+        }
+      }
+    }
+
+    /* Record changes in the number of boundary edges, and disconnect */
+    /*   dead triangles from their neighbors.                         */
+    for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
+      sym(testtri, neighbor);
+      if (neighbor.tri == dummytri) {
+        /* There is no neighboring triangle on this edge, so this edge    */
+        /*   is a boundary edge.  This triangle is being deleted, so this */
+        /*   boundary edge is deleted.                                    */
+        hullsize--;
+      } else {
+        /* Disconnect the triangle from its neighbor. */
+        dissolve(neighbor);
+        /* There is a neighboring triangle on this edge, so this edge */
+        /*   becomes a boundary edge when this triangle is deleted.   */
+        hullsize++;
+      }
+    }
+    /* Return the dead triangle to the pool of triangles. */
+    triangledealloc(testtri.tri);
+    virusloop = (triangle **) viri.traverse();
+  }
+  /* Empty the virus pool. */
+  viri.restart();
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  regionplague()   Spread regional attributes and/or area constraints      */
+/*                   (from a .poly file) throughout the mesh.                */
+/*                                                                           */
+/*  This procedure operates in two phases.  The first phase spreads an       */
+/*  attribute and/or an area constraint through a (segment-bounded) region.  */
+/*  The triangles are marked to ensure that each triangle is added to the    */
+/*  virus pool only once, so the procedure will terminate.                   */
+/*                                                                           */
+/*  The second phase uninfects all infected triangles, returning them to     */
+/*  normal.                                                                  */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::regionplague(REAL attribute, REAL area)
+{
+  struct triedge testtri;
+  struct triedge neighbor;
+  triangle **virusloop;
+  triangle **regiontri;
+  struct edge neighborshelle;
+  point regionorg, regiondest, regionapex;
+  triangle ptr;             /* Temporary variable used by sym() and onext(). */
+  shelle sptr;                      /* Temporary variable used by tspivot(). */
+
+  if (verbose > 1) {
+    printf("  Marking neighbors of marked triangles.\n");
+  }
+  /* Loop through all the infected triangles, spreading the attribute      */
+  /*   and/or area constraint to their neighbors, then to their neighbors' */
+  /*   neighbors.                                                          */
+  viri.traversalinit();
+  virusloop = (triangle **) viri.traverse();
+  while (virusloop != (triangle **) NULL) {
+    testtri.tri = *virusloop;
+    /* A triangle is marked as infected by messing with one of its shell */
+    /*   edges, setting it to an illegal value.  Hence, we have to       */
+    /*   temporarily uninfect this triangle so that we can examine its   */
+    /*   adjacent shell edges.                                           */
+    uninfect(testtri);
+    if (regionattrib) {
+      /* Set an attribute. */
+      setelemattribute(testtri, eextras, attribute);
+    }
+    if (vararea) {
+      /* Set an area constraint. */
+      setareabound(testtri, area);
+    }
+    if (verbose > 2) {
+      /* Assign the triangle an orientation for convenience in */
+      /*   checking its points.                                */
+      testtri.orient = 0;
+      org(testtri, regionorg);
+      dest(testtri, regiondest);
+      apex(testtri, regionapex);
+      printf("    Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
+             regionorg[0], regionorg[1], regiondest[0], regiondest[1],
+             regionapex[0], regionapex[1]);
+    }
+    /* Check each of the triangle's three neighbors. */
+    for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
+      /* Find the neighbor. */
+      sym(testtri, neighbor);
+      /* Check for a shell between the triangle and its neighbor. */
+      tspivot(testtri, neighborshelle);
+      /* Make sure the neighbor exists, is not already infected, and */
+      /*   isn't protected by a shell edge.                          */
+      if ((neighbor.tri != dummytri) && !infected(neighbor)
+          && (neighborshelle.sh == dummysh)) {
+        if (verbose > 2) {
+          org(neighbor, regionorg);
+          dest(neighbor, regiondest);
+          apex(neighbor, regionapex);
+          printf("    Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
+                 regionorg[0], regionorg[1], regiondest[0], regiondest[1],
+                 regionapex[0], regionapex[1]);
+        }
+        /* Infect the neighbor. */
+        infect(neighbor);
+        /* Ensure that the neighbor's neighbors will be infected. */
+        regiontri = (triangle **) viri.alloc();
+        *regiontri = neighbor.tri;
+      }
+    }
+    /* Remark the triangle as infected, so it doesn't get added to the */
+    /*   virus pool again.                                             */
+    infect(testtri);
+    virusloop = (triangle **) viri.traverse();
+  }
+
+  /* Uninfect all triangles. */
+  if (verbose > 1) {
+    printf("  Unmarking marked triangles.\n");
+  }
+  viri.traversalinit();
+  virusloop = (triangle **) viri.traverse();
+  while (virusloop != (triangle **) NULL) {
+    testtri.tri = *virusloop;
+    uninfect(testtri);
+    virusloop = (triangle **) viri.traverse();
+  }
+  /* Empty the virus pool. */
+  viri.restart();
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  carveholes()   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 mesh2d::
+carveholes(REAL *holelist, int holes, REAL *regionlist, int regions)
+{
+  struct triedge searchtri;
+  struct triedge triangleloop;
+  struct triedge *regiontris;
+  triangle **holetri;
+  triangle **regiontri;
+  point searchorg, searchdest;
+  enum locateresult intersect;
+  int i;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+  if (!(quiet || (noholes && convex))) {
+    printf("Removing unwanted triangles.\n");
+    if (verbose && (holes > 0)) {
+      printf("  Marking holes for elimination.\n");
+    }
+  }
+
+  if (regions > 0) {
+    /* Allocate storage for the triangles in which region points fall. */
+    regiontris = (struct triedge *) new struct triedge[regions];
+    if (regiontris == (struct triedge *) NULL) {
+      printf("Error:  Out of memory.\n");
+      exit(1);
+    }
+  }
+
+  if (((holes > 0) && !noholes) || !convex || (regions > 0)) {
+    /* Initialize a pool of viri to be used for holes, concavities, */
+    /*   regional attributes, and/or regional area constraints.     */
+    viri.init(sizeof(triangle *), VIRUSPERBLOCK, POINTER, 0);
+  }
+
+  if (!convex) {
+    /* Mark as infected any unprotected triangles on the boundary. */
+    /*   This is one way by which concavities are created.         */
+    infecthull();
+  }
+
+  if ((holes > 0) && !noholes) {
+    /* Infect each triangle in which a hole lies. */
+    for (i = 0; i < 2 * holes; i += 2) {
+      /* 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)) {
+        /* Start searching from some triangle on the outer boundary. */
+        searchtri.tri = dummytri;
+        searchtri.orient = 0;
+        symself(searchtri);
+        /* Ensure that the hole is to the left of this boundary edge; */
+        /*   otherwise, locate() will falsely report that the hole    */
+        /*   falls within the starting triangle.                      */
+        org(searchtri, searchorg);
+        dest(searchtri, searchdest);
+        if (counterclockwise(searchorg, searchdest, &holelist[i]) > 0.0) {
+          /* Find a triangle that contains the hole. */
+          intersect = locate(&holelist[i], &searchtri);
+          if ((intersect != OUTSIDE) && (!infected(searchtri))) {
+            /* Infect the triangle.  This is done by marking the triangle */
+            /*   as infect and including the triangle in the virus pool.  */
+            infect(searchtri);
+            holetri = (triangle **) viri.alloc();
+            *holetri = searchtri.tri;
+          }
+        }
+      }
+    }
+  }
+
+  /* Now, we have to find all the regions BEFORE we carve the holes, because */
+  /*   locate() won't work when the triangulation is no longer convex.       */
+  /*   (Incidentally, this is the reason why regional attributes and area    */
+  /*   constraints can't be used when refining a preexisting mesh, which     */
+  /*   might not be convex; they can only be used with a freshly             */
+  /*   triangulated PSLG.)                                                   */
+  if (regions > 0) {
+    /* Find the starting triangle for each region. */
+    for (i = 0; i < regions; i++) {
+      regiontris[i].tri = dummytri;
+      /* Ignore region points that aren't within the bounds of the mesh. */
+      if ((regionlist[4 * i] >= xmin) && (regionlist[4 * i] <= xmax) &&
+          (regionlist[4 * i + 1] >= ymin) && (regionlist[4 * i + 1] <= ymax)) {
+        /* Start searching from some triangle on the outer boundary. */
+        searchtri.tri = dummytri;
+        searchtri.orient = 0;
+        symself(searchtri);
+        /* Ensure that the region point is to the left of this boundary */
+        /*   edge; otherwise, locate() will falsely report that the     */
+        /*   region point falls within the starting triangle.           */
+        org(searchtri, searchorg);
+        dest(searchtri, searchdest);
+        if (counterclockwise(searchorg, searchdest, &regionlist[4 * i]) >
+            0.0) {
+          /* Find a triangle that contains the region point. */
+          intersect = locate(&regionlist[4 * i], &searchtri);
+          if ((intersect != OUTSIDE) && (!infected(searchtri))) {
+            /* Record the triangle for processing after the */
+            /*   holes have been carved.                    */
+            triedgecopy(searchtri, regiontris[i]);
+          }
+        }
+      }
+    }
+  }
+
+  if (viri.items > 0) {
+    /* Carve the holes and concavities. */
+    plague();
+  }
+  /* The virus pool should be empty now. */
+
+  if (regions > 0) {
+    if (!quiet) {
+      if (regionattrib) {
+        if (vararea) {
+          printf("Spreading regional attributes and area constraints.\n");
+        } else {
+          printf("Spreading regional attributes.\n");
+        }
+      } else { 
+        printf("Spreading regional area constraints.\n");
+      }
+    }
+    if (regionattrib && !refine) {
+      /* Assign every triangle a regional attribute of zero. */
+      triangles.traversalinit();
+      triangleloop.orient = 0;
+      triangleloop.tri = triangletraverse();
+      while (triangleloop.tri != (triangle *) NULL) {
+        setelemattribute(triangleloop, eextras, 0.0);
+        triangleloop.tri = triangletraverse();
+      }
+    }
+    for (i = 0; i < regions; i++) {
+      if (regiontris[i].tri != dummytri) {
+        /* Make sure the triangle under consideration still exists. */
+        /*   It may have been eaten by the virus.                   */
+        if (regiontris[i].tri[3] != (triangle) NULL) {
+          /* Put one triangle in the virus pool. */
+          infect(regiontris[i]);
+          regiontri = (triangle **) viri.alloc();
+          *regiontri = regiontris[i].tri;
+          /* Apply one region's attribute and/or area constraint. */
+          regionplague(regionlist[4 * i + 2], regionlist[4 * i + 3]);
+          /* The virus pool should be empty now. */
+        }
+      }
+    }
+    if (regionattrib && !refine) {
+      /* Note the fact that each triangle has an additional attribute. */
+      eextras++;
+    }
+  }
+
+  /* Free up memory. */
+  if (((holes > 0) && !noholes) || !convex || (regions > 0)) {
+    viri.deinit();
+  }
+  if (regions > 0) {
+    delete [] regiontris;
+  }
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Carving out holes and concavities ends here               *********/
+
+/********* I/O routines begin here                                   *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  transfernodes()   Read the points from memory.                           */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::transfernodes(REAL *pointlist, REAL *pointattriblist,
+                           int *pointmarkerlist, int numberofpoints,
+                           int numberofpointattribs)
+{
+  point pointloop;
+  REAL x, y;
+  int i, j;
+  int coordindex;
+  int attribindex;
+
+  inpoints = numberofpoints;
+  mesh_dim = 2;
+  nextras = numberofpointattribs;
+  readnodefile = 0;
+  if (inpoints < 3) {
+    printf("Error:  Input must have at least three input points.\n");
+    exit(1);
+  }
+
+  if (!restartsymbol) {
+    initializepointpool();
+  }
+
+  /* Read the points. */
+  coordindex = 0;
+  attribindex = 0;
+  for (i = 0; i < inpoints; i++) {
+    pointloop = (point) points.alloc();
+    /* Read the point coordinates. */
+    x = pointloop[0] = pointlist[coordindex++];
+    y = pointloop[1] = pointlist[coordindex++];
+    /* Read the point attributes. */
+    for (j = 0; j < numberofpointattribs; j++) {
+      pointloop[2 + j] = pointattriblist[attribindex++];
+    }
+    if (pointmarkerlist != (int *) NULL) {
+      /* Read a point marker. */
+      setpointmark(pointloop, pointmarkerlist[i]);
+    } else {
+      /* If no markers are specified, they default to zero. */
+      setpointmark(pointloop, 0);
+    }
+    x = pointloop[0];
+    y = pointloop[1];
+    /* Determine the smallest and largest x and y coordinates. */
+    if (i == 0) {
+      xmin = xmax = x;
+      ymin = ymax = y;
+    } else {
+      xmin = (x < xmin) ? x : xmin;
+      xmax = (x > xmax) ? x : xmax;
+      ymin = (y < ymin) ? y : ymin;
+      ymax = (y > ymax) ? y : ymax;
+    }
+  }
+
+  /* Nonexistent x value used as a flag to mark circle events in sweepline */
+  /*   Delaunay algorithm.                                                 */
+  xminextreme = 10 * xmin - 9 * xmax;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  writenodes()   Number the points and write them to a .node file.         */
+/*                                                                           */
+/*  To save memory, the point numbers are written over the shell markers     */
+/*  after the points are written to a file.                                  */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::
+writenodes(REAL **pointlist, REAL **pointattriblist, int **pointmarkerlist)
+{
+  REAL *plist;
+  REAL *palist;
+  int *pmlist;
+  int coordindex;
+  int attribindex;
+  point pointloop;
+  int pointnumber;
+  int i;
+
+  if (!quiet) {
+    printf("Writing points.\n");
+  }
+  /* Allocate memory for output points if necessary. */
+  if (*pointlist == (REAL *) NULL) {
+    *pointlist = (REAL *) new REAL[points.items * 2];
+    if (*pointlist == (REAL *) NULL) {
+      printf("Error:  Out of memory.\n");
+      exit(1);
+    }
+  }
+  /* Allocate memory for output point attributes if necessary. */
+  if ((nextras > 0) && (*pointattriblist == (REAL *) NULL)) {
+    *pointattriblist = (REAL *) new REAL[points.items * nextras];
+    if (*pointattriblist == (REAL *) NULL) {
+      printf("Error:  Out of memory.\n");
+      exit(1);
+    }
+  }
+  /* Allocate memory for output point markers if necessary. */
+  if (!nobound && (*pointmarkerlist == (int *) NULL)) {
+    *pointmarkerlist = (int *) new int[points.items];
+    if (*pointmarkerlist == (int *) NULL) {
+      printf("Error:  Out of memory.\n");
+      exit(1);
+    }
+  }
+  plist = *pointlist;
+  palist = *pointattriblist;
+  pmlist = *pointmarkerlist;
+  coordindex = 0;
+  attribindex = 0;
+
+  points.traversalinit();
+  pointloop = pointtraverse();
+  pointnumber = firstnumber;
+  while (pointloop != (point) NULL) {
+    /* X and y coordinates. */
+    plist[coordindex++] = pointloop[0];
+    plist[coordindex++] = pointloop[1];
+    /* Point attributes. */
+    for (i = 0; i < nextras; i++) {
+      palist[attribindex++] = pointloop[2 + i];
+    }
+    if (!nobound) {
+      /* Copy the boundary marker. */
+      pmlist[pointnumber - firstnumber] = pointmark(pointloop);
+    }
+
+    setpointmark(pointloop, pointnumber);
+    pointloop = pointtraverse();
+    pointnumber++;
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  numbernodes()   Number the points.                                       */
+/*                                                                           */
+/*  Each point is assigned a marker equal to its number.                     */
+/*                                                                           */
+/*  Used when writenodes() is not called because no .node file is written.   */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::numbernodes()
+{
+  point pointloop;
+  int pointnumber;
+
+  points.traversalinit();
+  pointloop = pointtraverse();
+  pointnumber = firstnumber;
+  while (pointloop != (point) NULL) {
+    setpointmark(pointloop, pointnumber);
+    pointloop = pointtraverse();
+    pointnumber++;
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  writeelements()   Write the triangles to an .ele file.                   */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::writeelements(int **trianglelist, REAL **triangleattriblist)
+{
+  int *tlist;
+  REAL *talist;
+  int pointindex;
+  int attribindex;
+  struct triedge triangleloop;
+  point p1, p2, p3;
+  point mid1, mid2, mid3;
+  int elementnumber;
+  int i;
+
+  if (!quiet) {
+    printf("Writing triangles.\n");
+  }
+  /* Allocate memory for output triangles if necessary. */
+  if (*trianglelist == (int *) NULL) {
+    *trianglelist = (int *) new int[triangles.items *
+                               ((order + 1) * (order + 2) / 2)];
+    if (*trianglelist == (int *) NULL) {
+      printf("Error:  Out of memory.\n");
+      exit(1);
+    }
+  }
+  /* Allocate memory for output triangle attributes if necessary. */
+  if ((eextras > 0) && (*triangleattriblist == (REAL *) NULL)) {
+    *triangleattriblist = (REAL *) new REAL[triangles.items * eextras];
+    if (*triangleattriblist == (REAL *) NULL) {
+      printf("Error:  Out of memory.\n");
+      exit(1);
+    }
+  }
+  tlist = *trianglelist;
+  talist = *triangleattriblist;
+  pointindex = 0;
+  attribindex = 0;
+
+  triangles.traversalinit();
+  triangleloop.tri = triangletraverse();
+  triangleloop.orient = 0;
+  elementnumber = firstnumber;
+  while (triangleloop.tri != (triangle *) NULL) {
+    org(triangleloop, p1);
+    dest(triangleloop, p2);
+    apex(triangleloop, p3);
+    if (order == 1) {
+      tlist[pointindex++] = pointmark(p1);
+      tlist[pointindex++] = pointmark(p2);
+      tlist[pointindex++] = pointmark(p3);
+    } else {
+      mid1 = (point) triangleloop.tri[highorderindex + 1];
+      mid2 = (point) triangleloop.tri[highorderindex + 2];
+      mid3 = (point) triangleloop.tri[highorderindex];
+      tlist[pointindex++] = pointmark(p1);
+      tlist[pointindex++] = pointmark(p2);
+      tlist[pointindex++] = pointmark(p3);
+      tlist[pointindex++] = pointmark(mid1);
+      tlist[pointindex++] = pointmark(mid2);
+      tlist[pointindex++] = pointmark(mid3);
+    }
+
+    for (i = 0; i < eextras; i++) {
+      talist[attribindex++] = elemattribute(triangleloop, i);
+    }
+
+    triangleloop.tri = triangletraverse();
+    elementnumber++;
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  writepoly()   Write the segments and holes to a .poly file.              */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::writepoly(int **segmentlist, int **segmentmarkerlist)
+{
+  int *slist;
+  int *smlist;
+  int index;
+  struct edge shelleloop;
+  point endpoint1, endpoint2;
+  int shellenumber;
+
+  if (!quiet) {
+    printf("Writing segments.\n");
+  }
+  /* Allocate memory for output segments if necessary. */
+  if (*segmentlist == (int *) NULL) {
+    *segmentlist = (int *) new int[shelles.items * 2];
+    if (*segmentlist == (int *) NULL) {
+      printf("Error:  Out of memory.\n");
+      exit(1);
+    }
+  }
+  /* Allocate memory for output segment markers if necessary. */
+  if (!nobound && (*segmentmarkerlist == (int *) NULL)) {
+    *segmentmarkerlist = (int *) new int[shelles.items];
+    if (*segmentmarkerlist == (int *) NULL) {
+      printf("Error:  Out of memory.\n");
+      exit(1);
+    }
+  }
+  slist = *segmentlist;
+  smlist = *segmentmarkerlist;
+  index = 0;
+
+  shelles.traversalinit();
+  shelleloop.sh = shelletraverse();
+  shelleloop.shorient = 0;
+  shellenumber = firstnumber;
+  while (shelleloop.sh != (shelle *) NULL) {
+    sorg(shelleloop, endpoint1);
+    sdest(shelleloop, endpoint2);
+    /* Copy indices of the segment's two endpoints. */
+    slist[index++] = pointmark(endpoint1);
+    slist[index++] = pointmark(endpoint2);
+    if (!nobound) {
+      /* Copy the boundary marker. */
+      smlist[shellenumber - firstnumber] = mark(shelleloop);
+    }
+
+    shelleloop.sh = shelletraverse();
+    shellenumber++;
+  }
+}
+
+void mesh2d::writeedges(int **edgelist, int **edgemarkerlist)
+{
+  int *elist;
+  int *emlist;
+  int index;
+  struct triedge triangleloop, trisym;
+  struct edge checkmark;
+  point p1, p2;
+  int edgenumber;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  shelle sptr;                      /* Temporary variable used by tspivot(). */
+
+  if (!quiet) {
+    printf("Writing edges.\n");
+  }
+  /* Allocate memory for edges if necessary. */
+  if (*edgelist == (int *) NULL) {
+    *edgelist = (int *) new int[edges * 2];
+    if (*edgelist == (int *) NULL) {
+      printf("Error:  Out of memory.\n");
+      exit(1);
+    }
+  }
+  /* Allocate memory for edge markers if necessary. */
+  if (!nobound && (*edgemarkerlist == (int *) NULL)) {
+    *edgemarkerlist = (int *) new int[edges];
+    if (*edgemarkerlist == (int *) NULL) {
+      printf("Error:  Out of memory.\n");
+      exit(1);
+    }
+  }
+  elist = *edgelist;
+  emlist = *edgemarkerlist;
+  index = 0;
+
+  triangles.traversalinit();
+  triangleloop.tri = triangletraverse();
+  edgenumber = firstnumber;
+  /* To loop over the set of edges, loop over all triangles, and look at   */
+  /*   the three edges of each triangle.  If there isn't another triangle  */
+  /*   adjacent to the edge, operate on the edge.  If there is another     */
+  /*   adjacent triangle, operate on the edge only if the current triangle */
+  /*   has a smaller pointer than its neighbor.  This way, each edge is    */
+  /*   considered only once.                                               */
+  while (triangleloop.tri != (triangle *) NULL) {
+    for (triangleloop.orient = 0; triangleloop.orient < 3;
+         triangleloop.orient++) {
+      sym(triangleloop, trisym);
+      if ((triangleloop.tri < trisym.tri) || (trisym.tri == dummytri)) {
+        org(triangleloop, p1);
+        dest(triangleloop, p2);
+        elist[index++] = pointmark(p1);
+        elist[index++] = pointmark(p2);
+        if (nobound) {
+        } else {
+          /* Edge number, indices of two endpoints, and a boundary marker. */
+          /*   If there's no shell edge, the boundary marker is zero.      */
+          if (useshelles) {
+            tspivot(triangleloop, checkmark);
+            if (checkmark.sh == dummysh) {
+              emlist[edgenumber - firstnumber] = 0;
+            } else {
+              emlist[edgenumber - firstnumber] = mark(checkmark);
+            }
+          } else {
+            emlist[edgenumber - firstnumber] = trisym.tri == dummytri;
+          }
+        }
+        edgenumber++;
+      }
+    }
+    triangleloop.tri = triangletraverse();
+  }
+}
+
+void mesh2d::writeneighbors(int **neighborlist)
+{
+  int *nlist;
+  int index;
+  struct triedge triangleloop, trisym;
+  int elementnumber;
+  int neighbor1, neighbor2, neighbor3;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+  if (!quiet) {
+    printf("Writing neighbors.\n");
+  }
+  /* Allocate memory for neighbors if necessary. */
+  if (*neighborlist == (int *) NULL) {
+    *neighborlist = (int *) new int[triangles.items * 3];
+    if (*neighborlist == (int *) NULL) {
+      printf("Error:  Out of memory.\n");
+      exit(1);
+    }
+  }
+  nlist = *neighborlist;
+  index = 0;
+
+  triangles.traversalinit();
+  triangleloop.tri = triangletraverse();
+  triangleloop.orient = 0;
+  elementnumber = firstnumber;
+  while (triangleloop.tri != (triangle *) NULL) {
+    * (int *) (triangleloop.tri + 6) = elementnumber;
+    triangleloop.tri = triangletraverse();
+    elementnumber++;
+  }
+  * (int *) (dummytri + 6) = -1;
+
+  triangles.traversalinit();
+  triangleloop.tri = triangletraverse();
+  elementnumber = firstnumber;
+  while (triangleloop.tri != (triangle *) NULL) {
+    triangleloop.orient = 1;
+    sym(triangleloop, trisym);
+    neighbor1 = * (int *) (trisym.tri + 6);
+    triangleloop.orient = 2;
+    sym(triangleloop, trisym);
+    neighbor2 = * (int *) (trisym.tri + 6);
+    triangleloop.orient = 0;
+    sym(triangleloop, trisym);
+    neighbor3 = * (int *) (trisym.tri + 6);
+    nlist[index++] = neighbor1;
+    nlist[index++] = neighbor2;
+    nlist[index++] = neighbor3;
+
+    triangleloop.tri = triangletraverse();
+    elementnumber++;
+  }
+}
+
+void mesh2d::writegid(int trilibrary)
+{
+  FILE *outfile;
+  point pointloop;
+  char gidfilename[FILENAMESIZE];
+  int pointnumber;
+  int i;
+
+  if (trilibrary) {
+    sprintf(gidfilename, "tmpmesh.gid");
+  }
+
+  if (!quiet) {
+    printf("Writing %s.\n", gidfilename);
+  }
+  outfile = fopen(gidfilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("  Error:  Cannot create file %s.\n", gidfilename);
+    return;
+  }
+
+  fprintf(outfile, "mesh dimension = 2 elemtype triangle nnode = 3\n");
+  fprintf(outfile, "coordinates\n");
+
+  points.traversalinit();
+  pointloop = pointtraverse();
+  pointnumber = firstnumber;
+  while (pointloop != (point) NULL) {
+    // Point number, x and y coordinates.
+    if (firstnumber == 0) {
+      // Gid need start index from one.
+      fprintf(outfile, "%4d    %.17g  %.17g", pointnumber + 1, pointloop[0],
+              pointloop[1]);
+    } else {
+      fprintf(outfile, "%4d    %.17g  %.17g", pointnumber, pointloop[0],
+              pointloop[1]);
+    }
+    for (i = 0; i < nextras; i++) {
+      // Write an attribute.
+      fprintf(outfile, "  %.17g", pointloop[i + 2]);
+    }
+    fprintf(outfile, "\n");
+    setpointmark(pointloop, pointnumber);
+    pointloop = pointtraverse();
+    pointnumber++;
+  }
+
+  fprintf(outfile, "end coordinates\n");
+
+  struct triedge triangleloop;
+  point p1, p2, p3;
+  int elementnumber;
+
+  fprintf(outfile, "elements\n");
+
+  triangles.traversalinit();
+  triangleloop.tri = triangletraverse();
+  triangleloop.orient = 0;
+  elementnumber = 1;
+  while (triangleloop.tri != (triangle *) NULL) {
+    org(triangleloop, p1);
+    dest(triangleloop, p2);
+    apex(triangleloop, p3);
+    // Triangle number, indices for three points.
+    if (firstnumber == 0) {
+      // Gid need start index from one.
+      fprintf(outfile, "%4d    %4d  %4d  %4d", elementnumber,
+              pointmark(p1)+1, pointmark(p2)+1, pointmark(p3)+1);
+    } else {
+      fprintf(outfile, "%4d    %4d  %4d  %4d", elementnumber,
+              pointmark(p1), pointmark(p2), pointmark(p3));
+    }
+
+    for (i = 0; i < eextras; i++) {
+      fprintf(outfile, "  %.17g", elemattribute(triangleloop, i));
+    }
+    fprintf(outfile, "\n");
+
+    triangleloop.tri = triangletraverse();
+    elementnumber++;
+  }
+
+  fprintf(outfile, "end elements\n");
+  fclose(outfile);
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* I/O routines end here                                     *********/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  main() or triangulate()   Gosh, do everything.                           */
+/*                                                                           */
+/*  The sequence is roughly as follows.  Many of these steps can be skipped, */
+/*  depending on the command line switches.                                  */
+/*                                                                           */
+/*  - Initialize constants and parse the command line.                       */
+/*  - Read the points from a file and either                                 */
+/*    - triangulate them (no -r), or                                         */
+/*    - read an old mesh from files and reconstruct it (-r).                 */
+/*  - Insert the PSLG segments (-p), and possibly segments on the convex     */
+/*      hull (-c).                                                           */
+/*  - Read the holes (-p), regional attributes (-pA), and regional area      */
+/*      constraints (-pa).  Carve the holes and concavities, and spread the  */
+/*      regional attributes and area constraints.                            */
+/*  - Enforce the constraints on minimum angle (-q) and maximum area (-a).   */
+/*      Also enforce the conforming Delaunay property (-q and -a).           */
+/*  - Compute the number of edges in the resulting mesh.                     */
+/*  - Promote the mesh's linear triangles to higher order elements (-o).     */
+/*  - Write the output files and print the statistics.                       */
+/*  - Check the consistency and Delaunay property of the mesh (-C).          */
+/*                                                                           */
+/*****************************************************************************/
+
+void mesh2d::triangulate(struct triangulateio *in, struct triangulateio *out,
+                         struct triangulateio *vorout)
+{
+  REAL *holearray;                                        /* Array of holes. */
+  REAL *regionarray;   /* Array of regional attributes and area constraints. */
+
+  transfernodes(in->pointlist, in->pointattributelist, in->pointmarkerlist,
+                in->numberofpoints, in->numberofpointattributes);
+
+  hullsize = delaunay();                        /* Triangulate the points. */
+
+  /* Ensure that no point can be mistaken for a triangular bounding */
+  /*   box point in insertsite().                                   */
+  infpoint1 = (point) NULL;
+  infpoint2 = (point) NULL;
+  infpoint3 = (point) NULL;
+
+  if (useshelles) {
+    checksegments = 1;                  /* Segments will be introduced next. */
+    if (!refine) {
+      /* Insert PSLG segments and/or convex hull segments. */
+      insegments = formskeleton(in->segmentlist, in->segmentmarkerlist,
+                                in->numberofsegments);
+    }
+  }
+
+  if (poly) {
+    holearray = in->holelist;
+    holes = in->numberofholes;
+    regionarray = in->regionlist;
+    regions = in->numberofregions;
+    if (!refine) {
+      /* Carve out holes and concavities. */
+      carveholes(holearray, holes, regionarray, regions);
+    }
+  } else {
+    /* Without a PSLG, there can be no holes or regional attributes   */
+    /*   or area constraints.  The following are set to zero to avoid */
+    /*   an accidental free() later.                                  */
+    holes = 0;
+    regions = 0;
+  }
+
+  /* Compute the number of edges. */
+  edges = (3l * triangles.items + hullsize) / 2l;
+
+  if (!quiet) {
+    printf("\n");
+  }
+
+  if (out) {
+    out->numberofpoints = points.items;
+    out->numberofpointattributes = nextras;
+    out->numberoftriangles = triangles.items;
+    out->numberofcorners = (order + 1) * (order + 2) / 2;
+    out->numberoftriangleattributes = eextras;
+    out->numberofedges = edges;
+    if (useshelles) {
+      out->numberofsegments = shelles.items;
+    } else {
+      out->numberofsegments = hullsize;
+    }
+  }
+  if (vorout != (struct triangulateio *) NULL) {
+    vorout->numberofpoints = triangles.items;
+    vorout->numberofpointattributes = nextras;
+    vorout->numberofedges = edges;
+  }
+  if (out) {
+    /* If not using iteration numbers, don't write a .node file if one was */
+    /*   read, because the original one would be overwritten!              */
+    if (nonodewritten || (noiterationnum && readnodefile)) {
+      if (!quiet) {
+        printf("NOT writing points.\n");
+      }
+      numbernodes();             /* We must remember to number the points. */
+    } else {
+      writenodes(&out->pointlist, &out->pointattributelist,
+                 &out->pointmarkerlist);
+    }
+    if (noelewritten) {
+      if (!quiet) {
+        printf("NOT writing triangles.\n");
+      }
+    } else {
+      writeelements(&out->trianglelist, &out->triangleattributelist);
+    }
+    /* The -c switch (convex switch) causes a PSLG to be written */
+    /*   even if none was read.                                  */
+    if (poly || convex) {
+      /* If not using iteration numbers, don't overwrite the .poly file. */
+      if (nopolywritten || noiterationnum) {
+        if (!quiet) {
+          printf("NOT writing segments.\n");
+        }
+      } else {
+        writepoly(&out->segmentlist, &out->segmentmarkerlist);
+        out->numberofholes = holes;
+        out->numberofregions = regions;
+        if (poly) {
+          if (holes > 0) {
+            out->holelist = new REAL[holes * 2];
+            memcpy(out->holelist, in->holelist, holes * 2* sizeof(REAL));
+          }
+		      if (regions > 0) {
+		        out->regionlist = new REAL[regions * 4];
+		        memcpy(out->regionlist, in->regionlist, regions * 4 * sizeof(REAL));
+		      }
+        } else {
+          out->holelist = (REAL *) NULL;
+          out->regionlist = (REAL *) NULL;
+        }
+      }
+    }
+    if (edgesout) {
+      writeedges(&out->edgelist, &out->edgemarkerlist);
+    }
+    if (neighbors) {
+      writeneighbors(&out->neighborlist);
+    }
+  }
+  if (geomview) {
+    writegid(1);
+  }
+}
diff --git a/Tetgen/trilib.h b/Tetgen/trilib.h
new file mode 100644
index 0000000000..f873e4c155
--- /dev/null
+++ b/Tetgen/trilib.h
@@ -0,0 +1,515 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// trilib.h    Declaration class mesh2d for two-dimensional mesh generator.  //
+//                                                                           //
+// Tetgen Version 1.0 beta                                                   //
+// July, 2001                                                                //
+//                                                                           //
+// Si hang                                                                   //
+// Email: sihang@weboo.com                                                   //
+// http://www.weboo.com/sh/tetgen.htm                                        //
+//                                                                           //
+// You are free to use, copy and modify the sources under certain            //
+// circumstances, provided this copyright notice remains intact.             //
+// See the file LICENSE for details.                                         //
+//                                                                           //
+// This file with it's couple file trilib.cpp are modified version of the    //
+// triangle program of Jonathan Richard Shewchuk, which is public available  //
+// from the following Web page with its license(see below):                  //
+//                                                                           //
+//             http://www.cs.cmu.edu/~quake/triangle.html                    //
+//                                                                           //
+// In Tetgen, there frequently need to generate a constrained Delaunay       //
+// triangulation of a given facet. For example, in facet recovery stage, for //
+// each facet, it is necessary maintain a two-dimensional Delaunay triangul- //
+// ation of its vertices, independent from the tetrahedralization in which   //
+// we hope its subfaces will eventually appear. For each triangular subface  //
+// in a facet triangulation, look for a matching face in the tetrahedraliza- //
+// tion.                                                                     //
+//                                                                           //
+// For this purpose, I embeded an object of two-dimensional Delaunay triang- //
+// ulator as member variable of class mesh3d(declared in tetlib.h). The type //
+// (class mesh2d) of this object is declared in this file, it encapsulates   //
+// most of the variables and functions of triangle program.                  //
+//                                                                           //
+// The usage of class mesh2d is very simple. To call mesh2d in functions,    //
+// use the triangulateio structure(defined below). You only write following  //
+// lines in functions:                                                       //
+//                                                                           //
+//      mesh2d mymesh;                                                       //
+//      struct triangulateio in, out;                                        //
+//      char switches[] = "pznQXPN";  // Commandline switches.               //
+//                                                                           //
+//      // Initialize 'in' and 'out'                                         //
+//      triangulateioinit(&in);                                              //
+//      triangulateioinit(&out);                                             //
+//                                                                           //
+//      // Set input PSLG data to 'in'                                       //
+//      ...                                                                  //
+//                                                                           //
+//      // Do mesh, the corresponding result will store in 'out'             //
+//      mymesh(switches, &in, &out, NULL);                                   //
+//                                                                           //
+//      ...                                                                  //
+//                                                                           //
+//      // Before return, don't forget to free 'in' and 'out'                //
+//      triangulateiodeinit(&in);                                            //
+//      triangulateiodeinit(&out);                                           //
+//                                                                           //
+// Please see the above Web page to get more detail descripton of command    //
+// line switches.                                                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+/*****************************************************************************/
+/*                                                                           */
+/*  Traingle program license:                                                */
+/*                                                                           */
+/*  Triangle                                                                 */
+/*  A Two-Dimensional Quality Mesh Generator                                 */
+/*  and Delaunay Triangulator.                                               */
+/*  Version 1.3                                                              */
+/*                                                                           */
+/*  Copyright 1996                                                           */
+/*  Jonathan Richard Shewchuk                                                */
+/*  School of Computer Science                                               */
+/*  Carnegie Mellon University                                               */
+/*  5000 Forbes Avenue                                                       */
+/*  Pittsburgh, Pennsylvania  15213-3891                                     */
+/*  jrs@cs.cmu.edu                                                           */
+/*                                                                           */
+/*  This program may be freely redistributed under the condition that the    */
+/*    copyright notices (including this entire header and the copyright      */
+/*    notice printed when the `-h' switch is selected) are not removed, and  */
+/*    no compensation is received.  Private, research, and institutional     */
+/*    use is free.  You may distribute modified versions of this code UNDER  */
+/*    THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE   */
+/*    SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE   */
+/*    AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR    */
+/*    NOTICE IS GIVEN OF THE MODIFICATIONS.  Distribution of this code as    */
+/*    part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT  */
+/*    WITH THE AUTHOR.  (If you are not directly supplying this code to a    */
+/*    customer, and you are instead telling them how they can obtain it for  */
+/*    free, then you are not required to make any arrangement with me.)      */
+/*                                                                           */
+/*  Disclaimer:  Neither I nor Carnegie Mellon warrant this code in any way  */
+/*    whatsoever.  This code is provided "as-is".  Use at your own risk.     */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef trilibH
+#define trilibH
+
+#include "defines.h"
+#include "linklist.h"
+
+/*****************************************************************************/
+/*                                                                           */
+/*  The `triangulateio' structure.                                           */
+/*                                                                           */
+/*  Used to pass data into and out of the triangulate() procedure.           */
+/*                                                                           */
+/*                                                                           */
+/*  Arrays are used to store points, triangles, markers, and so forth.  In   */
+/*  all cases, the first item in any array is stored starting at index [0].  */
+/*  However, that item is item number `1' unless the `z' switch is used, in  */
+/*  which case it is item number `0'.  Hence, you may find it easier to      */
+/*  index points (and triangles in the neighbor list) if you use the `z'     */
+/*  switch.  Unless, of course, you're calling Triangle from a Fortran       */
+/*  program.                                                                 */
+/*                                                                           */
+/*  Description of fields (except the `numberof' fields, which are obvious): */
+/*                                                                           */
+/*  `pointlist':  An array of point coordinates.  The first point's x        */
+/*    coordinate is at index [0] and its y coordinate at index [1], followed */
+/*    by the coordinates of the remaining points.  Each point occupies two   */
+/*    REALs.                                                                 */
+/*  `pointattributelist':  An array of point attributes.  Each point's       */
+/*    attributes occupy `numberofpointattributes' REALs.                     */
+/*  `pointmarkerlist':  An array of point markers; one int per point.        */
+/*                                                                           */
+/*  `trianglelist':  An array of triangle corners.  The first triangle's     */
+/*    first corner is at index [0], followed by its other two corners in     */
+/*    counterclockwise order, followed by any other nodes if the triangle    */
+/*    represents a nonlinear element.  Each triangle occupies                */
+/*    `numberofcorners' ints.                                                */
+/*  `triangleattributelist':  An array of triangle attributes.  Each         */
+/*    triangle's attributes occupy `numberoftriangleattributes' REALs.       */
+/*  `trianglearealist':  An array of triangle area constraints; one REAL per */
+/*    triangle.  Input only.                                                 */
+/*  `neighborlist':  An array of triangle neighbors; three ints per          */
+/*    triangle.  Output only.                                                */
+/*                                                                           */
+/*  `segmentlist':  An array of segment endpoints.  The first segment's      */
+/*    endpoints are at indices [0] and [1], followed by the remaining        */
+/*    segments.  Two ints per segment.                                       */
+/*  `segmentmarkerlist':  An array of segment markers; one int per segment.  */
+/*                                                                           */
+/*  `holelist':  An array of holes.  The first hole's x and y coordinates    */
+/*    are at indices [0] and [1], followed by the remaining holes.  Two      */
+/*    REALs per hole.  Input only, although the pointer is copied to the     */
+/*    output structure for your convenience.                                 */
+/*                                                                           */
+/*  `regionlist':  An array of regional attributes and area constraints.     */
+/*    The first constraint's x and y coordinates are at indices [0] and [1], */
+/*    followed by the regional attribute and index [2], followed by the      */
+/*    maximum area at index [3], followed by the remaining area constraints. */
+/*    Four REALs per area constraint.  Note that each regional attribute is  */
+/*    used only if you select the `A' switch, and each area constraint is    */
+/*    used only if you select the `a' switch (with no number following), but */
+/*    omitting one of these switches does not change the memory layout.      */
+/*    Input only, although the pointer is copied to the output structure for */
+/*    your convenience.                                                      */
+/*                                                                           */
+/*  `edgelist':  An array of edge endpoints.  The first edge's endpoints are */
+/*    at indices [0] and [1], followed by the remaining edges.  Two ints per */
+/*    edge.  Output only.                                                    */
+/*  `edgemarkerlist':  An array of edge markers; one int per edge.  Output   */
+/*    only.                                                                  */
+/*  `normlist':  An array of normal vectors, used for infinite rays in       */
+/*    Voronoi diagrams.  The first normal vector's x and y magnitudes are    */
+/*    at indices [0] and [1], followed by the remaining vectors.  For each   */
+/*    finite edge in a Voronoi diagram, the normal vector written is the     */
+/*    zero vector.  Two REALs per edge.  Output only.                        */
+/*                                                                           */
+/*                                                                           */
+/*  Any input fields that Triangle will examine must be initialized.         */
+/*  Furthermore, for each output array that Triangle will write to, you      */
+/*  must either provide space by setting the appropriate pointer to point    */
+/*  to the space you want the data written to, or you must initialize the    */
+/*  pointer to NULL, which tells Triangle to allocate space for the results. */
+/*  The latter option is preferable, because Triangle always knows exactly   */
+/*  how much space to allocate.  The former option is provided mainly for    */
+/*  people who need to call Triangle from Fortran code, though it also makes */
+/*  possible some nasty space-saving tricks, like writing the output to the  */
+/*  same arrays as the input.                                                */
+/*                                                                           */
+/*  Triangle will not free() any input or output arrays, including those it  */
+/*  allocates itself; that's up to you.                                      */
+/*                                                                           */
+/*  Here's a guide to help you decide which fields you must initialize       */
+/*  before you call triangulate().                                           */
+/*                                                                           */
+/*  `in':                                                                    */
+/*                                                                           */
+/*    - `pointlist' must always point to a list of points; `numberofpoints'  */
+/*      and `numberofpointattributes' must be properly set.                  */
+/*      `pointmarkerlist' must either be set to NULL (in which case all      */
+/*      markers default to zero), or must point to a list of markers.  If    */
+/*      `numberofpointattributes' is not zero, `pointattributelist' must     */
+/*      point to a list of point attributes.                                 */
+/*    - If the `r' switch is used, `trianglelist' must point to a list of    */
+/*      triangles, and `numberoftriangles', `numberofcorners', and           */
+/*      `numberoftriangleattributes' must be properly set.  If               */
+/*      `numberoftriangleattributes' is not zero, `triangleattributelist'    */
+/*      must point to a list of triangle attributes.  If the `a' switch is   */
+/*      used (with no number following), `trianglearealist' must point to a  */
+/*      list of triangle area constraints.  `neighborlist' may be ignored.   */
+/*    - If the `p' switch is used, `segmentlist' must point to a list of     */
+/*      segments, `numberofsegments' must be properly set, and               */
+/*      `segmentmarkerlist' must either be set to NULL (in which case all    */
+/*      markers default to zero), or must point to a list of markers.        */
+/*    - If the `p' switch is used without the `r' switch, then               */
+/*      `numberofholes' and `numberofregions' must be properly set.  If      */
+/*      `numberofholes' is not zero, `holelist' must point to a list of      */
+/*      holes.  If `numberofregions' is not zero, `regionlist' must point to */
+/*      a list of region constraints.                                        */
+/*    - If the `p' switch is used, `holelist', `numberofholes',              */
+/*      `regionlist', and `numberofregions' is copied to `out'.  (You can    */
+/*      nonetheless get away with not initializing them if the `r' switch is */
+/*      used.)                                                               */
+/*    - `edgelist', `edgemarkerlist', `normlist', and `numberofedges' may be */
+/*      ignored.                                                             */
+/*                                                                           */
+/*  `out':                                                                   */
+/*                                                                           */
+/*    - `pointlist' must be initialized (NULL or pointing to memory) unless  */
+/*      the `N' switch is used.  `pointmarkerlist' must be initialized       */
+/*      unless the `N' or `B' switch is used.  If `N' is not used and        */
+/*      `in->numberofpointattributes' is not zero, `pointattributelist' must */
+/*      be initialized.                                                      */
+/*    - `trianglelist' must be initialized unless the `E' switch is used.    */
+/*      `neighborlist' must be initialized if the `n' switch is used.  If    */
+/*      the `E' switch is not used and (`in->numberofelementattributes' is   */
+/*      not zero or the `A' switch is used), `elementattributelist' must be  */
+/*      initialized.  `trianglearealist' may be ignored.                     */
+/*    - `segmentlist' must be initialized if the `p' or `c' switch is used,  */
+/*      and the `P' switch is not used.  `segmentmarkerlist' must also be    */
+/*      initialized under these circumstances unless the `B' switch is used. */
+/*    - `edgelist' must be initialized if the `e' switch is used.            */
+/*      `edgemarkerlist' must be initialized if the `e' switch is used and   */
+/*      the `B' switch is not.                                               */
+/*    - `holelist', `regionlist', `normlist', and all scalars may be ignored.*/
+/*                                                                           */
+/*  `vorout' (only needed if `v' switch is used):                            */
+/*                                                                           */
+/*    - `pointlist' must be initialized.  If `in->numberofpointattributes'   */
+/*      is not zero, `pointattributelist' must be initialized.               */
+/*      `pointmarkerlist' may be ignored.                                    */
+/*    - `edgelist' and `normlist' must both be initialized.                  */
+/*      `edgemarkerlist' may be ignored.                                     */
+/*    - Everything else may be ignored.                                      */
+/*                                                                           */
+/*  After a call to triangulate(), the valid fields of `out' and `vorout'    */
+/*  will depend, in an obvious way, on the choice of switches used.  Note    */
+/*  that when the `p' switch is used, the pointers `holelist' and            */
+/*  `regionlist' are copied from `in' to `out', but no new space is          */
+/*  allocated; be careful that you don't free() the same array twice.  On    */
+/*  the other hand, Triangle will never copy the `pointlist' pointer (or any */
+/*  others); new space is allocated for `out->pointlist', or if the `N'      */
+/*  switch is used, `out->pointlist' remains uninitialized.                  */
+/*                                                                           */
+/*  All of the meaningful `numberof' fields will be properly set; for        */
+/*  instance, `numberofedges' will represent the number of edges in the      */
+/*  triangulation whether or not the edges were written.  If segments are    */
+/*  not used, `numberofsegments' will indicate the number of boundary edges. */
+/*                                                                           */
+/*****************************************************************************/
+
+struct triangulateio {
+  REAL *pointlist;                                               /* In / out */
+  REAL *pointattributelist;                                      /* In / out */
+  int *pointmarkerlist;                                          /* In / out */
+  int numberofpoints;                                            /* In / out */
+  int numberofpointattributes;                                   /* In / out */
+
+  int *trianglelist;                                             /* In / out */
+  REAL *triangleattributelist;                                   /* In / out */
+  REAL *trianglearealist;                                         /* In only */
+  int *neighborlist;                                             /* Out only */
+  int numberoftriangles;                                         /* In / out */
+  int numberofcorners;                                           /* In / out */
+  int numberoftriangleattributes;                                /* In / out */
+
+  int *segmentlist;                                              /* In / out */
+  int *segmentmarkerlist;                                        /* In / out */
+  int numberofsegments;                                          /* In / out */
+
+  REAL *holelist;                        /* In / pointer to array copied out */
+  int numberofholes;                                      /* In / copied out */
+
+  REAL *regionlist;                      /* In / pointer to array copied out */
+  int numberofregions;                                    /* In / copied out */
+
+  int *edgelist;                                                 /* Out only */
+  int *edgemarkerlist;            /* Not used with Voronoi diagram; out only */
+  REAL *normlist;                /* Used only with Voronoi diagram; out only */
+  int numberofedges;                                             /* Out only */
+};
+
+void triangulateioinit(struct triangulateio*);
+void triangulateiodeinit(struct triangulateio*);
+void triangulateioreport(struct triangulateio*, int, int, int, int, int, int);
+
+/* The triangle data structure.  Each triangle contains three pointers to    */
+/*   adjoining triangles, plus three pointers to vertex points, plus three   */
+/*   pointers to shell edges (defined below; these pointers are usually      */
+/*   `dummysh').  It may or may not also contain user-defined attributes     */
+/*   and/or a floating-point "area constraint".  It may also contain extra   */
+/*   pointers for nodes, when the user asks for high-order elements.         */
+/*   Because the size and structure of a `triangle' is not decided until     */
+/*   runtime, I haven't simply defined the type `triangle' to be a struct.   */
+
+typedef REAL **triangle;            /* Really:  typedef triangle *triangle   */
+
+/* An oriented triangle:  includes a pointer to a triangle and orientation.  */
+/*   The orientation denotes an edge of the triangle.  Hence, there are      */
+/*   three possible orientations.  By convention, each edge is always        */
+/*   directed to point counterclockwise about the corresponding triangle.    */
+
+struct triedge {
+  triangle *tri;
+  int orient;                                         /* Ranges from 0 to 2. */
+};
+
+/* The shell data structure.  Each shell edge contains two pointers to       */
+/*   adjoining shell edges, plus two pointers to vertex points, plus two     */
+/*   pointers to adjoining triangles, plus one shell marker.                 */
+
+typedef REAL **shelle;                  /* Really:  typedef shelle *shelle   */
+
+/* An oriented shell edge:  includes a pointer to a shell edge and an        */
+/*   orientation.  The orientation denotes a side of the edge.  Hence, there */
+/*   are two possible orientations.  By convention, the edge is always       */
+/*   directed so that the "side" denoted is the right side of the edge.      */
+
+struct edge {
+  shelle *sh;
+  int shorient;                                       /* Ranges from 0 to 1. */
+};
+
+/* The point data structure.  Each point is actually an array of REALs.      */
+/*   The number of REALs is unknown until runtime.  An integer boundary      */
+/*   marker, and sometimes a pointer to a triangle, is appended after the    */
+/*   REALs.                                                                  */
+
+typedef REAL *point;
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// class mesh2d                                                              //
+//                                                                           //
+// The class simply encapsulating the well-coded and well-performed 2D unst- //
+// ructed mesh generator TRIANGLE's functions into a single calss so it can  //
+// be called directly from my 3D mesh program.                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+class mesh2d {
+
+  public:
+
+    enum locateresult {INTRIANGLE, ONEDGE, ONVERTEX, OUTSIDE};
+    enum insertsiteresult {SUCCESSFULPOINT, ENCROACHINGPOINT, VIOLATINGPOINT,
+                           DUPLICATEPOINT};
+    enum finddirectionresult {WITHIN, LEFTCOLLINEAR, RIGHTCOLLINEAR};
+
+  public:
+
+    memorypool triangles;
+    memorypool shelles;
+    memorypool points;
+    memorypool viri;
+
+    REAL xmin, xmax, ymin, ymax;
+    REAL xminextreme;
+    int inpoints, inelements, insegments, holes, regions;
+    long edges, hullsize;
+    int mesh_dim;
+    int nextras, eextras;
+    int triwords, shwords;
+    int pointmarkindex, point2triindex;
+    int highorderindex, elemattribindex, areaboundindex;
+    int checksegments;
+    int readnodefile;
+    long samples;
+    unsigned long randomseed;
+    long incirclecount, counterclockcount;
+    long circumcentercount;
+
+    int poly, refine, quality, vararea, fixedarea, regionattrib, convex;
+    int firstnumber;
+    int edgesout, voronoi, neighbors, geomview;
+    int nopolywritten, nonodewritten, noelewritten, noiterationnum;
+    int nobound, noholes, nobisect, noexact;
+    int incremental, sweepline, dwyer;
+    int splitseg, steiner, steinerleft;
+    int docheck, quiet, verbose;
+    int useshelles, order;
+    int restartsymbol;
+    REAL minangle, goodangle;
+    REAL maxarea;
+
+    point infpoint1, infpoint2, infpoint3;
+
+    triangle *dummytri;
+    triangle *dummytribase;
+    shelle *dummysh;
+    shelle *dummyshbase;
+
+    struct triedge recenttri;
+
+    static int plus1mod3[3];
+    static int minus1mod3[3];
+
+  public:
+
+    // User interaction routines
+    void syntax();
+    void info();
+    void internalerror();
+    void parsecommandline(int, char**, int);
+
+    // Debugging routines
+    void printtriangle(struct triedge*);
+    void printshelle(struct edge*);
+
+    // Memory management routines
+    void dummyinit(int, int);
+    void initializepointpool();
+    void initializetrisegpools();
+    void triangledealloc(triangle*);
+    triangle *triangletraverse();
+    void shelledealloc(shelle*);
+    shelle *shelletraverse();
+    void pointdealloc(point);
+    point pointtraverse();
+    point getpoint(int number);
+
+    // Constructors
+    void maketriangle(struct triedge*);
+    void makeshelle(struct edge*);
+
+    void triangleinit();
+    void triangledeinit();
+    void trianglerestart();
+
+    // Geometric predicates
+    REAL counterclockwise(point, point, point);
+    REAL iincircle(point, point, point, point);
+
+    // Point location routines
+    unsigned long randomnation(unsigned int);
+    void makepointmap();
+    enum locateresult preciselocate(point, struct triedge*);
+    enum locateresult locate(point, struct triedge*);
+
+    // Mesh transformation routines
+    void insertshelle(struct triedge*, int);
+    void flip(struct triedge*);
+    enum insertsiteresult insertsite(point, struct triedge*, struct edge*,
+                                     int, int);
+
+    // Divide-and-conquer Delaunay triangulation
+    void pointsort(point*, int);
+    void pointmedian(point*, int, int, int);
+    void alternateaxes(point*, int, int);
+    void mergehulls(struct triedge*, struct triedge*, struct triedge*,
+                    struct triedge*, int);
+    void divconqrecurse(point*, int, int, struct triedge*, struct triedge*);
+    long removeghosts(struct triedge*);
+    long divconqdelaunay();
+
+    // General mesh construction routines
+    long delaunay();
+
+    // Segment (shell edge) insertion routines
+    enum finddirectionresult finddirection(struct triedge*, point);
+    void segmentintersection(struct triedge*, struct edge*, point);
+    int scoutsegment(struct triedge*, point, int);
+    void conformingedge(point, point, int);
+    void delaunayfixup(struct triedge*, int);
+    void constrainededge(struct triedge*, point, int);
+    void insertsegment(point endpoint1, point endpoint2, int newmark);
+    void markhull();
+    int formskeleton(int*, int*, int);
+
+    // Carving out holes and concavities routines
+    void infecthull();
+    void plague();
+    void regionplague(REAL attribute, REAL area);
+    void carveholes(REAL*, int, REAL*, int);
+
+    // I/O routines
+    void transfernodes(REAL*, REAL*, int*, int, int);
+    void numbernodes();
+    void writenodes(REAL**, REAL**, int**);
+    void writeelements(int**, REAL**);
+    void writepoly(int**, int**);
+    void writeedges(int**, int**);
+    void writeneighbors(int**);
+    void writegid(int);
+
+  public:
+
+    mesh2d(char* triswtches) {
+      triangleinit();
+      parsecommandline(1, &triswtches, 1);
+    }
+    ~mesh2d() { triangledeinit(); }
+
+    void triangulate(struct triangulateio *in, struct triangulateio *out,
+                     struct triangulateio *vorout);
+};
+
+#endif // ifndef trilibH
-- 
GitLab