From c0e0d22b4da2ef2efc28bdd98c89bf4fe6cbcbc7 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Sat, 27 Jun 2009 06:57:08 +0000
Subject: [PATCH] revert to old tetgen code for now: the new code is just too
 buggy

you can use the new code by configuring with --enable-tetgen-new
---
 configure                        |   61 +-
 configure.in                     |   31 +-
 contrib/TetgenNew/LICENSE        |   66 +
 contrib/TetgenNew/Makefile       |   65 +
 contrib/TetgenNew/README         |   16 +
 contrib/TetgenNew/behavior.cxx   |  531 ++++
 contrib/TetgenNew/constrain.cxx  | 4416 +++++++++++++++++++++++++++++
 contrib/TetgenNew/delaunay.cxx   | 1464 ++++++++++
 contrib/TetgenNew/flip.cxx       | 2128 ++++++++++++++
 contrib/TetgenNew/geom.cxx       | 4517 ++++++++++++++++++++++++++++++
 contrib/TetgenNew/io.cxx         | 3148 +++++++++++++++++++++
 contrib/TetgenNew/main.cxx       |  387 +++
 contrib/TetgenNew/memorypool.cxx |  981 +++++++
 contrib/TetgenNew/meshio.cxx     | 1237 ++++++++
 contrib/TetgenNew/meshstat.cxx   | 1764 ++++++++++++
 contrib/TetgenNew/predicates.cxx | 4187 +++++++++++++++++++++++++++
 contrib/TetgenNew/refine.cxx     |  249 ++
 contrib/TetgenNew/surface.cxx    | 1795 ++++++++++++
 contrib/TetgenNew/tetgen.h       | 1922 +++++++++++++
 19 files changed, 28948 insertions(+), 17 deletions(-)
 create mode 100644 contrib/TetgenNew/LICENSE
 create mode 100644 contrib/TetgenNew/Makefile
 create mode 100644 contrib/TetgenNew/README
 create mode 100644 contrib/TetgenNew/behavior.cxx
 create mode 100644 contrib/TetgenNew/constrain.cxx
 create mode 100644 contrib/TetgenNew/delaunay.cxx
 create mode 100644 contrib/TetgenNew/flip.cxx
 create mode 100644 contrib/TetgenNew/geom.cxx
 create mode 100644 contrib/TetgenNew/io.cxx
 create mode 100644 contrib/TetgenNew/main.cxx
 create mode 100644 contrib/TetgenNew/memorypool.cxx
 create mode 100644 contrib/TetgenNew/meshio.cxx
 create mode 100644 contrib/TetgenNew/meshstat.cxx
 create mode 100644 contrib/TetgenNew/predicates.cxx
 create mode 100644 contrib/TetgenNew/refine.cxx
 create mode 100644 contrib/TetgenNew/surface.cxx
 create mode 100644 contrib/TetgenNew/tetgen.h

diff --git a/configure b/configure
index 08514685cf..70b44ee07f 100755
--- a/configure
+++ b/configure
@@ -1972,6 +1972,7 @@ if test "${enable_mpi+set}" = set; then
   enableval=$enable_mpi;
 fi
 
+
 # Check whether --enable-graphics was given.
 if test "${enable_graphics+set}" = set; then
   enableval=$enable_graphics;
@@ -1982,6 +1983,11 @@ if test "${enable_minimal+set}" = set; then
   enableval=$enable_minimal;
 fi
 
+# Check whether --enable-tetgen-new was given.
+if test "${enable_tetgen_new+set}" = set; then
+  enableval=$enable_tetgen_new;
+fi
+
 
 if test "x$enable_minimal" = "xyes"; then
   enable_gui=no;
@@ -4691,8 +4697,44 @@ _ACEOF
     fi
   fi
 
+    if test "x$enable_tetgen_new" = "xyes"; then
+    { echo "$as_me:$LINENO: checking for ./contrib/TetgenNew/tetgen.h" >&5
+echo $ECHO_N "checking for ./contrib/TetgenNew/tetgen.h... $ECHO_C" >&6; }
+if test "${ac_cv_file___contrib_TetgenNew_tetgen_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  test "$cross_compiling" = yes &&
+  { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+   { (exit 1); exit 1; }; }
+if test -r "./contrib/TetgenNew/tetgen.h"; then
+  ac_cv_file___contrib_TetgenNew_tetgen_h=yes
+else
+  ac_cv_file___contrib_TetgenNew_tetgen_h=no
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_file___contrib_TetgenNew_tetgen_h" >&5
+echo "${ECHO_T}$ac_cv_file___contrib_TetgenNew_tetgen_h" >&6; }
+if test $ac_cv_file___contrib_TetgenNew_tetgen_h = yes; then
+  TETGEN="yes"
+fi
+
+    if test "x${TETGEN}" = "xyes"; then
+      GMSH_DIRS="${GMSH_DIRS} contrib/TetgenNew"
+      GMSH_LIBS="${GMSH_LIBS} -lGmshTetgenNew"
+      cat >>confdefs.h <<\_ACEOF
+#define HAVE_TETGEN 1
+_ACEOF
+
+      BO="${BO} TetgenNew"
+      { echo "$as_me:$LINENO: WARNING: You are building with an experimental version of Tetgen that" >&5
+echo "$as_me: WARNING: You are building with an experimental version of Tetgen that" >&2;}
+      { echo "$as_me:$LINENO: WARNING: is KNOWN TO BE BUGGY on 64 bits archs and on WIN32/MSVC." >&5
+echo "$as_me: WARNING: is KNOWN TO BE BUGGY on 64 bits archs and on WIN32/MSVC." >&2;}
+    fi
+  else
     if test "x$enable_tetgen" != "xno"; then
-    { echo "$as_me:$LINENO: checking for ./contrib/Tetgen/tetgen.h" >&5
+      { echo "$as_me:$LINENO: checking for ./contrib/Tetgen/tetgen.h" >&5
 echo $ECHO_N "checking for ./contrib/Tetgen/tetgen.h... $ECHO_C" >&6; }
 if test "${ac_cv_file___contrib_Tetgen_tetgen_h+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
@@ -4713,20 +4755,21 @@ if test $ac_cv_file___contrib_Tetgen_tetgen_h = yes; then
   TETGEN="yes"
 fi
 
-    if test "x${TETGEN}" = "xyes"; then
-      GMSH_DIRS="${GMSH_DIRS} contrib/Tetgen"
-      GMSH_LIBS="${GMSH_LIBS} -lGmshTetgen"
-      cat >>confdefs.h <<\_ACEOF
+      if test "x${TETGEN}" = "xyes"; then
+        GMSH_DIRS="${GMSH_DIRS} contrib/Tetgen"
+        GMSH_LIBS="${GMSH_LIBS} -lGmshTetgen"
+        cat >>confdefs.h <<\_ACEOF
 #define HAVE_TETGEN 1
 _ACEOF
 
-      BO="${BO} Tetgen"
-      { echo "$as_me:$LINENO: WARNING: By including Tetgen you have to comply with Tetgen' special" >&5
+        BO="${BO} Tetgen"
+        { echo "$as_me:$LINENO: WARNING: By including Tetgen you have to comply with Tetgen' special" >&5
 echo "$as_me: WARNING: By including Tetgen you have to comply with Tetgen' special" >&2;}
-      { echo "$as_me:$LINENO: WARNING: licensing requirements stated in contrib/Tetgen/LICENSE. To" >&5
+        { echo "$as_me:$LINENO: WARNING: licensing requirements stated in contrib/Tetgen/LICENSE. To" >&5
 echo "$as_me: WARNING: licensing requirements stated in contrib/Tetgen/LICENSE. To" >&2;}
-      { echo "$as_me:$LINENO: WARNING: disable Tetgen, use the --disable-tetgen option" >&5
+        { echo "$as_me:$LINENO: WARNING: disable Tetgen, use the --disable-tetgen option" >&5
 echo "$as_me: WARNING: disable Tetgen, use the --disable-tetgen option" >&2;}
+      fi
     fi
   fi
 
diff --git a/configure.in b/configure.in
index 9aff10bd24..d6e3e75863 100644
--- a/configure.in
+++ b/configure.in
@@ -145,8 +145,11 @@ AC_ARG_ENABLE(tree-browser,
 AC_ARG_ENABLE(mpi,
               AC_HELP_STRING([--enable-mpi],
                              [enable MPI support (default=no)]))
+
+dnl undocumented options
 AC_ARG_ENABLE(graphics)
 AC_ARG_ENABLE(minimal)
+AC_ARG_ENABLE(tetgen-new)
 
 dnl "minimal" build shortcut
 if test "x$enable_minimal" = "xyes"; then
@@ -485,16 +488,28 @@ if test "x$enable_contrib" != "xno"; then
   fi
 
   dnl Check for Tetgen
-  if test "x$enable_tetgen" != "xno"; then
-    AC_CHECK_FILE(./contrib/Tetgen/tetgen.h,TETGEN="yes")
+  if test "x$enable_tetgen_new" = "xyes"; then
+    AC_CHECK_FILE(./contrib/TetgenNew/tetgen.h,TETGEN="yes")
     if test "x${TETGEN}" = "xyes"; then
-      GMSH_DIRS="${GMSH_DIRS} contrib/Tetgen"
-      GMSH_LIBS="${GMSH_LIBS} -lGmshTetgen"
+      GMSH_DIRS="${GMSH_DIRS} contrib/TetgenNew"
+      GMSH_LIBS="${GMSH_LIBS} -lGmshTetgenNew"
       AC_DEFINE(HAVE_TETGEN)
-      BO="${BO} Tetgen"
-      AC_MSG_WARN([By including Tetgen you have to comply with Tetgen' special])
-      AC_MSG_WARN([licensing requirements stated in contrib/Tetgen/LICENSE. To])
-      AC_MSG_WARN([disable Tetgen, use the --disable-tetgen option])
+      BO="${BO} TetgenNew"
+      AC_MSG_WARN([You are building with an experimental version of Tetgen that])
+      AC_MSG_WARN([is KNOWN TO BE BUGGY on 64 bits archs and on WIN32/MSVC.])
+    fi
+  else
+    if test "x$enable_tetgen" != "xno"; then
+      AC_CHECK_FILE(./contrib/Tetgen/tetgen.h,TETGEN="yes")
+      if test "x${TETGEN}" = "xyes"; then
+        GMSH_DIRS="${GMSH_DIRS} contrib/Tetgen"
+        GMSH_LIBS="${GMSH_LIBS} -lGmshTetgen"
+        AC_DEFINE(HAVE_TETGEN)
+        BO="${BO} Tetgen"
+        AC_MSG_WARN([By including Tetgen you have to comply with Tetgen' special])
+        AC_MSG_WARN([licensing requirements stated in contrib/Tetgen/LICENSE. To])
+        AC_MSG_WARN([disable Tetgen, use the --disable-tetgen option])
+      fi
     fi
   fi
 
diff --git a/contrib/TetgenNew/LICENSE b/contrib/TetgenNew/LICENSE
new file mode 100644
index 0000000000..65e5262522
--- /dev/null
+++ b/contrib/TetgenNew/LICENSE
@@ -0,0 +1,66 @@
+TetGen License
+--------------
+
+The software (TetGen) is licensed under the terms of the  MIT  license
+with the following exceptions:
+
+Distribution of  modified  versions  of this code is permissible UNDER
+THE CONDITION THAT  THIS CODE AND ANY MODIFICATIONS  MADE TO IT IN THE
+SAME SOURCE FILES  tetgen.h AND tetgen.cxx  REMAIN UNDER  COPYRIGHT OF
+THE  ORIGINAL AUTHOR,  BOTH  SOURCE AND OBJECT  CODE  ARE MADE  FREELY
+AVAILABLE  WITHOUT   CHARGE,   AND  CLEAR   NOTICE  IS  GIVEN  OF  THE 
+MODIFICATIONS.
+
+Distribution of this code for  any  commercial purpose  is permissible
+ONLY BY DIRECT ARRANGEMENT WITH THE COPYRIGHT OWNER.
+
+The full  license text is reproduced below.
+
+This means that TetGen is no free software, but for private, research,
+and  educational purposes it  can be  used at  absolutely no  cost and
+without further arrangements.
+
+
+For details, see http://tetgen.berlios.de
+
+==============================================================================
+
+TetGen
+A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator
+Version 1.4 (Released on January 14, 2006).
+
+Copyright 2002, 2004, 2005, 2006 
+Hang Si
+Rathausstr. 9, 10178 Berlin, Germany
+si@wias-berlin.de
+
+Permission is hereby granted, free  of charge, to any person obtaining
+a  copy  of this  software  and  associated  documentation files  (the
+"Software"), to  deal in  the Software without  restriction, including
+without limitation  the rights to  use, copy, modify,  merge, publish,
+distribute,  sublicense and/or  sell copies  of the  Software,  and to
+permit persons to whom the Software  is furnished to do so, subject to
+the following conditions:
+
+Distribution of  modified  versions  of this code is permissible UNDER
+THE CONDITION THAT  THIS CODE AND ANY MODIFICATIONS  MADE TO IT IN THE
+SAME SOURCE FILES  tetgen.h AND tetgen.cxx  REMAIN UNDER  COPYRIGHT OF
+THE  ORIGINAL AUTHOR,  BOTH  SOURCE AND OBJECT  CODE  ARE MADE  FREELY
+AVAILABLE  WITHOUT   CHARGE,   AND  CLEAR   NOTICE  IS  GIVEN  OF  THE 
+MODIFICATIONS.
+
+Distribution of this code for  any  commercial purpose  is permissible
+ONLY BY DIRECT ARRANGEMENT WITH THE COPYRIGHT OWNER.
+
+The  above  copyright  notice  and  this permission  notice  shall  be
+included in all copies or substantial portions of the Software.
+
+THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
+EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT  SHALL THE AUTHORS OR COPYRIGHT HOLDERS  BE LIABLE FOR ANY
+CLAIM, DAMAGES OR  OTHER LIABILITY, WHETHER IN AN  ACTION OF CONTRACT,
+TORT  OR OTHERWISE, ARISING  FROM, OUT  OF OR  IN CONNECTION  WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+==============================================================================
\ No newline at end of file
diff --git a/contrib/TetgenNew/Makefile b/contrib/TetgenNew/Makefile
new file mode 100644
index 0000000000..a9109b4bce
--- /dev/null
+++ b/contrib/TetgenNew/Makefile
@@ -0,0 +1,65 @@
+# Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle
+#
+# See the LICENSE.txt file for license information. Please report all
+# bugs and problems to <gmsh@geuz.org>.
+
+include ../../variables
+
+LIB = ../../lib/libGmshTetgen${LIBEXT}
+
+# Don't optimize Tetgen
+CFLAGS = ${FLAGS} ${DASH}DTETLIBRARY
+
+SRC = behavior.cxx\
+      constrain.cxx\
+      delaunay.cxx\
+      flip.cxx\
+      geom.cxx\
+      io.cxx\
+      main.cxx\
+      memorypool.cxx\
+      meshio.cxx\
+      meshstat.cxx\
+      predicates.cxx\
+      refine.cxx\
+      surface.cxx
+
+OBJ = ${SRC:.cxx=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cxx
+
+${LIB}: ${OBJ} 
+	${AR} ${ARFLAGS}${LIB} ${OBJ} 
+	${RANLIB} ${LIB}
+
+cpobj: ${OBJ} 
+	cp -f ${OBJ} ../../lib/
+
+.cxx${OBJEXT}:
+	${CXX} ${CFLAGS} ${DASH}c $<
+
+clean:
+	${RM} *.o *.obj
+
+depend:
+	(sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+         ${CXX} -MM ${CFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+        ) > Makefile.new
+	cp Makefile Makefile.bak
+	cp Makefile.new Makefile
+	rm -f Makefile.new
+
+# DO NOT DELETE THIS LINE
+behavior${OBJEXT}: behavior.cxx tetgen.h
+constrain${OBJEXT}: constrain.cxx tetgen.h
+delaunay${OBJEXT}: delaunay.cxx tetgen.h
+flip${OBJEXT}: flip.cxx tetgen.h
+geom${OBJEXT}: geom.cxx tetgen.h
+io${OBJEXT}: io.cxx tetgen.h
+main${OBJEXT}: main.cxx tetgen.h
+memorypool${OBJEXT}: memorypool.cxx tetgen.h
+meshio${OBJEXT}: meshio.cxx tetgen.h
+meshstat${OBJEXT}: meshstat.cxx tetgen.h
+predicates${OBJEXT}: predicates.cxx tetgen.h
+refine${OBJEXT}: refine.cxx tetgen.h
+surface${OBJEXT}: surface.cxx tetgen.h
diff --git a/contrib/TetgenNew/README b/contrib/TetgenNew/README
new file mode 100644
index 0000000000..5e86013395
--- /dev/null
+++ b/contrib/TetgenNew/README
@@ -0,0 +1,16 @@
+This is an EXPERIMENTAL version of TetGen provided by Hang Si for Gmsh
+
+Please see the documentation of TetGen (available at the following link) for
+compiling and using TetGen.
+
+            http://tetgen.berlios.de/index.html
+
+TetGen may be freely copied, modified, and redistributed under the
+copyright notices stated in the file LICENSE.
+
+Please send bugs/comments to Hang Si <si@wias-berlin.de>
+
+Thank you and enjoy!
+
+Hang Si
+
diff --git a/contrib/TetgenNew/behavior.cxx b/contrib/TetgenNew/behavior.cxx
new file mode 100644
index 0000000000..e25f7e772c
--- /dev/null
+++ b/contrib/TetgenNew/behavior.cxx
@@ -0,0 +1,531 @@
+#ifndef behaviorCXX
+#define behaviorCXX
+
+#include "tetgen.h"
+
+static REAL PI = 3.14159265358979323846264338327950288419716939937510582;
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetgenbehavior()    Initialize veriables of 'tetgenbehavior'.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+tetgenbehavior::tetgenbehavior()
+{
+  // Initialize command line switches.
+  plc = 0;
+  quality = 0;
+  refine = 0;
+  coarse = 0;
+  metric = 0;
+  minratio = 2.0;
+  goodratio = 0.0;
+  minangle = 20.0;
+  goodangle = 0.0;
+  maxdihedral = 165.0;
+  mindihedral = 5.0;
+  varvolume = 0;
+  fixedvolume = 0;
+  maxvolume = -1.0;
+  regionattrib = 0;
+  bowyerwatson = 1;
+  convexity = 0;
+  insertaddpoints = 0;
+  diagnose = 0;
+  conformdel = 0;
+  zeroindex = 0;
+  facesout = 0;
+  edgesout = 0;
+  neighout = 0;
+  voroout = 0;
+  meditview = 0;
+  gidview = 0;
+  geomview = 0;
+  order = 1;
+  nojettison = 0;
+  nobound = 0;
+  nonodewritten = 0;
+  noelewritten = 0;
+  nofacewritten = 0;
+  noiterationnum = 0;
+  nobisect = 0;
+  steinerleft = -1l;
+  nomerge = 0;
+  docheck = 0;
+  quiet = 0;
+  verbose = 0;
+  useshelles = 0;
+  epsilon = 1.0e-8;
+  object = NONE;
+  // Initialize strings
+  commandline[0] = '\0';
+  infilename[0] = '\0';
+  outfilename[0] = '\0';
+  addinfilename[0] = '\0';
+  bgmeshfilename[0] = '\0';
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// versioninfo()    Print the version information of TetGen.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenbehavior::versioninfo()
+{
+  printf("Develop Version (Started on August 9, 2008).\n");
+  printf("\n");
+  printf("Copyright (C) 2002 - 2008\n");
+  printf("Hang Si\n");
+  printf("Mohrenstr. 39, 10117 Berlin, Germany\n");
+  printf("si@wias-berlin.de\n");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// syntax()    Print list of command line switches and exit the program.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenbehavior::syntax()
+{
+  printf("  tetgen [-prq_Ra_AiMYS_T_dzo_fenvgGOJBNEFICQVh] input_file\n");
+  printf("    -p  Tetrahedralizes a piecewise linear complex (PLC).\n");
+  printf("    -r  Reconstructs a previously generated mesh.\n");
+  printf("    -q  Quality mesh generation (adding new mesh points to ");
+  printf("improve mesh quality).\n");
+  printf("    -R  Mesh coarsening (deleting redundant mesh points).\n");
+  printf("    -a  Applies a maximum tetrahedron volume constraint.\n");
+  printf("    -A  Assigns attributes to identify tetrahedra in different ");
+  printf("regions.\n");
+  printf("    -i  Inserts a list of additional points into mesh.\n");
+  printf("    -M  Does not merge coplanar facets.\n");
+  printf("    -Y  Suppresses boundary facets/segments splitting.\n");
+  printf("    -S  Specifies maximum number of added points.\n");
+  printf("    -T  Sets a tolerance for coplanar test (default 1e-8).\n");
+  printf("    -d  Detects self-intersections of facets of the PLC.\n");
+  printf("    -z  Numbers all output items starting from zero.\n");
+  printf("    -o2 Generates second-order subparametric elements.\n");
+  printf("    -f  Outputs all faces to .face file.");
+  printf("file.\n");
+  printf("    -e  Outputs all edges to .edge file.\n");
+  printf("    -n  Outputs tetrahedra neighbors to .neigh file.\n");
+  printf("    -v  Outputs Voronoi diagram to files.\n");
+  printf("    -g  Outputs mesh to .mesh file for viewing by Medit.\n");
+  printf("    -G  Outputs mesh to .msh file for viewing by Gid.\n");
+  printf("    -O  Outputs mesh to .off file for viewing by Geomview.\n");
+  printf("    -J  No jettison of unused vertices from output .node file.\n");
+  printf("    -B  Suppresses output of boundary information.\n");
+  printf("    -N  Suppresses output of .node file.\n");
+  printf("    -E  Suppresses output of .ele file.\n");
+  printf("    -F  Suppresses output of .face file.\n");
+  printf("    -I  Suppresses mesh iteration numbers.\n");
+  printf("    -C  Checks the consistency of the final mesh.\n");
+  printf("    -Q  Quiet:  No terminal output except errors.\n");
+  printf("    -V  Verbose:  Detailed information, more terminal output.\n");
+  printf("    -h  Help:  A brief instruction for using TetGen.\n");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// usage()    Print a brief instruction for using TetGen.                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenbehavior::usage()
+{
+  printf("TetGen\n");
+  printf("A Quality Tetrahedral Mesh Generator and 3D Delaunay ");
+  printf("Triangulator\n");
+  versioninfo();
+  printf("\n");
+  printf("What Can TetGen Do?\n");
+  printf("\n");
+  printf("  TetGen generates exact Delaunay tetrahedralizations, exact\n");
+  printf("  constrained Delaunay tetrahedralizations, and quality ");
+  printf("tetrahedral\n  meshes. The latter are nicely graded and whose ");
+  printf("tetrahedra have\n  radius-edge ratio bounded, thus are suitable ");
+  printf("for finite element and\n  finite volume analysis.\n"); 
+  printf("\n");
+  printf("Command Line Syntax:\n");
+  printf("\n");
+  printf("  Below is the command line syntax of TetGen with a list of ");
+  printf("short\n");
+  printf("  descriptions. Underscores indicate that numbers may optionally\n");
+  printf("  follow certain switches.  Do not leave any space between a ");
+  printf("switch\n");
+  printf("  and its numeric parameter.  \'input_file\' contains input data\n");
+  printf("  depending on the switches you supplied which may be a ");
+  printf("  piecewise\n");
+  printf("  linear complex or a list of nodes.  File formats and detailed\n");
+  printf("  description of command line switches are found in user's ");
+  printf("manual.\n");
+  printf("\n");
+  syntax();
+  printf("\n");
+  printf("Examples of How to Use TetGen:\n");
+  printf("\n");
+  printf("  \'tetgen object\' reads vertices from object.node, and writes ");
+  printf("their\n  Delaunay tetrahedralization to object.1.node and ");
+  printf("object.1.ele.\n");
+  printf("\n");
+  printf("  \'tetgen -p object\' reads a PLC from object.poly or object.");
+  printf("smesh (and\n  possibly object.node) and writes its constrained ");
+  printf("Delaunay\n  tetrahedralization to object.1.node, object.1.ele and ");
+  printf("object.1.face.\n");
+  printf("\n");
+  printf("  \'tetgen -pq1.414a.1 object\' reads a PLC from object.poly or\n");
+  printf("  object.smesh (and possibly object.node), generates a mesh ");
+  printf("whose\n  tetrahedra have radius-edge ratio smaller than 1.414 and ");
+  printf("have volume\n  of 0.1 or less, and writes the mesh to ");
+  printf("object.1.node, object.1.ele\n  and object.1.face.\n");
+  printf("\n");
+  printf("Please send bugs/comments to Hang Si <si@wias-berlin.de>\n");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// parse_commandline()    Read the command line, identify switches, and set  //
+//                        up options and file names.                         //
+//                                                                           //
+// 'argc' and 'argv' are the same parameters passed to the function main()   //
+// of a C/C++ program. They together represent the command line user invoked //
+// from an environment in which TetGen is running.                           //
+//                                                                           //
+// When TetGen is invoked from an environment. 'argc' is nonzero, switches   //
+// and input filename should be supplied as zero-terminated strings in       //
+// argv[0] through argv[argc - 1] and argv[0] shall be the name used to      //
+// invoke TetGen, i.e. "tetgen".  Switches are previously started with a     //
+// dash '-' to identify them from the input filename.                        //
+//                                                                           //
+// When TetGen is called from within another program. 'argc' is set to zero. //
+// switches are given in one zero-terminated string (no previous dash is     //
+// required.), and 'argv' is a pointer points to this string.  No input      //
+// filename is required (usually the input data has been directly created by //
+// user in the 'tetgenio' structure).  A default filename 'tetgen-tmpfile'   //
+// will be created for debugging output purpose.                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenbehavior::parse_commandline(int argc, char **argv)
+{
+  int startindex;
+  int increment;
+  int meshnumber;
+  int scount;
+  int i, j, k;
+  char workstring[1024];
+
+  // First determine the input style of the switches.
+  if (argc == 0) {
+    startindex = 0;                    // Switches are given without a dash.
+    argc = 1;                    // For running the following for-loop once.
+    commandline[0] = '\0';
+  } else {
+    startindex = 1;
+    strcpy(commandline, argv[0]);
+    strcat(commandline, " ");
+  }
+  
+  // Rcount used to count the number of '-R' be used.
+  scount = 0;
+
+  for (i = startindex; i < argc; i++) {
+    // Remember the command line switches.
+    strcat(commandline, argv[i]);
+    strcat(commandline, " ");
+    if (startindex == 1) {
+      // Is this string a filename?
+      if (argv[i][0] != '-') {
+        strncpy(infilename, argv[i], 1024 - 1);
+        infilename[1024 - 1] = '\0';
+        // Go to the next string directly.
+        continue;                     
+      }
+    }
+    // Parse the individual switch from the string.
+    for (j = startindex; argv[i][j] != '\0'; j++) {
+      if (argv[i][j] == 'p') {
+        plc = 1;
+      } else if (argv[i][j] == 'r') {
+        refine = 1;
+      } else if (argv[i][j] == 'R') {
+        coarse = 1;
+      } else if (argv[i][j] == 'q') {
+        quality++;
+        if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+            (argv[i][j + 1] == '.')) {
+          k = 0;
+          while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+                 (argv[i][j + 1] == '.')) {
+            j++;
+            workstring[k] = argv[i][j];
+            k++;
+          }
+          workstring[k] = '\0';
+          if (quality == 1) {
+            minratio = (REAL) strtod(workstring, (char **) NULL);
+          } else if (quality == 2) {
+            mindihedral = (REAL) strtod(workstring, (char **) NULL);
+          } else if (quality == 3) {
+            maxdihedral = (REAL) strtod(workstring, (char **) NULL);
+          }
+        }
+      } else if (argv[i][j] == 'm') {
+        metric++;
+      } else if (argv[i][j] == 'a') {
+        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] == '.') || (argv[i][j + 1] == 'e') ||
+                 (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
+            j++;
+            workstring[k] = argv[i][j];
+            k++;
+          }
+          workstring[k] = '\0';
+          maxvolume = (REAL) strtod(workstring, (char **) NULL);
+        } else {
+          varvolume = 1;
+        }
+      } else if (argv[i][j] == 'A') {
+        regionattrib++;
+      } else if (argv[i][j] == 'b') {
+        bowyerwatson = 0;
+      } else if (argv[i][j] == 'c') {
+        convexity++;
+      } else if (argv[i][j] == 'i') {
+        insertaddpoints = 1;
+      } else if (argv[i][j] == 'd') {
+        diagnose = 1;
+      } else if (argv[i][j] == 'z') {
+        zeroindex = 1;
+      } else if (argv[i][j] == 'f') {
+        facesout = 1;
+      } else if (argv[i][j] == 'e') {
+        edgesout++;
+      } else if (argv[i][j] == 'n') {
+        neighout++;
+      } else if (argv[i][j] == 'v') {
+        voroout = 1;
+      } else if (argv[i][j] == 'g') {
+        meditview = 1;
+      } else if (argv[i][j] == 'G') {
+        gidview = 1;
+      } else if (argv[i][j] == 'O') {
+        geomview = 1;
+      } else if (argv[i][j] == 'M') {
+        nomerge = 1;
+      } else if (argv[i][j] == 'Y') {
+        nobisect++;
+      } else if (argv[i][j] == 'J') {
+        nojettison = 1;
+      } else if (argv[i][j] == 'B') {
+        nobound = 1;
+      } else if (argv[i][j] == 'N') {
+        nonodewritten = 1;
+      } else if (argv[i][j] == 'E') {
+        noelewritten = 1;
+        if (argv[i][j + 1] == '2') {
+          j++;
+          noelewritten = 2;
+        }
+      } else if (argv[i][j] == 'F') {
+        nofacewritten = 1;
+      } else if (argv[i][j] == 'I') {
+        noiterationnum = 1;
+      } else if (argv[i][j] == 'o') {
+        if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
+          k = 0;
+          while ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
+            j++;
+            workstring[k] = argv[i][j];
+            k++;
+          }
+          workstring[k] = '\0';
+          order = (int) strtol(workstring, (char **) NULL, 0);
+        }
+      } else if (argv[i][j] == 'S') {
+        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';
+          steinerleft = (int) strtol(workstring, (char **) NULL, 0);
+        } 
+      } else if (argv[i][j] == 'D') {
+        conformdel++;
+      } else 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';
+          epsilon = (REAL) strtod(workstring, (char **) NULL);
+        } 
+      } else if (argv[i][j] == 'C') {
+        docheck++;
+      } else if (argv[i][j] == 'Q') {
+        quiet = 1;
+      } else if (argv[i][j] == 'V') {
+        verbose++;
+      // } else if (argv[i][j] == 'v') {
+        // versioninfo();
+        // terminatetetgen(0);
+      } else if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
+                 (argv[i][j] == '?')) {
+        usage();
+        terminatetetgen(0);
+      } else {
+        printf("Warning:  Unknown switch -%c.\n", argv[i][j]);
+      }
+    }
+  }
+
+  if (startindex == 0) {
+    // Set a temporary filename for debugging output.
+    strcpy(infilename, "tetgen-tmpfile");
+  } else {
+    if (infilename[0] == '\0') {
+      // No input file name. Print the syntax and exit.
+      syntax();
+      terminatetetgen(0);
+    }
+    // Recognize the object from file extension if it is available.
+    if (!strcmp(&infilename[strlen(infilename) - 5], ".node")) {
+      infilename[strlen(infilename) - 5] = '\0';
+      object = NODES;
+    } else if (!strcmp(&infilename[strlen(infilename) - 5], ".poly")) {
+      infilename[strlen(infilename) - 5] = '\0';
+      object = POLY;
+      plc = 1;
+    } else if (!strcmp(&infilename[strlen(infilename) - 6], ".smesh")) {
+      infilename[strlen(infilename) - 6] = '\0';
+      object = POLY;
+      plc = 1;
+    } else if (!strcmp(&infilename[strlen(infilename) - 4], ".off")) {
+      infilename[strlen(infilename) - 4] = '\0';
+      object = OFF;
+      plc = 1;
+    } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ply")) {
+      infilename[strlen(infilename) - 4] = '\0';
+      object = PLY;
+      plc = 1;
+    } else if (!strcmp(&infilename[strlen(infilename) - 4], ".stl")) {
+      infilename[strlen(infilename) - 4] = '\0';
+      object = STL;
+      plc = 1;
+    } else if (!strcmp(&infilename[strlen(infilename) - 5], ".mesh")) {
+      infilename[strlen(infilename) - 5] = '\0';
+      object = MEDIT;
+      plc = 1;
+    } else if (!strcmp(&infilename[strlen(infilename) - 4], ".vtk")) {
+      infilename[strlen(infilename) - 4] = '\0';
+      object = VTK;
+      plc = 1;
+    } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ele")) {
+      infilename[strlen(infilename) - 4] = '\0';
+      object = MESH;
+      refine = 1;
+    }
+  }
+  plc = plc || diagnose;
+  useshelles = plc || refine || coarse || quality;
+  goodratio = minratio;
+  goodratio *= goodratio;
+
+  // Detect improper combinations of switches.
+  if (plc && refine) {
+    printf("Error:  Switch -r cannot use together with -p.\n");
+    return false;
+  }
+  if (refine && (plc || noiterationnum)) {
+    printf("Error:  Switches %s cannot use together with -r.\n",
+           "-p, -d, and -I");
+    return false;
+  }
+  if (diagnose && (quality || insertaddpoints || (order == 2) || neighout
+      || docheck)) {
+    printf("Error:  Switches %s cannot use together with -d.\n",
+           "-q, -i, -o2, -n, and -C");
+    return false;
+  }
+
+  // Be careful not to allocate space for element area constraints that 
+  //   will never be assigned any value (other than the default -1.0).
+  if (!refine && !plc) {
+    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 || !plc) {
+    regionattrib = 0;
+  }
+  // If '-a' or '-aa' is in use, enable '-q' option too.
+  if (fixedvolume || varvolume) {
+    if (quality == 0) {
+      quality = 1;
+    }
+  }
+  // Calculate the goodangle for testing bad subfaces.
+  goodangle = cos(minangle * PI / 180.0);
+  goodangle *= goodangle;
+
+  increment = 0;
+  strcpy(workstring, infilename);
+  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(outfilename, infilename);
+  } else if (increment == 0) {
+    strcpy(outfilename, infilename);
+    strcat(outfilename, ".1");
+  } else {
+    workstring[increment] = '%';
+    workstring[increment + 1] = 'd';
+    workstring[increment + 2] = '\0';
+    sprintf(outfilename, workstring, meshnumber + 1);
+  }
+  // Additional input file name has the end ".a".
+  strcpy(addinfilename, infilename);
+  strcat(addinfilename, ".a");
+  // Background filename has the form "*.b.ele", "*.b.node", ...
+  strcpy(bgmeshfilename, infilename);
+  strcat(bgmeshfilename, ".b");
+
+  return true;
+}
+
+#endif // ifndef behaviorCXX
diff --git a/contrib/TetgenNew/constrain.cxx b/contrib/TetgenNew/constrain.cxx
new file mode 100644
index 0000000000..2bdd61a326
--- /dev/null
+++ b/contrib/TetgenNew/constrain.cxx
@@ -0,0 +1,4416 @@
+#ifndef constrainCXX
+#define constrainCXX
+
+#include "tetgen.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// finddirection()    Find the tet on the path from one point to another.    //
+//                                                                           //
+// The path starts from 'searchtet''s origin and ends at 'endpt'. On finish, //
+// 'searchtet' contains a tet on the path, its origin does not change.       //
+//                                                                           //
+// The return value indicates one of the following cases (let 'searchtet' be //
+// abcd, a is the origin of the path):                                       //
+//   - ACROSSVERT, edge ab is collinear with the path;                       //
+//   - ACROSSEDGE, edge bc intersects with the path;                         //
+//   - ACROSSFACE, face bcd intersects with the path.                        //
+//                                                                           //
+// WARNING: This routine is designed for convex triangulations, and will not //
+// generally work after the holes and concavities have been carved.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::intersection tetgenmesh::finddirection(triface* searchtet, 
+  point endpt)
+{
+  triface neightet;
+  point pa, pb, pc, pd, pn;
+  enum {HMOVE, RMOVE, LMOVE} nextmove;
+  enum {HCOPLANE, RCOPLANE, LCOPLANE, NCOPLANE} cop;
+  REAL hori, rori, lori;
+  REAL dmin, dist;
+
+  tetrahedron ptr;
+  int *iptr, tver;
+
+  // The origin is fixed.
+  pa = org(*searchtet);
+  if ((point) searchtet->tet[7] == dummypoint) {
+    // A hull tet. Choose the neighbor of its base face.
+    searchtet->loc = 0;
+    symself(*searchtet);
+    // Reset the origin to be pa.
+    if ((point) searchtet->tet[4] == pa) {
+      searchtet->loc = 0; searchtet->ver = 0;
+    } else if ((point) searchtet->tet[5] == pa) {
+      searchtet->loc = 0; searchtet->ver = 2;
+    } else if ((point) searchtet->tet[6] == pa) {
+      searchtet->loc = 0; searchtet->ver = 4;
+    } else {
+      assert((point) searchtet->tet[7] == pa); // SELF_CHECK
+      searchtet->loc = 1; searchtet->ver = 2;
+    }
+  }
+  if (searchtet->ver & 01) {
+    // Switch to the 0th edge ring.
+    esymself(*searchtet);
+    enextself(*searchtet);
+  }
+  pb = dest(*searchtet);
+  pc = apex(*searchtet);
+
+  // Check whether the destination or apex is 'endpt'.
+  if (pb == endpt) {
+    // pa->pb is the search edge.
+    return ACROSSVERT;
+  }
+  if (pc == endpt) {
+    // pa->pc is the search edge.
+    enext2self(*searchtet);
+    esymself(*searchtet);
+    return ACROSSVERT;
+  }
+
+  // Walk through tets at pa until the right one is found.
+  while (1) {
+
+    pd = oppo(*searchtet);
+
+    if (b->verbose > 2) {
+      printf("      From tet (%d, %d, %d, %d) to %d.\n", pointmark(pa),
+        pointmark(pb), pointmark(pc), pointmark(pd), pointmark(endpt));
+    }
+
+    // Check whether the opposite vertex is 'endpt'.
+    if (pd == endpt) {
+      // pa->pd is the search edge.
+      enext0fnextself(*searchtet);
+      enext2self(*searchtet);
+      esymself(*searchtet);
+      return ACROSSVERT;
+    }
+    // Check if we have entered outside of the domain.
+    if (pd == dummypoint) {
+      assert(0);
+    }
+
+    // Now assume that the base face abc coincides with the horizon plane,
+    //   and d lies above the horizon.  The search point 'endpt' may lie
+    //   above or below the horizon.  We test the orientations of 'endpt'
+    //   with respect to three planes: abc (horizon), bad (right plane),
+    //   and acd (left plane). 
+    hori = orient3d(pa, pb, pc, endpt);
+    rori = orient3d(pb, pa, pd, endpt);
+    lori = orient3d(pa, pc, pd, endpt);
+    orient3dcount += 3;
+
+    // Now decide the tet to move.  It is possible there are more than one
+    //   tet are viable moves. Use the opposite points of thier neighbors
+    //   to discriminate, i.e., we choose the tet whose opposite point has
+    //   the shortest distance to 'endpt'.
+    if (hori > 0) {
+      if (rori > 0) {
+        if (lori > 0) {
+          // Any of the three neighbors is a viable move.
+          nextmove = HMOVE;
+          sym(*searchtet, neightet);
+          pn = oppo(neightet);
+          if (pn != dummypoint) {
+            dmin = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]);
+          } else {
+            dmin = NORM2(xmax - xmin, ymax - ymin, zmax - zmin);
+          }
+          enext0fnext(*searchtet, neightet);
+          symself(neightet);
+          pn = oppo(neightet);
+          if (pn != dummypoint) {
+            dist = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]);
+          } else {
+            dist = dmin;
+          }
+          if (dist < dmin) {
+            nextmove = RMOVE;
+            dmin = dist;
+          }
+          enext2fnext(*searchtet, neightet);
+          symself(neightet);
+          pn = oppo(neightet);
+          if (pn != dummypoint) {
+            dist = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]);
+          } else {
+            dist = dmin;
+          }
+          if (dist < dmin) {
+            nextmove = LMOVE;
+            dmin = dist;
+          }
+        } else {
+          // Two tets, below horizon and below right, are viable.
+          nextmove = HMOVE;
+          sym(*searchtet, neightet);
+          pn = oppo(neightet);
+          if (pn != dummypoint) {
+            dmin = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]);
+          } else {
+            dmin = NORM2(xmax - xmin, ymax - ymin, zmax - zmin);
+          }
+          enext0fnext(*searchtet, neightet);
+          symself(neightet);
+          pn = oppo(neightet);
+          if (pn != dummypoint) {
+            dist = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]);
+          } else {
+            dist = dmin;
+          }
+          if (dist < dmin) {
+            nextmove = RMOVE;
+            dmin = dist;
+          }
+        }
+      } else {
+        if (lori > 0) {
+          // Two tets, below horizon and below left, are viable.
+          nextmove = HMOVE;
+          sym(*searchtet, neightet);
+          pn = oppo(neightet);
+          if (pn != dummypoint) {
+            dmin = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]);
+          } else {
+            dmin = NORM2(xmax - xmin, ymax - ymin, zmax - zmin);
+          }
+          enext2fnext(*searchtet, neightet);
+          symself(neightet);
+          pn = oppo(neightet);
+          if (pn != dummypoint) {
+            dist = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]);
+          } else {
+            dist = dmin;
+          }
+          if (dist < dmin) {
+            nextmove = LMOVE;
+            dmin = dist;
+          }
+        } else {
+          // The tet below horizon is chosen.
+          nextmove = HMOVE;
+        }
+      }
+    } else {
+      if (rori > 0) {
+        if (lori > 0) {
+          // Two tets, below right and below left, are viable.
+          nextmove = RMOVE;
+          enext0fnext(*searchtet, neightet);
+          symself(neightet);
+          pn = oppo(neightet);
+          if (pn != dummypoint) {
+            dmin = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]);
+          } else {
+            dmin = NORM2(xmax - xmin, ymax - ymin, zmax - zmin);
+          }
+          enext2fnext(*searchtet, neightet);
+          symself(neightet);
+          pn = oppo(neightet);
+          if (pn != dummypoint) {
+            dist = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]);
+          } else {
+            dist = dmin;
+          }
+          if (dist < dmin) {
+            nextmove = LMOVE;
+            dmin = dist;
+          }
+        } else {
+          // The tet below right is chosen.
+          nextmove = RMOVE;
+        }
+      } else {
+        if (lori > 0) {
+          // The tet below left is chosen.
+          nextmove = LMOVE;
+        } else {
+          // 'endpt' lies either on the plane(s) or across face bcd.
+          if (hori == 0) {
+            if (rori == 0) {
+              // pa->'endpt' is COLLINEAR with pa->pb.
+              return ACROSSVERT;
+            }
+            if (lori == 0) {
+              // pa->'endpt' is COLLINEAR with pa->pc.
+              enext2self(*searchtet);
+              esymself(*searchtet);
+              return ACROSSVERT;
+            }
+            // pa->'endpt' crosses the edge pb->pc.
+            // enextself(*searchtet);
+            // return ACROSSEDGE;
+            cop = HCOPLANE;
+            break;
+          }
+          if (rori == 0) {
+            if (lori == 0) {
+              // pa->'endpt' is COLLINEAR with pa->pd.
+              enext0fnextself(*searchtet); // face abd.
+              enext2self(*searchtet);
+              esymself(*searchtet);
+              return ACROSSVERT;
+            }
+            // pa->'endpt' crosses the edge pb->pd.
+            // enext0fnextself(*searchtet); // face abd.
+            // enextself(*searchtet);
+            // return ACROSSEDGE;
+            cop = RCOPLANE;
+            break;
+          }
+          if (lori == 0) {
+            // pa->'endpt' crosses the edge pc->pd.
+            // enext2fnextself(*searchtet);  // face cad
+            // enext2self(*searchtet);
+            // return ACROSSEDGE;
+            cop = LCOPLANE;
+            break;
+          }
+          // pa->'endpt' crosses the face bcd.
+          // enextfnextself(*searchtet);
+          // return ACROSSFACE;
+          cop = NCOPLANE;
+          break;
+        }
+      }
+    }
+
+    // Move to the next tet, fix pa as its origin.
+    if (nextmove == RMOVE) {
+      fnextself(*searchtet);
+    } else if (nextmove == LMOVE) {
+      enext2self(*searchtet);
+      fnextself(*searchtet);
+      enextself(*searchtet);
+    } else { // HMOVE
+      symedgeself(*searchtet);
+      enextself(*searchtet);
+    }
+    assert(org(*searchtet) == pa); // SELF_CHECK
+    pb = dest(*searchtet);
+    pc = apex(*searchtet);
+
+  } // while (1)
+
+  // Either case ACROSSEDGE or ACROSSFACE.
+  if (b->epsilon > 0) {
+    // Use tolerance to re-evaluate the orientations.
+    if (cop != HCOPLANE) {
+      if (iscoplanar(pa, pb, pc, endpt, hori)) hori = 0;
+    }
+    if (cop != RCOPLANE) {
+      if (iscoplanar(pb, pa, pd, endpt, rori)) rori = 0;
+    }
+    if (cop != LCOPLANE) {
+      if (iscoplanar(pa, pc, pd, endpt, lori)) lori = 0;
+    }
+    // It is not possible that all orientations are zero.
+    assert(!((hori == 0) && (rori == 0) && (lori == 0))); // SELF_CHECK
+  }
+  
+  // Now decide the degenerate cases.
+  if (hori == 0) {
+    if (rori == 0) {
+      // pa->'endpt' is COLLINEAR with pa->pb.
+      return ACROSSVERT;
+    }
+    if (lori == 0) {
+      // pa->'endpt' is COLLINEAR with pa->pc.
+      enext2self(*searchtet);
+      esymself(*searchtet);
+      return ACROSSVERT;
+    }
+    // pa->'endpt' crosses the edge pb->pc.
+    return ACROSSEDGE;
+  }
+  if (rori == 0) {
+    if (lori == 0) {
+      // pa->'endpt' is COLLINEAR with pa->pd.
+      enext0fnextself(*searchtet); // face abd.
+      enext2self(*searchtet);
+      esymself(*searchtet);
+      return ACROSSVERT;
+    }
+    // pa->'endpt' crosses the edge pb->pd.
+    enext0fnextself(*searchtet); // face abd.
+    esymself(*searchtet);
+    enextself(*searchtet);
+    return ACROSSEDGE;
+  }
+  if (lori == 0) {
+    // pa->'endpt' crosses the edge pc->pd.
+    enext2fnextself(*searchtet);  // face cad
+    esymself(*searchtet);
+    return ACROSSEDGE;
+  }
+  // pa->'endpt' crosses the face bcd.
+  return ACROSSFACE;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// scoutsegment()    Look for a given segment in the tetrahedralization T.   //
+//                                                                           //
+// Search an edge in the tetrahedralization that matches the given segmment. //
+// If such an edge exists, the segment is 'locked' at the edge. 'searchtet'  //
+// returns this (constrained) edge. Otherwise, the segment is missing.       //
+//                                                                           //
+// The returned value indicates one of the following cases:                  //
+//   - SHAREEDGE, the segment exists and is inserted in T;                   //
+//   - ACROSSVERT, the segment intersects a vertex ('refpt').                //
+//   - ACROSSEDGE, the segment intersects an edge (in 'searchtet').          //
+//   - ACROSSFACE, the segment crosses a face (in 'searchtet').              //
+//                                                                           //
+// If the returned value is ACROSSEDGE or ACROSSFACE, i.e., the segment is   //
+// missing, 'refpt' returns the reference point for splitting thus segment,  //
+// 'searchtet' returns a tet containing the 'refpt'.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::intersection tetgenmesh::scoutsegment(face* sseg,
+  triface* searchtet, point* refpt)
+{
+  triface neightet, reftet;
+  face splitsh, checkseg;
+  point startpt, endpt;
+  point pa, pb, pc, pd;
+  enum location loc;
+  enum intersection dir;
+  REAL angmax, ang;
+  long facecount;
+  int types[2], poss[4];
+  int pos, i;
+
+  tetrahedron ptr;
+  shellface sptr;
+  int *iptr, tver;
+
+  startpt = sorg(*sseg);
+  endpt = sdest(*sseg);
+
+  // Is 'searchtet' a valid handle?
+  if (searchtet->tet == NULL) {
+    point2tetorg(startpt, *searchtet);
+  } else {
+    assert(org(*searchtet) == startpt); // SELF_CHECK
+  }
+
+  if (b->verbose > 1) {
+    printf("    Scout seg (%d, %d).\n", pointmark(startpt), pointmark(endpt));
+  }
+
+  dir = finddirection(searchtet, endpt);
+
+  if (dir == ACROSSVERT) {
+    pd = dest(*searchtet);
+    if (pd == endpt) {
+      // Found! Insert the segment.
+      tsspivot(*searchtet, checkseg);  // SELF_CHECK
+      if (checkseg.sh == NULL) {
+        // Let the segment remember an adjacent tet.
+        sstbond(*sseg, *searchtet);
+        neightet = *searchtet;
+        do {
+          tssbond1(neightet, *sseg);
+          fnextself(neightet);
+        } while (neightet.tet != searchtet->tet);
+      } else {
+        // Collision! This can happy during facet recovery.
+        // See fig/dump-cavity-case19, -case20.
+        assert(checkseg.sh == sseg->sh); // SELF_CHECK
+      }
+      // The job is done. 
+      return SHAREEDGE;
+    } else {
+      // A point is on the path.
+      *refpt = pd;
+      return ACROSSVERT;
+    }
+  }
+
+  if (b->verbose > 1) {
+    printf("    Scout ref point of seg (%d, %d).\n", pointmark(startpt), 
+      pointmark(endpt));
+  }
+  facecount = across_face_count;
+
+  enextfnextself(*searchtet); // Go to the opposite face.
+  symedgeself(*searchtet); // Enter the adjacent tet.
+
+  pa = org(*searchtet);
+  angmax = interiorangle(pa, startpt, endpt, NULL);
+  *refpt = pa;
+  pb = dest(*searchtet);
+  ang = interiorangle(pb, startpt, endpt, NULL);
+  if (ang > angmax) {
+    angmax = ang;
+    *refpt = pb;
+  }
+
+  // Check whether two segments are intersecting.
+  if (dir == ACROSSEDGE) {
+    tsspivot(*searchtet, checkseg);
+    if (checkseg.sh != NULL) {
+      printf("Error:  Invalid PLC. Two segments intersect.\n");
+      startpt = farsorg(*sseg);
+      endpt = farsdest(*sseg);
+      pa = farsorg(checkseg);
+      pb = farsdest(checkseg);
+      printf("  1st: (%d, %d), 2nd: (%d, %d).\n", pointmark(startpt), 
+        pointmark(endpt), pointmark(pa), pointmark(pb));
+      terminatetetgen(1);
+    }
+    across_edge_count++;
+  }
+  
+  pc = apex(*searchtet);
+  ang = interiorangle(pc, startpt, endpt, NULL);
+  if (ang > angmax) {
+    angmax = ang;
+    *refpt = pc;
+  }
+  reftet = *searchtet; // Save the tet containing the refpt.
+
+  // Search intersecting faces along the segment.
+  while (1) {
+
+    pd = oppo(*searchtet);
+    assert(pd != dummypoint);  // SELF_CHECK
+
+    if (b->verbose > 2) {
+      printf("      Passing face (%d, %d, %d, %d), dir(%d).\n", pointmark(pa),
+        pointmark(pb), pointmark(pc), pointmark(pd), (int) dir);
+    }
+    across_face_count++;
+
+    // Stop if we meet 'endpt'.
+    if (pd == endpt) break;
+
+    ang = interiorangle(pd, startpt, endpt, NULL);
+    if (ang > angmax) {
+      angmax = ang;
+      *refpt = pd;
+      reftet = *searchtet;
+    }
+
+    // Find a face intersecting the segment.
+    if (dir == ACROSSFACE) {
+      // One of the three oppo faces in 'searchtet' intersects the segment.
+      neightet.tet = searchtet->tet;
+      neightet.ver = 0;
+      for (i = 0; i < 3; i++) {
+        neightet.loc = locpivot[searchtet->loc][i];
+        pa = org(neightet);
+        pb = dest(neightet);
+        pc = apex(neightet);
+        pd = oppo(neightet); // The above point.
+        if (tri_edge_test(pa, pb, pc, startpt, endpt, pd, 1, types, poss)) {
+          dir = (enum intersection) types[0];
+          pos = poss[0];
+          break;
+        } else {
+          dir = DISJOINT;
+          pos = 0;
+        }
+      }
+      assert(dir != DISJOINT);  // SELF_CHECK
+    } else { // dir == ACROSSEDGE
+      // Check the two opposite faces (of the edge) in 'searchtet'.
+      neightet = *searchtet;
+      neightet.ver = 0;
+      for (i = 0; i < 2; i++) {
+        neightet.loc = locverpivot[searchtet->loc][searchtet->ver][i];
+        pa = org(neightet);
+        pb = dest(neightet);
+        pc = apex(neightet);
+        pd = oppo(neightet); // The above point.
+        if (tri_edge_test(pa, pb, pc, startpt, endpt, pd, 1, types, poss)) {
+          dir = (enum intersection) types[0];
+          pos = poss[0];
+          break;
+        } else {
+          dir = DISJOINT;
+          pos = 0;
+        }
+      }
+      if (dir == DISJOINT) {
+        // No intersection. Go to the next tet.
+        dir = ACROSSEDGE;
+        fnextself(*searchtet);
+        continue;
+      }
+    }
+
+    if (dir == ACROSSVERT) {
+      // This segment passing a vertex. Choose it and return.
+      for (i = 0; i < pos; i++) {
+        enextself(neightet);
+      }
+      pd = org(neightet);
+      if (b->verbose > 2) {
+        angmax = interiorangle(pd, startpt, endpt, NULL);
+      }
+      *refpt = pd;
+      break;
+    }
+    if (dir == ACROSSEDGE) {
+      // Get the edge intersects with the segment.
+      for (i = 0; i < pos; i++) {
+        enextself(neightet);
+      }
+    }
+    // Go to the next tet.
+    symedge(neightet, *searchtet);
+
+    if (dir == ACROSSEDGE) {
+      // Check whether two segments are intersecting.
+      tsspivot(*searchtet, checkseg);
+      if (checkseg.sh != NULL) {
+        printf("Error:  Invalid PLC! Two segments intersect.\n");
+        startpt = farsorg(*sseg);
+        endpt = farsdest(*sseg);
+        pa = farsorg(checkseg);
+        pb = farsdest(checkseg);
+        printf("    1st: (%d, %d), 2nd: (%d, %d).\n", pointmark(startpt), 
+          pointmark(endpt), pointmark(pa), pointmark(pb));
+        terminatetetgen(1);
+      }
+      across_edge_count++;
+    }
+
+  } // while (1)
+
+  // dir is either ACROSSVERT, or ACROSSEDGE, or ACROSSFACE.
+  if (b->verbose > 2) {
+    printf("      Refpt %d (%g), visited %ld faces.\n", pointmark(*refpt),
+      angmax / PI * 180.0, (int) dir, across_face_count - facecount);
+  }
+  if (across_face_count - facecount > across_max_count) {
+    across_max_count = across_face_count - facecount;
+  }
+
+  *searchtet = reftet;
+  return dir;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// getsegmentsplitpoint()    Calculate a split point in the given segment.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::getsegmentsplitpoint(face* sseg, point refpt, REAL* vt)
+{
+  point ei, ej, ek;
+  REAL split, L, d, d1, d2, d3;
+  int stype, sign;
+  int i;
+
+  // Decide the type of this segment.
+  sign = 1;
+  ei = sorg(*sseg);
+  ej = sdest(*sseg);
+
+  if (getpointtype(ei) == ACUTEVERTEX) {
+    if (getpointtype(ej) == ACUTEVERTEX) {
+      // Both ei and ej are ACUTEVERTEX.
+      stype = 0;
+    } else {
+      // ej is either a RIDGEVERTEX or a STEINERVERTEX.
+      stype = 1;
+    }
+  } else {
+    if (getpointtype(ei) == RIDGEVERTEX) {
+      if (getpointtype(ej) == ACUTEVERTEX) {
+        stype = 1; sign = -1;
+      } else {
+        if (getpointtype(ej) == RIDGEVERTEX) {
+          // Both ei and ej are non-acute.
+          stype = 0;
+        } else {
+          // ej is a STEINERVETEX.
+          ek = farsdest(*sseg);
+          if (getpointtype(ek) == ACUTEVERTEX) {
+            stype = 1; sign = -1;
+          } else {
+            stype = 0;
+          }
+        }
+      }
+    } else {
+      // ei is a STEINERVERTEX.
+      if (getpointtype(ej) == ACUTEVERTEX) {
+        stype = 1; sign = -1;
+      } else {
+        ek = farsorg(*sseg);
+        if (getpointtype(ej) == RIDGEVERTEX) {
+          if (getpointtype(ek) == ACUTEVERTEX) {
+            stype = 1;
+          } else {
+            stype = 0;
+          }
+        } else {
+          // Both ei and ej are STEINERVETEXs. ei has priority.
+          if (getpointtype(ek) == ACUTEVERTEX) {
+            stype = 1;
+          } else {
+            ek = farsdest(*sseg);
+            if (getpointtype(ek) == ACUTEVERTEX) {
+              stype = 1; sign = -1;
+            } else {
+              stype = 0;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // Adjust the endpoints: ei, ej.
+  if (sign == -1) {
+    sesymself(*sseg);
+    ei = sorg(*sseg);
+    ej = sdest(*sseg);
+  }
+
+  if (b->verbose > 1) {
+    printf("    Split a type-%d seg(%d, %d) ref(%d)", stype,
+      pointmark(ei), pointmark(ej), pointmark(refpt));
+    if (stype) {
+      ek = farsorg(*sseg);
+      printf(" ek(%d)", pointmark(ek));
+    }
+    printf(".\n");
+  }
+
+  // Calculate the split point.
+  if (stype == 0) {
+    // Use rule-1.
+    L = DIST(ei, ej);
+    d1 = DIST(ei, refpt);
+    d2 = DIST(ej, refpt);
+    if (d1 < d2) {
+      // Choose ei as center.
+      if (d1 < 0.5 * L) {
+        split = d1 / L;
+        // Adjust split if it is close to middle. (2009-02-01)
+        if ((split > 0.4) || (split < 0.6)) split = 0.5;
+      } else {
+        split = 0.5;
+      }
+      for (i = 0; i < 3; i++) {
+        vt[i] = ei[i] + split * (ej[i] - ei[i]);
+      }
+    } else {
+      // Choose ej as center.
+      if (d2 < 0.5 * L) {
+        split = d2 / L;
+        // Adjust split if it is close to middle. (2009-02-01)
+        if ((split > 0.4) || (split < 0.6)) split = 0.5;
+      } else {
+        split = 0.5;
+      }
+      for (i = 0; i < 3; i++) {
+        vt[i] = ej[i] + split * (ei[i] - ej[i]);
+      }
+    }
+    r1count++;
+  } else {
+    // Use rule-2.
+    ek = farsorg(*sseg);
+    L = DIST(ek, ej);
+    d = DIST(ek, refpt);
+    split = d / L;
+    for (i = 0; i < 3; i++) {
+      vt[i] = ek[i] + split * (ej[i] - ek[i]);
+    }
+    d1 = DIST(vt, refpt);
+    d2 = DIST(vt, ej);
+    if (d1 > d2) {
+      // Use rule-3.
+      d3 = DIST(ei, refpt);
+      if (d1 < 0.5 * d3) {
+        split = (d - d1) / L;
+      } else {
+        split = (d - 0.5 * d3) / L;
+      }
+      for (i = 0; i < 3; i++) {
+        vt[i] = ek[i] + split * (ej[i] - ek[i]);
+      }
+    }
+    d1 > d2 ? r3count++ : r2count++;
+  }
+
+  if (b->verbose > 1) {
+    printf("    split (%g), vt (%g, %g, %g).\n", split, vt[0], vt[1], vt[2]);
+  }
+}
+
+// This function only use Rule-1 to split the segment. refpt may be NULL.
+// Added 2009-05-20.
+
+void tetgenmesh::getsegmentsplitpoint2(face* sseg, point refpt, REAL* vt)
+{
+  point ei, ej;
+  REAL split, L, d, d1, d2;
+  int i;
+
+  ei = sorg(*sseg);
+  ej = sdest(*sseg);
+
+  if (b->verbose > 1) {
+    printf("    Split seg(%d, %d) ref(%d).\n", pointmark(ei), pointmark(ej), 
+      refpt ? pointmark(refpt) : -1);
+  }
+
+  if (refpt != NULL) {
+    L = DIST(ei, ej);
+    d1 = DIST(ei, refpt);
+    d2 = DIST(ej, refpt);
+    if (d1 < d2) {
+      // Choose ei as center.
+      if (d1 < 0.5 * L) {
+        split = d1 / L;
+        // Adjust split if it is close to middle. (2009-02-01)
+        // if ((split > 0.4) || (split < 0.6)) split = 0.5;
+      } else {
+        split = 0.5;
+      }
+      for (i = 0; i < 3; i++) {
+        vt[i] = ei[i] + split * (ej[i] - ei[i]);
+      }
+    } else {
+      // Choose ej as center.
+      if (d2 < 0.5 * L) {
+        split = d2 / L;
+        // Adjust split if it is close to middle. (2009-02-01)
+        // if ((split > 0.4) || (split < 0.6)) split = 0.5;
+      } else {
+        split = 0.5;
+      }
+      for (i = 0; i < 3; i++) {
+        vt[i] = ej[i] + split * (ei[i] - ej[i]);
+      }
+    }
+  } else {
+    split = 0.5;
+    for (i = 0; i < 3; i++) {
+      vt[i] = ei[i] + split * (ej[i] - ei[i]);
+    }
+  }
+  r1count++;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// getsegmentsplitpoint3()    Calculate a split point in the given segment.  //
+//                                                                           //
+// This routine does not check far origin and far dest.                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::getsegmentsplitpoint3(face* sseg, point refpt, REAL* vt)
+{
+  point ei, ej, ek;
+  REAL split, L, d, d1, d2, d3;
+  int stype, sign;
+  int i;
+
+  // Decide the type of this segment.
+  sign = 1;
+  ei = sorg(*sseg);
+  ej = sdest(*sseg);
+  ek = NULL;
+
+  // ei can be an ACUTEVERTEX, or a RIDGEVERTEX, or a STEINERVERTEX.
+  if (getpointtype(ei) == ACUTEVERTEX) {
+    if (getpointtype(ej) == ACUTEVERTEX) {
+      // ej is an ACUTEVERTEX.
+      stype = 0;
+    } else {
+      // ej is either a RIDGEVERTEX or a STEINERVERTEX.
+      stype = 1;
+      ek = ei;
+    }
+  } else {
+    if (getpointtype(ei) == RIDGEVERTEX) {
+      if (getpointtype(ej) == ACUTEVERTEX) {
+        // ej is an ACUTEVERTEX.
+        stype = 1; 
+        sign = -1; // Exchange ei and ej.
+        ek = ej;
+      } else {
+        if (getpointtype(ej) == RIDGEVERTEX) {
+          // ej is a RIDGEVERTEX.
+          stype = 0;
+        } else {
+          // ej is a STEINERVETEX.
+          stype = 0;
+          /* ek = farsdest(*sseg);
+          if (getpointtype(ek) == ACUTEVERTEX) {
+            stype = 1; sign = -1;
+          } else {
+            stype = 0;
+          }*/
+        }
+      }
+    } else {
+      // ei is a STEINERVERTEX.
+      if (getpointtype(ej) == ACUTEVERTEX) {
+        stype = 1; 
+        sign = -1; // Exchange ei and ej.
+        ek = ej;
+      } else {
+        // ej is either a RIDGEVERTEX or STEINERVERTEX.
+        stype = 0;
+        /*ek = farsorg(*sseg);
+        if (getpointtype(ej) == RIDGEVERTEX) {
+          if (getpointtype(ek) == ACUTEVERTEX) {
+            stype = 1;
+          } else {
+            stype = 0;
+          }
+        } else {
+          // Both ei and ej are STEINERVETEXs. ei has priority.
+          if (getpointtype(ek) == ACUTEVERTEX) {
+            stype = 1;
+          } else {
+            ek = farsdest(*sseg);
+            if (getpointtype(ek) == ACUTEVERTEX) {
+              stype = 1; sign = -1;
+            } else {
+              stype = 0;
+            }
+          }
+        }*/
+      }
+    }
+  }
+
+  // Adjust the endpoints: ei, ej.
+  if (sign == -1) {
+    sesymself(*sseg);
+    ei = sorg(*sseg);
+    ej = sdest(*sseg);
+  }
+
+  if (b->verbose > 1) {
+    printf("    Split a type-%d seg(%d, %d) ref(%d).\n", stype,
+      pointmark(ei), pointmark(ej), pointmark(refpt));
+  }
+
+  // Calculate the split point.
+  if (stype == 0) {
+    // Use rule-1.
+    L = DIST(ei, ej);
+    d1 = DIST(ei, refpt);
+    d2 = DIST(ej, refpt);
+    if (d1 < d2) {
+      // Choose ei as center.
+      if (d1 < 0.5 * L) {
+        split = d1 / L;
+        // Adjust split if it is close to middle. (2009-02-01)
+        if ((split > 0.4) || (split < 0.6)) split = 0.5;
+      } else {
+        split = 0.5;
+      }
+      for (i = 0; i < 3; i++) {
+        vt[i] = ei[i] + split * (ej[i] - ei[i]);
+      }
+    } else {
+      // Choose ej as center.
+      if (d2 < 0.5 * L) {
+        split = d2 / L;
+        // Adjust split if it is close to middle. (2009-02-01)
+        if ((split > 0.4) || (split < 0.6)) split = 0.5;
+      } else {
+        split = 0.5;
+      }
+      for (i = 0; i < 3; i++) {
+        vt[i] = ej[i] + split * (ei[i] - ej[i]);
+      }
+    }
+    r1count++;
+  } else {
+    // Use rule-2.
+    // ek = farsorg(*sseg);
+    L = DIST(ek, ej);
+    d = DIST(ek, refpt);
+    split = d / L;
+    for (i = 0; i < 3; i++) {
+      vt[i] = ek[i] + split * (ej[i] - ek[i]);
+    }
+    d1 = DIST(vt, refpt);
+    d2 = DIST(vt, ej);
+    if (d1 > d2) {
+      // Use rule-3.
+      d3 = DIST(ei, refpt);
+      if (d1 < 0.5 * d3) {
+        split = (d - d1) / L;
+      } else {
+        split = (d - 0.5 * d3) / L;
+      }
+      for (i = 0; i < 3; i++) {
+        vt[i] = ek[i] + split * (ej[i] - ek[i]);
+      }
+    }
+    d1 > d2 ? r3count++ : r2count++;
+  }
+
+  if (b->verbose > 1) {
+    printf("    split (%g), vt (%g, %g, %g).\n", split, vt[0], vt[1], vt[2]);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// delaunizesegments()    Recover segments in a Delaunay tetrahedralization. //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::delaunizesegments()
+{
+  triface searchtet;
+  face splitsh;
+  face *psseg, sseg;
+  point refpt, newpt;
+  enum intersection dir;
+  bool visflag;
+
+  // Loop until 'subsegstack' is empty.
+  while (subsegstack->objects > 0l) {
+    // seglist is used as a stack.
+    subsegstack->objects--;
+    psseg = (face *) fastlookup(subsegstack, subsegstack->objects);
+    sseg = *psseg;
+
+    if (!sinfected(sseg)) continue; // Not a missing segment.
+    suninfect(sseg);
+
+    // Insert the segment.
+    searchtet.tet = NULL;
+    dir = scoutsegment(&sseg, &searchtet, &refpt);
+
+    if (dir != SHAREEDGE) {
+      // The segment is missing, split it.
+      spivot(sseg, splitsh);
+      if (dir != ACROSSVERT) {
+        // Create the new point.
+        makepoint(&newpt);
+        // getsegmentsplitpoint(&sseg, refpt, newpt);
+        getsegmentsplitpoint3(&sseg, refpt, newpt);
+        setpointtype(newpt, STEINERVERTEX);
+        // Split the segment by newpt.
+        sinsertvertex(newpt, &splitsh, &sseg, true, false);
+        // Insert newpt into the DT. If 'checksubfaces == 1' the current
+        //   mesh is constrained Delaunay (but may not Delaunay).
+        visflag = (checksubfaces == 1);
+        insertvertex(newpt, &searchtet, true, visflag, false, false);
+      } else {
+        /*if (getpointtype(refpt) != ACUTEVERTEX) {
+          setpointtype(refpt, RIDGEVERTEX);
+        }
+        // Split the segment by refpt.
+        sinsertvertex(refpt, &splitsh, &sseg, true, false);*/
+        printf("Error:  Invalid PLC! A point and a segment intersect.\n");
+        point pa, pb;
+        pa = farsorg(sseg);
+        pb = farsdest(sseg);
+        printf("  Point: %d. Segment: (%d, %d).\n", pointmark(refpt),
+          pointmark(pa), pointmark(pb));
+        terminatetetgen(1);
+      }
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// scoutsubface()    Look for a given subface in the tetrahedralization T.   //
+//                                                                           //
+// 'ssub' is the subface, denoted as abc. If abc exists in T, it is 'locked' //
+// at the place where the two tets sharing at it.                            //
+//                                                                           //
+// The returned value indicates one of the following cases:                  //
+//   - SHAREFACE, abc exists and is inserted;                                //
+//   - TOUCHEDGE, a vertex (the origin of 'searchtet') lies on ab.           //
+//   - EDGETRIINT, all three edges of abc are missing.                       //
+//   - ACROSSTET, a tet (in 'searchtet') crosses the facet containg abc.     //
+//                                                                           //
+// If the retunred value is ACROSSTET, the subface is missing.  'searchtet'  //
+// returns a tet which shares the same edge as 'pssub'.                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::intersection tetgenmesh::scoutsubface(face* pssub,
+  triface* searchtet)
+{
+  triface spintet;
+  face checksh;
+  point pa, pb, pc, pd;
+  enum intersection dir;
+  int i;
+
+  tetrahedron ptr;
+  int tver;
+
+  if (searchtet->tet == NULL) {
+    // Search an edge of 'ssub' in tetrahedralization.
+    pssub->shver = 0;
+    for (i = 0; i < 3; i++) {
+      pa = sorg(*pssub);
+      pb = sdest(*pssub);
+      // Do not search dummypoint.
+      assert(pa != dummypoint); // SELF_CHECK
+      assert(pb != dummypoint); // SELF_CHECK
+      // Get a tet whose origin is pa.
+      decode(point2tet(pa), *searchtet);
+      assert(searchtet->tet != NULL); // SELF_CHECK
+      assert(searchtet->tet[4] != NULL); // SELF_CHECK
+      if ((point) searchtet->tet[4] == pa) {
+        searchtet->loc = 0; searchtet->ver = 0;
+      } else if ((point) searchtet->tet[5] == pa) {
+        searchtet->loc = 0; searchtet->ver = 2;
+      } else if ((point) searchtet->tet[6] == pa) {
+        searchtet->loc = 0; searchtet->ver = 4;
+      } else {
+        if ((point) searchtet->tet[7] != pa) {
+          printf("Error: Bad pt-to-tet at %d\n", pointmark(pa));
+          assert(0);
+        }
+        searchtet->loc = 1; searchtet->ver = 2;
+      }
+      // Search the edge from pa->pb.
+      dir = finddirection(searchtet, pb);
+      if (dir == ACROSSVERT) {
+        if (dest(*searchtet) == pb) {
+          // Found the edge. Break the loop.
+          break;
+        } else {
+          // A vertex lies on the search edge. Return it.
+          enextself(*searchtet);
+          return TOUCHEDGE;
+        }
+      }
+      senextself(*pssub);
+    }
+    if (i == 3) {
+      // None of the three edges exists.
+      return EDGETRIINT; // ab intersects the face in 'searchtet'.
+    }
+  } else {
+    // 'searchtet' holds the current edge of 'pssub'.
+    pa = org(*searchtet);
+    pb = dest(*searchtet);
+  }
+
+  pc = sapex(*pssub);
+
+  if (b->verbose > 1) {
+    printf("    Scout subface (%d, %d, %d) (%ld).\n", pointmark(pa),
+      pointmark(pb), pointmark(pc), subfacstack->objects);
+  }
+
+  // Searchtet holds edge pa->pb. Search a face with apex pc.
+  spintet = *searchtet;
+  while (1) {
+    fnextself(spintet);
+    pd = apex(spintet);  // pd may be dummypoint. Search the face anyway.
+    if (pd == pc) {
+      // Found! Insert the subface.
+      tspivot(spintet, checksh); // SELF_CHECK
+      if (checksh.sh == NULL) {
+        tsbond(spintet, *pssub);
+        symedgeself(spintet);
+        tspivot(spintet, checksh); // SELF_CHECK
+        assert(checksh.sh == NULL); // SELF_CHECK
+        tsbond(spintet, *pssub);
+        return SHAREFACE;
+      } else {
+        // Another subface is laready inserted.
+        assert(checksh.sh != pssub->sh); // SELF_CHECK
+        // Comment: This is possible when there are faked tets.
+        *searchtet = spintet;
+        return COLLISIONFACE;
+      }
+    }
+    if (pd == apex(*searchtet)) break;
+  }
+
+  return ACROSSTET;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// scoutcrosstet()    Scout a tetrahedron across a facet.                    //
+//                                                                           //
+// A subface (abc) of the facet (F) is given in 'pssub', 'searchtet' holds   //
+// the edge ab, it is the tet starting the search.  'facpoints' contains all //
+// points which are co-facet with a, b, and c.                               //
+//                                                                           //
+// The subface (abc) was produced by a 2D CDT algorithm under the Assumption //
+// that F is flat. In real data, however, F may not be strictly flat.  Hence //
+// a tet (abde) that crosses abc may be in one of the two cases: (i) abde    //
+// intersects F in its interior, or (ii) abde intersects F on its boundary.  //
+// In case (i) F (or part of it) is missing in DT and needs to be recovered. //
+// In (ii) F is not missing, the surface mesh of F needs to be adjusted.     //
+//                                                                           //
+// This routine distinguishes the two cases by the returned value, which is  //
+//   - ACROSSTET, if it is case (i), 'searchtet' is abde, d and e lies below //
+//     and above abc, respectively, neither d nor e is dummypoint; or        //
+//   - ACROSSFACE, if it is case (ii), 'searchtet' is abde, where the face   //
+//     abd intersects abc, i.e., d is co-facet with abc, e may be co-facet   //
+//     with abc or dummypoint.                                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::intersection tetgenmesh::scoutcrosstet(face *pssub, 
+  triface* searchtet, arraypool* facpoints)
+{
+  triface spintet, crossface;
+  point pa, pb, pc, pd, pe;
+  REAL ori, ori1, len, n[3];
+  REAL r, dr, drmin;
+  bool cofacetflag;
+  int i;
+
+  if (facpoints != NULL) {
+    // Infect all vertices of the facet.
+    for (i = 0; i < facpoints->objects; i++) {
+      pd = * (point *) fastlookup(facpoints, i);
+      pinfect(pd);
+    }
+  }
+
+  // Search an edge crossing the facet containing abc.
+  if (searchtet->ver & 01) {
+    esymself(*searchtet); // Adjust to 0th edge ring.
+    sesymself(*pssub);
+  }
+
+  pa = sorg(*pssub);
+  pb = sdest(*pssub);
+  pc = sapex(*pssub);
+
+  // Search an apex lies below the subface. Note that such apex may not
+  //   exist which indicates there is a co-facet apex.
+  cofacetflag = false;
+  pd = apex(*searchtet);
+  spintet = *searchtet;
+  while (1) {
+    if (pd != dummypoint) {
+      ori = orient3d(pa, pb, pc, pd);
+      if ((ori != 0) && pinfected(pd)) {
+        ori = 0; // Force d be co-facet with abc.
+      }
+      if (ori > 0) {
+        break; // Found a lower point.
+      }
+    }
+    fnextself(spintet); // Go to the next face.
+    pd = apex(spintet);
+    if (pd == apex(*searchtet)) {
+      cofacetflag = true; break; // Not found.
+    }
+  }
+  if (!cofacetflag) {
+    // Search a tet whose apex->oppo crosses the facet containig abc.
+    while (1) {
+      pe = oppo(spintet);
+      if (pe != dummypoint) {
+        ori = orient3d(pa, pb, pc, pe);
+        if ((ori != 0) && pinfected(pe)) {
+          ori = 0; // Force pe be co-facet with abc.
+        }
+        if (ori < 0) {
+          break;  // stop at pd->pe.
+        }
+        if (ori == 0) {
+          cofacetflag = true; break; // Found a co-facet point.
+        }
+      }    
+      fnextself(spintet);
+    }
+    *searchtet = spintet;
+    // Now if "cofacetflag != true", searchtet contains a cross tet (abde), 
+    //   where d and e lie below and above abc, respectively, and 
+    //   orient3d(a, b, d, e) < 0.
+  }
+
+  if (cofacetflag) {
+    // There are co-facet points. Calculate a point above the subface.
+    facenormal(pa, pb, pc, n, 1);
+    len = sqrt(DOT(n, n));
+    n[0] /= len;
+    n[1] /= len;
+    n[2] /= len;
+    len = DIST(pa, pb);
+    len += DIST(pb, pc);
+    len += DIST(pc, pa);
+    len /= 3.0;
+    dummypoint[0] = pa[0] + len * n[0];
+    dummypoint[1] = pa[1] + len * n[1];
+    dummypoint[2] = pa[2] + len * n[2];
+    // Search a co-facet point d, s.t. (i) [a, b, d] intersects [a, b, c],
+    //   AND (ii) a, b, c, d has the closet circumradius of [a, b, c].
+    // NOTE: (ii) is needed since there may be several points satisfy (i).
+    circumsphere(pa, pb, pc, NULL, n, &r);
+    crossface.tet = NULL;
+    pe = apex(*searchtet);
+    spintet = *searchtet;
+    while (1) {
+      pd = apex(spintet);
+      if (pd != dummypoint) {
+        ori = orient3d(pa, pb, pc, pd);
+        if ((ori == 0) || pinfected(pd)) {
+          ori1 = orient3d(pa, pb, dummypoint, pd);
+          if (ori1 > 0) {
+            // [a, b, d] intersects with [a, b, c].
+            if (pinfected(pd)) {
+              len = DIST(n, pd);
+              dr = fabs(len - r);
+              if (crossface.tet == NULL) {
+                // This is the first cross face.
+                crossface = spintet;
+                drmin = dr;
+              } else {
+                if (dr < drmin) {
+                  crossface = spintet;
+                  drmin = dr;
+                }
+              }
+            } else {
+              assert(ori == 0); // SELF_CHECK
+              // Found a coplanar but not co-facet point (pd).
+              printf("Error:  Invalid PLC! A point and a subface intersect\n");
+              // get_origin_facet_corners(pssub, &pa, &pb, &pc);
+              printf("  Point %d. Subface (#%d) (%d, %d, %d)\n", 
+                pointmark(pd), getshellmark(*pssub), pointmark(pa), 
+                pointmark(pb), pointmark(pc));
+              terminatetetgen(1);
+            }
+          }
+        }
+      }
+      fnextself(spintet); // Go to the next face.
+      // assert(apex(spintet) != pe); // SELF_CHECK
+      if (apex(spintet) == pe) {
+        break;
+      }
+    }
+    if(crossface.tet == NULL) {
+      assert(crossface.tet != NULL); // Not handled yet.
+    }
+    *searchtet = crossface;
+    dummypoint[0] = dummypoint[1] = dummypoint[2] = 0;
+  }
+
+  if (cofacetflag) {
+    if (b->verbose > 1) {
+      printf("    Found a co-facet face (%d, %d, %d) op (%d).\n", 
+        pointmark(pa), pointmark(pb), pointmark(apex(*searchtet)), 
+        pointmark(oppo(*searchtet)));
+    }
+    if (facpoints != NULL) {
+      // Unmark all facet vertices.
+      for (i = 0; i < facpoints->objects; i++) {
+        pd = * (point *) fastlookup(facpoints, i);
+        puninfect(pd);
+      }
+    }
+    // Comment: Now no vertex is infected.
+    if (getpointtype(apex(*searchtet)) == VOLVERTEX) {
+      // A vertex lies on the facet.
+      enext2self(*searchtet); // org(*searchtet) == pd
+      return TOUCHFACE;
+    }
+    return ACROSSFACE;
+  } else {
+    // Return a crossing tet.
+    if (b->verbose > 1) {
+      printf("    Found a crossing tet (%d, %d, %d, %d).\n", pointmark(pa),
+        pointmark(pb), pointmark(apex(spintet)), pointmark(pe));
+    }
+    // Comment: if facpoints != NULL, co-facet vertices are stll infected.
+    //   They will be uninfected in formcavity();
+    return ACROSSTET; // abc intersects the volume of 'searchtet'.
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// recoversubfacebyflips()   Recover a subface by flips in the surface mesh. //
+//                                                                           //
+// A subface [a, b, c] ('pssub') intersects with a face [a, b, d] ('cross-   //
+// face'), where a, b, c, and d belong to the same facet.  It indicates that //
+// the face [a, b, d] should appear in the surface mesh.                     //
+//                                                                           //
+// This routine recovers [a, b, d] in the surface mesh through a sequence of //
+// 2-to-2 flips. No Steiner points is needed. 'pssub' returns [a, b, d].     //
+//                                                                           //
+// If 'facfaces' is not NULL, all flipped subfaces are queued for recovery.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::recoversubfacebyflips(face* pssub, triface* crossface, 
+  arraypool *facfaces)
+{
+  triface neightet;
+  face flipfaces[2];
+  face checkseg;
+  point pa, pb, pc, pd, pe;
+  REAL ori, len, n[3];
+
+  tetrahedron ptr;
+  shellface sptr;
+  int tver;
+
+  // Get the missing subface is [a, b, c].
+  pa = sorg(*pssub);
+  pb = sdest(*pssub);
+  pc = sapex(*pssub);
+
+  // The crossface is [a, b, d, e].
+  // assert(org(*crossface) == pa);
+  // assert(dest(*crossface) == pb);
+  pd = apex(*crossface);
+  pe = dummypoint; // oppo(*crossface);
+
+  if (pe == dummypoint) {
+    // Calculate a point above the faces.
+    facenormal(pa, pb, pd, n, 1);
+    len = sqrt(DOT(n, n));
+    n[0] /= len;
+    n[1] /= len;
+    n[2] /= len;
+    len = DIST(pa, pb);
+    len += DIST(pb, pd);
+    len += DIST(pd, pa);
+    len /= 3.0;
+    pe[0] = pa[0] + len * n[0];
+    pe[1] = pa[1] + len * n[1];
+    pe[2] = pa[2] + len * n[2];
+  }
+
+  // Adjust face [a, b, c], so that edge [b, c] crosses edge [a, d].
+  ori = orient3d(pb, pc, pe, pd);
+  assert(ori != 0); // SELF_CHECK
+
+  if (ori > 0) {
+    // Swap a and b.
+    sesymself(*pssub);
+    symedgeself(*crossface);
+    pa = sorg(*pssub);
+    pb = sdest(*pssub);
+    if (pe == dummypoint) {
+      pe[0] = pe[1] = pe[2] = 0;
+    }
+    pe = dummypoint; // oppo(*crossface);
+  }
+
+  while (1) {
+
+    // Flip edge [b, c], edge [a, d] is missing.
+    senext(*pssub, flipfaces[0]);
+    sspivot(flipfaces[0], checkseg); // SELF_CHECK
+    assert(checkseg.sh == NULL); // SELF_CHECK
+    spivot(flipfaces[0], flipfaces[1]);
+
+    stpivot(flipfaces[1], neightet);
+    if (neightet.tet != NULL) {
+      // A recovered subface, clean sub<==>tet connections.
+      tsdissolve(neightet);
+      symself(neightet);
+      tsdissolve(neightet);
+      stdissolve(flipfaces[1]);
+    }
+
+    flip22(flipfaces, 0);
+
+    // Add them into list (make ensure that they must be recovered).
+    facfaces->newindex((void **) &pssub);
+    *pssub = flipfaces[0];
+    facfaces->newindex((void **) &pssub);
+    *pssub = flipfaces[1];
+
+    // Find the edge [a, b].
+    senext(flipfaces[1], *pssub);
+    assert(sorg(*pssub) == pa); // SELF_CHECK
+    assert(sdest(*pssub) == pb); // SELF_CHECK
+
+    pc = sapex(*pssub);
+    if (pc == pd) break;
+
+    if (pe == dummypoint) {
+      // Calculate a point above the faces.
+      facenormal(pa, pb, pd, n, 1);
+      len = sqrt(DOT(n, n));
+      n[0] /= len;
+      n[1] /= len;
+      n[2] /= len;
+      len = DIST(pa, pb);
+      len += DIST(pb, pd);
+      len += DIST(pd, pa);
+      len /= 3.0;
+      pe[0] = pa[0] + len * n[0];
+      pe[1] = pa[1] + len * n[1];
+      pe[2] = pa[2] + len * n[2];
+    }
+
+    while (1) {
+      ori = orient3d(pb, pc, pe, pd);
+      assert(ori != 0); // SELF_CHECK
+      if (ori > 0) {
+        senext2self(*pssub);
+        spivotself(*pssub);
+        if (sorg(*pssub) != pa) sesymself(*pssub);
+        pb = sdest(*pssub);
+        pc = sapex(*pssub);
+        continue;
+      }
+      break;
+    }
+  }
+
+  if (pe == dummypoint) {
+    pe[0] = pe[1] = pe[2] = 0;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// formcavity()    Form the cavity of a missing region.                      //
+//                                                                           //
+// A missing region R is a set of co-facet (co-palanr) subfaces. 'pssub' is  //
+// a missing subface [a, b, c]. 'crosstets' contains only one tet, [a, b, d, //
+// e], where d and e lie below and above [a, b, c], respectively.  Other     //
+// crossing tets are sought from this tet and saved in 'crosstets'.          //
+//                                                                           //
+// The cavity C is divided into two parts by R,one at top and one at bottom. //
+// 'topfaces' and 'botfaces' return the upper and lower boundary faces of C. //
+// 'toppoints' contains vertices of 'crosstets' in the top part of C, and so //
+// does 'botpoints'. Both 'toppoints' and 'botpoints' contain vertices of R. //
+//                                                                           //
+// NOTE: 'toppoints' may contain points which are not vertices of any top    //
+// faces, and so may 'botpoints'. Such points may belong to other facets and //
+// need to be present after the recovery of this cavity (P1029.poly).        //
+//                                                                           //
+// A pair of boundary faces: 'firsttopface' and 'firstbotface', are saved.   //
+// They share the same edge in the boundary of the missing region.           //
+//                                                                           //
+// 'facpoints' contains all vertices of the facet containing R.  They are    //
+// used for searching the crossing tets. On input all vertices are infected. //
+// They are uninfected after the cavity is formed.                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::formcavity(face *pssub, arraypool* crosstets, 
+  arraypool* topfaces, arraypool* botfaces, arraypool* toppoints,
+  arraypool* botpoints, arraypool* facpoints)
+{
+  arraypool *crossedges;
+  triface *parytet, crosstet, spintet, neightet, faketet;
+  face neighsh, checksh;
+  face checkseg;
+  point pa, pb, pc, pf, pg;
+  point *ppt;
+  REAL ori;
+  int i, j;
+
+  int *iptr;
+
+  // Get the missing subface abc.
+  pa = sorg(*pssub);
+  pb = sdest(*pssub);
+  pc = sapex(*pssub);
+
+  // Comment: Now all facet vertices are infected.
+
+  // Get a crossing tet abde.
+  parytet = (triface *) fastlookup(crosstets, 0); // face abd.
+  // The edge de crosses the facet. d lies below abc.
+  enext2fnext(*parytet, crosstet);
+  enext2self(crosstet); 
+  esymself(crosstet); // the edge d->e at face [d,e,a]
+  infect(crosstet);
+  *parytet = crosstet; // Save it in list.
+
+  // Temporarily re-use 'topfaces'.
+  crossedges = topfaces;
+  crossedges->newindex((void **) &parytet);
+  *parytet = crosstet;
+
+  // Collect all crossing tets.  Each cross tet is saved in the standard
+  //   form deab, where de is a corrsing edge, orient3d(d,e,a,b) < 0. 
+  // NOTE: hull tets may be collected. See fig/dump-cavity-case2a(b).lua.
+  //   Make sure that neither d nor e is dummypoint.
+  for (i = 0; i < crossedges->objects; i++) {
+    crosstet = * (triface *) fastlookup(crossedges, i);
+    // It may already be tested.
+    if (!edgemarked(crosstet)) {
+      // Collect all tets sharing at the edge.
+      pg = apex(crosstet);
+      spintet = crosstet;
+      while (1) {
+        // Mark this edge as tested.
+        markedge(spintet);
+        if (!infected(spintet)) {
+          infect(spintet);
+          crosstets->newindex((void **) &parytet);
+          *parytet = spintet;
+        }
+        // Go to the neighbor tet.
+        fnextself(spintet);
+        // Check the validity of the PLC.
+        tspivot(spintet, checksh);
+        if (checksh.sh != NULL) {
+          printf("Error:  Invalid PLC! Two subfaces intersect.\n");
+          printf("  1st (#%4d): (%d, %d, %d)\n", getshellmark(*pssub),
+            pointmark(pa), pointmark(pb), pointmark(pc));
+          printf("  2nd (#%4d): (%d, %d, %d)\n", getshellmark(checksh),
+            pointmark(sorg(checksh)), pointmark(sdest(checksh)),
+            pointmark(sapex(checksh)));
+          terminatetetgen(1);
+        }
+        if (apex(spintet) == pg) break;
+      }
+      // Detect new cross edges.
+      while (1) {
+        // Remember: spintet is edge d->e, d lies below abc.
+        pf = apex(spintet);
+        if (pf != dummypoint) { // Do not grab a hull edge.
+          if (!pinfected(pf)) {
+            // There exist a crossing edge, either d->f, or f->e.
+            ori = orient3d(pa, pb, pc, pf);
+            if (ori == 0) {
+              printf("Error:  Invalid PLC! Point and subface intersect.\n");
+              printf("   Point %d, subface (#%4d): (%d, %d, %d)\n", 
+                pointmark(pf), getshellmark(*pssub), pointmark(pa), 
+                pointmark(pb), pointmark(pc));
+              terminatetetgen(1);
+            }
+            if (ori < 0) {
+              // The edge d->f corsses the facet.
+              enext2fnext(spintet, neightet);
+              esymself(neightet); // d->f.
+            } else {
+              // The edge f->e crosses the face.
+              enextfnext(spintet, neightet);
+              esymself(neightet); // f->e.
+            }
+            if (!edgemarked(neightet)) {
+              // Add a new cross edge.
+              crossedges->newindex((void **) &parytet);
+              *parytet = neightet;
+            }
+          }
+        }
+        fnextself(spintet);
+        if (apex(spintet) == pg) break;
+      }
+    }
+  }
+
+  // Unmark all facet vertices.
+  for (i = 0; i < facpoints->objects; i++) {
+    ppt = (point *) fastlookup(facpoints, i);
+    puninfect(*ppt);
+  }
+
+  // Comments: Now no vertex is marked. Next we will mark vertices which 
+  //   belong to the top and bottom boundary faces of the cavity and put
+  //   them in 'toppopints' and 'botpoints', respectively.
+
+  // All cross tets are found. Unmark cross edges.
+  for (i = 0; i < crossedges->objects; i++) {
+    crosstet = * (triface *) fastlookup(crossedges, i);
+    if (edgemarked(crosstet)) {
+      // Add the vertices of the cross edge [d, e] in lists. It must be
+      //   that d lies below the facet (i.e., its a bottom vertex).
+      //   Note that a cross edge contains no dummypoint.
+      pf = org(crosstet);
+      assert(pf != dummypoint); // SELF_CHECK
+      if (!pinfected(pf)) {
+        pinfect(pf);
+        botpoints->newindex((void **) &ppt); // Add a bottom vertex.
+        *ppt = pf;
+      }
+      pf = dest(crosstet);
+      assert(pf != dummypoint); // SELF_CHECK
+      if (!pinfected(pf)) {
+        pinfect(pf);
+        toppoints->newindex((void **) &ppt); // Add a top vertex.
+        *ppt = pf;
+      }
+      // Unmark this edge in all tets containing it.
+      pg = apex(crosstet);
+      spintet = crosstet;
+      while (1) {
+        assert(edgemarked(spintet)); // SELF_CHECK
+        unmarkedge(spintet);
+        fnextself(spintet); // Go to the neighbor tet.
+        if (apex(spintet) == pg) break;
+      }
+    }
+  }
+
+  if (b->verbose > 1) {
+    printf("    Formed cavity: %ld (%ld) cross tets (edges).\n", 
+      crosstets->objects, crossedges->objects);
+  }
+  crossedges->restart();
+
+  // Find a pair of cavity boundary faces from the top and bottom sides of
+  //   the facet each, and they share the same edge. Save them in the
+  //   global variables: firsttopface, firstbotface. They will be used in
+  //   fillcavity() for gluing top and bottom new tets.
+  for (i = 0; i < crosstets->objects; i++) {
+    crosstet = * (triface *) fastlookup(crosstets, i);
+    enextfnext(crosstet, spintet);
+    enextself(spintet);
+    symedge(spintet, neightet);
+    if (!infected(neightet)) {
+      // A top face.
+      firsttopface = neightet;
+    } else {
+      continue; // Go to the next cross tet.
+    }
+    enext2fnext(crosstet, spintet);
+    enext2self(spintet);
+    symedge(spintet, neightet);
+    if (!infected(neightet)) {
+      // A bottom face.
+      firstbotface = neightet;
+    } else {
+      continue;
+    }
+    break;
+  }
+  assert(i < crosstets->objects); // SELF_CHECK
+  
+  // Collect the top and bottom faces and the middle vertices. Since all top
+  //   and bottom vertices have been marked in above. Unmarked vertices are
+  //   middle vertices.
+  // NOTE 1: Hull tets may be collected. Process them as normal one.
+  //   (see fig/dump-cavity-case2.lua.)
+  // NOTE 2: Some previously recovered subfaces may be completely
+  //   contained in a cavity (see fig/dump-cavity-case6.lua). In such case,
+  //   we create two faked tets to hold this subface, one at each side.
+  //   The faked tets will be removed in fillcavity().
+  for (i = 0; i < crosstets->objects; i++) {
+    crosstet = * (triface *) fastlookup(crosstets, i);
+    enextfnext(crosstet, spintet);
+    enextself(spintet);
+    symedge(spintet, neightet);
+    if (!infected(neightet)) {
+      // A top face.
+      topfaces->newindex((void **) &parytet);
+      *parytet = neightet;
+    } else {
+      // Check if this side is a subface.
+      tspivot(spintet, neighsh);
+      if (neighsh.sh != NULL) {
+        // Found a subface (inside the cavity)!
+        maketetrahedron(&faketet);  // Create a faked tet.
+        setorg(faketet, org(spintet));
+        setdest(faketet, dest(spintet));
+        setapex(faketet, apex(spintet));
+        setoppo(faketet, NULL);
+        tsbond(faketet, neighsh); // Let it hold the subface.
+        // Add a top face (at faked tet).
+        topfaces->newindex((void **) &parytet);
+        *parytet = faketet;
+      }
+    }
+    enext2fnext(crosstet, spintet);
+    enext2self(spintet);
+    symedge(spintet, neightet);
+    if (!infected(neightet)) {
+      // A bottom face.
+      botfaces->newindex((void **) &parytet);
+      *parytet = neightet;
+    } else {
+      tspivot(spintet, neighsh);
+      if (neighsh.sh != NULL) {
+        // Found a subface (inside the cavity)!
+        maketetrahedron(&faketet);  // Create a faked tet.
+        setorg(faketet, org(spintet));
+        setdest(faketet, dest(spintet));
+        setapex(faketet, apex(spintet));
+        setoppo(faketet, NULL);
+        tsbond(faketet, neighsh); // Let it hold the subface.
+        // Add a bottom face (at faked tet).
+        botfaces->newindex((void **) &parytet);
+        *parytet = faketet;
+      }
+    }
+    // Add middle vertices if there are (skip dummypoint).
+    pf = org(neightet);
+    if (!pinfected(pf)) {
+      if (pf != dummypoint) {
+        pinfect(pf);
+        botpoints->newindex((void **) &ppt); // Add a bottom vertex.
+        *ppt = pf;
+        toppoints->newindex((void **) &ppt); // Add a top vertex.
+        *ppt = pf;
+      }
+    }
+    pf = dest(neightet);
+    if (!pinfected(pf)) {
+      if (pf != dummypoint) {
+        pinfect(pf);
+        botpoints->newindex((void **) &ppt); // Add a bottom vertex.
+        *ppt = pf;
+        toppoints->newindex((void **) &ppt); // Add a top vertex.
+        *ppt = pf;
+      }
+    }
+  }
+
+  // Unmark all collected top, bottom, and middle vertices.
+  for (i = 0; i < toppoints->objects; i++) {
+    ppt = (point *) fastlookup(toppoints, i);
+    puninfect(*ppt);
+  }
+  for (i = 0; i < botpoints->objects; i++) {
+    ppt = (point *) fastlookup(botpoints, i);
+    puninfect(*ppt);
+  }
+  // Comments: Now no vertex is marked.
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// delaunizecavity()    Fill a cavity by Delaunay tetrahedra.                //
+//                                                                           //
+// The tetrahedralizing cavity is the half (top or bottom part) of the whole //
+// cavity.  The boundary faces of the half cavity are given in 'cavfaces',   //
+// the bounday faces of the internal facet are not given.  These faces will  //
+// be recovered later in fillcavity().                                       //
+//                                                                           //
+// This routine first constructs the DT of the vertices by the Bowyer-Watson //
+// algorithm.  Then it identifies the boundary faces of the cavity in DT.    //
+// The DT is returned in 'newtets'.                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces, 
+  arraypool *cavshells, arraypool *newtets, arraypool *crosstets,
+  arraypool *misfaces)
+{
+  triface *parytet, searchtet, neightet, spintet, *parytet1;
+  face checksh, tmpsh, *parysh;
+  face checkseg;
+  point pa, pb, pc, pd, pt[3], *parypt;
+  // badface *newflipface;
+  enum intersection dir;
+  REAL ori;
+  // int miscount;
+  int i, j;
+
+  tetrahedron ptr;
+  int *iptr, tver;
+
+  if (b->verbose > 1) {
+    printf("    Delaunizing cavity: %ld points, %ld faces.\n", 
+      cavpoints->objects, cavfaces->objects);
+  }
+
+  // Get four non-coplanar points (no dummypoint).
+  parytet = (triface *) fastlookup(cavfaces, 0);
+  pa = org(*parytet);
+  pb = dest(*parytet);
+  pc = apex(*parytet);
+  pinfect(pa);
+  pinfect(pb);
+  pinfect(pc);
+  pd = NULL;
+  for (i = 1; i < cavfaces->objects; i++) {
+    parytet = (triface *) fastlookup(cavfaces, i);
+    pt[0] = org(*parytet);
+    pt[1] = dest(*parytet);
+    pt[2] = apex(*parytet);
+    for (j = 0; j < 3; j++) {
+      if (pt[j] != dummypoint) { // Do not include a hull point.
+        if (!pinfected(pt[j])) {
+          ori = orient3d(pa, pb, pc, pt[j]);
+          if (ori != 0) {
+            pd = pt[j];
+            if (ori > 0) {  // Swap pa and pb.
+              pt[j] = pa; pa = pb; pb = pt[j]; 
+            }
+            break;
+          }
+        }
+      }
+    }
+    if (pd != NULL) break;
+  }
+  assert(i < cavfaces->objects); // SELF_CHECK
+  pinfect(pd);
+
+  // Create an init DT.
+  initialDT(pa, pb, pc, pd);
+
+  for (i = 0; i < cavpoints->objects; i++) {
+    pt[0] = * (point *) fastlookup(cavpoints, i);
+    assert(pt[0] != dummypoint); // SELF_CHECK
+    if (!pinfected(pt[0])) {
+      // pinfect(pt[0]); // Mark it as inserted.
+      searchtet = recenttet;
+      insertvertex(pt[0], &searchtet, true, false, false, false);
+    } else {
+      puninfect(pt[0]); // It is already inserted.
+    }
+  }
+  // Comment: All vertices of the cavity are NOT marked.
+
+  while (1) {
+
+  // Identify boundary faces. Mark interior tets. Save missing faces.
+  for (i = 0; i < cavfaces->objects; i++) {
+    parytet = (triface *) fastlookup(cavfaces, i);
+    // Skip an interior face (due to the enlargement of the cavity).
+    if (infected(*parytet)) continue;
+    // This face may contain dummypoint (See fig/dum-cavity-case2).
+    //   If so, dummypoint must be its apex.
+    parytet->ver = 4; 
+    pt[0] = org(*parytet);
+    pt[1] = dest(*parytet);
+    pt[2] = apex(*parytet);
+    // Create a temp subface.
+    makeshellface(subfacepool, &tmpsh);
+    setshvertices(tmpsh, pt[0], pt[1], pt[2]);
+    // Insert tmpsh in DT.
+    searchtet.tet = NULL; 
+    dir = scoutsubface(&tmpsh, &searchtet);
+    if (dir == SHAREFACE) {
+      // Identify the inter and outer tets at tempsh.
+      stpivot(tmpsh, neightet);
+      // neightet and tmpsh refer to the same edge [pt[0], pt[1]].
+      //   Moreover, neightet is in 0th edge ring (see decode()).
+      if (org(neightet) != pt[1]) {
+        symedgeself(neightet);
+        assert(org(neightet) == pt[1]); // SELF_CHECK
+        // Make sure that tmpsh is connected with an interior tet. 
+        tsbond(neightet, tmpsh);
+      }
+      assert(dest(neightet) == pt[0]); // SELF_CHECK
+      // The following step is now done in fillcavity(), 2009-04-24.
+      // // Mark neightet as interior. 
+      // if (!infected(neightet)) {
+      //   infect(neightet);
+      // }
+    } else if (dir == COLLISIONFACE) {
+      // A subface is already inserted (see fig/dum-cavity-case6).
+      assert(oppo(*parytet) == NULL); // It must be a faked tet.
+      // Searchtet's face collides it. Adjust to 0th edge ring.
+      if ((searchtet.ver & 01) != 0) esymself(searchtet);
+      // Let the subface remember its adjacent tet at its inside.
+      if (org(searchtet) != pt[1]) {
+        symedgeself(searchtet);
+        assert(org(searchtet) == pt[1]); // SELF_CHECK
+      }
+      assert(dest(searchtet) == pt[0]); // SELF_CHECK
+      tmpsh.sh[9] = (shellface) encode(searchtet);
+    } else {
+      if (b->verbose > 1) {
+        printf("  p:draw_subface(%d, %d, %d) -- %d is missing\n",
+          pointmark(pt[0]), pointmark(pt[1]), pointmark(pt[2]), i);
+      }
+      shellfacedealloc(subfacepool, tmpsh.sh);
+      // Save this face in list.
+      misfaces->newindex((void **) &parytet1);
+      *parytet1 = *parytet;
+      /*if (dir == EDGETRIINT) {
+        assert(0); // Face unmatched. Not process yet.
+      }
+      // Search an edge crossing this face.
+      dir = scoutcrosstet(&tmpsh, &searchtet, NULL);
+      assert(dir == ACROSSTET); // SELF_CHECK
+      // Save this pair of points.
+      newflipface = (badface *) flippool->alloc();
+      newflipface->forg = apex(searchtet);
+      newflipface->fdest = oppo(searchtet);
+      newflipface->nextitem = futureflip;
+      futureflip = newflipface;
+      // if (b->verbose > 1) {        
+        printf("  p:draw_subseg(%d, %d)\n", pointmark(newflipface->forg),
+          pointmark(newflipface->fdest));
+      // }
+      miscount++;*/
+      continue;
+    }
+    // Remember tmpsh (use the adjacent tet slot). 
+    // parytet->tet[parytet->loc] = (tetrahedron) sencode(tmpsh);
+    tmpsh.sh[0] = (shellface) encode(*parytet);
+    // Save this subface.
+    cavshells->newindex((void **) &parysh);
+    *parysh = tmpsh;
+  }
+
+  if (misfaces->objects > 0) {
+    // Removing tempoaray subfaces.
+    for (i = 0; i < cavshells->objects; i++) {
+      parysh = (face *) fastlookup(cavshells, i);
+      stpivot(*parysh, neightet);
+      uninfect(neightet);
+      tsdissolve(neightet); // Detach it from adj. tets.
+      symself(neightet);
+      tsdissolve(neightet);
+      shellfacedealloc(subfacepool, parysh->sh);
+    }
+    cavshells->restart();
+
+    // Infect the points which are of the cavity.
+    for (i = 0; i < cavpoints->objects; i++) {
+      pt[0] = * (point *) fastlookup(cavpoints, i);
+      pinfect(pt[0]); // Mark it as inserted.
+    }
+
+    // Enlarge the cavity.
+    for (i = 0; i < misfaces->objects; i++) {
+      // Get a missing face.
+      parytet = (triface *) fastlookup(misfaces, i);
+      if (!infected(*parytet)) {
+        // Put it into crossing tet list.
+        infect(*parytet);
+        crosstets->newindex((void **) &parytet1);
+        *parytet1 = *parytet;
+        // Insert the opposite point if it is not in DT.
+        pd = oppo(*parytet);
+        if (!pinfected(pd)) {
+          if (b->verbose > 1) {
+            printf("    Insert the opposite point %d.\n", pointmark(pd));
+          }
+          pinfect(pd);
+          cavpoints->newindex((void **) &parypt);
+          *parypt = pd;
+          searchtet = recenttet;
+          insertvertex(pd, &searchtet, true, false, false, false);
+        }
+        // Check for a missing subface.
+        tspivot(*parytet, checksh);
+        if (checksh.sh != NULL) {
+          if (b->verbose > 1) {
+            printf("    Queue a subface x%lx (%d, %d, %d).\n", 
+              (unsigned long) checksh.sh, pointmark(sorg(checksh)),
+              pointmark(sdest(checksh)), pointmark(sapex(checksh)));
+          }
+          stdissolve(checksh);
+          subfacstack->newindex((void **) &parysh);
+          *parysh = checksh;
+        }
+        // Add three opposite faces into the boundary list.
+        for (j = 0; j < 3; j++) {
+          enext0fnext(*parytet, neightet);
+          symself(neightet);
+          if (!infected(neightet)) {
+            if (b->verbose > 1) {
+              printf("    Add a cavface (%d, %d, %d).\n",
+                pointmark(org(neightet)), pointmark(dest(neightet)),
+                pointmark(apex(neightet)));
+            }
+            cavfaces->newindex((void **) &parytet1);
+            *parytet1 = neightet;
+          } else {
+            // Check if a subface is missing again.
+            tspivot(neightet, checksh);
+            if (checksh.sh != NULL) {
+              if (b->verbose > 1) {
+                printf("    Queue a subface x%lx (%d, %d, %d).\n", 
+                  (unsigned long) checksh.sh, pointmark(sorg(checksh)),
+                  pointmark(sdest(checksh)), pointmark(sapex(checksh)));
+              }
+              stdissolve(checksh);
+              subfacstack->newindex((void **) &parysh);
+              *parysh = checksh;
+            }
+          }
+          enextself(*parytet);
+        } // j
+      } // if (!infected(parytet))
+    }
+
+    // Uninfect the points which are of the cavity.
+    for (i = 0; i < cavpoints->objects; i++) {
+      pt[0] = * (point *) fastlookup(cavpoints, i);
+      puninfect(pt[0]);
+    }
+
+    misfaces->restart();
+    cavityexpcount++;
+    continue;
+  }
+
+  break;
+
+  } // while (1)
+
+  // Collect all tets of the DT. All new tets are marktested.
+  marktest(recenttet);
+  newtets->newindex((void **) &parytet);
+  *parytet = recenttet;
+  for (i = 0; i < newtets->objects; i++) {
+    searchtet = * (triface *) fastlookup(newtets, i);
+    for (searchtet.loc = 0; searchtet.loc < 4; searchtet.loc++) {
+      sym(searchtet, neightet);
+      if (!marktested(neightet)) {
+        marktest(neightet);
+        newtets->newindex((void **) &parytet);
+        *parytet = neightet;
+      }
+    }
+  }
+
+  cavpoints->restart();
+  // Comment: Now no vertex is marked.
+  cavfaces->restart();
+
+  if (cavshells->objects > maxcavsize) {
+    maxcavsize = cavshells->objects;
+  }
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// fillcavity()    Fill new tets into the cavity.                            //
+//                                                                           //
+// The new tets are stored in two disjoint sets(which share the same facet). //
+// 'topfaces' and 'botfaces' are the boundaries of these two sets, respect-  //
+// ively. 'midfaces' is empty on input, and will store faces in the facet.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::fillcavity(arraypool* topshells, arraypool* botshells,
+  arraypool* midfaces, arraypool* facpoints)
+{
+  arraypool *cavshells;
+  triface *parytet, bdrytet, toptet, bottet, neightet, midface;
+  face checksh, *parysh;
+  face checkseg;
+  point pa, pb, pc, pf, pg;
+  REAL ori, len, n[3];
+  bool mflag, bflag;
+  int i, j, k;
+
+  tetrahedron ptr;
+  int *iptr, tver;
+
+  // Connect newtets to tets outside the cavity.
+  for (k = 0; k < 2; k++) {
+    cavshells = (k == 0 ? topshells : botshells);
+    if (cavshells != NULL) {
+      for (i = 0; i < cavshells->objects; i++) {
+        // Get a temp subface.
+        parysh = (face *) fastlookup(cavshells, i);
+        // Get the boundary tet outsode the cavity.
+        decode(parysh->sh[0], bdrytet);
+        pa = org(bdrytet);
+        pb = dest(bdrytet);
+        pc = apex(bdrytet);
+        // Get the adjacent new tet.
+        stpivot(*parysh, neightet);
+        assert(org(neightet) == pb); // SELF_CHECK
+        assert(dest(neightet) == pa); // SELF_CHECK
+        // Mark neightet as an interior tet of this cavity, 2009-04-24.
+        // Comment: We know neightet is an interior tet.
+        if (!infected(neightet)) {
+          infect(neightet);
+        }
+        if (oppo(bdrytet) != NULL) {
+          // Bond the two tets.
+          bond(bdrytet, neightet); // Also cleared the pointer to tmpsh.
+        }
+        // Bond a subface (if it exists).
+        tspivot(bdrytet, checksh);
+        if (checksh.sh != NULL) {
+          tsbond(neightet, checksh); // Also cleared the pointer to tmpsh.
+        } else {
+          tsdissolve(neightet); // No subface, clear the pointer to tmpsh.
+        }
+        // Update the point-to-tets map.
+        point2tet(pa) = encode(neightet);
+        point2tet(pb) = encode(neightet);
+        point2tet(pc) = encode(neightet);
+        // Delete the temp subface.
+        // shellfacedealloc(subfacepool, parysh->sh);
+        if (oppo(bdrytet) == NULL) {
+          // Delete a faked tet.
+          tetrahedrondealloc(bdrytet.tet);
+        }
+      }
+    } // if (cavshells != NULL)
+  }
+
+  mflag = true;  // Initialize it.
+
+  if (midfaces != NULL) {
+
+  // Mark all facet vertices for finding middle subfaces.
+  for (i = 0; i < facpoints->objects; i++) {
+    pf = * (point *) fastlookup(facpoints, i);
+    pinfect(pf);
+  }
+
+  // The first pair of top and bottom tets share the same edge [a, b].
+  // toptet = * (triface *) fastlookup(topfaces, 0);
+  if (infected(firsttopface)) {
+    // The cavity was enlarged. This tet is included in the interior
+    //   (as those of a crossing tet). Find the updated top boundary face
+    //   by rotating the faces around this edge (until an uninfect tet).
+    pa = apex(firsttopface);
+    while (1) {
+      fnextself(firsttopface);
+      if (!infected(firsttopface)) break;
+      assert(apex(firsttopface) != pa); // SELF_CHECK
+    }
+  }
+  toptet = firsttopface;
+  symedgeself(toptet);
+  // Search a subface from the top mesh.
+  while (1) {
+    enext0fnextself(toptet); // The next face in the same tet.
+    pc = apex(toptet);
+    if (pinfected(pc)) break; // [a,b,c] is a subface.
+    symedgeself(toptet); // Go to the same face in the adjacent tet.
+  }
+  // Search the subface [a,b,c] in the bottom mesh.
+  // bottet = * (triface *) fastlookup(botfaces, 0);
+  if (infected(firstbotface)) {
+    pa = apex(firstbotface);
+    while (1) {
+      fnextself(firstbotface);
+      if (!infected(firstbotface)) break;
+      assert(apex(firstbotface) != pa); // SELF_CHECK
+    }
+  }
+  bottet = firstbotface;
+  symedgeself(bottet);
+  while (1) {
+    enext0fnextself(bottet); // The next face in the same tet.
+    pf = apex(bottet);
+    if (pf == pc) break; // Face matched.
+    if (pinfected(pf)) {
+      mflag = false; break; // Not matched.
+    }
+    symedgeself(bottet);
+  }
+  if (mflag) {
+    // Connect the two tets together.
+    bond(toptet, bottet);
+    // Both are interior tets.
+    infect(toptet);
+    infect(bottet);
+    // Add this face into search list.
+    esymself(toptet); // Choose the 0th edge ring.
+    markface(toptet);
+    midfaces->newindex((void **) &parytet);
+    *parytet = toptet;
+  }
+
+  // Match pairs of subfaces (middle faces), connect top and bottom tets.
+  for (i = 0; i < midfaces->objects && mflag; i++) {
+    // Get a matched middle face [a, b, c]
+    midface = * (triface *) fastlookup(midfaces, i);
+    // It is inside the cavity.
+    assert(marktested(midface)); // SELF_CHECK 
+    // Check the neighbors at edges [b, c] and [c, a].
+    for (j = 0; j < 2 && mflag; j++) {
+      enextself(midface); // [b, c] or [c, a].
+      pg = apex(midface);
+      toptet = midface;
+      bflag = false;
+      while (1) {
+        // Go to the next face in the same tet.
+        enext0fnextself(toptet);
+        pc = apex(toptet);
+        if (pinfected(pc)) {
+          break; // Find a subface.
+        }
+        if (pc == dummypoint) {
+          break; // Find a subface.
+        }
+        /* if (pc == pg) {
+          // The adjacent face is not a middle face.
+          bflag = true; break; 
+        }*/
+        // Go to the same face in the adjacent tet.
+        symedgeself(toptet);
+        // Do we walk outside the cavity? 
+        if (!marktested(toptet)) {
+          // Yes, the adjacent face is not a middle face.
+          bflag = true; break; 
+        }
+      }
+      if (!bflag) {
+        // assert(marktested(toptet)); // SELF_CHECK
+        if (!facemarked(toptet)) {
+          symedge(midface, bottet);
+          while (1) {
+            enext0fnextself(bottet);
+            pf = apex(bottet);
+            if (pf == pc) break; // Face matched.
+            if (pinfected(pf)) {
+              mflag = false; break; // Not matched
+            }
+            symedgeself(bottet);
+          }
+          if (mflag) {
+            if (marktested(bottet)) {
+              // Connect two tets together.
+              bond(toptet, bottet);
+              // Both are interior tets.
+              infect(toptet);
+              infect(bottet);
+              // Add this face into list.
+              esymself(toptet);
+              markface(toptet);
+              midfaces->newindex((void **) &parytet);
+              *parytet = toptet;
+            } else {
+              // The 'bottet' is not inside the cavity! 
+              // This case can happen when the cavity was enlarged, and the
+              //   'toptet' is a co-facet (sub)face adjacent to the missing
+              //   region, and it is a boundary face of the top cavity.
+              // So the toptet and bottet should be bonded already through
+              //   a temp subface. See fig/dump-cavity-case18. Check it.
+              symedge(toptet, neightet);
+              assert(neightet.tet == bottet.tet); // SELF_CHECK
+              assert(neightet.loc == bottet.loc); // SELF_CHECK
+              // Do not add this face into 'midfaces'.
+            }
+          }
+        }
+      }
+    } // j
+  } // i
+
+  } // if (midfaces != NULL)
+
+  if (mflag) {
+    if (midfaces != NULL) {
+      if (b->verbose > 1) {
+        printf("    Found %ld middle subfaces.\n", midfaces->objects);
+      }
+      if (midfaces->objects > maxregionsize) {
+        maxregionsize = midfaces->objects;
+      }
+      // Unmark middle faces.
+      for (i = 0; i < midfaces->objects; i++) {
+        // Get a matched middle face [a, b, c]
+        midface = * (triface *) fastlookup(midfaces, i);
+        assert(facemarked(midface)); // SELF_CHECK
+        unmarkface(midface);
+      }
+    }
+    // Bond subsegments to new tets. 
+    // Comment: *** The following code does redundant job. Should be
+    //   re-placed in the future.
+    for (k = 0; k < 2; k++) {
+      cavshells = (k == 0 ? topshells : botshells);
+      if (cavshells != NULL) {
+        for (i = 0; i < cavshells->objects; i++) {
+          parysh = (face *) fastlookup(cavshells, i);
+          decode(parysh->sh[0], bdrytet);
+          if (bdrytet.tet[4] != NULL) {
+            // Not a faked tet. Bond a subsegment (if it exists).
+            for (j = 0; j < 3; j++) {
+              tsspivot(bdrytet, checkseg);
+              if (checkseg.sh != NULL) {
+                symedge(bdrytet, neightet);
+                assert(marktested(neightet)); // SELF_CHECK
+                // Let the segment remember an adjacent tet.
+                sstbond(checkseg, neightet);
+                while (1) {
+                  tssbond1(neightet, checkseg);
+                  fnextself(neightet);
+                  if (!marktested(neightet)) break;
+                }
+              }
+              enextself(bdrytet);
+            }
+          } else {
+            // A faked tet. There is an interior subface. Use it.
+            // See fig/dump-cavity-case19.
+            stpivot(*parysh, neightet);
+            assert(marktested(neightet)); // SELF_CHECK
+            tspivot(neightet, checksh);
+            assert(checksh.sh != NULL); // SELF_CHECK
+            assert(checksh.sh != parysh->sh); // // SELF_CHECK
+            // Align them at the same directed edge.
+            pa = org(neightet);
+            pb = dest(neightet);
+            for (j = 0; j < 3; j++) {
+              if (sorg(checksh) == pa) break;
+              senextself(checksh);
+            }
+            assert(j < 3); // SELF_CHECK
+            if (sdest(checksh) != pb) {
+              senext2self(checksh);
+              sesymself(checksh);
+            }
+            assert(sdest(checksh) == pb); // SELF_CHECK
+            // Bond a subsegment (if it exists).
+            for (j = 0; j < 3; j++) {
+              sspivot(checksh, checkseg);
+              if (checkseg.sh != NULL) {
+                // Let the segment remember an adjacent tet.
+                sstbond(checkseg, neightet);
+                toptet = neightet;
+                while (1) {
+                  tssbond1(toptet, checkseg);
+                  fnextself(toptet);
+                  if (apex(toptet) == apex(neightet)) break;
+                }
+              }
+              senextself(checksh);
+              enextself(neightet);
+            }
+          }
+        }
+      } // if (cavshells != NULL)
+    }
+  } else {
+    // Faces at top and bottom are not matched. There exists non-Delaunay
+    //   subedges. See fig/dump-cavity-case5.lua. 
+    pa = org(toptet);
+    pb = dest(toptet);
+    pc = apex(toptet);
+    pf = apex(bottet);
+    if (b->verbose > 1) {
+      printf("  p:draw_tet(%d, %d, %d, %d) -- top tet.\n", pointmark(pa), 
+        pointmark(pb), pointmark(pc), pointmark(oppo(toptet)));
+      printf("  p:draw_tet(%d, %d, %d, %d) -- bot tet.\n", 
+        pointmark(org(bottet)), pointmark(dest(bottet)), 
+        pointmark(apex(bottet)), pointmark(oppo(bottet)));
+    }
+    // Calculate a point above the faces.
+    facenormal(pa, pb, pc, n, 1);
+    len = sqrt(DOT(n, n));
+    n[0] /= len;
+    n[1] /= len;
+    n[2] /= len;
+    len = DIST(pa, pb);
+    len += DIST(pb, pc);
+    len += DIST(pc, pa);
+    len /= 3.0;
+    dummypoint[0] = pa[0] + len * n[0];
+    dummypoint[1] = pa[1] + len * n[1];
+    dummypoint[2] = pa[2] + len * n[2];
+    // Find the crossing edges.
+    ori = orient3d(pb, pc, dummypoint, pf);
+    assert(ori != 0); // SELF_CHECK
+    if (ori < 0) {
+      // The top edge [b, c] intersects the bot edge [a, f].
+      enextself(toptet); 
+      enextself(bottet);
+    } else {
+      // The top edge [c, a] intersects the bot edge [f, b].
+      enext2self(toptet); 
+      enext2self(bottet); 
+    }
+    // Split one of the edges, choose the one has longer length.
+    n[0] = DIST(org(toptet), dest(toptet));
+    n[1] = DIST(org(bottet), dest(bottet));
+    if (n[0] > n[1]) {
+      pf = org(toptet);
+      pg = dest(toptet);
+    } else {
+      pf = org(bottet);
+      pg = dest(bottet);
+    }
+    if (b->verbose > 1) {
+      printf("  Found a non-Delaunay edge (%d, %d)\n", pointmark(pf), 
+        pointmark(pg));
+    }
+    // Create the midpoint of the non-Delaunay edge.
+    for (i = 0; i < 3; i++) {
+      dummypoint[i] = 0.5 * (pf[i] + pg[i]);
+    }
+    // Set a tet for searching the new point.
+    recenttet = firsttopface;
+    // dummypoint[0] = dummypoint[1] = dummypoint[2] = 0;
+    ndelaunayedgecount++;
+  }
+
+  if (facpoints != NULL) {
+    // Unmark all facet vertices.
+    for (i = 0; i < facpoints->objects; i++) {
+      pf = * (point *) fastlookup(facpoints, i);
+      puninfect(pf);
+    }
+  }
+  
+  // Delete the temp subfaces.
+  for (k = 0; k < 2; k++) {
+    cavshells = (k == 0 ? topshells : botshells);
+    if (cavshells != NULL) {
+      for (i = 0; i < cavshells->objects; i++) {
+        parysh = (face *) fastlookup(cavshells, i);
+        shellfacedealloc(subfacepool, parysh->sh);
+      }
+    }
+  }
+
+  topshells->restart();
+  if (botshells != NULL) {
+    botshells->restart();
+  }
+  if (midfaces != NULL) {
+    midfaces->restart();
+  }
+  // Comment: Now no vertex is marked.
+
+  return mflag;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// carvecavity()    Delete old tets and outer new tets of the cavity.        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
+  arraypool *botnewtets)
+{
+  arraypool *newtets;
+  triface *parytet, *pnewtet, neightet;
+  face checkseg, *parysh;
+  int i, j, k;
+
+  // NOTE: Some subsegments may contained inside the cavity. They must be
+  //   queued for recovery. See fig/dump-cavity-case20.
+  // Comment: This check should be avoided in the future. Do the check in
+  //   routine delaunizecavity() is NOT enough. (2009-04-24).
+  for (i = 0; i < crosstets->objects; i++) {
+    parytet = (triface *) fastlookup(crosstets, i);
+    assert(infected(*parytet)); // SELF_CHECK
+    if (parytet->tet[8] != NULL) {
+      for (j = 0; j < 6; j++) {
+        parytet->loc = edge2locver[j][0];
+        parytet->ver = edge2locver[j][1];
+        tsspivot(*parytet, checkseg);
+        if (checkseg.sh != NULL) {
+          if (!sinfected(checkseg)) {
+            // It is not queued yet.
+            neightet = *parytet;
+            while (1) {
+              fnextself(neightet);
+              if (!infected(neightet)) break;
+              if (apex(neightet) == apex(*parytet)) break;
+            }
+            if (infected(neightet)) {
+              if (b->verbose > 1) {
+                printf("    Queue a missing segment (%d, %d).\n",
+                  pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
+              }
+              // Clean the seg-to-tet pointer.
+              stdissolve(checkseg);
+              sinfect(checkseg);
+              subsegstack->newindex((void **) &parysh);
+              *parysh = checkseg;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // Delete the old tets in cavity.
+  for (i = 0; i < crosstets->objects; i++) {
+    parytet = (triface *) fastlookup(crosstets, i);
+    tetrahedrondealloc(parytet->tet);
+  }
+  crosstets->restart(); // crosstets will be re-used.
+
+  // Collect infected new tets in cavity.
+  for (k = 0; k < 2; k++) {
+    newtets = (k == 0 ? topnewtets : botnewtets);
+    if (newtets != NULL) {
+      for (i = 0; i < newtets->objects; i++) {
+        parytet = (triface *) fastlookup(newtets, i);
+        if (infected(*parytet)) {
+          crosstets->newindex((void **) &pnewtet);
+          *pnewtet = *parytet;
+        }
+      }
+    }
+  }
+  // Collect all new tets in cavity.
+  for (i = 0; i < crosstets->objects; i++) {
+    parytet = (triface *) fastlookup(crosstets, i);
+    if (i == 0) {
+      recenttet = *parytet; // Remember a live handle.
+    }
+    for (j = 0; j < 4; j++) {
+      decode(parytet->tet[j], neightet);
+      if (marktested(neightet)) { // Is it a new tet?
+        if (!infected(neightet)) {
+          // Find an interior tet.
+          assert((point) neightet.tet[7] != dummypoint); // SELF_CHECK
+          infect(neightet);
+          crosstets->newindex((void **) &pnewtet);
+          *pnewtet = neightet;
+        }
+      }
+    }
+  }
+
+  // Delete outer new tets.
+  for (k = 0; k < 2; k++) {
+    newtets = (k == 0 ? topnewtets : botnewtets);
+    if (newtets != NULL) {
+      for (i = 0; i < newtets->objects; i++) {
+        parytet = (triface *) fastlookup(newtets, i);
+        if (infected(*parytet)) {
+          // This is an interior tet.
+          uninfect(*parytet);
+          unmarktest(*parytet);
+        } else {
+          // An outer tet. Delete it.
+          tetrahedrondealloc(parytet->tet);
+        }
+      }
+    }
+  }
+
+  crosstets->restart();
+  topnewtets->restart();
+  if (botnewtets != NULL) {
+    botnewtets->restart();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// restorecavity()    Reconnect old tets and delete new tets of the cavity.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::restorecavity(arraypool *crosstets, arraypool *topnewtets,
+  arraypool *botnewtets)
+{
+  triface *parytet, neightet;
+  face checksh;
+  point *ppt;
+  int i, j;
+
+  // Reconnect crossing tets to cavity boundary.
+  for (i = 0; i < crosstets->objects; i++) {
+    parytet = (triface *) fastlookup(crosstets, i);
+    assert(infected(*parytet)); // SELF_CHECK
+    if (i == 0) {
+      recenttet = *parytet; // Remember a live handle.
+    }
+    parytet->ver = 0;
+    for (parytet->loc = 0; parytet->loc < 4; parytet->loc++) {
+      symedge(*parytet, neightet);
+      if (!infected(neightet)) {
+        bond(*parytet, neightet);
+        tspivot(*parytet, checksh);
+        if (checksh.sh != NULL) {
+          tsbond(*parytet, checksh);
+        }
+      }
+    }
+    // Update the point-to-tet map.
+    parytet->loc = 0;
+    ppt = (point *) &(parytet->tet[4]);
+    for (j = 0; j < 4; j++) {
+      point2tet(ppt[j]) = encode(*parytet);
+    }
+  }
+
+  // Uninfect all crossing tets.
+  for (i = 0; i < crosstets->objects; i++) {
+    parytet = (triface *) fastlookup(crosstets, i);
+    uninfect(*parytet);
+  }
+
+  // Delete new tets.
+  for (i = 0; i < topnewtets->objects; i++) {
+    parytet = (triface *) fastlookup(topnewtets, i);
+    tetrahedrondealloc(parytet->tet);
+  }
+
+  if (botnewtets != NULL) {
+    for (i = 0; i < botnewtets->objects; i++) {
+      parytet = (triface *) fastlookup(botnewtets, i);
+      tetrahedrondealloc(parytet->tet);
+    }
+  }
+
+  crosstets->restart();
+  topnewtets->restart();
+  if (botnewtets != NULL) {
+    botnewtets->restart();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// splitsubedge()    Split a non-Delaunay edge (not a segment) in the        //
+//                   surface mesh of a facet.                                //
+//                                                                           //
+// The new point 'newpt' will be inserted in the tetrahedral mesh if it does //
+// not cause any existing (sub)segments become non-Delaunay.  Otherwise, the //
+// new point is not inserted and one of such subsegments will be split.      //
+//                                                                           //
+// Next,the actual inserted new point is also inserted into the surface mesh.//
+// Non-Delaunay segments and newly created subfaces are queued for recovery. //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::splitsubedge(point newpt, face *searchsh, arraypool *facfaces,
+  arraypool *facpoints)
+{
+  triface searchtet;
+  face *psseg, sseg;
+  point pa, pb;
+  enum location loc;
+  int s, i;
+
+  // Try to insert the point. Do not insert if it will encroach any segment
+  //   (noencsegflag is TRUE). Queue encroacged subfaces.
+  assert(subsegstack->objects == 0l); // SELF_CHECK
+  searchtet = recenttet; // Start search it from recentet
+  loc = insertvertex(newpt, &searchtet, true, true, true, false);
+
+  if (loc == ENCSEGMENT) {
+    // Some segments are encroached. Randomly pick one to split.
+    assert(subsegstack->objects > 0l);
+    s = randomnation(subsegstack->objects);
+    psseg = (face *) fastlookup(subsegstack, s);
+    sseg = *psseg;
+    pa = sorg(sseg);
+    pb = sdest(sseg);
+    for (i = 0; i < 3; i++) newpt[i] = 0.5 * (pa[i] + pb[i]);
+    // Uninfect all queued segments.
+    for (i = 0; i < subsegstack->objects; i++) {
+      psseg = (face *) fastlookup(subsegstack, i);
+      suninfect(*psseg);
+    }
+    subsegstack->restart();  // Clear the queue.
+    // Split the segment. Two subsegments are queued.
+    sinsertvertex(newpt, searchsh, &sseg, true, false);
+    // Insert the point. Missing segments are queued. 
+    searchtet = recenttet; // Start search it from recentet
+    insertvertex(newpt, &searchtet, true, true, false, false);
+  } else {
+    // Calc an above point for point location in surface triangulation.
+    calculateabovepoint(facpoints, NULL, NULL, NULL); 
+    // Insert the new point on facet. New subfaces are queued for reocvery.
+    loc = sinsertvertex(newpt, searchsh, NULL, true, false);
+    if (loc == OUTSIDE) {
+      assert(0); // Not handled yet.
+    }
+    // Clear the above point.
+    dummypoint[0] = dummypoint[1] = dummypoint[2] = 0;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// constrainedfacets()    Recover subfaces saved in 'subfacestack'.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::constrainedfacets()
+{
+  /*
+  arraypool *crosstets, *topnewtets, *botnewtets;
+  arraypool *topfaces, *botfaces, *midfaces;
+  arraypool *topshells, *botshells, *facfaces;
+  arraypool *toppoints, *botpoints, *facpoints;
+  */
+  triface *parytet, searchtet, neightet;
+  face *pssub, ssub, neighsh;
+  face checkseg;
+  point *ppt, pt, newpt;
+  enum intersection dir;
+  bool success, delaunayflag;
+  int facetcount;
+  int bakhullsize;
+  int s, i, j;
+
+  /* // Initialize arrays.
+  crosstets = new arraypool(sizeof(triface), 10);
+  topnewtets = new arraypool(sizeof(triface), 10);
+  botnewtets = new arraypool(sizeof(triface), 10);
+  topfaces = new arraypool(sizeof(triface), 10);
+  botfaces = new arraypool(sizeof(triface), 10);
+  midfaces = new arraypool(sizeof(triface), 10);
+  toppoints = new arraypool(sizeof(point), 8);
+  botpoints = new arraypool(sizeof(point), 8);
+  facpoints = new arraypool(sizeof(point), 8);
+  facfaces = new arraypool(sizeof(face), 10);
+  topshells = new arraypool(sizeof(face), 10);
+  botshells = new arraypool(sizeof(face), 10);
+  */
+
+  facetcount = 0;
+
+  // Loop until 'subfacstack' is empty.
+  while (subfacstack->objects > 0l) {
+    subfacstack->objects--;
+    pssub = (face *) fastlookup(subfacstack, subfacstack->objects);
+    ssub = *pssub;
+
+    if (ssub.sh[3] == NULL) continue; // Skip a dead subface.
+
+    stpivot(ssub, neightet);
+    if (neightet.tet == NULL) {
+      // Find an unrecovered subface.
+      smarktest(ssub);
+      tg_facfaces->newindex((void **) &pssub);
+      *pssub = ssub;
+      // Get all subfaces and vertices of the same facet.
+      for (i = 0; i < tg_facfaces->objects; i++) {
+        ssub = * (face *) fastlookup(tg_facfaces, i);
+        for (j = 0; j < 3; j++) {
+          sspivot(ssub, checkseg);
+          if (checkseg.sh == NULL) {
+            spivot(ssub, neighsh);
+            assert(neighsh.sh != NULL); // SELF_CHECK
+            if (!smarktested(neighsh)) {
+              // It may be already recovered.
+              stpivot(neighsh, neightet);
+              if (neightet.tet == NULL) {
+                smarktest(neighsh);
+                tg_facfaces->newindex((void **) &pssub);
+                *pssub = neighsh;
+              }
+            }
+          }
+          pt = sorg(ssub);
+          if (!pinfected(pt)) {
+            pinfect(pt);
+            tg_facpoints->newindex((void **) &ppt);
+            *ppt = pt;
+          }
+          senextself(ssub);
+        } // j
+      } // i
+      // Have found all facet subfaces (vertices). Uninfect them.
+      for (i = 0; i < tg_facfaces->objects; i++) {
+        pssub = (face *) fastlookup(tg_facfaces, i);
+        sunmarktest(*pssub);
+      }
+      for (i = 0; i < tg_facpoints->objects; i++) {
+        ppt = (point *) fastlookup(tg_facpoints, i);
+        puninfect(*ppt);
+      }
+      if (b->verbose > 1) {
+        printf("  Recover facet #%d: %ld subfaces, %ld vertices.\n", 
+          facetcount + 1, tg_facfaces->objects, tg_facpoints->objects);
+      }
+      facetcount++;
+
+      // Loop until 'tg_facfaces' is empty.
+      while (tg_facfaces->objects > 0l) {
+        // Get the last subface of this array.
+        tg_facfaces->objects--;
+        pssub = (face *) fastlookup(tg_facfaces, tg_facfaces->objects);
+        ssub = *pssub;
+
+        stpivot(ssub, neightet);
+        if (neightet.tet != NULL) continue; // Not a missing subface.
+
+        // Insert the subface.
+        searchtet.tet = NULL;
+        dir = scoutsubface(&ssub, &searchtet);
+        if (dir == SHAREFACE) continue; // The subface is inserted.
+        assert(dir != COLLISIONFACE); // SELF_CHECK
+
+        // Not exist. Push the subface back into stack.
+        s = randomnation(tg_facfaces->objects + 1);
+        tg_facfaces->newindex((void **) &pssub);
+        *pssub = * (face *) fastlookup(tg_facfaces, s);
+        * (face *) fastlookup(tg_facfaces, s) = ssub;
+
+        if (dir == EDGETRIINT) continue; // All three edges are missing.
+
+        // Search for a crossing tet.
+        dir = scoutcrosstet(&ssub, &searchtet, tg_facpoints);
+
+        if (dir == ACROSSTET) {
+          // Recover subfaces by local retetrahedralization.
+          cavitycount++;
+          bakhullsize = hullsize;
+          checksubsegs = checksubfaces = 0;
+          tg_crosstets->newindex((void **) &parytet);
+          *parytet = searchtet;
+          // Form a cavity of crossing tets.
+          formcavity(&ssub, tg_crosstets, tg_topfaces, tg_botfaces, 
+            tg_toppoints, tg_botpoints, tg_facpoints);
+          delaunayflag = true;
+          // Tetrahedralize the top part. Re-use 'tg_midfaces'.
+          success = delaunizecavity(tg_toppoints, tg_topfaces, tg_topshells,
+            tg_topnewtets, tg_crosstets, tg_midfaces);
+          if (success) {
+            // Tetrahedralize the bottom part. Re-use 'tg_midfaces'.
+            success = delaunizecavity(tg_botpoints, tg_botfaces, tg_botshells,
+              tg_botnewtets, tg_crosstets, tg_midfaces);
+            if (success) {
+              // Fill the cavity with new tets.
+              success = fillcavity(tg_topshells, tg_botshells, tg_midfaces,
+                tg_facpoints);
+              if (success) {
+                // Delete old tets and outer new tets.
+                carvecavity(tg_crosstets, tg_topnewtets, tg_botnewtets);
+              }
+            } else {
+              delaunayflag = false;
+            }
+          } else {
+            delaunayflag = false;
+          }
+          if (!success) {
+            // Restore old tets and delete new tets.
+            restorecavity(tg_crosstets, tg_topnewtets, tg_botnewtets);
+          }
+          /*if (!delaunayflag) {
+            dump_facetof(&ssub, "facet1.lua");
+            while (futureflip != NULL) {
+              formedgecavity(futureflip->forg, futureflip->fdest, tg_crosstets,
+                tg_topfaces, tg_toppoints);
+              tg_crosstets->restart();
+              tg_topfaces->restart();
+              tg_toppoints->restart();
+              futureflip = futureflip->nextitem;
+            }
+            flippool->restart();
+            outnodes(0);
+            checkmesh();
+            checkshells(1);
+            assert(0); // Stop the program.
+          }*/
+          hullsize = bakhullsize;
+          checksubsegs = checksubfaces = 1;
+        } else if (dir == ACROSSFACE) {
+          // Recover subfaces by flipping edges in surface mesh.
+          recoversubfacebyflips(&ssub, &searchtet, tg_facfaces);
+          success = true;
+        } else { // dir == TOUCHFACE
+          assert(0);
+        }
+        if (!success) break;
+      } // while
+
+      if (tg_facfaces->objects > 0l) {
+        // Found a non-Delaunay edge, split it (or a segment close to it).
+        // Create a new point at the middle of this edge, its coordinates
+        //   were saved in dummypoint in 'fillcavity()'.
+        makepoint(&newpt);
+        for (i = 0; i < 3; i++) newpt[i] = dummypoint[i];
+        setpointtype(newpt, STEINERVERTEX);
+        dummypoint[0] = dummypoint[1] = dummypoint[2] = 0;
+        // Insert the new point. Starting search it from 'ssub'.
+        splitsubedge(newpt, &ssub, tg_facfaces, tg_facpoints);
+        tg_facfaces->restart();
+      }
+      // Clear the list of facet vertices.
+      tg_facpoints->restart();
+
+      // Some subsegments may be queued, recover them.
+      if (subsegstack->objects > 0l) {
+        delaunizesegments();
+      }
+      // Now the mesh should be constrained Delaunay.
+    } // if (neightet.tet == NULL) 
+  }
+
+  /* // Delete arrays.
+  delete crosstets;
+  delete topnewtets;
+  delete botnewtets;
+  delete topfaces;
+  delete botfaces;
+  delete midfaces;
+  delete toppoints;
+  delete botpoints;
+  delete facpoints;
+  delete facfaces;
+  delete topshells;
+  delete botshells;
+  */
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// scoutsegment2()    Search a segment in tetrahedralization.                //
+//                                                                           //
+// Search an edge in tetrahedralization that matches the given segmment. If  //
+// such an edge exists, the segment is 'locked' at that edge. 'searchtet'    //
+// returns this (constrained) edge.  Otherwise, the segment is missing.      //
+//                                                                           //
+// If the segment is missing, and the array 'crosstets' is given, it returns //
+// all crossing tetrahedra by this segment.                                  //
+//                                                                           //
+// The returned value indicates one of the following cases:                  //
+//   - SHAREEDGE, the segment exists and is inserted in T;                   //
+//   - ACROSSVERT, the segment passes a vertex (the origin of 'searchtet').  //
+//   - ACROSSEDGE, the segment intersects an edge (in 'searchtet').          //
+//   - ACROSSFACE, the segment crosses a face (in 'searchtet').              //
+//   - ACROSSSUBSEG, the segment intersects a segment (in 'searchtet').      //
+//   - ACROSSSUBFACE, the segment crosses a subface (in 'searchtet').        //
+//   - ACROSSTET, the segment is missing and the cavity has formed.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::intersection tetgenmesh::scoutsegment2(face* sseg,
+  triface* searchtet, arraypool* crosstets)
+{
+  triface neightet, spintet, *parytet;
+  face checksh, checkseg;
+  point pa, pb, pc, pd, pe, pf;// *ppt, *parypt;
+  enum intersection dir;
+  int types[2], poss[4];
+  int pos, i;
+
+  tetrahedron ptr;
+  int *iptr, tver;
+
+  pa = sorg(*sseg);
+  pb = sdest(*sseg);
+
+  if (b->verbose > 1) {
+    printf("  Search edge (%d, %d).\n", pointmark(pa), pointmark(pb));
+  }
+
+  // Search a tet whose origin is pa.
+  point2tetorg(pa, *searchtet);
+
+  // Search the line segment [pa, pb].
+  dir = finddirection(searchtet, pb);
+  if (dir == ACROSSVERT) {
+    if (dest(*searchtet) == pb) {
+      // Found! Insert the segment.
+      tsspivot(*searchtet, checkseg);  // SELF_CHECK
+      if (checkseg.sh == NULL) {
+        // Let the segment remember an adjacent tet.
+        sstbond(*sseg, *searchtet);
+        neightet = *searchtet;
+        do {
+          tssbond1(neightet, *sseg);
+          fnextself(neightet);
+        } while (neightet.tet != searchtet->tet);
+      } else {
+        // Collision! This can happy during facet recovery.
+        // See fig/dump-cavity-case19, -case20.
+        assert(checkseg.sh == sseg->sh); // SELF_CHECK
+      }
+      return SHAREEDGE; // The edge is not missing.
+    } else {
+      enextself(*searchtet);
+      return ACROSSVERT; // The edge intersects a vertex.
+    }
+  }
+
+  // The edge is missing, shall we form the edge cavity?
+  if (crosstets == NULL) {
+    // Go to the face/edge it crosses.
+    enextfnextself(*searchtet);
+    return dir; // ACROSSFACE and ACROSSEDGE
+  }
+
+  // The possible cases are: ACROSSFACE and ACROSSEDGE.
+  // Go to the opposite (intersect) face.
+  enextfnextself(*searchtet);
+  // Add this tet into list.
+  infect(*searchtet);
+  crosstets->newindex((void **) &parytet);
+  *parytet = *searchtet;
+  /*// Add all vertices of this tet into list.
+  ppt = (point *) &(searchtet->tet[4]);
+  for (i = 0; i < 4; i++) {
+    pinfect(ppt[i]);
+    cavpoints->newindex((void **) &parypt);
+    *parypt = ppt[i];
+  }*/
+
+  // Collect all crossing tets of the edge [a, b].
+  while (1) {
+
+    // Enter the next crossing tet.
+    symedgeself(*searchtet);
+    pf = oppo(*searchtet);
+
+    if (dir == ACROSSFACE) {
+      if (!infected(*searchtet)) { // Add this tet into list.
+        infect(*searchtet);
+        crosstets->newindex((void **) &parytet);
+        *parytet = *searchtet;
+      }
+      /*if (!pinfected(pf)) { // Add the opposite point into list.
+        pinfect(pf);
+        cavpoints->newindex((void **) &parypt);
+        *parypt = pf;
+      }*/
+      tspivot(*searchtet, checksh); // Check if a subface is crossed.
+      if (checksh.sh != NULL) {
+        // The edge intersect a subface.
+        dir = ACROSSSUBFACE;
+        break;
+      }
+    } else { // dir == ACROSSEDGE
+      // Add all tets containing this edge into list.
+      pc = apex(*searchtet);
+      spintet = *searchtet;
+      while (1) {
+        fnextself(spintet);
+        if (!infected(spintet)) { // Add this tet into list.
+          infect(spintet);
+          crosstets->newindex((void **) &parytet);
+          *parytet = spintet;
+        }
+        pd = oppo(spintet);
+        /*if (!pinfected(pd)) { // Add the opposite point into list.
+          pinfect(pd);
+          cavpoints->newindex((void **) &parypt);
+          *parypt = pd;
+        }*/
+        if (apex(spintet) == pc) break;
+      }
+      tsspivot(spintet, checkseg); // Check if a segment is crossed.
+      if (checkseg.sh != NULL) {
+        // The edge intersects a subsegment.
+        *searchtet = spintet;
+        dir = ACROSSSUBSEG;
+        break;
+      }
+    }
+
+    // Stop if we reach the endpoint.
+    if (pf == pb) break;
+
+    // Search the next tet crossing by [a, b].
+    if (dir == ACROSSFACE) {
+      // One of the 3 opposite faces in 'searchtet' must intersect [a, b].
+      neightet.tet = searchtet->tet;
+      neightet.ver = 0;
+      for (i = 0; i < 3; i++) {
+        neightet.loc = locpivot[searchtet->loc][i];
+        pc = org(neightet);
+        pd = dest(neightet);
+        pe = apex(neightet);
+        pf = oppo(neightet); // The above point.
+        // Test if face [c, d, e] intersects edge [a, b]? Report their
+        //   intersection type ('level' = 1).
+        if (tri_edge_test(pc, pd, pe, pa, pb, pf, 1, types, poss)) {
+          dir = (enum intersection) types[0];
+          pos = poss[0];
+          break;
+        } else {
+          dir = DISJOINT;
+          pos = 0;
+        }
+      }
+      assert(dir != DISJOINT);  // SELF_CHECK
+    } else { // dir == ACROSSEDGE
+      // Find a face (or edge) intersecting with [a, b].
+      spintet = *searchtet; // Backup the starting tet.
+      while (1) {
+        // Check the two opposite faces (of the edge) in 'searchtet'.
+        neightet.tet = searchtet->tet;
+        neightet.ver = 0;
+        for (i = 0; i < 2; i++) {
+          neightet.loc = locverpivot[searchtet->loc][searchtet->ver][i];
+          pc = org(neightet);
+          pd = dest(neightet);
+          pe = apex(neightet);
+          pf = oppo(neightet); // The above point.
+          // Test if face [c, d, e] intersects edge [a, b]? Report their
+          //   intersection type ('level' = 1).
+          if (tri_edge_test(pc, pd, pe, pa, pb, pf, 1, types, poss)) {
+            dir = (enum intersection) types[0];
+            pos = poss[0];
+            break;
+          } else {
+            dir = DISJOINT;
+            pos = 0;
+          }
+        }
+        if (dir == DISJOINT) {
+          // No intersection. Go to the next tet.
+          fnextself(*searchtet);
+          // Should NOT return to the starting tet.
+          assert(searchtet->tet != spintet.tet); // SELF_CHECK
+          continue; // Continue the search.
+        }
+        break; // Found!
+      } // while (1)
+    }
+
+    // Go to the intersect face or edge.
+    if (dir != ACROSSFACE) {
+      // 'dir' is either ACROSSFACE or ACROSSEDGE.
+      assert(dir == ACROSSEDGE); // SELF_CHECK
+      for (i = 0; i < pos; i++) {
+        enextself(neightet);
+      }
+    }
+    *searchtet = neightet;
+
+  } // while (1)
+
+  if ((dir == ACROSSSUBSEG) || (dir == ACROSSSUBFACE)) {
+    // Uninfect the collected crossing tets and vertices.
+    for (i = 0; i < crosstets->objects; i++) {
+      parytet = (triface *) fastlookup(crosstets, i);
+      uninfect(*parytet);
+    }
+    /*for (i = 0; i < cavpoints->objects; i++) {
+      parypt = (point *) fastlookup(cavpoints, i);
+      puninfect(*parypt);
+    }*/
+    crosstets->restart();
+    // cavpoints->restart();
+    return dir;
+  }
+
+  /*//We can form the edge cavity.
+  for (i = 0; i < crosstets->objects; i++) {
+    parytet = (triface *) fastlookup(crosstets, i);
+    *searchtet = *parytet;
+    for (searchtet->loc = 0; searchtet->loc < 4; searchtet->loc++) {
+      sym(*searchtet, neightet);
+      if (!infected(neightet)) {
+        // A cavity bounday face.
+        cavfaces->newindex((void **) &parytet);
+        *parytet = neightet;
+      }
+    }
+  }
+  // Uninfect the vertices.
+  for (i = 0; i < cavpoints->objects; i++) {
+    parypt = (point *) fastlookup(cavpoints, i);
+    puninfect(*parypt);
+  }
+  // Comment: All crossing tets are infected.
+  */
+
+  if (b->verbose > 1) {
+    printf("    Formed edge cavity: %ld tets.\n", crosstets->objects);
+  }
+
+  return ACROSSTET;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetrasegcavity()    Tetrahedralize a cavity for recovering a segment.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::tetrasegcavity(face* sseg, arraypool* crosstets,
+  arraypool* cavpoints, arraypool* cavfaces, arraypool* cavshells, 
+  arraypool* newtets, arraypool* misfaces, arraypool* missegs,
+  arraypool* fixedseglist)
+{
+  triface searchtet, neightet, spintet, *parytet, *parytet1;
+  face tmpsh, *parysh;
+  face checkseg, *paryseg;
+  point pt[4], pswap, *parypt;
+  enum intersection dir;
+  REAL ori;
+  bool success;
+  int i, j;
+
+  tetrahedron ptr;
+  int *iptr, tver;
+
+  // cavpoints are collected.
+  for (i = 0; i < crosstets->objects; i++) {
+    parytet = (triface *) fastlookup(crosstets, i);
+    for (j = 0; j < 4; j++) {
+      pt[0] = (point) parytet->tet[4 + j];
+      if (!pinfected(pt[0])) {
+        pinfect(pt[0]);
+        cavpoints->newindex((void **) &parypt);
+        *parypt = pt[0];
+      }
+    }
+  }
+  for (i = 0; i < cavpoints->objects; i++) {
+    parypt = (point *) fastlookup(cavpoints, i);
+    puninfect(*parypt);
+  }
+
+  if (b->verbose > 1) {
+    printf("    Tetrahedralizing segment cavity: %ld points.\n", 
+      cavpoints->objects, cavfaces->objects);
+  }
+
+  // Form an initial constrained tetrahedralization (CT) which has only one
+  //   tetrahedron containing the given segment.
+
+  // The first two points are the endpoints of the segment.
+  pt[0] = sorg(*sseg);
+  pt[1] = sdest(*sseg);
+  pinfect(pt[0]);
+  pinfect(pt[1]);
+
+  // Get the third and fourth points.
+  for (i = 0; i < cavpoints->objects; i++) {
+    parypt = (point *) fastlookup(cavpoints, i);
+    if (!pinfected(*parypt)) {
+      pt[2] = *parypt;
+      i++;
+      for (; i < cavpoints->objects; i++) {
+        parypt = (point *) fastlookup(cavpoints, i);
+        if (!pinfected(*parypt)) {
+          ori = orient3d(pt[0], pt[1], pt[2], *parypt);
+          if (ori != 0) {
+            pt[3] = *parypt;
+            if (ori > 0) {  // Swap pa and pb.
+              pswap = pt[0]; pt[0] = pt[1]; pt[1] = pswap;
+            }
+            break;
+          }
+        }
+      } // i 
+      break;
+    }
+  } // i
+  assert(i < cavpoints->objects); // SELF_CHECK
+  pinfect(pt[2]);
+  pinfect(pt[3]);
+
+  // Create an initial DT.
+  initialDT(pt[0], pt[1], pt[2], pt[3]);
+
+  // Insert the segment (turns a DT into a CT).
+  scoutsegment2(sseg, &searchtet, NULL);
+
+  // Insert the other points into the CT (the segment is respected).
+  for (i = 0; i < cavpoints->objects; i++) {
+    parypt = (point *) fastlookup(cavpoints, i);
+    if (!pinfected(*parypt)) {
+      // pinfect(*parypt);
+      searchtet = recenttet; // No random samples.
+      // Insert the point by flips. Set 'flipflag' = 3, do not flip a segment.
+      flipinsertvertex(*parypt, &searchtet, 3);
+    } else {
+      puninfect(*parypt);
+    }
+  }
+  // Comment: All vertices of the cavity are NOT marked.
+
+  success = true;
+
+  while (1) {
+
+    // cavfaces are collected.
+    for (i = 0; i < crosstets->objects; i++) {
+      parytet = (triface *) fastlookup(crosstets, i);
+      searchtet = *parytet;
+      for (searchtet.loc = 0; searchtet.loc < 4; searchtet.loc++) {
+        sym(searchtet, neightet);
+        if (!infected(neightet)) {
+          // A cavity bounday face.
+          cavfaces->newindex((void **) &parytet);
+          *parytet = neightet;
+        }
+      }
+    }
+
+    // Identify boundary faces. Mark interior tets. Save missing faces.
+    for (i = 0; i < cavfaces->objects; i++) {
+      parytet = (triface *) fastlookup(cavfaces, i);
+      // The tet of this face is exteriorly adjacent to the cavity.
+      assert(!infected(*parytet)); // SELF_CHECK
+      // This face may contain dummypoint (See fig/dump-cavity-case2).
+      //   If so, dummypoint must be its apex.
+      parytet->ver = 4; 
+      pt[0] = org(*parytet);
+      pt[1] = dest(*parytet);
+      pt[2] = apex(*parytet);
+      // Create a temp subface.
+      makeshellface(subfacepool, &tmpsh);
+      setshvertices(tmpsh, pt[0], pt[1], pt[2]);
+      // Insert tmpsh in CT.
+      searchtet.tet = NULL;
+      dir = scoutsubface(&tmpsh, &searchtet);
+      if (dir == SHAREFACE) {
+        // Identify the inter and outer tets at tempsh.
+        stpivot(tmpsh, neightet);
+        // neightet and tmpsh refer to the same edge [pt[0], pt[1]].
+        //   Moreover, neightet is in 0th edge ring (see decode()).
+        if (org(neightet) != pt[1]) {
+          symedgeself(neightet);
+          assert(org(neightet) == pt[1]); // SELF_CHECK
+          // Make sure that tmpsh is connected with an interior tet. 
+          tsbond(neightet, tmpsh);
+        }
+        assert(dest(neightet) == pt[0]); // SELF_CHECK
+      } else if (dir == COLLISIONFACE) {
+        // A subface is already inserted.
+        assert(0); // Not handled yet.
+      } else {
+        if (b->verbose > 1) {
+          printf("    p:draw_subface(%d, %d, %d) -- %d is missing\n",
+            pointmark(pt[0]), pointmark(pt[1]), pointmark(pt[2]), i);
+        }
+        shellfacedealloc(subfacepool, tmpsh.sh);
+        // Save this face in list.
+        misfaces->newindex((void **) &parytet1);
+        *parytet1 = *parytet;
+        continue;
+      }
+      // Remember tmpsh (use the adjacent tet slot). 
+      // parytet->tet[parytet->loc] = (tetrahedron) sencode(tmpsh);
+      tmpsh.sh[0] = (shellface) encode(*parytet);
+      // Save this subface.
+      cavshells->newindex((void **) &parysh);
+      *parysh = tmpsh;
+    } // for (i)
+
+    if (misfaces->objects > 0) {
+      // Removing tempoaray subfaces.
+      for (i = 0; i < cavshells->objects; i++) {
+        parysh = (face *) fastlookup(cavshells, i);
+        stpivot(*parysh, neightet);
+        uninfect(neightet);
+        tsdissolve(neightet); // Detach it from adj. tets.
+        symself(neightet);
+        tsdissolve(neightet);
+        shellfacedealloc(subfacepool, parysh->sh);
+      }
+      cavshells->restart();
+
+      for (i = 0; i < cavpoints->objects; i++) {
+        parypt = (point *) fastlookup(cavpoints, i);
+        pinfect(*parypt);
+      }
+
+      // Enlarge the cavity. 
+      for (i = 0; i < misfaces->objects; i++) {
+        // Get a missing face.
+        parytet = (triface *) fastlookup(misfaces, i);
+        // For this routine we do not check subface(s).
+        if (!infected(*parytet)) {
+          // This face should not be on the hull.
+          assert((point) parytet->tet[7] != dummypoint); // SELF_CHECK
+          // Check if we can enclose this tet into our cavity.
+          infect(*parytet);
+          // Check its six edges for enclosed segments.
+          neightet.tet = parytet->tet;
+          for (j = 0; j < 6; j++) {
+            neightet.loc = edge2locver[j][0];
+            neightet.ver = edge2locver[j][1];
+            tsspivot(neightet, checkseg);
+            if (checkseg.sh != NULL) {
+              // Check if this segment is inside our cavity.
+              spintet = neightet;
+              while (1) {
+                fnextself(spintet);
+                if (!infected(spintet)) break; // Not inside.
+                if (apex(spintet) == apex(neightet)) {
+                  if (b->verbose > 1) {
+                    printf("  p:draw_subseg(%d, %d) -- is inside.\n",
+                      pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
+                  }
+                  if (!smarktested(checkseg)) {
+                    missegs->newindex((void **) &parysh);
+                    *parysh = checkseg;
+                  } else {
+                    if (b->verbose > 1) {
+                      printf("  !! A fixed segment.\n");
+                    }
+                    success = false;
+                  }
+                  break;
+                }
+              } // while (1)
+              if (!success) break;
+            }
+          } // j
+          if (success) {
+            // We can enlarge the cavity.
+            if (b->verbose > 1) {
+               printf("    Add a crosstet (%d, %d, %d, %d).\n",
+                 pointmark(org(*parytet)), pointmark(dest(*parytet)),
+                 pointmark(apex(*parytet)), pointmark(oppo(*parytet)));
+            }
+            crosstets->newindex((void **) &parytet1);
+            *parytet1 = *parytet;
+            // Insert the opposite point if it is not in CT.
+            pt[0] = oppo(*parytet);
+            if (!pinfected(pt[0])) {
+              if (b->verbose > 1) {
+                printf("    Insert oppo-point %d.\n", pointmark(pt[0]));
+              }
+              pinfect(pt[0]);
+              cavpoints->newindex((void **) &parypt);
+              *parypt = pt[0];
+              searchtet = recenttet;
+              flipinsertvertex(pt[0], &searchtet, 3);
+            }
+            /*// Add three opposite faces into the boundary list.
+            for (j = 0; j < 3; j++) {
+              enext0fnext(*parytet, neightet);
+              symself(neightet);
+              if (!infected(neightet)) {
+                if (b->verbose > 1) {
+                  printf("    Add a cavface (%d, %d, %d).\n",
+                    pointmark(org(neightet)), pointmark(dest(neightet)),
+                    pointmark(apex(neightet)));
+                }
+                cavfaces->newindex((void **) &parytet1);
+                *parytet1 = neightet;
+              } else {
+                // It is an interior face, we do not check subface
+                //   for this routine.
+              }
+              enextself(*parytet); 
+            } // j */
+          } else {
+            // Do not enlarge it due to an existing segment.
+            uninfect(*parytet);
+          }
+        } // if (!infected(*parytet))
+        if (!success) break;
+      } // i
+
+      for (i = 0; i < cavpoints->objects; i++) {
+        parypt = (point *) fastlookup(cavpoints, i);
+        puninfect(*parypt);
+      }
+
+      misfaces->restart();
+      cavfaces->restart();
+
+      if (success && (missegs->objects > 0l)) {
+        // The cavity has been enlarged, but some segments are enclosed.
+        if (!smarktested(*sseg)) {
+          smarktest(*sseg);
+          fixedseglist->newindex((void **) &paryseg);
+          *paryseg = *sseg;
+        }
+        // SELF_CHECK
+        assert(cavshells->objects == 0l);
+        assert(newtets->objects == 0l);
+        // Recover the missing segments inside the enlarged cavity.
+        success = recoversegments(fixedseglist, missegs, cavfaces, cavshells,
+                                  misfaces, newtets);
+        // SELF_CHECK
+        assert(missegs->objects == 0l); 
+        assert(cavshells->objects == 0l);
+        assert(newtets->objects == 0l);
+        assert(cavfaces->objects == 0l);
+      }
+
+      if (success) {
+        // Cavity has enlarged. Continue to recover the segment.
+        cavityexpcount++;
+        continue;
+      }
+    } // if (misfaces->objects > 0)
+
+    break; // Leave the loop.
+
+  } // while (1)
+
+  // Collect all tets of the DT.
+  marktest(recenttet);
+  newtets->newindex((void **) &parytet);
+  *parytet = recenttet;
+  for (i = 0; i < newtets->objects; i++) {
+    searchtet = * (triface *) fastlookup(newtets, i);
+    for (searchtet.loc = 0; searchtet.loc < 4; searchtet.loc++) {
+      sym(searchtet, neightet);
+      if (!marktested(neightet)) {
+        marktest(neightet);
+        newtets->newindex((void **) &parytet);
+        *parytet = neightet;
+      }
+    }
+  }
+  // Comment: All new tets are marktested.
+
+  cavpoints->restart(); // Comment: Now no vertex is marked.
+  cavfaces->restart();
+
+  return success;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// recoversegments()    Recover segments by local remeshing.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::recoversegments(arraypool* fixedseglist, arraypool *recosegs,
+  arraypool* cavfaces, arraypool* cavshells, arraypool* misfaces,
+  arraypool* newtets)
+{
+  arraypool *crosstets;
+  arraypool *missegs;
+  arraypool *cavpoints;
+  triface searchtet;
+  face *psseg, sseg;
+  enum intersection dir;
+  bool success;
+  long bakhullsize;
+  long cavitycount;
+  int i;
+
+  if (b->verbose > 1) {
+    printf("  Recovering %ld segments (%ld fixed segments).\n",
+      recosegs->objects, fixedseglist->objects);
+  }
+
+  // Initialize arrays.
+  crosstets = new arraypool(sizeof(triface), 10);
+  missegs = new arraypool(sizeof(face), 8);
+  cavpoints = new arraypool(sizeof(point), 8);
+
+  success = true;
+
+  // Loop until 'recosegs' is empty.
+  while (recosegs->objects > 0l) {
+    // seglist is used as a stack.
+    recosegs->objects--;
+    psseg = (face *) fastlookup(recosegs, recosegs->objects);
+    sseg = *psseg;
+
+    // It is not a global missing segment.
+    assert(!sinfected(sseg)); 
+
+    // Form the segment cavity.
+    searchtet.tet = NULL;
+    dir = scoutsegment2(&sseg, &searchtet, crosstets);
+
+    // The segment is missing.
+    assert(dir != SHAREEDGE); // SELF_CHECK
+
+    if (dir == ACROSSTET) {
+      // Recover the segment by local re-meshing.
+      bakhullsize = hullsize;
+      success = tetrasegcavity(&sseg, crosstets, cavpoints, cavfaces, 
+        cavshells, newtets, misfaces, missegs, fixedseglist);
+      // Do not clean 'fixedseglist'.
+      hullsize = bakhullsize;
+      if (success) {
+        // The segment is recovered.
+        fillcavity(cavshells, NULL, NULL, NULL);
+        carvecavity(crosstets, newtets, NULL);
+      } else {
+        // Unable to recover the segment.
+        restorecavity(crosstets, newtets, NULL);
+        break;
+      }
+    } else {
+      // Unexpected return type.
+      assert(0); // Not handled yet.
+    }
+  }
+
+  if (recosegs->objects > 0l) {
+    recosegs->restart();
+  }
+
+  delete crosstets;
+  delete missegs;
+  delete cavpoints;
+
+  return success;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// constrainedsegments()    Recover segments in a constrained                //
+//                          tetrahedralization.                              //
+//                                                                           //
+// 'recoverseglist' contains a list of recovering segments, 'fixedseglist'   //
+// is an accumulated list of segments which are inside current tetrahedrali- //
+// zation and must "fix" at their places (do not remove them). All segments  //
+// in 'fixedseglist' are smarktested.                                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::constrainedsegments()
+{
+  arraypool *crosstets, *newtets, *misfaces;
+  arraypool *cavfaces;
+  arraypool *cavpoints;
+  arraypool *cavshells;
+  arraypool *fixedseglist, *missegs;
+  triface searchtet;
+  face splitsh;
+  face *psseg, sseg;
+  point newpt, pa, pb;
+  enum intersection dir;
+  bool success;
+  long bakhullsize;
+  long cavitycount;
+  long steinptcount;
+  int i;
+
+  if (b->verbose) {
+    printf("  Recovering %ld segments.\n", subsegstack->objects);
+  }
+
+  // Initialize arrays.
+  crosstets = new arraypool(sizeof(triface), 10);
+  newtets = new arraypool(sizeof(triface), 10);
+  misfaces = new arraypool(sizeof(triface), 10);
+  cavfaces = new arraypool(sizeof(triface), 10);
+  cavshells = new arraypool(sizeof(face), 10);
+  cavpoints = new arraypool(sizeof(point), 8);
+  fixedseglist = new arraypool(sizeof(face), 8);
+  missegs = new arraypool(sizeof(face), 8);
+
+  cavitycount = 0l;
+  steinptcount = 0l;
+
+  // Loop until 'subsegstack' is empty.
+  while (subsegstack->objects > 0l) {
+    // seglist is used as a stack.
+    subsegstack->objects--;
+    psseg = (face *) fastlookup(subsegstack, subsegstack->objects);
+    sseg = *psseg;
+
+    if (!sinfected(sseg)) continue; // Not a missing segment.
+    suninfect(sseg);
+
+    // Insert the segment.
+    searchtet.tet = NULL;
+    dir = scoutsegment2(&sseg, &searchtet, crosstets);
+
+    if (dir != SHAREEDGE) {
+      // The segment is missing.
+      if (dir == ACROSSTET) {
+        // Recover the segment by local re-meshing.
+        bakhullsize = hullsize;
+        success = tetrasegcavity(&sseg, crosstets, cavpoints, cavfaces,
+          cavshells, newtets, misfaces, missegs, fixedseglist);
+        hullsize = bakhullsize;
+        // Unmark the testmarked segments.
+        for (i = 0; i < fixedseglist->objects; i++) {
+          psseg = (face *) fastlookup(fixedseglist, i);
+          assert(smarktested(*psseg));
+          sunmarktest(*psseg);
+        }
+        fixedseglist->restart(); // Clear this list.
+        if (success) {
+          // The segment is recovered.
+          fillcavity(cavshells, NULL, NULL, NULL);
+          carvecavity(crosstets, newtets, NULL);
+          cavitycount++;
+        } else {
+          // Unable to recover the segment.
+          restorecavity(crosstets, newtets, NULL);
+          /*// Split the segment at its middle.
+          makepoint(&newpt);
+          pa = sorg(sseg);
+          pb = sdest(sseg);
+          for (i = 0; i < 3; i++) {
+            newpt[i] = 0.5 * (pa[i] + pb[i]);
+          }
+          setpointtype(newpt, STEINERVERTEX);
+          // Insert the point into the surface mesh.
+          spivot(sseg, splitsh);
+          // Two subsegments are queued in 'subsegstack' for recovery.
+          sinsertvertex(newpt, &splitsh, &sseg, true, false);
+          // Insert the point into the CT. 
+          point2tetorg(pa, searchtet);
+          // Set 'flipflag' = 3, do not flip a segment.
+          flipinsertvertex(newpt, &searchtet, 3);
+          */
+          steinptcount++;
+        }
+      } else if (dir == ACROSSVERT) {
+        printf("Error:  Invalid PLC! A point and a segment intersect.\n");
+        pa = farsorg(sseg);
+        pb = farsdest(sseg);
+        printf("  Point: %d. Segment: (%d, %d).\n", pointmark(org(searchtet)),
+          pointmark(pa), pointmark(pb));
+        terminatetetgen(1);
+      } else if (dir == ACROSSSUBSEG) {
+        printf("Error:  Invalid PLC! Two segments intersect.\n");
+        pa = farsorg(sseg);
+        pb = farsdest(sseg);
+        printf("  1st: (%d, %d)", pointmark(pa), pointmark(pb));
+        tsspivot(searchtet, sseg);
+        assert(sseg.sh != NULL);
+        pa = farsorg(sseg);
+        pb = farsdest(sseg);
+        printf("  2nd: (%d, %d).\n", pointmark(pa), pointmark(pb));
+        terminatetetgen(1);
+      } else if (dir == ACROSSSUBFACE) {
+        printf("Error:  Invalid PLC! A segment and a subface intersect.\n");
+        pa = farsorg(sseg);
+        pb = farsdest(sseg);
+        printf("  Segment: (%d, %d)", pointmark(pa), pointmark(pb));
+        tspivot(searchtet, splitsh);
+        printf("  Subface: (%d, %d, %d)", pointmark(sorg(splitsh)),
+          pointmark(sdest(splitsh)), pointmark(sapex(splitsh)));
+        terminatetetgen(1);
+      }
+    }
+  }
+
+  if (b->verbose) {
+    printf("  %ld cavities remeshed.\n", cavitycount);
+    printf("  %ld Steiner points inserted.\n", steinptcount);
+  }
+
+  delete crosstets;
+  delete newtets;
+  delete misfaces;
+  delete cavfaces;
+  delete cavshells;
+  delete cavpoints;
+  delete fixedseglist;
+  delete missegs;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// formskeleton()    Form a constrained tetrahedralization.                  //
+//                                                                           //
+// The segments and facets of a PLS will be recovered.                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::formskeleton()
+{
+  face *pssub, ssub;
+  REAL bakeps;
+  long bakflip22count;
+  long bakcavitycount;
+  int s, i;
+
+  if (!b->quiet) {
+    printf("Recovering boundaries.\n");
+  }
+
+  // Bakup the epsilon.
+  bakeps = b->epsilon;
+  b->epsilon = 0;
+
+  // Put all segments into the list.
+  if (b->order == 4) {  // '-o4' option (for debug)
+    // The sequential order.
+    subsegpool->traversalinit();
+    for (i = 0; i < subsegpool->items; i++) {
+      ssub.sh = shellfacetraverse(subsegpool);
+      sinfect(ssub);  // Only save it once.
+      subsegstack->newindex((void **) &pssub);
+      *pssub = ssub;
+    }
+  } else {
+    // Randomly order the segments.
+    subsegpool->traversalinit();
+    for (i = 0; i < subsegpool->items; i++) {
+      s = randomnation(i + 1);
+      // Move the s-th seg to the i-th.
+      subsegstack->newindex((void **) &pssub);
+      *pssub = * (face *) fastlookup(subsegstack, s);
+      // Put i-th seg to be the s-th.
+      ssub.sh = shellfacetraverse(subsegpool);
+      sinfect(ssub);  // Only save it once.
+      pssub = (face *) fastlookup(subsegstack, s);
+      *pssub = ssub;
+    }
+  }
+
+  // Segments will be introduced.
+  checksubsegs = 1;
+
+  // Recover segments.
+  if (b->nobisect == 0) {
+    if (b->verbose) {
+      printf("  Delaunizing segments.\n");
+    }
+
+    delaunizesegments();
+
+    if (b->verbose) {
+      printf("  %d protecting points.\n", r1count + r2count + r3count);
+    }
+  } else {
+    // -Y option, constrained recover.
+    constrainedsegments();
+  }
+
+  // Randomly order the subfaces.
+  subfacepool->traversalinit();
+  for (i = 0; i < subfacepool->items; i++) {
+    s = randomnation(i + 1);
+    // Move the s-th subface to the i-th.
+    subfacstack->newindex((void **) &pssub);
+    *pssub = * (face *) fastlookup(subfacstack, s);
+    // Put i-th subface to be the s-th.
+    ssub.sh = shellfacetraverse(subfacepool);
+    pssub = (face *) fastlookup(subfacstack, s);
+    *pssub = ssub;
+  }
+
+  // Subfaces will be introduced.
+  checksubfaces = 1;
+  bakflip22count = flip22count;
+  bakcavitycount = cavitycount;
+
+  if (b->verbose) {
+    printf("  Constraining facets.\n");
+  }
+
+  // Initialize arrays.
+  tg_crosstets = new arraypool(sizeof(triface), 10);
+  tg_topnewtets = new arraypool(sizeof(triface), 10);
+  tg_botnewtets = new arraypool(sizeof(triface), 10);
+  tg_topfaces = new arraypool(sizeof(triface), 10);
+  tg_botfaces = new arraypool(sizeof(triface), 10);
+  tg_midfaces = new arraypool(sizeof(triface), 10);
+  tg_toppoints = new arraypool(sizeof(point), 8);
+  tg_botpoints = new arraypool(sizeof(point), 8);
+  tg_facpoints = new arraypool(sizeof(point), 8);
+  tg_facfaces = new arraypool(sizeof(face), 10);
+  tg_topshells = new arraypool(sizeof(face), 10);
+  tg_botshells = new arraypool(sizeof(face), 10);
+
+  // Recover facets.
+  constrainedfacets();
+
+  // Delete arrays.
+  delete tg_crosstets;
+  delete tg_topnewtets;
+  delete tg_botnewtets;
+  delete tg_topfaces;
+  delete tg_botfaces;
+  delete tg_midfaces;
+  delete tg_toppoints;
+  delete tg_botpoints;
+  delete tg_facpoints;
+  delete tg_facfaces;
+  delete tg_topshells;
+  delete tg_botshells;
+
+  if (b->verbose) {
+    printf("  %ld subedge flips.\n", flip22count - bakflip22count);
+    printf("  %ld cavities remeshed.\n", cavitycount - bakcavitycount);
+  }
+
+  // checksubsegs = 0;
+  b->epsilon = bakeps;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// carveholes()    Remove tetrahedra not in the mesh domain.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::carveholes()
+{
+  arraypool *tetarray;
+  triface tetloop, neightet, hulltet, *parytet, *parytet1, fliptets[3];
+  triface openface, casface;
+  triface *regiontets;
+  face checksh, neighsh, flipshs[2];
+  face checkseg;
+  point *ppt, pa, pb, pc;
+  enum location loc;
+  REAL volume;
+  int attrnum, attr, maxattr;
+  int flatcount;
+  int i, j, k;
+
+  tetrahedron ptr;
+  int *iptr, tver;
+
+  if (!b->quiet) {
+    printf("Removing exterior tetrahedra.\n");
+  }
+
+  // Initialize the pool of exterior tets.
+  tetarray = new arraypool(sizeof(triface), 10);
+
+  maxattr = 0; // Choose a small number here.
+  attrnum = in->numberoftetrahedronattributes;
+
+  // Mark as infected any unprotected hull tets.
+  tetrahedronpool->traversalinit();
+  tetloop.loc = 0;
+  tetloop.tet = alltetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    if ((point) tetloop.tet[7] == dummypoint) {
+      // Is this side protected by a subface?
+      tspivot(tetloop, checksh);
+      if (checksh.sh == NULL) {
+        infect(tetloop);
+        tetarray->newindex((void **) &parytet);
+        *parytet = tetloop;
+      }
+    }
+    tetloop.tet = alltetrahedrontraverse();
+  }
+
+  hullsize -= tetarray->objects;
+
+  if (in->numberofholes > 0) {
+    // Mark as infected any tets inside volume holes.
+    for (i = 0; i < 3 * in->numberofholes; i += 3) {
+      // Search a tet containing the i-th hole point.
+      neightet.tet = NULL;
+      randomsample(&(in->holelist[i]), &neightet);
+      loc = locate(&(in->holelist[i]), &neightet);
+      if (loc != OUTSIDE) {
+        infect(neightet);
+        tetarray->newindex((void **) &parytet);
+        *parytet = neightet;
+      }
+    }
+  }
+
+  if (b->regionattrib && (in->numberofregions > 0)) { // If has -A option.
+    // Record the tetrahedra that contains the region points for assigning
+    //   region attributes after the holes have been carved.
+    regiontets = new triface[in->numberofregions];
+    // Mark as marktested any tetrahedra inside volume regions.
+    for (i = 0; i < 5 * in->numberofregions; i += 5) {
+      // Search a tet containing the i-th hole point.
+      neightet.tet = NULL;
+      randomsample(&(in->regionlist[i]), &neightet);
+      loc = locate(&(in->regionlist[i]), &neightet);
+      if (loc != OUTSIDE) {
+        regiontets[i/5] = neightet;
+        if ((int) in->regionlist[i + 3] > maxattr) {
+          maxattr = (int) in->regionlist[i + 3];
+        }
+      } else {
+        if (b->verbose) {
+          printf("Warning:  The %d-th region point is in outside.\n", i/5+1);
+        }
+        regiontets[i/5].tet = NULL;
+      }
+    }
+  }
+
+  // Find and infect all exterior tets (in concave place and in holes).
+  for (i = 0; i < tetarray->objects; i++) {
+    parytet = (triface *) fastlookup(tetarray, i);
+    tetloop = *parytet;
+    for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
+      symedge(tetloop, neightet);
+      // Is this side protected by a subface?
+      tspivot(tetloop, checksh);
+      if (checksh.sh == NULL) {
+        // Not protected. Infect it if it is not a hull tet.
+        if ((point) neightet.tet[7] != dummypoint) {
+          if (!infected(neightet)) {
+            infect(neightet);
+            tetarray->newindex((void **) &parytet);
+            *parytet = neightet;
+          }
+        }
+      } else {
+        // Its adjacent tet is protected.
+        if ((point) neightet.tet[7] == dummypoint) {
+          // A hull tet. It is dead.
+          assert(!infected(neightet));
+          infect(neightet);
+          tetarray->newindex((void **) &parytet);
+          *parytet = neightet;
+          // Both sides of this subface are exterior.
+          stdissolve(checksh);
+          hullsize--;
+        } else {
+          if (!infected(neightet)) {
+            // Let the subface connect to the "live" tet.
+            tsbond(neightet, checksh);
+          } else {
+            // Both sides of this subface are exterior.
+            stdissolve(checksh);
+          }
+        }
+      }
+    }
+  }
+
+  if (b->regionattrib && (in->numberofregions > 0)) {
+    // Re-check saved region tets to see if they lie outside.
+    for (i = 0; i < in->numberofregions; i++) {
+      if (infected(regiontets[i])) {
+        if (b->verbose) {
+          printf("Warning:  The %d-th region point is in outside.\n", i+1);
+        }
+        regiontets[i].tet = NULL;
+      }
+    }
+  }
+
+  // Remove all exterior tetrahedra (including infected hull tets).
+  for (i = 0; i < tetarray->objects; i++) {
+    parytet = (triface *) fastlookup(tetarray, i);
+    tetloop = *parytet;
+    for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
+      symedge(tetloop, neightet);
+      if (!infected(neightet)) {
+        // A "live" tet (may be a hull tet). Clear its adjacent tet.
+        neightet.tet[neightet.loc] = NULL;
+      }
+    }
+    tetrahedrondealloc(parytet->tet);
+  }
+
+  tetarray->restart(); // Re-use it for new hull tets.
+
+  // Create new hull tets. 
+  // Update point-to-tet map, segment-to-tet map, and subface-to-tet map.
+  tetrahedronpool->traversalinit();
+  tetloop.ver = 0;
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
+      if (tetloop.tet[tetloop.loc] == NULL) {
+        tspivot(tetloop, checksh);
+        assert(checksh.sh != NULL); // SELF_CHECK
+        // Create a new hull tet.
+        maketetrahedron(&hulltet);
+        pa = org(tetloop);
+        pb = dest(tetloop);
+        pc = apex(tetloop);
+        setvertices(hulltet, pb, pa, pc, dummypoint);
+        bond(tetloop, hulltet);
+        // Update subface-to-tet map.
+        tsbond(hulltet, checksh);
+        // Update segment-to-tet map.
+        for (i = 0; i < 3; i++) {
+          tsspivot(tetloop, checkseg);
+          if (checkseg.sh != NULL) {
+            tssbond1(hulltet, checkseg);
+            sstbond(checkseg, hulltet);
+          }
+          enextself(tetloop);
+          enext2self(hulltet);
+        }
+        // Save this hull tet in list.
+        tetarray->newindex((void **) &parytet);
+        *parytet = hulltet;
+      }
+    }
+    tetloop.loc = 0;
+    ptr = encode(tetloop);
+    ppt = (point *) tetloop.tet;
+    for (i = 4; i < 8; i++) {
+      point2tet(ppt[i]) = ptr;
+    }
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  // Update the hull size.
+  hullsize += tetarray->objects;
+
+  // Connect new hull tets.
+  for (i = 0; i < tetarray->objects; i++) {
+    parytet = (triface *) fastlookup(tetarray, i);
+    hulltet = *parytet;
+    assert(oppo(hulltet) == dummypoint); // SELF_CHECK
+    hulltet.ver = 0;
+    for (j = 0; j < 3; j++) {
+      enext0fnext(hulltet, neightet);
+      if (neightet.tet[neightet.loc] == NULL) {
+        esym(hulltet, casface);
+        while (1) {
+          symedgeself(casface);
+          enext0fnextself(casface);
+          if (apex(casface) == dummypoint) break;
+        }
+        bond(neightet, casface);
+      }
+      enextself(hulltet);
+    }
+  }
+
+  //////////////////////////////////////////////////////////////////////
+  // Peel off "flat" tetrahedra at boundary. 
+  //
+  // A tet is flat if it contains two subfaces of the same facet. 
+  // Flat tets are possible when a facet is defined by non-exactly 
+  // coplanar vertices.
+
+  tetarray->restart(); // Re-use this array.
+  flatcount = 0;
+
+  // Queue flat tets.
+  tetrahedronpool->traversalinit();
+  tetloop.ver = 0;
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    // Does this tet contain subfaces?
+    if (tetloop.tet[9] != NULL) {
+      // Look at shared subface at its 6 edges.
+      for (i = 0; i < 6; i++) {
+        tetloop.loc = edge2locver[i][0];
+        tetloop.ver = edge2locver[i][1];
+        // Is this edge a segment?
+        tsspivot(tetloop, checkseg);
+        if (checkseg.sh == NULL) {
+          // No segment. Is this edge shared by two subfaces?
+          tspivot(tetloop, checksh);
+          if (checksh.sh != NULL) {
+            enext0fnext(tetloop, neightet);
+            tspivot(neightet, neighsh);
+            if (neighsh.sh != NULL) {
+              if (b->verbose > 1) {
+                ppt = (point *) &tetloop.tet[4];
+                printf("    p:draw_tet(%d, %d, %d, %d) -- flat\n",
+                  pointmark(ppt[0]), pointmark(ppt[1]), pointmark(ppt[2]),
+                  pointmark(ppt[3]));
+              }
+              tetarray->newindex((void **) &parytet);
+              *parytet = tetloop;
+              break;
+            } // neighsh.sh != NULL
+          } // checksh.sh != NULL
+        } // checkseg.sh != NULL
+      } // i
+    }
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  if (tetarray->objects > 0) {
+    if (b->verbose) {
+      printf("  Removing flat boundary tetrahedra.\n");
+    }
+  }
+
+  // Remove flat tets, new flat tets are queued.
+  for (i = 0; i < tetarray->objects; i++) {
+    parytet = (triface *) fastlookup(tetarray, i);
+    assert(parytet->tet[4] != NULL); // SELF_CHECK
+    sym(*parytet, neightet);
+    if ((point) neightet.tet[7] != dummypoint) {
+      continue; // An internal face. Can't be peeled off.
+    }
+
+    if (b->verbose > 1) {
+      printf("    i = %d.\n", i);
+    }
+
+    enext0fnext(*parytet, neightet);
+    pa = org(*parytet);
+    pb = dest(*parytet);
+    tspivot(*parytet, flipshs[0]); // [0] abc
+    for (j = 0; j < 3; j++) {
+      if (sorg(flipshs[0]) == pa) break;
+      senextself(flipshs[0]);
+    }
+    assert(j < 3); // SELF_CHECK
+    if (sdest(flipshs[0]) != pb) {
+      senext2self(flipshs[0]);
+      sesymself(flipshs[0]);
+    }
+    assert(sdest(flipshs[0]) == pb); // SELF_CHECK
+    tspivot(neightet, flipshs[1]); // [1] bda
+    for (j = 0; j < 3; j++) {
+      if (sorg(flipshs[1]) == pb) break;
+      senextself(flipshs[1]);
+    }
+    assert(j < 3); // SELF_CHECK
+    if (sdest(flipshs[1]) != pa) {
+      senext2self(flipshs[1]);
+      sesymself(flipshs[1]);
+    }
+    assert(sdest(flipshs[1]) == pa); // SELF_CHECK
+
+    // Detach abc and bad.
+    sym(*parytet, casface);
+    tsdissolve(*parytet);
+    tsdissolve(casface);
+    sym(neightet, casface);
+    tsdissolve(neightet);
+    tsdissolve(casface);
+
+    // flip [0]abc,[1]bad to [0]cdb, [1]dca
+    flip22(flipshs, 0);
+
+    for (k = 0; k < 2; k++) {
+      if (k == 0) {
+        // Insert flipshs[0] [c,d,b] to adjacent tets.
+        enextfnext(*parytet, neightet); // face [b,c,d].
+        enextself(neightet); // edge [c,d] in face [c,d,b].
+      } else {
+        // Insert flipshs[1] [d,c,a] to adjacent tets.
+        enext2fnext(*parytet, neightet); // face [c,a,d].
+        enext2self(neightet); // edge [d,c] in face [d,c,a].
+      }
+      symedge(neightet, casface);
+      assert((point) casface.tet[7] != dummypoint); // SELF_CHECK
+      tspivot(neightet, checksh); // SELF_CHECK
+      assert(checksh.sh == NULL); // SELF_CHECK
+      tsbond(neightet, flipshs[k]);
+      tsbond(casface, flipshs[k]);
+      // Check for new invalid tet(s) (at edge [d,b] and [b,c]).
+      for (j = 0; j < 2; j++) {
+        enextself(casface); // edges [d,b], [b,c].
+        tsspivot(casface, checkseg);
+        if (checkseg.sh == NULL) {
+          enext0fnext(casface, openface);
+          tspivot(openface, checksh);
+          if (checksh.sh != NULL) {
+            if (b->verbose > 1) {
+               ppt = (point *) &casface.tet[4];
+               printf("    p:draw_tet(%d, %d, %d, %d) -- flat\n",
+                 pointmark(ppt[0]), pointmark(ppt[1]), pointmark(ppt[2]),
+                 pointmark(ppt[3]));
+            }
+            tetarray->newindex((void **) &parytet1);
+            *parytet1 = casface;
+            break;
+          }
+        }
+      } // j
+    } // k
+
+    // Peel the flat boundary tet by a flip32.
+    fliptets[0] = *parytet;
+    fnext(fliptets[0], fliptets[1]);
+    fnext(fliptets[1], fliptets[2]);
+    assert(apex(fliptets[2]) == dummypoint); // SELF_CHECK
+    assert(oppo(fliptets[2]) == apex(fliptets[0])); // SELF_CHECK
+
+    // Flip the tets (with hull tets, do not propagate).
+    flip32(fliptets, 1, 0);
+    // Now the flat boundary tet is removed.
+    flatcount++;
+  } // i
+
+  if (tetarray->objects > 0) {
+    if (b->verbose) {
+      printf("  %d flat tets are removed.\n", flatcount);
+    }
+  }
+
+  /////////////////////////////////////////////////////////////////////////
+
+  // Set region attributes (when has -A and -AA options).
+  if (b->regionattrib) {
+
+    if (!b->quiet) {
+      printf("Spreading region attributes.\n");
+    }
+
+    // If has user-defined region attributes.
+    if (in->numberofregions > 0) {
+      // Spread region attributes.
+      for (i = 0; i < 5 * in->numberofregions; i += 5) {
+        if (regiontets[i/5].tet != NULL) {
+          attr = (int) in->regionlist[i + 3];
+          volume = in->regionlist[i + 4];
+          tetarray->restart(); // Re-use this array.
+          infect(regiontets[i/5]);
+          tetarray->newindex((void **) &parytet);
+          *parytet = regiontets[i/5];
+          // Collect and set attrs for all tets of this region.
+          for (j = 0; j < tetarray->objects; j++) {
+            parytet = (triface *) fastlookup(tetarray, j);
+            tetloop = *parytet;
+            setelemattribute(tetloop.tet, attrnum, attr);
+            if (b->varvolume) { // If has -a option.
+              setvolumebound(tetloop.tet, volume);
+            }
+            for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
+              sym(tetloop, neightet);
+              // Is this side protected by a subface?
+              tspivot(tetloop, checksh);
+              if (checksh.sh == NULL) {
+                // Not protected. It must not be a hull tet.
+                // assert((point) neightet.tet[7] != dummypoint);
+                if ((point) neightet.tet[7] == dummypoint) {
+                  assert(0);
+                }
+                if (!infected(neightet)) {
+                  infect(neightet);
+                  tetarray->newindex((void **) &parytet);
+                  *parytet = neightet;
+                }
+              } else {
+                // Protected. Set attribute for hull tet as well.
+                if ((point) neightet.tet[7] == dummypoint) {
+                  setelemattribute(neightet.tet, attrnum, attr);
+                  if (b->varvolume) { // If has -a option.
+                    setvolumebound(neightet.tet, volume);
+                  }
+                }
+              }
+            } // loc
+          } // j
+        }
+      } // i
+      delete [] regiontets;
+    }
+
+    if (b->regionattrib > 1) { // If has -AA option.
+      // Set attributes for all tetrahedra.
+      attr = maxattr + 1;
+      tetrahedronpool->traversalinit();
+      tetloop.tet = tetrahedrontraverse();
+      while (tetloop.tet != (tetrahedron *) NULL) {
+        if (!infected(tetloop)) {
+          // An unmarked region.
+          tetarray->restart(); // Re-use this array.
+          infect(tetloop);
+          tetarray->newindex((void **) &parytet);
+          *parytet = tetloop;
+          // Find and mark all tets.
+          for (j = 0; j < tetarray->objects; j++) {
+            parytet = (triface *) fastlookup(tetarray, j);
+            tetloop = *parytet;
+            setelemattribute(tetloop.tet, attrnum, attr);
+            for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
+              sym(tetloop, neightet);
+              // Is this side protected by a subface?
+              tspivot(tetloop, checksh);
+              if (checksh.sh == NULL) {
+                // Not protected. It must not be a hull tet.
+                assert((point) neightet.tet[7] != dummypoint);
+                if (!infected(neightet)) {
+                  infect(neightet);
+                  tetarray->newindex((void **) &parytet);
+                  *parytet = neightet;
+                }
+              } else {
+                // Protected. Set attribute for hull tet as well.
+                if ((point) neightet.tet[7] == dummypoint) {
+                  setelemattribute(neightet.tet, attrnum, attr);
+                }
+              }
+            } // loc
+          }
+          attr++; // Increase the attribute.
+        }
+        tetloop.tet = tetrahedrontraverse();
+      }
+      // Until here, every tet has a region attribute.
+    }
+
+    // Uninfect processed tets.
+    tetrahedronpool->traversalinit();
+    tetloop.tet = tetrahedrontraverse();
+    while (tetloop.tet != (tetrahedron *) NULL) {
+      uninfect(tetloop);
+      tetloop.tet = tetrahedrontraverse();
+    }
+
+    // Mesh elements contain region attributes now.
+    in->numberoftetrahedronattributes++;
+
+  } // if (b->regionattrib)
+
+  delete tetarray;
+}
+
+#endif // #ifndef constrainCXX
diff --git a/contrib/TetgenNew/delaunay.cxx b/contrib/TetgenNew/delaunay.cxx
new file mode 100644
index 0000000000..a023c94b20
--- /dev/null
+++ b/contrib/TetgenNew/delaunay.cxx
@@ -0,0 +1,1464 @@
+#ifndef delaunayCXX
+#define delaunayCXX
+
+#include "tetgen.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// randomnation()    Generate a random number between 0 and 'choices' - 1.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+unsigned long tetgenmesh::randomnation(unsigned long choices)
+{
+  unsigned long newrandom;
+
+  if (choices >= 714025l) {
+    newrandom = (randomseed * 1366l + 150889l) % 714025l;
+    randomseed = (newrandom * 1366l + 150889l) % 714025l;
+    newrandom = newrandom * (choices / 714025l) + randomseed;
+    if (newrandom >= choices) {
+      return newrandom - choices;
+    } else {
+      return newrandom;
+    }
+  } else {
+    randomseed = (randomseed * 1366l + 150889l) % 714025l;
+    return randomseed % choices;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// randomsample()    Randomly sample the tetrahedra for point loation.       //
+//                                                                           //
+// This routine implements Muecke's Jump-and-walk point location algorithm.  //
+// It improves the simple walk-through by "jumping" to a good starting point //
+// via random sampling.  Searching begins from one of handles:  the input    //
+// 'searchtet', a recently encountered tetrahedron 'recenttet',  or from one //
+// chosen from a random sample.  The choice is made by determining which one //
+// 's origin is closest to the point we are searcing for.  Having chosen the //
+// starting tetrahedron, the simple Walk-through algorithm is executed.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::randomsample(point searchpt, triface *searchtet)
+{
+  tetrahedron *firsttet, *tetptr;
+  point torg;
+  void **sampleblock;
+  long sampleblocks, samplesperblock, samplenum;
+  unsigned long alignptr;
+  REAL searchdist, dist;
+  int tetblocks, i, j;
+
+  if ((searchtet->tet != NULL) && (searchtet->tet[4] != NULL)) {
+    // Get the distance from the suggested starting tet to the search point.
+    if ((point) searchtet->tet[7] != dummypoint) {
+      torg = org(*searchtet);
+    } else {
+      torg = (point) searchtet->tet[4];
+    }
+    searchdist = NORM2(searchpt[0] - torg[0], searchpt[1] - torg[1], 
+                       searchpt[2] - torg[2]);
+  } else {
+    searchdist = NORM2(xmax - xmin, ymax - ymin, zmax - zmin);
+  }
+
+  // If a recently encountered tetrahedron has been recorded and has not
+  //   been deallocated, test it as a good starting point.
+  if ((recenttet.tet != NULL) && (recenttet.tet[4] != NULL)) {
+    if ((point) recenttet.tet[7] != dummypoint) {
+      torg = org(recenttet);
+    } else {
+      torg = (point) recenttet.tet[4];
+    }
+    dist = NORM2(searchpt[0] - torg[0], searchpt[1] - torg[1],
+                 searchpt[2] - torg[2]);
+    if (dist <= searchdist) {
+      *searchtet = recenttet;
+      searchdist = dist;
+    }
+  }
+
+  // Select "good" candidate using k random samples, taking the closest one.
+  //   The number of random samples taken is proportional to the fourth root
+  //   of the number of tetrahedra in the mesh.
+  while (samples * samples * samples * samples < tetrahedronpool->items) {
+    samples++;
+  }
+  // Find how much blocks in current tet pool.
+  tetblocks = (tetrahedronpool->maxitems + ELEPERBLOCK - 1) / ELEPERBLOCK;
+  // Find the average samles per block. Each block at least have 1 sample.
+  samplesperblock = (samples + tetblocks - 1) / tetblocks;
+  sampleblocks = samples / samplesperblock;
+  sampleblock = tetrahedronpool->firstblock;
+  for (i = 0; i < sampleblocks; i++) {
+    alignptr = (unsigned long) (sampleblock + 1);
+    firsttet = (tetrahedron *)
+               (alignptr + (unsigned long) tetrahedronpool->alignbytes
+               - (alignptr % (unsigned long) tetrahedronpool->alignbytes));
+    for (j = 0; j < samplesperblock; j++) {
+      if (i == tetblocks - 1) {
+        // This is the last block.
+        samplenum = randomnation((int)
+                      (tetrahedronpool->maxitems - (i * ELEPERBLOCK)));
+      } else {
+        samplenum = randomnation(ELEPERBLOCK);
+      }
+      tetptr = (tetrahedron *)
+               (firsttet + (samplenum * tetrahedronpool->itemwords));
+      if (tetptr[4] != (tetrahedron) NULL) {
+        torg = (point) tetptr[4];
+        dist = NORM2(searchpt[0] - torg[0], searchpt[1] - torg[1],
+	             searchpt[2] - torg[2]);
+        if (dist < searchdist) {
+          searchtet->tet = tetptr;
+          searchtet->loc = 0;
+          searchtet->ver = 0;
+          searchdist = dist;
+        }
+      } else {
+        if (i != tetblocks - 1) j--;
+      }
+    }
+    sampleblock = (void **) *sampleblock;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// locate()    Find a simplex containing a given point.                      //
+//                                                                           //
+// This routine implements the simple Walk-through point location algorithm. //
+// Begins its search from 'searchtet', assume there is a line segment L from //
+// the origin of 'searchtet' to the query point 'searchpt', and simply walk  //
+// towards 'searchpt' by traversing all faces intersected by L.              //
+//                                                                           //
+// On completion, 'searchtet' is a tetrahedron that contains 'searchpt'. The //
+// returned value indicates one of the following cases:                      //
+//   - ONVERTEX, the search point lies on the origin of 'searchtet'.         //
+//   - ONEDGE, the search point lies on an edge of 'searchtet'.              //
+//   - ONFACE, the search point lies on a face of 'searchtet'.               //
+//   - INTET, the search point lies in the interior of 'searchtet'.          //
+//   - OUTSIDE, the search point lies outside the mesh. 'searchtet' is a     //
+//     hull tetrahedron whose base face is visible by the search point.      //
+//                                                                           //
+// WARNING: This routine is designed for convex triangulations, and will not //
+// generally work after the holes and concavities have been carved.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::location tetgenmesh::locate(point searchpt,triface* searchtet)
+{
+  triface neightet;
+  point torg, tdest, tapex, toppo, ntoppo;
+  enum {ORGMOVE, DESTMOVE, APEXMOVE} nextmove;
+  REAL ori, oriorg, oridest, oriapex;
+  REAL searchdist, dist;
+
+  tetrahedron ptr;
+  int *iptr;
+
+  if ((point) searchtet->tet[7] == dummypoint) {
+    // A hull tet. Choose the neighbor of its base face.
+    searchtet->loc = 0;
+    symself(*searchtet);
+  } else {
+    // Stay in the 0th edge ring.
+    if (searchtet->ver & 01) esymself(*searchtet);
+  }
+  // Let searchtet be the face such that 'searchpt' lies above to it.
+  for (; ; searchtet->loc = (searchtet->loc + 1) % 4) { 
+    torg = org(*searchtet);
+    tdest = dest(*searchtet);
+    tapex = apex(*searchtet);
+    ori = orient3d(torg, tdest, tapex, searchpt); orient3dcount++;
+    if (ori < 0) {
+      // searchpt lies above searchtet's face.
+      break;
+    } else if (ori > 0) {
+      // searchpt lies below searchtet's face.
+      symself(*searchtet);
+      torg = org(*searchtet);
+      tdest = dest(*searchtet);
+      tapex = apex(*searchtet);
+      break;
+    }
+    // searchpt is coplanar with searchtet's face. Go to the next face.
+  }
+
+  // Walk through tetrahedra to locate the point.
+  while (true) {
+
+    ptloc_count++;  // Algorithimic count.
+
+    toppo = oppo(*searchtet);
+    
+    // Check if we have walked out of the domain.
+    if (toppo == dummypoint) {
+      return OUTSIDE;
+    }
+    
+    // Check if the vertex is we seek.
+    if (toppo == searchpt) {
+      // Adjust the origin of searchtet to be searchpt.
+      enext0fnextself(*searchtet);
+      esymself(*searchtet);
+      enext2self(*searchtet);
+      return ONVERTEX;
+    }
+
+    // We enter from serarchtet's base face. There are three other faces in
+    //   searchtet (all connecting to toppo), which one is the exit?
+    oriorg = orient3d(tdest, tapex, toppo, searchpt); 
+    oridest = orient3d(tapex, torg, toppo, searchpt);
+    oriapex = orient3d(torg, tdest, toppo, searchpt);
+    orient3dcount+=3;
+
+    // Now decide which face to move. It is possible there are more than one
+    //   faces are viable moves. Use the opposite points of thier neighbors
+    //   to discriminate, i.e., we choose the face whose opposite point has
+    //   the shortest distance to searchpt.
+    if (oriorg < 0) {
+      if (oridest < 0) {
+        if (oriapex < 0) {
+          // Any of the three faces is a viable move. 
+          nextmove = ORGMOVE;
+          enextfnext(*searchtet, neightet);
+          symself(neightet);
+          ntoppo = oppo(neightet);
+          if (ntoppo != dummypoint) {
+            searchdist = NORM2(searchpt[0] - ntoppo[0],
+                               searchpt[1] - ntoppo[1],
+                               searchpt[2] - ntoppo[2]);
+          } else {
+            searchdist = NORM2(xmax - xmin, ymax - ymin, zmax - zmin);
+          }
+          enext2fnext(*searchtet, neightet);
+          symself(neightet);
+          ntoppo = oppo(neightet);
+          if (ntoppo != dummypoint) {
+            dist = NORM2(searchpt[0] - ntoppo[0], searchpt[1] - ntoppo[1],
+                         searchpt[2] - ntoppo[2]);
+          } else {
+            dist = searchdist;
+          }
+          if (dist < searchdist) {
+            nextmove = DESTMOVE;
+            searchdist = dist;
+          }
+          enext0fnext(*searchtet, neightet);
+          symself(neightet);
+          ntoppo = oppo(neightet);
+          if (ntoppo != dummypoint) {
+            dist = NORM2(searchpt[0] - ntoppo[0], searchpt[1] - ntoppo[1],
+                         searchpt[2] - ntoppo[2]);
+          } else {
+            dist = searchdist;
+          }
+          if (dist < searchdist) {
+            nextmove = APEXMOVE;
+            searchdist = dist;
+          }
+        } else {
+          // Two faces, opposite to origin and destination, are viable.
+          nextmove = ORGMOVE;
+          enextfnext(*searchtet, neightet);
+          symself(neightet);
+          ntoppo = oppo(neightet);
+          if (ntoppo != dummypoint) {
+            searchdist = NORM2(searchpt[0] - ntoppo[0],
+                               searchpt[1] - ntoppo[1],
+                               searchpt[2] - ntoppo[2]);
+          } else {
+            searchdist = NORM2(xmax - xmin, ymax - ymin, zmax - zmin);
+          }
+          enext2fnext(*searchtet, neightet);
+          symself(neightet);
+          ntoppo = oppo(neightet);
+          if (ntoppo != dummypoint) {
+            dist = NORM2(searchpt[0] - ntoppo[0], searchpt[1] - ntoppo[1],
+                         searchpt[2] - ntoppo[2]);
+          } else {
+            dist = searchdist;
+          }
+          if (dist < searchdist) {
+            nextmove = DESTMOVE;
+            searchdist = dist;
+          }
+        }
+      } else {
+        if (oriapex < 0) {
+          // Two faces, opposite to origin and apex, are viable.
+          nextmove = ORGMOVE;
+          enextfnext(*searchtet, neightet);
+          symself(neightet);
+          ntoppo = oppo(neightet);
+          if (ntoppo != dummypoint) {
+            searchdist = NORM2(searchpt[0] - ntoppo[0],
+                               searchpt[1] - ntoppo[1],
+                               searchpt[2] - ntoppo[2]);
+          } else {
+            searchdist = NORM2(xmax - xmin, ymax - ymin, zmax - zmin);
+          }
+          enext0fnext(*searchtet, neightet);
+          symself(neightet);
+          ntoppo = oppo(neightet);
+          if (ntoppo != dummypoint) {
+            dist = NORM2(searchpt[0] - ntoppo[0], searchpt[1] - ntoppo[1],
+                         searchpt[2] - ntoppo[2]);
+          } else {
+            dist = searchdist;
+          }
+          if (dist < searchdist) {
+            nextmove = APEXMOVE;
+            searchdist = dist;
+          }
+        } else {
+          // Only the face opposite to origin is viable.
+          nextmove = ORGMOVE;
+        }
+      }
+    } else {
+      if (oridest < 0) {
+        if (oriapex < 0) {
+          // Two faces, opposite to destination and apex, are viable.
+          nextmove = DESTMOVE;
+          enext2fnext(*searchtet, neightet);
+          symself(neightet);
+          ntoppo = oppo(neightet);
+          if (ntoppo != dummypoint) {
+            searchdist = NORM2(searchpt[0] - ntoppo[0],
+                               searchpt[1] - ntoppo[1],
+                               searchpt[2] - ntoppo[2]);
+          } else {
+            searchdist = NORM2(xmax - xmin, ymax - ymin, zmax - zmin);
+          }
+          enext0fnext(*searchtet, neightet);
+          symself(neightet);
+          ntoppo = oppo(neightet);
+          if (ntoppo != dummypoint) {
+            dist = NORM2(searchpt[0] - ntoppo[0], searchpt[1] - ntoppo[1],
+                         searchpt[2] - ntoppo[2]);
+          } else {
+            dist = searchdist;
+          }
+          if (dist < searchdist) {
+            nextmove = APEXMOVE;
+            searchdist = dist;
+          }
+        } else {
+          // Only the face opposite to destination is viable.
+          nextmove = DESTMOVE;
+        }
+      } else {
+        if (oriapex < 0) {
+          // Only the face opposite to apex is viable.
+          nextmove = APEXMOVE;
+        } else {
+          // The point we seek must be on the boundary of or inside this
+          //   tetrahedron. Check for boundary cases.
+          if (oriorg == 0) {
+            // Go to the face opposite to origin.
+            enextfnextself(*searchtet);
+            if (oridest == 0) {
+              enextself(*searchtet); // edge apex->oppo
+              if (oriapex == 0) {
+                enextself(*searchtet); // oppo is duplicated with p.
+                return ONVERTEX;
+              }
+              return ONEDGE;
+            }
+            if (oriapex == 0) {
+              enext2self(*searchtet);
+              return ONEDGE;
+            }
+            return ONFACE;
+          }
+          if (oridest == 0) {
+            // Go to the face opposite to destination.
+            enext2fnextself(*searchtet);
+            if (oriapex == 0) {
+              enextself(*searchtet);
+              return ONEDGE;
+            }
+            return ONFACE;
+          }
+          if (oriapex == 0) {
+            // Go to the face opposite to apex
+            enext0fnextself(*searchtet);
+            return ONFACE;
+          }
+          return INTET;
+        }
+      }
+    }
+    
+    // Move to the selected face.
+    if (nextmove == ORGMOVE) {
+      enextfnextself(*searchtet);
+    } else if (nextmove == DESTMOVE) {
+      enext2fnextself(*searchtet);
+    } else {
+      enext0fnextself(*searchtet);
+    }
+    // Move to the adjacent tetrahedron (maybe a hull tetrahedron).
+    symself(*searchtet);
+    // Retreat the three vertices of the base face.
+    torg = org(*searchtet);
+    tdest = dest(*searchtet);
+    tapex = apex(*searchtet);
+
+  } // while (true)
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// initialDT()    Create an initial Delaunay tetrahedralization.             //
+//                                                                           //
+// The tetrahedralization contains only one tetrahedron abcd, and four hull  //
+// tetrahedra.  The points pa, pb, pc, and pd must be linearly independent.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::initialDT(point pa, point pb, point pc, point pd)
+{
+  triface firsttet, tetopa, tetopb, tetopc, tetopd;
+  triface worktet, worktet1;
+  int *iptr;
+
+  if (b->verbose > 1) {
+    printf("    Create init tet (%d, %d, %d, %d)\n", pointmark(pa),
+      pointmark(pb), pointmark(pc), pointmark(pd));
+  }
+
+  // Create the first tetrahedron.
+  maketetrahedron(&firsttet);
+  setvertices(firsttet, pa, pb, pc, pd);
+  // Create four hull tetrahedra.
+  maketetrahedron(&tetopa);
+  setvertices(tetopa, pb, pc, pd, dummypoint);
+  maketetrahedron(&tetopb);
+  setvertices(tetopb, pc, pa, pd, dummypoint);
+  maketetrahedron(&tetopc);
+  setvertices(tetopc, pa, pb, pd, dummypoint);
+  maketetrahedron(&tetopd);
+  setvertices(tetopd, pb, pa, pc, dummypoint);
+  hullsize += 4;
+
+  // Connect hull tetrahedra to firsttet (at four faces of firsttet).
+  bond(firsttet, tetopd); // ab
+  enext0fnext(firsttet, worktet);
+  bond(worktet, tetopc); // ab
+  enextfnext(firsttet, worktet);
+  bond(worktet, tetopa); // bc 
+  enext2fnext(firsttet, worktet);
+  bond(worktet, tetopb); // ca
+
+  // Connect hull tetrahedra together (at six edges of firsttet).
+  enext0fnext(tetopc, worktet); 
+  enext0fnext(tetopd, worktet1);
+  bond(worktet, worktet1); // ab
+  enext0fnext(tetopa, worktet);
+  enext2fnext(tetopd, worktet1);
+  bond(worktet, worktet1); // bc
+  enext0fnext(tetopb, worktet);
+  enextfnext(tetopd, worktet1);
+  bond(worktet, worktet1); // ca
+  enext2fnext(tetopc, worktet);
+  enextfnext(tetopb, worktet1);
+  bond(worktet, worktet1); // da
+  enext2fnext(tetopa, worktet);
+  enextfnext(tetopc, worktet1);
+  bond(worktet, worktet1); // db
+  enext2fnext(tetopb, worktet);
+  enextfnext(tetopa, worktet1);
+  bond(worktet, worktet1); // dc
+
+  // Set the vertex type.
+  if (getpointtype(pa) == UNUSEDVERTEX) {
+    setpointtype(pa, VOLVERTEX);
+  }
+  if (getpointtype(pb) == UNUSEDVERTEX) {
+    setpointtype(pb, VOLVERTEX);
+  }
+  if (getpointtype(pc) == UNUSEDVERTEX) {
+    setpointtype(pc, VOLVERTEX);
+  }
+  if (getpointtype(pd) == UNUSEDVERTEX) {
+    setpointtype(pd, VOLVERTEX);
+  }
+
+  // Update the point-to-tet map.
+  // if (checksubsegs || checksubfaces) {
+    point2tet(pa) = encode(firsttet);
+    point2tet(pb) = encode(firsttet);
+    point2tet(pc) = encode(firsttet);
+    point2tet(pd) = encode(firsttet);
+  // }
+
+  // Remember the first tetrahedron.
+  recenttet = firsttet;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertvertex()    Insert a point (p) into tetrahedralization (T).         //
+//                                                                           //
+// The point p will be first located in T. 'searchtet' is a suggested start- //
+// tetrahedron, it can be NULL. Note that p may lies outside T. In such case,//
+// the convex hull of T will be updated to include p as a vertex.            //
+//                                                                           //
+// If 'bwflag' is TRUE, the Bowyer-Watson algorithm is used to recover the   //
+// Delaunayness of T. Otherwise, do nothing with regard to the Delaunayness  //
+// T (T may be non-Delaunay after this function).                            //
+//                                                                           //
+// If 'visflag' is TRUE, force to check the visibility of the boundary faces //
+// of cavity. This is needed when T is not Delaunay.                         //
+//                                                                           //
+// If 'noencsegflag' is TRUE, only insert the point if it does not encroach  //
+// on any existing segment of the mesh. Otherwise, do not insert the point,  //
+// and all encroaching segments are returned in subsegstack.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::location tetgenmesh::insertvertex(point insertpt, 
+  triface *searchtet, bool bwflag, bool visflag, bool noencsegflag,
+  bool noencsubflag)
+{
+  triface *cavetet, *parytet, spintet, neightet, newtet, neineitet;
+  face *pssub, checksh;
+  face *psseg, sseg;
+  point *pts, pa, pb, pc;
+  enum location loc;
+  REAL sign, ori;
+  long tetcount;
+  bool enqflag;
+  int i, j, k;
+
+  badface *newflip, *lastflip;  // for bowyerwatson
+  triface fliptets[5], baktets[2];
+
+  tetrahedron ptr;
+  int *iptr, tver;
+
+  arraypool *swaplist; // for updating cavity.
+  long updatecount;
+
+  // clock_t loc_start, loc_end;
+
+  if (b->verbose > 1) {
+    printf("    Insert point %d\n", pointmark(insertpt));
+  }
+
+  // loc_start = clock();
+
+  tetcount = ptloc_count;
+  updatecount = 0l;
+  
+  if (searchtet->tet == NULL) {
+    randomsample(insertpt, searchtet);
+  }
+  loc = locate(insertpt, searchtet);
+
+  // loc_end = clock();
+  // tloctime += ((REAL) (loc_end - loc_start)) / CLOCKS_PER_SEC;
+
+  if (b->verbose > 1) {
+    printf("    Walk distance (# tets): %ld\n", ptloc_count - tetcount);
+  }
+
+  if (ptloc_max_count < (ptloc_count - tetcount)) {
+    ptloc_max_count = (ptloc_count - tetcount);
+  }
+
+  if (b->verbose > 1) {
+    printf("    Located (%d) tet (%d, %d, %d, %d).\n", (int) loc,
+      pointmark(org(*searchtet)), pointmark(dest(*searchtet)), 
+      pointmark(apex(*searchtet)), pointmark(oppo(*searchtet)));
+  }
+
+  if (loc == ONVERTEX) {
+    // The point already exists. Mark it and do nothing on it.
+    if (b->object != tetgenbehavior::STL) {
+      if (!b->quiet) {
+        printf("Warning:  Point #%d is duplicated with Point #%d. Ignored!\n",
+          pointmark(insertpt), pointmark(org(*searchtet)));
+      }
+    }
+    point2ppt(insertpt) = org(*searchtet);
+    setpointtype(insertpt, DUPLICATEDVERTEX);
+    dupverts++;
+    return loc;
+  }
+
+  // loc_start = clock();
+
+  tetcount = 0l;  // The number of deallocated tets.
+
+  // Create the initial boundary of the cavity.
+  if (loc == INTET || loc == OUTSIDE) {
+    // Add four adjacent boundary tets into list.
+    for (i = 0; i < 4; i++) {
+      decode(searchtet->tet[i], neightet);
+      cavetetlist->newindex((void **) &parytet);
+      *parytet = neightet;
+    }
+    if ((point) searchtet->tet[7] == dummypoint) hullsize--;
+    // tetrahedrondealloc(searchtet->tet);
+    infect(*searchtet);
+    caveoldtetlist->newindex((void **) &parytet);
+    *parytet = *searchtet;
+    tetcount = 1;
+    flip14count++;
+  } else if (loc == ONFACE) {
+    // Add six adjacent boundary tets into list.
+    for (i = 0; i < 3; i++) {
+      decode(searchtet->tet[locpivot[searchtet->loc][i]], neightet);
+      cavetetlist->newindex((void **) &parytet);
+      *parytet = neightet;
+    }
+    decode(searchtet->tet[searchtet->loc], spintet);
+    for (i = 0; i < 3; i++) {
+      decode(spintet.tet[locpivot[spintet.loc][i]], neightet);
+      cavetetlist->newindex((void **) &parytet);
+      *parytet = neightet;
+    }
+    if ((point) spintet.tet[7] == dummypoint) hullsize--;
+    if ((point) searchtet->tet[7] == dummypoint) hullsize--;
+    // tetrahedrondealloc(spintet.tet);
+    infect(spintet);
+    caveoldtetlist->newindex((void **) &parytet);
+    *parytet = spintet;
+    // tetrahedrondealloc(searchtet->tet);
+    infect(*searchtet);
+    caveoldtetlist->newindex((void **) &parytet);
+    *parytet = *searchtet;
+    tetcount = 2;
+    flip26count++;
+  } else if (loc == ONEDGE) {
+    // Add all adjacent boundary tets into list.
+    spintet = *searchtet;
+    tetcount = 0;
+    do {
+      fnextself(spintet);
+      tetcount++;
+      decode(spintet.tet[locverpivot[spintet.loc][spintet.ver][0]], neightet);
+      cavetetlist->newindex((void **) &parytet);
+      *parytet = neightet;
+      decode(spintet.tet[locverpivot[spintet.loc][spintet.ver][1]], neightet);
+      cavetetlist->newindex((void **) &parytet);
+      *parytet = neightet;
+    } while (spintet.tet != searchtet->tet);
+    // Delete old tets in the cavity.
+    spintet = *searchtet;
+    for (i = 0; i < tetcount; i++) {
+      fnext(spintet, neightet);
+      if ((point) spintet.tet[7] == dummypoint) hullsize--;
+      // tetrahedrondealloc(spintet.tet);
+      infect(spintet);
+      caveoldtetlist->newindex((void **) &parytet);
+      *parytet = spintet;
+      spintet = neightet;
+    }
+    flipn2ncount++;
+  }
+
+  // Form the cavity by including tets from initial boundary.
+  for (i = 0; i < cavetetlist->objects; i++) {
+    // 'cavetet' is actually an adjacent tet to the cavity.
+    cavetet = (triface *) fastlookup(cavetetlist, i);
+    // Do check if it is not infected (not deleted yet).
+    if (!infected(*cavetet)) { // if (cavetet->tet[4] != NULL) {
+      // Check for two possible cases for this tet: 
+      //   (1) It is a cavity tet, or
+      //   (2) it is a cavity boundary face.
+      // In case (1), the three other faces of this tet are added into
+      //   'cavetetlist' for later checking (we use a bread-first search),
+      //   and this tet gets deleted (infected).
+      enqflag = false;
+      if (!marktested(*cavetet)) {
+        pts = (point *) cavetet->tet;
+        if (pts[7] != dummypoint) {
+          // A volume tet. Operate on it if it has not been tested yet.
+          if (bwflag) {
+            // Use Bowyer-Watson algorithm, do Delaunay check.
+            sign = insphere_sos(pts[4], pts[5], pts[6], pts[7], insertpt);
+            enqflag = (sign < 0.0);
+          }
+        } else {
+          // It is a hull tet. Check if its base face is visible by p. 
+          //   This happens when p lies outside the hull face.
+          ori = orient3d(pts[4], pts[5], pts[6], insertpt); orient3dcount++;
+          enqflag = (ori < 0.0);
+          // Check if this face is coplanar with p. This case may create
+          //   a degenerate tet (zero volume). 
+          // Note: for convex domain, it can only happen at a hull face.
+          if (bwflag && (ori == 0.0)) {
+            newflip = (badface *) flippool->alloc();
+            newflip->tt = *cavetet; // Queue the adjacent tet (not in cavity).
+            newflip->tt.loc = 0; // Must be at the base face.
+            newflip->nextitem = NULL;
+            if (futureflip == NULL) {
+              lastflip = futureflip = newflip;
+            } else {
+              lastflip->nextitem = newflip;
+              lastflip = newflip;
+            }
+          }
+        } // if (pts[7] != dummypoint)
+        marktest(*cavetet); // Only test it once.
+      }
+      /*// Validation is needed when T is not a Delaunay triangulation. The
+      //   default cavity may not be star-shaped (fig/dump-cavity-case8).
+      if (visflag && !enqflag) {
+        if ((point) cavetet->tet[7] != dummypoint) {
+          // A non-hull cavity boundary face. Validate it.
+          cavetet->ver = 4;
+          pa = org(*cavetet);
+          pb = dest(*cavetet);
+          pc = apex(*cavetet);
+          ori = orient3d(pa, pb, pc, insertpt); orient3dcount++;
+          assert(ori != 0.0); // SELF_CHECK
+          enqflag = (ori < 0.0);
+          if (enqflag) {
+            updatecount++; // Cavity is updated.
+          }
+        }
+      }*/
+      if (enqflag) {
+        // Found a tet in the cavity. Put other three faces in check list.
+        for (j = 0; j < 3; j++) {
+          decode(cavetet->tet[locpivot[cavetet->loc][j]], neightet);
+          cavetetlist->newindex((void **) &parytet);
+          *parytet = neightet;
+        }
+        if ((point) cavetet->tet[7] == dummypoint) hullsize--;
+        // tetrahedrondealloc(cavetet->tet);
+        infect(*cavetet);
+        caveoldtetlist->newindex((void **) &parytet);
+        *parytet = *cavetet;
+        tetcount++;
+      } else {
+        // Found a boundary face of the cavity. It may be a face of a hull
+        //   tet which contains 'dummypoint'. Choose the edge in the face 
+        //   such that its endpoints are not 'dummypoint', while its apex
+        //   may be 'dummypoint' (see Fig. 1.4).
+        cavetet->ver = 4;
+        cavebdrylist->newindex((void **) &parytet);
+        *parytet = *cavetet;
+      }
+    } // if (cavetet->tet[4] != NULL)
+  }
+
+  if (b->verbose > 1) {
+    printf("    Size of the cavity: %d faces %d tets.\n",
+           cavebdrylist->objects, tetcount);
+  }
+
+  totaldeadtets += tetcount;
+  totalbowatcavsize += cavebdrylist->objects;
+  if (maxbowatcavsize < cavebdrylist->objects) {
+    maxbowatcavsize = cavebdrylist->objects;
+  }
+
+  if (checksubsegs) {
+    // Check if some (sub)segments are inside the cavity. Such segments
+    //   are queued in 'subsegstack'. 
+    for (i = 0; i < caveoldtetlist->objects; i++) {
+      cavetet = (triface *) fastlookup(caveoldtetlist, i);
+      for (j = 0; j < 6; j++) {
+        cavetet->loc = edge2locver[j][0];
+        cavetet->ver = edge2locver[j][1];
+        tsspivot(*cavetet, sseg);
+        if ((sseg.sh != NULL) && !sinfected(sseg)) {
+          // Check if this segment is inside the cavity.
+          spintet = *cavetet;
+          pa = apex(spintet);
+          enqflag = true;
+          while (1) {
+            fnextself(spintet);
+            if (!infected(spintet)) {
+              enqflag = false; break; // It is not inside.
+            }
+            if (apex(spintet) == pa) break;
+          }
+          if (enqflag) {
+            if (b->verbose > 1) {
+              printf("      Queue a missing segment (%d, %d).\n",
+                pointmark(sorg(sseg)), pointmark(sdest(sseg)));
+            }
+            // All tets containing this segment will be dead, clean the
+            //   seg-to-tet pointer.
+            stdissolve(sseg);
+            sinfect(sseg);  // Only save it once.
+            subsegstack->newindex((void **) &psseg);
+            *psseg = sseg;
+          }
+        }
+      }
+    }
+    if (noencsegflag) {
+      // Check for encroaching segment on the boundary of the cavity.
+      //   Encroached segments are queued in 'subsegstack'.
+      for (i = 0; i < cavebdrylist->objects; i++) {
+        cavetet = (triface *) fastlookup(cavebdrylist, i);
+        // 'cavetet' is an exterior tet adjacent to the cavity.
+        assert(cavetet->ver == 4); // SELF_CHECK
+        for (j = 0; j < 3; j++) {
+          tsspivot(*cavetet, sseg);
+          if (sseg.sh != NULL) {
+            // Found a segment. Check it if it is not queued yet.
+            if (!sinfected(sseg)) {
+              if (checkedge4encroach(sseg, insertpt, 0)) {
+                if (b->verbose > 1) {
+                  printf("      Queue an encroaching segment (%d, %d).\n",
+                    pointmark(sorg(sseg)), pointmark(sdest(sseg)));
+                }
+                // This segment will still be connected to a tet after the
+                //   insertion.
+                sinfect(sseg);  // Only save it once.
+                subsegstack->newindex((void **) &psseg);
+                *psseg = sseg;
+              }
+            }
+          }
+          enextself(*cavetet);
+        }
+      }
+    }
+  }
+
+  if (noencsegflag && (subsegstack->objects > 0)) {
+    // Found encroached subsegments! Do not insert this point.
+    for (i = 0; i < caveoldtetlist->objects; i++) {
+      cavetet = (triface *) fastlookup(caveoldtetlist, i);
+      uninfect(*cavetet);
+      unmarktest(*cavetet);
+    }
+    for (i = 0; i < cavebdrylist->objects; i++) {
+      cavetet = (triface *) fastlookup(cavebdrylist, i);
+      unmarktest(*cavetet); // Unmark it.
+    }
+    if (bwflag && (futureflip != NULL)) {
+      flippool->restart();
+      futureflip = NULL;
+    }
+    cavetetlist->restart();
+    cavebdrylist->restart();
+    caveoldtetlist->restart();
+    return ENCSEGMENT;
+  }
+
+  if (checksubfaces) {
+    // Check if some subfaces are inside the cavity. Such subfaces
+    //   are queued in 'subfacstack'. 
+    for (i = 0; i < caveoldtetlist->objects; i++) {
+      cavetet = (triface *) fastlookup(caveoldtetlist, i);
+      neightet.tet = cavetet->tet;
+      for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) {
+        tspivot(neightet, checksh);
+        if (checksh.sh != NULL) {
+          sym(neightet, neineitet);
+          // Do not check it if it is a hull tet.
+          if (infected(neineitet)) {
+            if (b->verbose > 1) {
+              printf("      Queue a missing subface (%d, %d, %d).\n",
+                pointmark(sorg(checksh)), pointmark(sdest(checksh)),
+                pointmark(sapex(checksh)));
+            }
+            tsdissolve(neineitet); // Disconnect a tet-sub bond.
+            stdissolve(checksh); // Disconnect the sub-tet bond.
+            // Add the missing subface into list.
+            subfacstack->newindex((void **) &pssub);
+            *pssub = checksh;
+          }
+        }
+      }
+    }
+    if (noencsubflag) {
+      // Check for encroaching subface on the boundary of the cavity.
+      //   Encroached subfaces are queued in 'subfacstack'.
+      for (i = 0; i < cavebdrylist->objects; i++) {
+        cavetet = (triface *) fastlookup(cavebdrylist, i);
+        // 'cavetet' is an exterior tet adjacent to the cavity.
+        assert(cavetet->ver == 4); // SELF_CHECK
+        tspivot(*cavetet, checksh);
+        if (checksh.sh != NULL) {
+          // checkface4encroach();
+        }
+      }
+    }
+  }
+
+  if (noencsubflag && (subfacstack->objects > 0)) {
+    // Found encroached subfaces! Do not insert this point.
+    for (i = 0; i < caveoldtetlist->objects; i++) {
+      cavetet = (triface *) fastlookup(caveoldtetlist, i);
+      uninfect(*cavetet);
+      unmarktest(*cavetet);
+    }
+    for (i = 0; i < cavebdrylist->objects; i++) {
+      cavetet = (triface *) fastlookup(cavebdrylist, i);
+      unmarktest(*cavetet); // Unmark it.
+    }
+    if (bwflag && (futureflip != NULL)) {
+      flippool->restart();
+      futureflip = NULL;
+    }
+    cavetetlist->restart();
+    cavebdrylist->restart();
+    caveoldtetlist->restart();
+    return ENCFACE;
+  }
+
+  if (visflag) {
+    // If T is not a Delaunay triangulation, the formed cavity may not be
+    //   star-shaped (fig/dump-cavity-case8). Validation is needed.
+    // Comment: The validation is done by removing tets from the cavity
+    //   until the cavity is star-shaped.
+    cavetetlist->restart(); // Re-use it.
+    for (i = 0; i < cavebdrylist->objects; i++) {
+      cavetet = (triface *) fastlookup(cavebdrylist, i);
+      // 'cavetet' is an exterior tet adjacent to the cavity.
+      assert(cavetet->ver == 4); // SELF_CHECK
+      symedge(*cavetet, neightet);
+      if (infected(neightet)) {
+        if ((point) cavetet->tet[7] != dummypoint) {
+          pa = org(*cavetet);
+          pb = dest(*cavetet);
+          pc = apex(*cavetet);
+          ori = orient3d(pa, pb, pc, insertpt); orient3dcount++;
+          // assert(ori != 0.0); // SELF_CHECK
+          enqflag = (ori > 0.0);
+        } else {
+          enqflag = true; // A hull face.
+        }
+        if (enqflag) {
+          // This face is valid, save it.
+          cavetetlist->newindex((void **) &parytet);
+          *parytet = *cavetet; 
+        } else {
+          if (b->verbose > 1) {
+            printf("    Cut tet (%d, %d, %d, %d)\n", pointmark(pb), 
+              pointmark(pa), pointmark(pc), pointmark(oppo(neightet)));
+          }
+          uninfect(neightet);
+          unmarktest(neightet);
+          updatecount++;
+          // Add three new faces to find new boundaries.
+          for (j = 0; j < 3; j++) {
+            enext0fnext(neightet, neineitet);
+            neineitet.ver = 4;
+            cavebdrylist->newindex((void **) &parytet);
+            *parytet = neineitet;
+            enextself(neightet);
+          }
+        }
+      } else {
+        // This face is not on the cavity boundary anymore.
+        unmarktest(*cavetet);
+      }
+    }
+    if (updatecount > 0) {
+      // Update the cavity boundary faces (fig/dump-cavity-case9).
+      cavebdrylist->restart();
+      for (i = 0; i < cavetetlist->objects; i++) {
+        cavetet = (triface *) fastlookup(cavetetlist, i);
+        // 'cavetet' was an exterior tet adjacent to the cavity.
+        assert(cavetet->ver == 4); // SELF_CHECK
+        symedge(*cavetet, neightet);
+        if (infected(neightet)) {
+          // It is a cavity boundary face.
+          cavebdrylist->newindex((void **) &parytet);
+          *parytet = *cavetet;
+        } else {
+          // Not a cavity boundary face.
+          unmarktest(*cavetet);
+        }
+      }
+      // Update the list of old tets.
+      cavetetlist->restart();
+      for (i = 0; i < caveoldtetlist->objects; i++) {
+        cavetet = (triface *) fastlookup(caveoldtetlist, i);
+        if (infected(*cavetet)) {
+          cavetetlist->newindex((void **) &parytet);
+          *parytet = *cavetet;
+        }
+      }
+      assert(cavetetlist->objects < i);
+      // Swap 'cavetetlist' and 'caveoldtetlist'.
+      swaplist = caveoldtetlist;
+      caveoldtetlist = cavetetlist;
+      cavetetlist = swaplist;
+      if (b->verbose > 1) {
+        printf("    Size of the updated cavity: %d faces %d tets.\n",
+          cavebdrylist->objects, caveoldtetlist->objects);
+      }
+    }
+  }
+
+  // Re-use this list for new cavity faces.
+  cavetetlist->restart();
+
+  // Create new tetrahedra in the Bowyer-Watson cavity and Connect them.
+  for (i = 0; i < cavebdrylist->objects; i++) {
+    cavetet = (triface *) fastlookup(cavebdrylist, i);
+    neightet = *cavetet;
+    unmarktest(neightet); // Unmark it.
+    // Get the oldtet (inside the cavity).
+    symedge(neightet, neineitet);
+    if (apex(neightet) != dummypoint) {
+      // Create a new tet in the cavity (see Fig. bowyerwatson 1 or 3).
+      maketetrahedron(&newtet);
+      setorg(newtet, dest(neightet));
+      setdest(newtet, org(neightet));
+      setapex(newtet, apex(neightet));
+      setoppo(newtet, insertpt);
+    } else {
+      // Create a new hull tet (see Fig. bowyerwatson 2).
+      hullsize++;
+      maketetrahedron(&newtet);
+      setorg(newtet, org(neightet));
+      setdest(newtet, dest(neightet));
+      setapex(newtet, insertpt);
+      setoppo(newtet, dummypoint);
+      // Note: the cavity boundary face is at the enext0fnext place.
+      enext0fnextself(newtet);
+    }
+    // Connect newtet <==> neightet, this also disconnect the old bond.
+    bond(newtet, neightet);
+    // Let the oldtet knows newtet (for connecting adjacent new tets).
+    if (org(newtet) != org(neineitet)) esymself(newtet);
+    neineitet.tet[neineitet.loc] = encode(newtet);
+    // Replace the old boundary face with the old tet in list.
+    *cavetet = neineitet; // *cavetet = newtet;
+    if (checksubsegs) {
+      newtet.ver &= ~1;  // Keep in 0th edge ring.
+      for (j = 0; j < 3; j++) {
+        tsspivot(neightet, sseg);
+        if (sseg.sh != NULL) {
+          if (sinfected(sseg)) {
+            // This case is only possible when the cavity has been updated.
+            assert(updatecount > 0); // SELF_CHECK
+            suninfect(sseg); // Dequeue a non-missing segment.
+          }
+          tssbond1(newtet, sseg);
+          sstbond(sseg, newtet);
+          // Do we need to care about encroached segments?
+          if ((badsegpool != NULL) && !smarktested(sseg)) {
+            // Queue the subsegment if it is encroached by the new point.
+            checkedge4encroach(sseg, insertpt, 1);
+          }
+        }
+        enextself(neightet);
+        enext2self(newtet);
+      }
+    }
+    if (checksubfaces) {
+      tspivot(neightet, checksh);
+      if (checksh.sh != NULL) {
+        tsbond(newtet, checksh); // Also disconnect the old bond.
+        // Do we need to care about encroached segments?
+        if ((badsubpool != NULL) && !smarktested(checksh)) {
+          // Queue the subface if it is encroached by the new point.
+          // checkface4encroach(checksh, insertpt, 1);
+        }
+      }
+    }
+    if (updatecount > 0l) {
+      // Save this face for locally Delaunay test.
+      cavetetlist->newindex((void **) &parytet);
+      *parytet = newtet;
+    }
+  }
+
+  // Set a handle for speeding point location.
+  recenttet = newtet;
+  point2tet(insertpt) = encode(newtet);
+
+  /*// Connect the set of new tetrahedra together.
+  for (i = 0; i < cavebdrylist->objects; i++) {
+    cavetet = (triface *) fastlookup(cavebdrylist, i);
+    cavetet->ver = 0;
+    for (j = 0; j < 3; j++) {
+      enext0fnext(*cavetet, newtet); // Go to the face.
+      // Operate on it if it is open.
+      if (newtet.tet[newtet.loc] == NULL) {
+        // Find its adjacent face by rotating faces around the edge of
+        //   cavetet. The rotating direction is opposite to newtet.
+        //   Stop the rotate at a face which is open.
+        esym(*cavetet, neightet); // Set the rotate dir.
+        do {
+          fnextself(neightet); // Go to the face in the adjacent tet.
+        } while (neightet.tet[neightet.loc] != NULL);
+        bond(newtet, neightet); // Connect newtet <==> neightet.
+      }
+      if (checksubsegs || checksubfaces) {
+        point2tet(org(*cavetet)) = encode(*cavetet);
+      }
+      enextself(*cavetet);
+    }
+  }*/
+
+  // Connect adjacent new tetrahedra together.
+  for (i = 0; i < cavebdrylist->objects; i++) {
+    cavetet = (triface *) fastlookup(cavebdrylist, i);
+    decode(cavetet->tet[cavetet->loc], newtet);
+    // assert(org(newtet) == org(*cavetet)); // SELF_CHECK
+    for (j = 0; j < 3; j++) {
+      enext0fnext(newtet, neightet); // Go to the face.
+      if (neightet.tet[neightet.loc] == NULL) {
+        spintet = *cavetet;
+        while (1) {
+          enext0fnextself(spintet);
+          decode(spintet.tet[spintet.loc], neineitet);
+          if (!infected(neineitet)) break;
+          symedgeself(spintet);
+        }
+        // Find the corresponding edge in neineitet.
+        pa = dest(newtet);
+        for (k = 0; k < 3; k++) {
+          if (org(neineitet) == pa) break;
+          enextself(neineitet);
+        }
+        assert(k < 3);  // SELF_CHECK
+        assert(dest(neineitet) == org(newtet)); // SELF_CHECK
+        enext0fnextself(neineitet);
+        bond(neightet, neineitet);
+        // Queue the internal face if the visflag is set.
+        //   See also fig/dump-cavity-case13.
+        if (visflag) {
+          cavetetlist->newindex((void **) &parytet);
+          *parytet = neightet;
+        }
+      }
+      point2tet(org(newtet)) = encode(newtet);
+      enextself(newtet);
+      enextself(*cavetet);
+    }
+  }
+
+  // Delete the old cavity tets.
+  for (i = 0; i < caveoldtetlist->objects; i++) {
+    cavetet = (triface *) fastlookup(caveoldtetlist, i);
+    tetrahedrondealloc(cavetet->tet);
+  }
+
+  // loc_end = clock();
+  // tinserttime += ((REAL) (loc_end - loc_start)) / CLOCKS_PER_SEC;
+
+  if (bwflag && (futureflip != NULL)) {
+    // There may exist degenerate tets. Check and remove them.
+    while (futureflip != NULL) {
+      // Dequeue an adjacent tet to the cavity.
+      fliptets[0] = futureflip->tt;
+      futureflip = futureflip->nextitem;
+
+      // Skip it if it is dead (by previous flip32s).
+      if (fliptets[0].tet[4] == NULL) continue;
+
+      // The possible degenerate tet, check it.
+      symself(fliptets[0]); 
+      // Skip it if its oppo is not 'p'. 
+      if (oppo(fliptets[0]) != insertpt) continue;
+      // This must be a new tet.
+      assert(oppo(fliptets[0]) == insertpt); // SELF_CHECK
+
+      pts = (point *) fliptets[0].tet;
+      ori = orient3d(pts[4], pts[5], pts[6], pts[7]); orient3dcount++;
+      
+      if (ori == 0) {
+        if (b->verbose > 1) {
+          printf("    Removing tet (%d, %d, %d, %d).\n", pointmark(pts[4]),
+            pointmark(pts[5]), pointmark(pts[6]), pointmark(pts[7]));
+        }
+        // Find the hull edge in cavetet.
+        fliptets[0].ver = 0;
+        for (j = 0; j < 3; j++) {
+          enext0fnext(fliptets[0], neightet);
+          symself(neightet);
+          if ((point) neightet.tet[7] == dummypoint) break;
+          enextself(fliptets[0]);
+        }
+        // Because of existing multiple degenerate cases. It is possible
+        //   that the other hull face is not pop yet.
+        if (j < 3) {
+          // Collect tets for flipping the edge.
+          for (j = 0; j < 3; j++) {
+            fnext(fliptets[j], fliptets[j + 1]);
+          }
+          if (fliptets[3].tet != fliptets[0].tet) {
+            printf("Internal error in insertvertex(): Unknown flip case.\n");
+            terminatetetgen(1);
+          }
+          // Do a 3-to-2 flip to remove the degenerate tet.
+          flip32(fliptets, 1, 0);
+          // Rememebr the new tet.
+          recenttet = fliptets[0];
+        } else {
+          // Put the face back into queue.
+          symself(fliptets[0]);
+          newflip = (badface *) flippool->alloc();
+          newflip->tt = fliptets[0]; // the adjacent tet (not in cavity).
+          newflip->nextitem = NULL;
+          if (futureflip == NULL) {
+            lastflip = futureflip = newflip;
+          } else {
+            lastflip->nextitem = newflip;
+            lastflip = newflip;
+          }
+        } // if (j < 3)
+      } // if (ori == 0)
+    }
+    flippool->restart();
+  }
+
+  if (bwflag && visflag) {
+    // Some new faces may be locally non-Delaunay. Check and fix them.
+    for (i = 0; i < cavetetlist->objects; i++) {
+      // Get a new face (whose opposite is p).
+      parytet = (triface *) fastlookup(cavetetlist, i);
+      if ((point) parytet->tet[7] == dummypoint) continue; // A hull face.
+      pa = oppo(*parytet);
+      futureflip = flippush(futureflip, parytet, pa);
+    }
+    // Recover Delaunay faces.
+    //   Set 'flipflag' = 2, s.t. all non-flippable faces are not ignoring, 
+    //   they are queued in the flip queue for the future flips.  One key
+    //   is that we also flip non-Delaunay segments and subfaces. This way
+    //   we are able to recover all non-Delaunay edges/faces (no proof yet),
+    //   i.e., the flip will terminate. 
+    // The flipped segments and subfaces are queued in 'subsegstack' and 
+    //   'subfacstack' for recovery.
+    lawsonflip3d(2);
+  }
+
+  // Set the point type.
+  if (getpointtype(insertpt) == UNUSEDVERTEX) {
+    setpointtype(insertpt, VOLVERTEX);
+  }
+
+  cavetetlist->restart();
+  cavebdrylist->restart();
+  caveoldtetlist->restart();
+  return loc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flipinsertvertex()    Insert a vertex (p) into tetrahedralization (T).    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flipinsertvertex(point insertpt, triface* searchtet, 
+  int flipflag)
+{
+  enum location loc;
+  long tetcount;
+
+  if (b->verbose > 1) {
+    printf("    Insert point %d\n", pointmark(insertpt));
+  }
+
+  tetcount = ptloc_count;
+  
+  if (searchtet->tet == NULL) {
+    randomsample(insertpt, searchtet);
+  }
+  loc = locate(insertpt, searchtet);
+
+  if (b->verbose > 1) {
+    printf("    Walk distance (# tets): %ld\n", ptloc_count - tetcount);
+  }
+
+  if (ptloc_max_count < (ptloc_count - tetcount)) {
+    ptloc_max_count = (ptloc_count - tetcount);
+  }
+
+  if (b->verbose > 1) {
+    printf("    Located (%d) tet (%d, %d, %d, %d).\n", (int) loc,
+      pointmark(org(*searchtet)), pointmark(dest(*searchtet)), 
+      pointmark(apex(*searchtet)), pointmark(oppo(*searchtet)));
+  }
+  
+  if (loc == ONVERTEX) {
+    // The point already exists. Mark it and do nothing on it.
+    // In a STL mesh, duplicated points are implicitly included.
+    if (b->object != tetgenbehavior::STL) {
+      if (!b->quiet) {
+        printf("Warning:  Point #%d is duplicated with Point #%d. Ignored!\n",
+          pointmark(insertpt), pointmark(org(*searchtet)));
+      }
+    }
+    point2ppt(insertpt) = org(*searchtet);
+    setpointtype(insertpt, DUPLICATEDVERTEX);
+    dupverts++;
+    return;
+  }
+
+  // Clear flip stack.
+  futureflip = (badface *) NULL;
+
+  // Insert the new point by flipping.
+  if (loc == ONFACE) {
+    flip26(insertpt, searchtet, flipflag);
+  } else if (loc == ONEDGE) {
+    flipn2n(insertpt, searchtet, flipflag);
+  } else { // (loc == INTET) || (loc == OUTSIDE)
+    flip14(insertpt, searchtet, flipflag);
+  }
+
+  recenttet = *searchtet; // Remember a handle.
+
+  // Set the point type.
+  if (getpointtype(insertpt) == UNUSEDVERTEX) {
+    setpointtype(insertpt, VOLVERTEX);
+  }
+
+  // If flipflag > 0, do Delaunay flip.
+  if (flipflag > 0) {
+    lawsonflip3d(flipflag);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// incrementaldelaunay()    Form a Delaunay tetrahedralization by increment- //
+//                          ally inserting vertices.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::incrementaldelaunay()
+{
+  triface searchtet;
+  point *permutarray, swapvertex;
+  REAL v1[3], v2[3], n[3];
+  REAL bboxsize, bboxsize2, bboxsize3, ori;
+  int randindex, i, j;
+
+  if (!b->quiet) {
+    printf("Delaunizing vertices.\n");
+  }
+
+  // Form a random permuation (uniformly at random) of the set of vertices.
+  permutarray = new point[in->numberofpoints];
+  pointpool->traversalinit();
+  if (b->order == 3) { // '-o3' option (for debug)
+    for (i = 0; i < in->numberofpoints; i++) {
+      permutarray[i] = (point) pointpool->traverse();
+    }
+  } else {
+    for (i = 0; i < in->numberofpoints; i++) {
+      randindex = randomnation(i + 1);
+      permutarray[i] = permutarray[randindex];
+      permutarray[randindex] = (point) pointpool->traverse();
+    }
+  }
+
+  // Calculate the diagonal size of its bounding box.
+  bboxsize = sqrt(NORM2(xmax - xmin, ymax - ymin, zmax - zmin));
+  bboxsize2 = bboxsize * bboxsize;
+  bboxsize3 = bboxsize2 * bboxsize;
+  
+  // Make sure the second vertex is not identical with the first one.
+  i = 1;
+  while ((DIST(permutarray[0], permutarray[i]) / bboxsize) < b->epsilon) {
+    i++;
+    if (i == in->numberofpoints - 1) {
+      printf("Exception:  All vertices are (nearly) identical (Tol = %g).\n",
+             b->epsilon);
+      terminatetetgen(1);
+    }
+  }
+  if (i > 1) {
+    // Swap to move the non-indetical vertex from index i to index 1.
+    swapvertex = permutarray[i];
+    permutarray[i] = permutarray[1];
+    permutarray[1] = swapvertex;
+  }
+
+  // Make sure the third vertex is not collinear with the first two.
+  i = 2;
+  for (j = 0; j < 3; j++) {
+    v1[j] = permutarray[1][j] - permutarray[0][j];
+    v2[j] = permutarray[i][j] - permutarray[0][j];
+  }
+  CROSS(v1, v2, n);
+  while ((sqrt(NORM2(n[0], n[1], n[2])) / bboxsize2) < b->epsilon) {
+    i++;
+    if (i == in->numberofpoints - 1) {
+      printf("Exception:  All vertices are (nearly) collinear (Tol = %g).\n",
+             b->epsilon);
+      terminatetetgen(1);
+    }
+    for (j = 0; j < 3; j++) {
+      v2[j] = permutarray[i][j] - permutarray[0][j];
+    }
+    CROSS(v1, v2, n);
+  }
+  if (i > 2) {
+    // Swap to move the non-indetical vertex from index i to index 1.
+    swapvertex = permutarray[i];
+    permutarray[i] = permutarray[2];
+    permutarray[2] = swapvertex;
+  }
+
+  // Make sure the fourth vertex is not coplanar with the first three.
+  i = 3;
+  ori = orient3d(permutarray[0], permutarray[1], permutarray[2], 
+                 permutarray[i]);
+  while ((fabs(ori) / bboxsize3) < b->epsilon) {
+    i++;
+    if (i == in->numberofpoints) {
+      printf("Exception:  All vertices are coplanar (Tol = %g).\n",
+             b->epsilon);
+      terminatetetgen(1);
+    }
+    ori = orient3d(permutarray[0], permutarray[1], permutarray[2], 
+                   permutarray[i]);
+  }
+  if (i > 3) {
+    // Swap to move the non-indetical vertex from index i to index 1.
+    swapvertex = permutarray[i];
+    permutarray[i] = permutarray[3];
+    permutarray[3] = swapvertex;
+  }
+
+  // Orient the first four vertices in permutarray so that they follow the
+  //   right-hand rule.
+  if (ori > 0.0) {
+    // Swap the first two vertices.
+    swapvertex = permutarray[0];
+    permutarray[0] = permutarray[1];
+    permutarray[1] = swapvertex;
+  }
+
+  // Create the initial Delaunay tetrahedralization.
+  initialDT(permutarray[0], permutarray[1], permutarray[2], permutarray[3]);
+
+  if (b->verbose) {
+    printf("  Incremental inserting vertices.\n");
+  }
+
+  if (b->bowyerwatson) {
+    // Use incremental Bowyer-Watson algorithm.
+    for (i = 4; i < in->numberofpoints; i++) {
+      if (b->verbose > 1) printf("    #%d", i);
+      searchtet.tet = NULL;  // Randomly sample tetrahedra.
+      insertvertex(permutarray[i], &searchtet, true, false, false, false);
+    }
+  } else {
+    // Use incremental flip algorithm.
+    for (i = 4; i < in->numberofpoints; i++) {
+      if (b->verbose > 1) printf("    #%d", i);
+      searchtet.tet = NULL;  // Randomly sample tetrahedra.
+      flipinsertvertex(permutarray[i], &searchtet, 1); 
+    }
+  }
+
+  delete [] permutarray;
+}
+
+#endif // #ifndef delaunayCXX
\ No newline at end of file
diff --git a/contrib/TetgenNew/flip.cxx b/contrib/TetgenNew/flip.cxx
new file mode 100644
index 0000000000..fbaf010acf
--- /dev/null
+++ b/contrib/TetgenNew/flip.cxx
@@ -0,0 +1,2128 @@
+#ifndef flipCXX
+#define flipCXX
+
+#include "tetgen.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flipshpush()    Push a subface edge into flip stack.                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+tetgenmesh::badface* tetgenmesh::flipshpush(badface* flipstack, face* flipedge)
+{
+  badface *newflipface;
+
+  newflipface = (badface *) flippool->alloc();
+  newflipface->ss = *flipedge;
+  newflipface->forg = sorg(*flipedge);
+  newflipface->fdest = sdest(*flipedge);
+  newflipface->nextitem = flipstack;
+
+  return newflipface;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip13()    Insert a vertex by transforming 1-to-3 subfaces.              //
+//                                                                           //
+// 'newpt' (p) lies in the interior of 'splitface' (abc).  This routine del- //
+// ete abc and replaces it by three subfaces: abp, bcp, and cap, respective- //
+// ly.  Return abp in 'splitface'.                                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flip13(point newpt, face* splitface, int flipflag)
+{
+  face newfaces[3], bdedge, casout, casin;
+  face checkface, checkseg;
+  point pa, pb, pc;
+  int i;
+
+  REAL area;
+  int shmark;
+
+  splitface->shver &= ~1;  // Stay in the 0th edge ring.
+
+  pa = sorg(*splitface);
+  pb = sdest(*splitface);
+  pc = sapex(*splitface);
+
+  if (b->verbose > 1) {
+    printf("    flip 1-to-3: %d, (%d, %d, %d)\n", pointmark(newpt),
+      pointmark(pa), pointmark(pb), pointmark(pc));
+  }
+  flip13count++;
+
+  // We need two new subfaces.
+  newfaces[0] = *splitface;
+  makeshellface(subfacepool, &(newfaces[1]));
+  makeshellface(subfacepool, &(newfaces[2]));
+
+  // Insert the new point p.
+  setsapex(newfaces[0], newpt);  // abc->abp.
+  setshvertices(newfaces[1], pb, pc, newpt); // bcp.
+  setshvertices(newfaces[2], pc, pa, newpt); // cap.
+
+  shmark = getshellmark(newfaces[0]);
+  setshellmark(newfaces[1], shmark);
+  setshellmark(newfaces[2], shmark);
+  if (checkconstraints) {
+    area = areabound(newfaces[0]);
+    areabound(newfaces[1]) = area;
+    areabound(newfaces[2]) = area;
+  }
+
+  // Connect outer boundary faces to new faces.
+  senext(newfaces[0], bdedge);
+  for (i = 1; i < 3; i++) {
+    spivot(bdedge, casout);
+    sspivot(bdedge, checkseg);
+    if (casout.sh != NULL) {
+      casin = casout;
+      if (checkseg.sh != NULL) {
+        spivot(casin, checkface);
+        while (checkface.sh != bdedge.sh) {
+          casin = checkface;
+          spivot(casin, checkface);
+        }
+      }
+      sbond1(newfaces[i], casout);
+      sbond1(casin, newfaces[i]);
+    }
+    if (checkseg.sh != NULL) {
+      ssdissolve(bdedge);
+      ssbond(newfaces[i], checkseg);
+    }
+    senextself(bdedge);
+  }
+
+  // Connect the three subfaces together. Reuse casout, casin.
+  for (i = 0; i < 3; i++) {
+    senext(newfaces[i], casout);
+    senext2(newfaces[(i + 1) % 3], casin);
+    sbond2(casout, casin);
+  }
+
+  if (flipflag) {
+    // Put the boundary edges into flip stack.
+    for (i = 0; i < 3; i++) {
+      futureflip = flipshpush(futureflip, &(newfaces[i]));
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flipn2nf()    Insert a vertex by transforming n-to-2n subfaces.           //
+//                                                                           //
+// The 'newpt'(p) lies on the edge (ab) of 'splitedge'(abc). Let the n faces //
+// containing ab be: abp[0], ..., abp[n-1], use an array 'flipfaces':  flip- //
+// faces[0], ..., flipfaces[n-1], to store them.  This routine removes the n //
+// subfaces and replaces them with 2n new subfaces: app[0], ..., app[n-1] (  //
+// (at top), pbp[0], ..., pbp[n-1] (at bottom), respectively.  On return,    //
+// 'splitedge' is apc.                                                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flipn2nf(point newpt, face* splitedges, int flipflag)
+{
+  face *abdedges, *bbdedges, *boutfaces, *binfaces;
+  face aseg, bseg, aoutseg, boutseg;
+  face checkface, checkseg;
+  point pa, pb, *pt;
+  int n, i;
+
+  shellface sptr;
+
+  splitedges[0].shver &= ~1;  // Stay in the 0th edge ring.
+
+  // Count the number of faces at ab.
+  n = 0;
+  checkface = splitedges[0];
+  do {
+    spivotself(checkface);
+    n++;
+  } while ((checkface.sh != NULL) && (checkface.sh != splitedges[0].sh));
+
+  // Allocate spaces.
+  abdedges = new face[n];
+  bbdedges = new face[n];
+  boutfaces = new face[n];
+  binfaces = new face[n];
+  pt = new point[n];
+
+  // Collect the faces, abp[0], ..., abp[n-1].
+  abdedges[0] = splitedges[0];
+  pt[0] = sapex(abdedges[0]);
+  for (i = 0; i < n - 1; i++) {
+    spivot(abdedges[i], abdedges[i + 1]);
+    if (sorg(abdedges[i + 1]) != sorg(splitedges[0])) {
+      sesymself(abdedges[i + 1]);
+    }
+    pt[i + 1] = sapex(abdedges[i + 1]);
+  }
+
+  pa = sorg(splitedges[0]);
+  pb = sdest(splitedges[0]);
+
+  if (b->verbose > 1) {
+    printf("    flip n-to-2n: %d, (%d, %d) %d ... (%d faces) \n", 
+      pointmark(newpt), pointmark(pa), pointmark(pb), pointmark(pt[0]), n); 
+  }
+  flipn2nfcount++;
+
+  // Get the old boundary edges: p[i]a, bp[i], i = 0, ..., n-1
+  for (i = 0; i < n; i++) {
+    senext(abdedges[i], bbdedges[i]);
+    senext2self(abdedges[i]);
+  }
+
+  // Collect outer boundary faces at bp[i].
+  for (i = 0; i < n; i++) {
+    spivot(bbdedges[i], boutfaces[i]);
+    binfaces[i] = boutfaces[i];
+    if (boutfaces[i].sh != NULL) {
+      sspivot(bbdedges[i], checkseg);
+      if (checkseg.sh != NULL) {
+        spivot(binfaces[i], checkface);
+        while (checkface.sh != bbdedges[i].sh) {
+          binfaces[i] = checkface;
+          spivot(binfaces[i], checkface);
+        }
+      }
+    }
+  }
+
+  // Insert the new point p.
+  for (i = 0; i < n; i++) {
+    setsapex(abdedges[i], newpt);  // ap[i]b->ap[i]p.
+    makeshellface(subfacepool, &(bbdedges[i]));
+    setshvertices(bbdedges[i], pb, pt[i], newpt); // bp[i]p.
+    setshellmark(bbdedges[i], getshellmark(abdedges[i]));
+    if (checkconstraints) {
+      areabound(bbdedges[i]) = areabound(abdedges[i]);
+    }
+  }
+
+  // Connect new boundary edges to outer faces.
+  for (i = 0; i < n; i++) {
+    if (boutfaces[i].sh != NULL) {
+      sbond1(bbdedges[i], boutfaces[i]);
+      sbond1(binfaces[i], bbdedges[i]);
+    }
+    senext2(abdedges[i], checkface);
+    sspivot(checkface, checkseg);  // Check subsegment.
+    if (checkseg.sh != NULL) {
+      ssdissolve(checkface);  // Clear the old bond.
+      ssbond(bbdedges[i], checkseg);
+    }
+  }
+
+  // Connect new subfaces to updated subfaces. (Reuse boutfaces, binfaces).
+  for (i = 0; i < n; i++) {
+    senext2(abdedges[i], boutfaces[i]);
+    senext(bbdedges[i], binfaces[i]);
+    sbond2(boutfaces[i], binfaces[i]);
+  }
+
+  // Create new subfaces ring at edge pb.
+  if (n > 1) {
+    for (i = 0; i < n; i++) {
+      senext2(bbdedges[i], boutfaces[i]);
+      senext2(bbdedges[(i + 1) % n], boutfaces[(i + 1) % n]);
+      sbond1(boutfaces[i], boutfaces[(i + 1) % n]);
+    }
+  }
+
+  // Check edge ab to see if it is a subsegment.
+  sspivot(splitedges[0], aseg);
+  if (aseg.sh != NULL) {
+    // Split a subsegment ab to ap and pb.
+    // if (sorg(aseg) != pa) sesymself(aseg);
+    aseg.shver = 0;
+    if (b->verbose > 1) {
+      printf("    flip 1-to-2: %d, (%d, %d).\n", pointmark(newpt), 
+        pointmark(sorg(aseg)), pointmark(sdest(aseg)));
+    }
+    // Insert the new point p.
+    makeshellface(subsegpool, &bseg);
+    setshvertices(bseg, newpt, sdest(aseg), NULL);
+    setsdest(aseg, newpt);
+    setshellmark(bseg, getshellmark(aseg));
+    if (checkconstraints) {
+      areabound(bseg) = areabound(aseg);
+    }
+    // Connect pb<->b#.
+    senext(aseg, aoutseg);
+    spivotself(aoutseg);
+    if (aoutseg.sh != NULL) {
+      senext(bseg, boutseg);
+      sbond2(boutseg, aoutseg);
+    }
+    // Connect ap <-> pb.
+    senext(aseg, aoutseg);
+    senext2(bseg, boutseg);
+    sbond2(aoutseg, boutseg);
+    // Connect seg ap to face ring of splitshs[0], this will disconnect the
+    //   old bonds as well. *** Because we mixed the edge versions ***
+    if (sorg(aseg) == sorg(splitedges[0])) {
+      for (i = 0; i < n; i++) {
+        senext(abdedges[i], boutfaces[i]);
+        ssbond(boutfaces[i], aseg);
+      }
+      // Connect seg pb to subfaces having it.
+      for (i = 0; i < n; i++) {
+        senext2(bbdedges[i], boutfaces[i]);
+        ssbond(boutfaces[i], bseg);
+      }
+    } else {
+      // The edge version is reversed.
+      assert(sdest(bseg) == sorg(splitedges[0]));
+      for (i = 0; i < n; i++) {
+        senext(abdedges[i], boutfaces[i]);
+        ssbond(boutfaces[i], bseg);
+      }
+      for (i = 0; i < n; i++) {
+        senext2(bbdedges[i], boutfaces[i]);
+        ssbond(boutfaces[i], aseg);
+      }
+    }
+  }
+
+  if (flipflag) {
+    // Put the boundary edges into flip stack.
+    for (i = 0; i < n; i++) {
+      futureflip = flipshpush(futureflip, &abdedges[i]);
+      futureflip = flipshpush(futureflip, &bbdedges[i]);
+    }
+  }
+
+  // Return apc = app[0] = splitedges[0].
+  senext2(bbdedges[0], splitedges[1]); // return pbp[0].
+
+  delete [] abdedges;
+  delete [] bbdedges;
+  delete [] boutfaces;
+  delete [] binfaces;
+  delete [] pt;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip22()    Remove an edge by transforming 2-to-2 subfaces.               //
+//                                                                           //
+// 'flipfaces' contains two faces: abc and bad. This routine removes these 2 //
+// faces and replaces them by two new faces: cdb and dca.                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flip22(face* flipfaces, int flipflag)
+{
+  face bdedges[4], outfaces[4], infaces[4], bdsegs[4];
+  face checkface, checkseg;
+  point pa, pb, pc, pd;
+  int i;
+
+  // Orient the two faces properly: abc and bad.
+  if (sorg(flipfaces[0]) == sorg(flipfaces[1])) {
+    sesymself(flipfaces[1]);
+  }
+
+  pa = sorg(flipfaces[0]);
+  pb = sdest(flipfaces[0]);
+  pc = sapex(flipfaces[0]);
+  pd = sapex(flipfaces[1]);
+
+  if (b->verbose > 1) {
+    printf("    flip 2-to-2: (%d, %d, %d, %d)\n", pointmark(pa),
+      pointmark(pb), pointmark(pc), pointmark(pd));
+  }
+  flip22count++;
+
+  // Collect the four boundary edges.
+  senext(flipfaces[0], bdedges[0]);
+  senext2(flipfaces[0], bdedges[1]);
+  senext(flipfaces[1], bdedges[2]);
+  senext2(flipfaces[1], bdedges[3]);
+
+  // Collect outer boundary faces.
+  for (i = 0; i < 4; i++) {
+    spivot(bdedges[i], outfaces[i]);
+    infaces[i] = outfaces[i];
+    sspivot(bdedges[i], bdsegs[i]);
+    if (outfaces[i].sh != NULL) {
+      sspivot(bdedges[i], checkseg);
+      if (checkseg.sh != NULL) {
+        spivot(infaces[i], checkface);
+        while (checkface.sh != bdedges[i].sh) {
+          infaces[i] = checkface;
+          spivot(infaces[i], checkface);
+        }
+      }
+    }
+  }
+
+  // Transform abc -> cdb.
+  setshvertices(flipfaces[0], pc, pd, pb);
+  // Transform bad -> dca.
+  setshvertices(flipfaces[1], pd, pc, pa);
+
+  // Reconnect boundary edges to outer boundary faces.
+  for (i = 0; i < 4; i++) {
+    if (outfaces[(3 + i) % 4].sh != NULL) {
+      sbond1(bdedges[i], outfaces[(3 + i) % 4]);
+      sbond1(infaces[(3 + i) % 4], bdedges[i]);
+    } else {
+      sdissolve(bdedges[i]);
+    }
+    if (bdsegs[(3 + i) % 4].sh != NULL) {
+      ssbond(bdedges[i], bdsegs[(3 + i) % 4]);
+    } else {
+      ssdissolve(bdedges[i]);
+    }
+  }
+
+  recentsh = flipfaces[0];
+
+  if (flipflag) {
+    // Put the boundary edges into flip stack.
+    for (i = 0; i < 4; i++) {
+      futureflip = flipshpush(futureflip, &bdedges[i]);
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// lawsonflip()    Flip non-locally Delaunay edges.                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::lawsonflip()
+{
+  face flipfaces[2];
+  face checkseg;
+  point pa, pb, pc, pd;
+  REAL sign;
+  long flipcount;
+
+  if (b->verbose > 1) {
+    printf("    Lawson flip %ld edges.\n", flippool->items);
+  }
+  flipcount = flip22count;
+
+  while (futureflip != (badface *) NULL) {
+    // Pop an edge from the stack.
+    flipfaces[0] = futureflip->ss;
+    pa = futureflip->forg;
+    pb = futureflip->fdest;
+    futureflip = futureflip->nextitem;
+
+    // Skip it if it is dead.
+    if (flipfaces[0].sh[3] == NULL) continue;
+    // Skip it if it is not the same edge as we saved.
+    if ((sorg(flipfaces[0]) != pa) || (sdest(flipfaces[0]) != pb)) continue;
+    // Skip it if it is a subsegment.
+    sspivot(flipfaces[0], checkseg);
+    if (checkseg.sh != NULL) continue;
+
+    // Get the adjacent face.
+    spivot(flipfaces[0], flipfaces[1]);
+    if (flipfaces[1].sh == NULL) continue; // Skip a hull edge.
+    pc = sapex(flipfaces[0]);
+    pd = sapex(flipfaces[1]);
+
+    sign = incircle3d(pa, pb, pc, pd);
+
+    if (sign < 0) {
+      // It is non-locally Delaunay. Flip it.
+      flip22(flipfaces, 1);
+    }
+  }
+
+  if (b->verbose > 1) {
+    printf("    %ld edges stacked, %ld flips.\n", flippool->items,
+      flip22count - flipcount);
+  }
+
+  flippool->restart();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flippush()    Push a face (possibly will be flipped) into stack.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+tetgenmesh::badface* tetgenmesh::flippush(badface* flipstack, 
+  triface* flipface, point pushpt)
+{
+  badface *newflipface;
+
+  newflipface = (badface *) flippool->alloc();
+  newflipface->tt = *flipface;
+  newflipface->foppo = pushpt;
+  newflipface->nextitem = flipstack;
+
+  return newflipface;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip14()    Insert a vertex by transforming 1-to-4 tetrahedra.            //
+//                                                                           //
+// 'newpt' (p) lies in the interior of 'splittet' (abcd).  This routine abcd //
+// abcd and replaces it by 4 new tets: abpd, bcpd, capd, and abcp, resepcti- //
+// vely.  Return abcp in 'splittet'.                                         //
+//                                                                           //
+// If abcd is a hull tet, we adjust it and let d be the dummypoint. In this  //
+// case, the three new tets: abpd, bcpd, and capd are hull tets.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flip14(point newpt, triface* splittet, int flipflag)
+{
+  triface fliptets[3], castets[3];
+  triface newface, casface;
+  face checksh, checkseg;
+  point pa, pb, pc, pd;
+  int i;
+
+  int *iptr;
+
+  // Check if the original tet is a hull tet.
+  if ((point) splittet->tet[7] == dummypoint) {
+    splittet->loc = 0;
+  }
+  splittet->ver = 0;
+
+  pa = org(*splittet);
+  pb = dest(*splittet);
+  pc = apex(*splittet);
+  pd = oppo(*splittet);
+
+  if (b->verbose > 1) {
+    printf("    flip 1-to-4: %d (%d, %d, %d, %d)\n", pointmark(newpt), 
+      pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd));
+  }
+  flip14count++;
+
+  // Get the outer boundary faces.
+  for(i = 0; i < 3; i++) {
+    fnext(*splittet, castets[i]);
+    enextself(*splittet);
+  }
+
+  if (checksubsegs) {
+    // Dealloc the space to subsegments.
+    if (splittet->tet[8] != NULL) {
+      tet2segpool->dealloc((shellface *) splittet->tet[8]);
+    }
+    splittet->tet[8] = NULL;
+  }
+  if (checksubfaces) {
+    // Dealloc the space to subfaces.
+    if (splittet->tet[9] != NULL) {
+      tet2subpool->dealloc((shellface *) splittet->tet[9]);
+    }
+    splittet->tet[9] = NULL;
+  }
+
+  // Update the number of hull tets.
+  if (pd == dummypoint) {
+    // We remove one old hull tet (abcp), but add three new hull tets.
+    hullsize += 2;
+  }
+  
+  // Create three new tets for abpd, bcpd, and capd.
+  maketetrahedron(&(fliptets[0]));
+  maketetrahedron(&(fliptets[1]));
+  maketetrahedron(&(fliptets[2]));
+  // Set the vertices.
+  setvertices(fliptets[0], pa, pb, newpt, pd);
+  setvertices(fliptets[1], pb, pc, newpt, pd);
+  setvertices(fliptets[2], pc, pa, newpt, pd);
+  // Update the old tet to abcp.
+  setoppo(*splittet, newpt);
+
+  // Bond the new tets to outer boundary tets.
+  for (i = 0; i < 3; i++) {
+    enext0fnext(fliptets[i], newface);
+    bond(newface, castets[i]);
+  }
+  // Bond the new tets together (at six interior faces).
+  for (i = 0; i < 3; i++) {
+    enext0fnext(*splittet, newface);
+    bond(newface, fliptets[i]);
+    enextself(*splittet);
+  }
+  for (i = 0; i < 3; i++) {
+    enextfnext(fliptets[i], newface);
+    enext2fnext(fliptets[(i + 1) % 3], casface);
+    bond(newface, casface);
+  }
+
+  if (checksubsegs) {
+    // Bond segments to new tets. Each new tet has three edges to be
+    //   checked, e.g., abpd has [a,b], [b,d], and [d,a]. The base tet 
+    //   abcd has three edges [a,b], [b,c] and [c,a], total 12 edges.
+    for (i = 0; i < 3; i++) {
+      enext0fnext(fliptets[i], newface); // [a,b], [b,c], [c,a].
+      tsspivot(castets[i], checkseg); 
+      if (checkseg.sh != NULL) {
+        tssbond1(*splittet, checkseg);
+        tssbond1(newface, checkseg);
+        // Let the segment remember an adjacent tet.
+        sstbond(checkseg, *splittet);
+      }
+      enextself(newface); // [b,d], [c,d], [a,d]
+      enext(castets[i], casface);
+      tsspivot(casface, checkseg); 
+      if (checkseg.sh != NULL) {
+        tssbond1(newface, checkseg);
+        sstbond(checkseg, newface);
+      }
+      enextself(newface); // [d,a], [d,b], [d,c]
+      enext2(castets[i], casface);
+      tsspivot(casface, checkseg);
+      if (checkseg.sh != NULL) {
+        tssbond1(newface, checkseg);
+        sstbond(checkseg, newface);
+      }
+      enextself(*splittet);
+    }
+  }
+
+  if (checksubfaces) {
+    // Bond subfaces to new tets.
+    sym(*splittet, casface);
+    tspivot(casface, checksh);
+    if (checksh.sh != NULL) {
+      tsbond(*splittet, checksh);
+    }
+    for (i = 0; i < 3; i++) {
+      enext0fnext(fliptets[i], newface);
+      tspivot(castets[i], checksh);
+      if (checksh.sh != NULL) {
+        tsbond(newface, checksh);
+      }
+    }
+  }
+
+  // Update the point-to-tet map.
+  point2tet(newpt) = encode(*splittet);
+  // The values in pa, pb, and pc are not changed.
+  point2tet(pd) = encode(fliptets[0]);
+
+  if (flipflag > 0) {
+    // Queue faces which may be locally non-Delaunay.
+    for (i = 0; i < 3; i++) {
+      enext0fnext(fliptets[i], newface);
+      futureflip = flippush(futureflip, &newface, newpt);
+    }
+    futureflip = flippush(futureflip, splittet, newpt);
+  }
+
+  // Return abcp in 'splittet'.
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip26()    Insert a vertex by transforming 2-to-6 tetrahedra.            //
+//                                                                           //
+// The 'newpt' (p) lies in the face 'splitface' (abc).  This routine removes //
+// the two tets sharing at abc: abcd and bace, replaces them with 6 new tets //
+// : abpd, bcpd, capd (at top), bape, cbpe, and acpe (at bottom). On return, //
+// 'splitface' is abpd.                                                      //
+//                                                                           //
+// On input, a, b, or c should not be dummypoint. If d is dummypoint, the 3  //
+// top new tets are hull tets.  If e is dummypoint,  we reconfigure e to d,  //
+// i.e., turn the two tets up-side down.                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flip26(point newpt, triface* splitface, int flipflag)
+{
+  triface fliptets[4], castets[4];
+  triface symface, newface, casface;
+  face checksh, checkseg;
+  point pa, pb, pc, pd, pe;
+  int i, j;
+
+  int *iptr;
+
+  splitface->ver &= ~1;
+  symedge(*splitface, symface);
+
+  if (oppo(symface) == dummypoint) {
+    // Swap the two old tets.
+    newface = *splitface;
+    *splitface = symface;
+    symface = newface;
+  }
+
+  pa = org(*splitface);
+  pb = dest(*splitface);
+  pc = apex(*splitface);
+  pd = oppo(*splitface);
+  pe = oppo(symface);
+
+  if (b->verbose > 1) {
+    printf("    flip 2-to-6: (%d, %d, %d, %d, %d)\n", pointmark(pa),
+      pointmark(pb), pointmark(pc), pointmark(pd), pointmark(pe));
+  }
+  flip26count++;
+
+  // Get the outer boundary faces.
+  enext(*splitface, fliptets[0]);
+  enext2(*splitface, fliptets[1]);
+  enext2(symface, fliptets[2]);
+  enext(symface, fliptets[3]);
+
+  for (i = 0; i < 4; i++) {
+    fnext(fliptets[i], castets[i]);
+  }
+
+  if (checksubsegs) {
+    // Dealloc the space to subsegments.
+    if (splitface->tet[8] != NULL) {
+      tet2segpool->dealloc((shellface *) splitface->tet[8]);
+    }
+    splitface->tet[8] = NULL;
+    if (symface.tet[8] != NULL) {
+      tet2segpool->dealloc((shellface *) symface.tet[8]);
+    }
+    symface.tet[8] = NULL;
+  }
+  if (checksubfaces) {
+    // Dealloc the space to subfaces.
+    if (splitface->tet[9] != NULL) {
+      tet2subpool->dealloc((shellface *) splitface->tet[9]);
+    }
+    splitface->tet[9] = NULL;
+    if (symface.tet[9] != NULL) {
+      tet2subpool->dealloc((shellface *) symface.tet[9]);
+    }
+    symface.tet[9] = NULL;
+  }
+
+  // Update the number of hull tets.
+  if (pd == dummypoint) {
+    // We remove one old hull tet (abcp), but add three new hull tets.
+    hullsize += 2;
+  }
+
+  // Create new tets.
+  maketetrahedron(&(fliptets[0])); // bcpd
+  maketetrahedron(&(fliptets[1])); // capd
+  maketetrahedron(&(fliptets[2])); // cbpe
+  maketetrahedron(&(fliptets[3])); // acpe
+
+  // Set new vertices.
+  setapex(*splitface, newpt);
+  setvertices(fliptets[0], pb, pc, newpt, pd);
+  setvertices(fliptets[1], pc, pa, newpt, pd);
+  setapex(symface, newpt);
+  setvertices(fliptets[2], pc, pb, newpt, pe);
+  setvertices(fliptets[3], pa, pc, newpt, pe);
+
+  // Bond the new tets to outer boundary faces.
+  for (i = 0; i < 4; i++) {
+    enext0fnext(fliptets[i], newface);
+    bond(newface, castets[i]);
+  }
+
+  // Bond the top and bottom new tets together.
+  bond(fliptets[0], fliptets[2]);
+  bond(fliptets[1], fliptets[3]);
+
+  // Bond the new tets together.
+  enextfnext(*splitface, newface);
+  enext2fnext(fliptets[0], casface);
+  bond(newface, casface);
+  enextfnext(fliptets[0], newface);
+  enext2fnext(fliptets[1], casface);
+  bond(newface, casface);
+  enextfnext(fliptets[1], newface);
+  enext2fnext(*splitface, casface);
+  bond(newface, casface);
+
+  enext2fnext(symface, newface);
+  enextfnext(fliptets[2], casface);
+  bond(newface, casface);
+  enext2fnext(fliptets[2], newface);
+  enextfnext(fliptets[3], casface);
+  bond(newface, casface);
+  enext2fnext(fliptets[3], newface);
+  enextfnext(symface, casface);
+  bond(newface, casface);
+
+  if (checksubsegs) {
+    // Bond segments. For each tet there are three edges to be checked,
+    //   total there are 18 edges.
+    for (i = 0; i < 3; i++) {
+      if (i < 2) {
+        enext0fnext(fliptets[i], newface);
+        casface = castets[i];
+      } else {
+        enext0fnext(*splitface, newface);
+        symedge(newface, casface);
+      }
+      for (j = 0; j < 3; j++) {
+        tsspivot(casface, checkseg);
+        if (checkseg.sh != NULL) {
+          tssbond1(newface, checkseg);
+          sstbond(checkseg, newface);
+        }
+        enextself(casface);
+        enextself(newface);
+      }
+    }
+    for (i = 0; i < 3; i++) {
+      if (i < 2) {
+        enext0fnext(fliptets[i + 2], newface);
+        casface = castets[i + 2];
+      } else {
+        enext0fnext(symface, newface);
+        symedge(newface, casface);
+      }
+      for (j = 0; j < 3; j++) {
+        tsspivot(casface, checkseg);
+        if (checkseg.sh != NULL) {
+          tssbond1(newface, checkseg);
+          sstbond(checkseg, newface);
+        }
+        enextself(casface);
+        enextself(newface);
+      }
+    }
+  }
+
+  if (checksubfaces) {
+    // Bond subfaces. There are total 6 faces to be checked.
+    for (i = 0; i < 3; i++) {
+      if (i < 2) {
+        enext0fnext(fliptets[i], newface);
+        casface = castets[i];
+      } else {
+        enext0fnext(*splitface, newface);
+        symedge(newface, casface);
+      }
+      tspivot(casface, checksh);
+      if (checksh.sh != NULL) {
+        tsbond(newface, checksh);
+      }
+    }
+    for (i = 0; i < 3; i++) {
+      if (i < 2) {
+        enext0fnext(fliptets[i + 2], newface);
+        casface = castets[i + 2];
+      } else {
+        enext0fnext(symface, newface);
+        symedge(newface, casface);
+      }
+      tspivot(casface, checksh);
+      if (checksh.sh != NULL) {
+        tsbond(newface, checksh);
+      }
+    }
+  }
+
+  // Update point-to-tet map.
+  point2tet(newpt) = encode(*splitface);
+  // The values in pa and pb are not changed.
+  point2tet(pc) = encode(fliptets[0]);
+  point2tet(pd) = encode(fliptets[0]);
+  point2tet(pe) = encode(fliptets[2]);
+
+  if (flipflag > 0) {
+    enext0fnext(*splitface, newface);
+    futureflip = flippush(futureflip, &newface, newpt);
+    enext0fnext(symface, newface);
+    futureflip = flippush(futureflip, &newface, newpt);
+    for (i = 0; i < 4; i++) {
+      enext0fnext(fliptets[i], newface);
+      futureflip = flippush(futureflip, &newface, newpt);
+    }
+  }
+
+  // Return abpd in 'splitface'.
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flipn2n()    Insert a vertex by transforming n-to-2n tetrahedra.          //
+//                                                                           //
+// The 'newpt'(p) lies on the edge (ab) of 'splitedge'(abcd). Let the n tets //
+// containing ab be: abp[0]p[1], ..., abp[n-1]p[0], use an array 'fliptets': //
+// 'fliptets[0]', ..., 'fliptets[n-1]', to store them.  This routine removes //
+// the n tets and replaces them with 2n new tets: app[0]p[1], ..., app[n-1]- //
+// p[0] (at top), pbp[0]p[1], ..., pbp[n-1]p[0] (at bottom) in 'fliptets[0]',//
+// ..., 'fliptets[2n-1]', respectively.  On return, 'splitedge' is apcd.     //
+//                                                                           //
+// On input, a and b should not be dummypoint. If p[0] is dummypoint, the 2  //
+// new tets connecting to p[0] are hull tets. If p[i], i != 0 is dummypoint, //
+// we reconfigure p[i] to p[0], i.e., up-shift the tets i times.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flipn2n(point newpt, triface* splitedge, int flipflag)
+{
+  triface *fliptets, *bfliptets, *castets;
+  triface newface, casface;
+  face checksh, checkseg;
+  point pa, pb, *pt;
+  int dummyflag; // 0 or 1.
+  int n, i, j;
+
+  int *iptr;
+
+  n = 0;
+  dummyflag = 0;
+
+  // First count the number n of tets having ab.
+  splitedge->ver &= ~1;
+  casface = *splitedge;
+  do {
+    n++;
+    if (apex(casface) == dummypoint) {
+      // Remeber this face (it's apex is dummypoint).
+      newface = casface;
+      dummyflag = n;
+    }
+    fnextself(casface);
+  } while (casface.tet != splitedge->tet);
+
+  // Allocate spaces for fliptets.
+  fliptets = new triface[n];
+  bfliptets = new triface[n];
+  castets = new triface[n];
+  pt = new point[n];
+
+  // Get the n old tets.
+  fliptets[0] = (dummyflag == 0 ? *splitedge : newface);
+  for (i = 0; i < n - 1; i++) {
+    fnext(fliptets[i], fliptets[i + 1]);
+  }
+  // Get the n apexes.
+  for (i = 0; i < n; i++) {
+    pt[i] = apex(fliptets[i]); 
+  }
+  pa = org(fliptets[0]);
+  pb = dest(fliptets[0]);
+
+  if (b->verbose > 1) {
+    printf("    flip n-to-2n: (%d, %d) %d %d ..., (n = %d)\n", pointmark(pa),
+      pointmark(pb), pointmark(pt[0]), pointmark(pt[1]), n);
+  }
+  flipn2ncount++;
+
+  // Get the outer boundary faces.
+  for (i = 0; i < n; i++) {
+    enext(fliptets[i], casface);  // at edge bp[i].
+    fnext(casface, castets[i]);
+  }
+
+  if (checksubsegs) {
+    for (i = 0; i < n; i++) {
+      if (fliptets[i].tet[8] != NULL) {
+        tet2segpool->dealloc((shellface *) fliptets[i].tet[8]);
+      }
+      fliptets[i].tet[8] = NULL;
+    }
+  }
+  if (checksubfaces) {
+    for (i = 0; i < n; i++) {
+      if (fliptets[i].tet[9] != NULL) {
+        tet2segpool->dealloc((shellface *) fliptets[i].tet[9]);
+      }
+      fliptets[i].tet[9] = NULL;
+    }
+  }
+
+  // Update the number of hull tets.
+  if (pt[0] == dummypoint) {
+    // We remove 2 old hull tet (abcp), but add 4 new hull tets.
+    hullsize += 2;
+  }
+
+  // Create n new tets.
+  if (pt[0] != dummypoint) {
+    setdest(fliptets[0], newpt);  // app[0]p[1]
+    setdest(fliptets[n - 1], newpt);  // app[n-1]p[0]
+    maketetrahedron(&(bfliptets[0])); // pbp[0]p[1]
+    maketetrahedron(&(bfliptets[n - 1])); // pbp[n-1]p[0]
+    setvertices(bfliptets[0], newpt, pb, pt[0], pt[1]);
+    setvertices(bfliptets[n - 1], newpt, pb, pt[n - 1], pt[0]);
+  } else {
+    // NOTE: the base face must contain no 'dummypoint'.
+    setdest(fliptets[0], newpt);  // app[0]p[1]
+    setdest(fliptets[n - 1], newpt);  // app[n-1]p[0]
+    maketetrahedron(&(bfliptets[0])); // pbp[0]p[1]
+    maketetrahedron(&(bfliptets[n - 1])); 
+    setvertices(bfliptets[0], pb, newpt, pt[1], pt[0]);
+    setvertices(bfliptets[n - 1], newpt, pb, pt[n - 1], pt[0]);
+    // Adjust the face of and bfliptets[0].
+    enext0fnextself(bfliptets[0]);
+    esymself(bfliptets[0]);
+  }
+  for (i = 1; i < n - 1; i++) {
+    setdest(fliptets[i], newpt); // app[i]p[i+1]
+    maketetrahedron(&(bfliptets[i])); // pbp[i]p[i+1]
+    setvertices(bfliptets[i], newpt, pb, pt[i], pt[i + 1]);
+  }
+
+  // Bond new tets to outer boundary faces.
+  for (i = 0; i < n; i++) {
+    enextfnext(bfliptets[i], newface);
+    bond(newface, castets[i]);
+  }
+  // Bond new tets together.
+  for (i = 0; i < n; i++) {
+    enext0fnext(bfliptets[i], newface);
+    bond(newface, bfliptets[(i + 1) % n]);
+  }
+  // Bond top and bottom new tets togther
+  for (i = 0; i < n; i++) {
+    enextfnext(fliptets[i], newface);
+    enext2fnext(bfliptets[i], casface);
+    bond(newface, casface);
+  }
+
+  if (checksubsegs) {
+    // Bond segments. There are total n x 3 edges.
+    for (i = 0; i < n; i++) {  // Top edges.
+      enext2fnext(fliptets[i], newface);
+      symedge(newface, casface);
+      for(j = 0; j < 3; j++) {
+        tsspivot(casface, checkseg);
+        if (checkseg.sh != NULL) {
+          tssbond1(newface, checkseg);
+          sstbond(checkseg, newface);
+        }
+        enextself(casface);
+        enextself(newface);
+      }
+    }
+    for (i = 0; i < n; i++) {  // Bottom edges.
+      enextfnext(bfliptets[i], newface);
+      casface = castets[i];
+      for(j = 0; j < 3; j++) {
+        tsspivot(casface, checkseg);
+        if (checkseg.sh != NULL) {
+          tssbond1(newface, checkseg);
+          sstbond(checkseg, newface);
+        }
+        enextself(casface);
+        enextself(newface);
+      }
+    }
+  }
+
+  if (checksubfaces) {
+    // Bond subfaces.
+    for (i = 0; i < n; i++) {  // Top faces.
+      enext2fnext(fliptets[i], newface);
+      symedge(newface, casface);
+      tspivot(casface, checksh);
+      if (checksh.sh != NULL) {
+        tsbond(newface, checksh);
+      }
+    }
+    for (i = 0; i < n; i++) {  // Bottom faces.
+      enextfnext(bfliptets[i], newface);
+      casface = castets[i];
+      tspivot(casface, checksh);
+      if (checksh.sh != NULL) {
+        tsbond(newface, checksh);
+      }
+    }
+  }
+
+  // Update the point-to-tet map.
+  point2tet(newpt) = encode(fliptets[0]);
+  // The values in pa, p[0], ..., p[n-1] are not changed.
+  point2tet(pb) = encode(bfliptets[0]);
+
+  if (flipflag > 0) {
+    for (i = 0; i < n; i++) {
+      enext2fnext(fliptets[i], newface);
+      futureflip = flippush(futureflip, &newface, newpt);
+    }
+    for (i = 0; i < n; i++) {
+      enextfnext(bfliptets[i], newface);
+      futureflip = flippush(futureflip, &newface, newpt);
+    }
+  }
+
+  // If dummyflag !=0, the original tet is shifted by (n - dummyflag + 1).
+  //*splitedge = (dummyflag == 0 ? fliptets[0] : fliptets[n - dummyflag + 1]);
+
+  delete [] fliptets;
+  delete [] bfliptets;
+  delete [] castets;
+  delete [] pt;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip23()    Remove a face by tranforming 2-to-3 tetrahedra.               //
+//                                                                           //
+// 'flipface' (abc) is shared by two tets: abcd and bace. This routine rep-  //
+// laces them by three new tets:  edab, edbc, and edca. As a result, the abc //
+// is replaced by the edge de. On return, 'flipface' is edab.                //
+//                                                                           //
+// If 'hullflag' > 0, one of {a, b, c, d, e} may be 'dummypoint'. There may  //
+// be hull tets involved in this flip.  There are two cases:                 //
+//   (1) If d is 'dummypoint', all three new tets are hull tets.  If e is    //
+//       'dummypoint', we reconfigure e to d, i.e., turn it up-side down.    //
+//   (2) If c is 'dummypoint' , two new tets edbc and edca are hull tets.    //
+//       If a or b is 'dummypoint', we reconfigure it to c, i.e., rotate the //
+//       three old tets counterclockwisely (right-hand rule) until a or b    //
+//       is in c's position (see Fig.).                                      //
+//                                                                           //
+// If 'flipflag != 0', the convex hull faces will be checked and flipped if  //
+// they are locally non-Delaunay. If 'flipflag == 1', we assume that d is a  //
+// newly inserted vertex, so only the lower part of the convex hull will be  //
+// checked (this avoids unnecessary insphere() testes).                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag)
+{
+  triface topcastets[3], botcastets[3];
+  triface newface, casface;
+  point pa, pb, pc, pd, pe;
+  int dummyflag;  // range = {-1, 0, 1, 2}.
+  int i;
+
+  face *pssub, checksh;
+  face checkseg;
+
+  int *iptr;
+
+  if (hullflag > 0) {
+    // Check if e is dummypoint.
+    if (oppo(fliptets[1]) == dummypoint) {
+      // Swap the two old tets.
+      newface = fliptets[0];
+      fliptets[0] = fliptets[1];
+      fliptets[1] = newface;
+      dummyflag = -1;  // e is dummypoint.
+    } else {
+      // Check if a or b is dummypoint.
+      if (org(fliptets[0]) == dummypoint) {
+        dummyflag = 1;  // a is dummypoint.
+      } else if (dest(fliptets[0]) == dummypoint) {
+        dummyflag = 2;  // b is dummypoint.
+      } else {
+        dummyflag = 0;  // either c or d is dummypoint.
+      }
+      i = dummyflag;
+      // Rotate i times.
+      for (; i > 0; i--) {
+        enextself(fliptets[0]);
+        enext2self(fliptets[1]);
+      }
+    }
+  }
+
+  pa = org(fliptets[0]);
+  pb = dest(fliptets[0]);
+  pc = apex(fliptets[0]);
+  pd = oppo(fliptets[0]);
+  pe = oppo(fliptets[1]);
+
+  if (b->verbose > 1) {
+    printf("    flip 2-to-3: (%d, %d, %d, %d, %d)\n", pointmark(pa),
+      pointmark(pb), pointmark(pc), pointmark(pd), pointmark(pe));
+  }
+  flip23count++;
+
+  // Get the outer boundary faces.
+  for (i = 0; i < 3; i++) {
+    fnext(fliptets[0], topcastets[i]);
+    enextself(fliptets[0]);
+  }
+  for (i = 0; i < 3; i++) {
+    fnext(fliptets[1], botcastets[i]);
+    enext2self(fliptets[1]);
+  }
+
+  if (checksubfaces) {
+    // Check if the flip face is subfaces.
+    tspivot(fliptets[0], checksh);
+    if (checksh.sh != NULL) {
+      if (b->verbose > 1) {
+        printf("      Queue a flipped subface (%d, %d, %d).\n",
+          pointmark(sorg(checksh)), pointmark(sdest(checksh)),
+          pointmark(sapex(checksh)));
+      }
+      stdissolve(checksh); // Disconnect the sub-tet bond.
+      // Add the missing subface into list.
+      subfacstack->newindex((void **) &pssub);
+      *pssub = checksh;
+    }
+  }
+
+  // Re-use fliptets[0] and fliptets[1].
+  fliptets[0].loc = fliptets[0].ver = 0;
+  fliptets[1].loc = fliptets[1].ver = 0;
+  elemmarker(fliptets[0].tet) = 0;
+  elemmarker(fliptets[1].tet) = 0;
+  if (checksubsegs) {
+    // Dealloc the space to subsegments.
+    if (fliptets[0].tet[8] != NULL) {
+      tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
+    }
+    fliptets[0].tet[8] = NULL;
+    if (fliptets[1].tet[8] != NULL) {
+      tet2segpool->dealloc((shellface *) fliptets[1].tet[8]);
+    }
+    fliptets[1].tet[8] = NULL;
+  }
+  if (checksubfaces) {
+    // Dealloc the space to subfaces.
+    if (fliptets[0].tet[9] != NULL) {
+      tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
+    }
+    fliptets[0].tet[9] = NULL;
+    if (fliptets[1].tet[9] != NULL) {
+      tet2subpool->dealloc((shellface *) fliptets[1].tet[9]);
+    }
+    fliptets[1].tet[9] = NULL;
+  }
+
+  if (hullflag > 0) {
+    // Check if d is dummytet.
+    if (pd != dummypoint) {
+      // Update fliptets[0] to edab.
+      setvertices(fliptets[0], pe, pd, pa, pb);
+      // Update fliptets[1] to edbc.
+      setvertices(fliptets[1], pe, pd, pb, pc);
+      // Create new tet edca.
+      maketetrahedron(&(fliptets[2]));
+      // Check if c is dummypoint.
+      if (pc != dummypoint) {
+        setvertices(fliptets[2], pe, pd, pc, pa);
+      } else {
+        setvertices(fliptets[2], pd, pe, pa, pc);
+        // Adjust deac->edca
+        enext0fnextself(fliptets[2]);
+        esymself(fliptets[2]);
+      }
+      // The hullsize does not change.
+    } else {
+      // d is dummypoint.
+      setvertices(fliptets[0], pa, pb, pe, pd); // Create abed.
+      setvertices(fliptets[1], pb, pc, pe, pd); // Create bced.
+      maketetrahedron(&(fliptets[2])); // Create caed.    
+      setvertices(fliptets[2], pc, pa, pe, pd);
+      // Adjust abed->edab, bced->edbc, caed->edca
+      for (i = 0; i < 3; i++) {
+        enext2fnextself(fliptets[i]);
+        enext2self(fliptets[i]);
+        esymself(fliptets[i]);
+      }
+      // We removed one old hull tet, and added three new hull tets.
+      hullsize += 2;
+    }
+  } else {
+    // Update fliptets[0] to edab.
+    setvertices(fliptets[0], pe, pd, pa, pb);
+    // Update fliptets[1] to edbc.
+    setvertices(fliptets[1], pe, pd, pb, pc);
+    // Create new tet edca.
+    maketetrahedron(&(fliptets[2]));
+    setvertices(fliptets[2], pe, pd, pc, pa);
+  }
+
+  // Bond three new tets together.
+  for (i = 0; i < 3; i++) {
+    enext0fnext(fliptets[i], newface);
+    bond(newface, fliptets[(i + 1) % 3]);
+  }
+  // Bond to top outer boundary faces (at abcd).
+  for (i = 0; i < 3; i++) {
+    enextfnext(fliptets[i], newface);
+    enextself(newface);
+    bond(newface, topcastets[i]);
+  }
+  // Bond bottom outer boundary faces (at bace).
+  for (i = 0; i < 3; i++) {
+    enext2fnext(fliptets[i], newface);
+    enext2self(newface);
+    bond(newface, botcastets[i]);
+  }
+
+  // Bond 15 subsegments if there are.
+  if (checksubsegs) {
+    // The middle three: ab, bc, ca.
+    for (i = 0; i < 3; i++) {
+      tsspivot(topcastets[i], checkseg);
+      if (checkseg.sh != NULL) {
+        enextfnext(fliptets[i], newface);
+        enextself(newface);
+        tssbond1(newface, checkseg);
+        sstbond(checkseg, newface);
+      }
+    }
+    // The top three: da, db, dc. Each edge belongs to two tets.
+    for (i = 0; i < 3; i++) {
+      enext2(topcastets[i], casface);
+      tsspivot(casface, checkseg);
+      if (checkseg.sh != NULL) {
+        enext(fliptets[i], newface);
+        tssbond1(newface, checkseg);
+        sstbond(checkseg, newface);
+        enext0fnext(fliptets[(i + 2) % 3], newface);
+        enextself(newface);
+        tssbond1(newface, checkseg);
+        sstbond(checkseg, newface);
+      }
+    }
+    // The bot three: ae, be, ce. Each edge belongs to two tets.
+    for (i = 0; i < 3; i++) {
+      enext(botcastets[i], casface);
+      tsspivot(casface, checkseg);
+      if (checkseg.sh != NULL) {
+        enext2(fliptets[i], newface);
+        tssbond1(newface, checkseg);
+        sstbond(checkseg, newface);
+        enext0fnext(fliptets[(i + 2) % 3], newface);
+        enext2self(newface);
+        tssbond1(newface, checkseg);
+        sstbond(checkseg, newface);
+      }
+    }
+  }
+
+  // Bond 6 subfaces if there are.
+  if (checksubfaces) {
+    for (i = 0; i < 3; i++) {
+      tspivot(topcastets[i], checksh);
+      if (checksh.sh != NULL) {
+        enextfnext(fliptets[i], newface);
+        enextself(newface);
+        tsbond(newface, checksh);
+      }
+    }
+    for (i = 0; i < 3; i++) {
+      tspivot(botcastets[i], checksh);
+      if (checksh.sh != NULL) {
+        enext2fnext(fliptets[i], newface);
+        enext2self(newface);
+        tsbond(newface, checksh);
+      }
+    }
+  }
+
+  // if (checksubsegs || checksubfaces) {
+    // Update the point-to-tet map.
+    point2tet(pa) = encode(fliptets[0]);
+    point2tet(pb) = encode(fliptets[0]);
+    point2tet(pc) = encode(fliptets[1]);
+    point2tet(pd) = encode(fliptets[0]);
+    point2tet(pe) = encode(fliptets[0]);
+  // }
+
+  if (hullflag > 0) {
+    if (dummyflag != 0) {
+      // Restore the original position of the points (for flipnm()).
+      if (dummyflag == -1) { 
+        // Reverse the edge.
+        for (i = 0; i < 3; i++) {
+          enext0fnextself(fliptets[i]);
+          esymself(fliptets[i]);
+        }
+        // Swap the last two new tets.
+        newface = fliptets[1];
+        fliptets[1] = fliptets[2];
+        fliptets[2] = newface;
+      } else {
+        // either a or b were swapped.
+        i = dummyflag;
+        // Down-shift new tets i times.
+        for (; i > 0; i--) {
+          newface = fliptets[0];
+          fliptets[0] = fliptets[2];
+          fliptets[2] = fliptets[1];
+          fliptets[1] = newface;
+        }
+      }
+    }
+  }
+
+  if (flipflag > 0) {
+    // Queue faces which may be locally non-Delaunay.  
+    pd = dest(fliptets[0]);
+    for (i = 0; i < 3; i++) {
+      enext2fnext(fliptets[i], newface);
+      futureflip = flippush(futureflip, &newface, pd);
+    }
+    if (flipflag > 1) {
+      pe = org(fliptets[0]);
+      for (i = 0; i < 3; i++) {
+        enextfnext(fliptets[i], newface);
+        futureflip = flippush(futureflip, &newface, pe);
+      }
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip32()    Remove an edge by transforming 3-to-2 tetrahedra.             //
+//                                                                           //
+// 'flipedge' (ab) is shared by three tets: edab, edbc, and edca. This rout- //
+// ine replaces them by two new tets:  abcd and bace.  As a result, the edge //
+// ab is replaced by the face abc. On return, 'flipedge' is abcd.            //
+//                                                                           //
+// If 'hullflag' > 0, one of {a, b, c, d, e} may be 'dummypoint'. There may  //
+// be hull tets involved in this flip.  There are two cases:                 //
+//   (1) If d is 'dummypoint', then abcd is hull tet, and bace is normal.    //
+//       If e is 'dummypoint', we reconfigure e to d, i.e., turnover it.     //
+//   (2) If c is 'dummypoint' then both abcd and bace are hull tets.         //
+//       If a or b is 'dummypoint', we reconfigure it to c, i.e., rotate the //
+//       three old tets counterclockwisely (right-hand rule) until a or b    //
+//       is in c's position (see Fig.).                                      //
+//                                                                           //
+// If 'flipflag != 0', the convex hull faces will be checked and flipped if  //
+// they are locally non-Delaunay. If 'flipflag == 1', we assume that a is a  //
+// newly inserted vertex, so only the two opposite faces of the convex hull  //
+// will be checked (this avoids unnecessary insphere() testes).              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flip32(triface* fliptets, int hullflag, int flipflag)
+{
+  triface topcastets[3], botcastets[3];
+  triface newface, casface;
+  point pa, pb, pc, pd, pe;
+  int dummyflag;  // Rangle = {-1, 0, 1, 2}
+  int i;
+
+  face *pssub, checksh;
+  face checkseg;
+
+  int *iptr; 
+
+  if (hullflag > 0) {
+    // Check if e is 'dummypoint'.
+    if (org(fliptets[0]) == dummypoint) {
+      // Reverse the edge.
+      for (i = 0; i < 3; i++) {
+        enext0fnextself(fliptets[i]);
+        esymself(fliptets[i]);
+      }
+      // Swap the last two tets.
+      newface = fliptets[1];
+      fliptets[1] = fliptets[2];
+      fliptets[2] = newface;
+      dummyflag = -1; // e is dummypoint.
+    } else {
+      // Check if a or b is the 'dummypoint'.
+      if (apex(fliptets[0]) == dummypoint) { 
+        dummyflag = 1;  // a is dummypoint.
+      } else if (apex(fliptets[1]) == dummypoint) {
+        dummyflag = 2;  // b is dummypoint.
+      } else {
+        dummyflag = 0;  // either c or d is dummypoint.
+      }
+      i = dummyflag;
+      // Down-shift i times.
+      for (; i > 0; i--) {
+        newface = fliptets[2];
+        fliptets[2] = fliptets[1];
+        fliptets[1] = fliptets[0];
+        fliptets[0] = newface;
+      }
+    }
+  }
+
+  pa = apex(fliptets[0]);
+  pb = apex(fliptets[1]);
+  pc = apex(fliptets[2]);
+  pd = dest(fliptets[0]);
+  pe = org(fliptets[0]);
+
+  if (b->verbose > 1) {
+    printf("    flip 3-to-2: (%d, %d, %d, %d, %d)\n", pointmark(pa),
+      pointmark(pb), pointmark(pc), pointmark(pd), pointmark(pe));
+  }
+  flip32count++;
+
+  // Get the outer boundary faces.
+  for (i = 0; i < 3; i++) {
+    enextfnext(fliptets[i], casface);
+    enextself(casface);
+    symedge(casface, topcastets[i]);
+  }
+  for (i = 0; i < 3; i++) {
+    enext2fnext(fliptets[i], casface);
+    enext2self(casface);
+    symedge(casface, botcastets[i]);
+  }
+
+  if (checksubsegs) {
+    // Check if the flip edge is subsegment.
+    tsspivot(fliptets[0], checkseg);
+    if ((checkseg.sh != NULL)) {
+      if (!sinfected(checkseg)) {
+        // This subsegment will be flipped. Queue it.
+        if (b->verbose > 1) {
+          printf("      Queue a flipped segment (%d, %d).\n",
+            pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
+        }
+        sinfect(checkseg);  // Only save it once.
+        subsegstack->newindex((void **) &pssub);
+        *pssub = checkseg;
+      }
+      // Clean the seg-to-tet pointer.
+      stdissolve(checkseg);
+    }
+  }
+
+  if (checksubfaces) {
+    // Check if the three flip faces are subfaces.
+    for (i = 0; i < 3; i++) {
+      tspivot(fliptets[i], checksh);
+      if (checksh.sh != NULL) {
+        if (b->verbose > 1) {
+          printf("      Queue a flipped subface (%d, %d, %d).\n",
+            pointmark(sorg(checksh)), pointmark(sdest(checksh)),
+            pointmark(sapex(checksh)));
+        }
+        stdissolve(checksh); // Disconnect the sub-tet bond.
+        // Add the missing subface into list.
+        subfacstack->newindex((void **) &pssub);
+        *pssub = checksh;
+      }
+    }
+  }
+
+  // Re-use fliptets[0] and fliptets[1].
+  fliptets[0].loc = fliptets[0].ver = 0;
+  fliptets[1].loc = fliptets[1].ver = 0;
+  elemmarker(fliptets[0].tet) = 0;
+  elemmarker(fliptets[1].tet) = 0;
+  if (checksubsegs) {
+    // Dealloc the space to subsegments.
+    if (fliptets[0].tet[8] != NULL) {
+      tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
+    }
+    fliptets[0].tet[8] = NULL;
+    if (fliptets[1].tet[8] != NULL) {
+      tet2segpool->dealloc((shellface *) fliptets[1].tet[8]);
+    }
+    fliptets[1].tet[8] = NULL;
+  }
+  if (checksubfaces) {
+    // Dealloc the space to subfaces.
+    if (fliptets[0].tet[9] != NULL) {
+      tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
+    }
+    fliptets[0].tet[9] = NULL;
+    if (fliptets[1].tet[9] != NULL) {
+      tet2subpool->dealloc((shellface *) fliptets[1].tet[9]);
+    }
+    fliptets[1].tet[9] = NULL;
+  }
+
+  // Delete an old tet.
+  tetrahedrondealloc(fliptets[2].tet);
+
+  if (hullflag > 0) {
+    // Check if c is dummypointc.
+    if (pc != dummypoint) {
+      // Check if d is dummypoint.
+      if (pd != dummypoint) {
+        // No hull tet is involved.
+      } else {
+        // We removed three old hull tets, and added on new hull tet.
+        hullsize -= 2;
+      }
+      setvertices(fliptets[0], pa, pb, pc, pd);
+      setvertices(fliptets[1], pb, pa, pc, pe);
+    } else {
+      // c is dummypoint. The two new tets are hull tets.
+      setvertices(fliptets[0], pb, pa, pd, pc);
+      setvertices(fliptets[1], pa, pb, pe, pc);
+      // Adjust badc -> abcd.
+      enext0fnextself(fliptets[0]);
+      esymself(fliptets[0]);
+      // Adjust abec -> bace.
+      enext0fnextself(fliptets[1]);
+      esymself(fliptets[1]);
+      // The hullsize does not changle.
+    }
+  } else {
+    setvertices(fliptets[0], pa, pb, pc, pd);
+    setvertices(fliptets[1], pb, pa, pc, pe);
+  }
+  
+  // Bond abcd <==> bace.
+  bond(fliptets[0], fliptets[1]);
+  // Bond new faces to top outer boundary faces (at abcd).
+  for (i = 0; i < 3; i++) {
+    enext0fnext(fliptets[0], newface);
+    bond(newface, topcastets[i]);
+    enextself(fliptets[0]);
+  }
+  // Bond new faces to bottom outer boundary faces (at bace).
+  for (i = 0; i < 3; i++) {
+    enext0fnext(fliptets[1], newface);
+    bond(newface, botcastets[i]);
+    enext2self(fliptets[1]);
+  }
+
+  if (checksubsegs) {
+    // Bond segments to new (flipped) tets.
+    for (i = 0; i < 3; i++) {
+      tsspivot(topcastets[i], checkseg);
+      if (checkseg.sh != NULL) {
+        tssbond1(fliptets[0], checkseg);
+        sstbond(checkseg, fliptets[0]);
+      }
+      enextself(fliptets[0]);
+    }
+    // The three top edges.
+    for (i = 0; i < 3; i++) {
+      enext0fnext(fliptets[0], newface);
+      enextself(newface); // edge b->d, c->d, a->d.
+      enext(topcastets[i], casface);
+      tsspivot(casface, checkseg);
+      if (checkseg.sh != NULL) {
+        tssbond1(newface, checkseg);
+        sstbond(checkseg, newface);
+      }
+      enextself(fliptets[0]);
+    }
+    // Process the bottom tet bace.
+    for (i = 0; i < 3; i++) {
+      tsspivot(botcastets[i], checkseg);
+      if (checkseg.sh != NULL) {
+        tssbond1(fliptets[1], checkseg);
+        sstbond(checkseg, fliptets[1]);
+      }
+      enext2self(fliptets[1]);
+    }
+    // The three bot edges.
+    for (i = 0; i < 3; i++) {
+      enext0fnext(fliptets[1], newface);
+      enext2self(newface); // edge b<-e, c<-e, a<-e.
+      enext2(botcastets[i], casface);
+      tsspivot(casface, checkseg);
+      if (checkseg.sh != NULL) {
+        tssbond1(newface, checkseg);
+        sstbond(checkseg, newface);
+      }
+      enext2self(fliptets[1]);
+    }
+  }
+
+  if (checksubfaces) {
+    // Bond the top three casing subfaces.
+    for (i = 0; i < 3; i++) {
+      tspivot(topcastets[i], checksh);
+      if (checksh.sh != NULL) {
+        enext0fnext(fliptets[0], newface);
+        tsbond(newface, checksh);
+      }
+      enextself(fliptets[0]);
+    }
+    // Bond the bottom three casing subfaces.
+    for (i = 0; i < 3; i++) {
+      tspivot(botcastets[i], checksh);
+      if (checksh.sh != NULL) {
+        enext0fnext(fliptets[1], newface);
+        tsbond(newface, checksh);
+      }
+      enext2self(fliptets[1]);
+    }
+  }
+
+  // if (checksubsegs || checksubfaces) {
+    // Update the point-to-tet map.
+    point2tet(pa) = encode(fliptets[0]);
+    point2tet(pb) = encode(fliptets[0]);
+    point2tet(pc) = encode(fliptets[0]);
+    point2tet(pd) = encode(fliptets[0]);
+    point2tet(pe) = encode(fliptets[1]);
+  // }
+
+  if (hullflag > 0) {
+    if (dummyflag != 0) {
+      // Restore the original position of the points (for flipnm()).
+      if (dummyflag == -1) {
+        // e were dummypoint. Swap the two new tets.
+        newface = fliptets[0];
+        fliptets[0] = fliptets[1];
+        fliptets[1] = newface;
+      } else {
+        // a or b was dummypoint.
+        i = dummyflag;
+        // Rotate toward left i times.
+        for (; i > 0; i--) {
+          enextself(fliptets[0]);
+          enext2self(fliptets[1]);
+        }
+      }
+    }
+  }
+  
+  if (flipflag > 0) {
+    // Queue faces which may be locally non-Delaunay.  
+    pa = org(fliptets[0]);
+    enextfnext(fliptets[0], newface);
+    futureflip = flippush(futureflip, &newface, pa);
+    enext2fnext(fliptets[1], newface);
+    futureflip = flippush(futureflip, &newface, pa);
+    if (flipflag > 1) {
+      pb = dest(fliptets[0]);
+      enext2fnext(fliptets[0], newface);
+      futureflip = flippush(futureflip, &newface, pb);
+      enextfnext(fliptets[1], newface);
+      futureflip = flippush(futureflip, &newface, pb);
+      pc = apex(fliptets[0]);
+      enext0fnext(fliptets[0], newface);
+      futureflip = flippush(futureflip, &newface, pc);
+      enext0fnext(fliptets[1], newface);
+      futureflip = flippush(futureflip, &newface, pc);
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flipnm()    Remove an edge by transforming n-to-m tetrahedra.             //
+//                                                                           //
+// This routine attemps to remove an edge, denoted as ab, by transforming a  //
+// set K of n tetrahedra containing ab into a set K' of m tetrahedra, where  //
+// K and K' have the same outer boundary, and ab is not in K', where n >= 3, //
+// m = 2 * n - 4. It can be viwed as a n-to-m flip.                          //
+//                                                                           //
+// 'oldtets' contains n tets sharing at ab. Imaging that ab perpendicularly  //
+// crosses your screen, b lies in front of a. Let the projections of the n   //
+// apexes, denoted as p[0], p[1], ..., p[n-1], onto screen in counterclock-  //
+// wise order (right-hand rule). The n tets are: abp[0]p[1], abp[1]p[2],..., //
+// abp[n-1]p[0], respectively.  If one of p[i] is dummypoint, we reconfigure //
+// it such that p[0] is dummypoint. a or b should not be dummypoint.         //
+//                                                                           //
+// The principle of the transformation is to recursively reduce the link of  //
+// ab by perform 2-to-3 flips until the link size of ab is 3, hence a 3-to-2 //
+// flip can be applied to remove the edge.                                   //
+//                                                                           //
+// Consider a face abp[i] (i in [0, n-1]), a flip23() can be applied if the  //
+// edge p[(i-1) % n]p[(i+1) % n] crosses it in its interior. Relabel p[i] to //
+// c, p[(i-1) % n] to e, and p[(i+1) % n] to d. This transforms the two tets,//
+// abcd and bace, to three tets, edab, edbc, and edca. The tet edab remains  //
+// in the star of ab, while edbc, and edca do not. As a result, p[i] (c) is  //
+// not on the link of ab anymore. The link size is reduced by 1. A recursion //
+// can be applied if n - 1 > 3.                                              //
+//                                                                           //
+// NOTE: In above, the flip23() can be applied even if the edge de crosses   //
+// ab, i.e., a, b, e, and d are coplanar. Although this will creare a degen- //
+// erate tet edab (has zero volume), it will be removed after ab is removed. //
+//                                                                           //
+// The number m can be counted as follows: there are n - 3 '2-to-3' flips, 1 //
+// '3-to-2' flip. Each '2-to-3' flip produces two new tets, and the '3-to-2' //
+// flip produces two new tets, hence m = (n - 3) * 2 + 2 = 2 * n - 4.        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+bool tetgenmesh::flipnm(int n, triface* oldtets, triface* newtets,
+  bool delaunay, queue* flipque)
+{
+  triface *recuroldtets, tmpoldtets[2], baktet;
+  point pa, pb, pc, pd, pe, pf;
+  bool success, doflip;
+  REAL sign, ori;
+  int *iptr, i, j;
+
+  // Check if any apex of ab is dummypoint.
+  for (i = n - 1; i > 0; i--) {
+    if (apex(oldtets[i]) == dummypoint) break;
+  }
+  // Now i is the shift distance to the first one.
+  for (; i > 0; i--) {
+    baktet = oldtets[0];
+    for (j = 0; j < n - 1; j++) {
+      oldtets[j] = oldtets[j + 1];
+    }
+    oldtets[n - 1] = baktet;
+  }
+
+  pa = org(oldtets[0]);
+  pb = dest(oldtets[0]);
+
+  if (b->verbose > 1) {
+    printf("    flip %d-to-%d: (%d, %d)\n", n, 2 * n - 4, pointmark(pa),
+           pointmark(pb));
+  }
+  flipnmcount++;
+
+  success = false;
+
+  for (i = 0; i < n; i++) {
+    pc = apex(oldtets[i]);
+    pd = apex(oldtets[(i + 1) % n]);
+    pe = apex(oldtets[(i != 0) ? i - 1 : n - 1]);
+    // Decide if the face abc is flipable.
+    if (pc != dummypoint) {
+      if ((pd != dummypoint) && (pc != dummypoint)) {
+        ori = orient3d(pa, pb, pd, pe);
+        if (ori >= 0) {  // Allow ori == 0, support 4-to-4 flip.
+          ori = orient3d(pb, pc, pd, pe);
+          if (ori > 0) {
+            ori = orient3d(pc, pa, pd, pe);
+          }
+        }
+        doflip = ori > 0;
+        if (doflip && delaunay) {
+          // Only do flip if abc is not a locally Delaunay face.
+          sign = insphere_sos(pa, pb, pc, pd, pe);
+          doflip = (sign < 0);
+        }
+      } else {
+        doflip = false;
+      }
+    } else {
+      // Two faces abd and abe are on the hull.
+      doflip = true; // 2-to-2 flip is possible.
+      if (delaunay) {
+        // Only do flip if ab is not a locally Delaunay edge.
+        pf = apex(oldtets[(i + 2) % n]);
+        sign = insphere_sos(pa, pb, pd, pf, pe);
+        doflip = (sign < 0);
+      }
+    }
+    if (doflip) {
+      // Get the two old tets.
+      tmpoldtets[0] = oldtets[i];
+      tmpoldtets[1] = oldtets[(i != 0) ? i - 1 : n - 1];
+      // Adjust tmpoldtets[1] (abec) -> bace.
+      enext0fnextself(tmpoldtets[1]);
+      esymself(tmpoldtets[1]);
+      // Adjust the tets so that newtets[2] will be edca (see Fig.).
+      enextself(tmpoldtets[0]);
+      enext2self(tmpoldtets[1]);
+      // Do flip23() on abp[i] (abc).
+      flip23(tmpoldtets, newtets, flipque);
+      // Form the new star of ab which has n-1 tets.
+      recuroldtets = new triface[n - 1];
+      // Set the remaining n-2 tets around ab.
+      for (j = 0; j < n - 2 ; j++) {
+        recuroldtets[j] = oldtets[(i + 1 + j) % n];
+      }
+      // Put the last tet having ab. Leave a copy in baktet.
+      recuroldtets[j] = baktet = newtets[2];
+      // Adjust recuroldtets[j] to abp[0]p[1] (see Fig.).
+      enext2fnextself(recuroldtets[j]);  // j == n - 2;
+      enext2self(recuroldtets[j]);
+      esymself(recuroldtets[j]);
+      // Check the size of the link of ab.
+      if (n > 4) {  // Actually, if (n - 1 > 3)
+        // Recursively do flipnm().
+        success = flipnm(n-1, recuroldtets, &(newtets[2]), delaunay, flipque);
+        // Are we success?
+        if (!success) {
+          if (!delaunay) {
+            // No! Reverse the flip23() operation.
+            newtets[2] = baktet; // Do we really need this?
+            flip32(newtets, tmpoldtets, flipque);
+            // Adjust the tets back to original position (see Fig.).
+            enext2self(tmpoldtets[0]);
+            enextself(tmpoldtets[1]);
+            // Adjust back to abp[(i-1) % n].
+            enext0fnextself(tmpoldtets[1]);
+            esymself(tmpoldtets[1]);
+            // Delete the two original old tets first.
+            tetrahedrondealloc(oldtets[i].tet);
+            tetrahedrondealloc(oldtets[(i != 0) ? i - 1 : n - 1].tet);
+            // Set the tets back to their original positions.
+            oldtets[i] = tmpoldtets[0];
+            oldtets[(i != 0) ? i - 1 : n - 1] = tmpoldtets[1];
+            // Delete the three new tets.
+            tetrahedrondealloc(newtets[0].tet);
+            tetrahedrondealloc(newtets[1].tet);
+            tetrahedrondealloc(newtets[2].tet); // = recuroldtets[j].tet
+          } else {
+            // Only delete the first two old tets. Their common face is
+            //   not locally Delaunay and has been flipped.
+            tetrahedrondealloc(oldtets[i].tet);
+            tetrahedrondealloc(oldtets[(i != 0) ? i - 1 : n - 1].tet);
+            // Here the tet recuroldtets[j] does not get deleted. It is
+            //   a part of current mesh.
+          }
+        } else {
+          // Delete the last tet in 'recuroldtets'. This tet is neither in
+          //   'oldtets' nor in 'newtets'.
+          tetrahedrondealloc(recuroldtets[j].tet);  // j == n - 2
+        } 
+      } else {
+        // Remove ab by a flip32().
+        flip32(recuroldtets, &(newtets[2]), flipque);
+        // Delete the last tet in 'recuroldtets'. This one is just created
+        //   by the flip 2-to-3 operation within this routine.
+        tetrahedrondealloc(recuroldtets[j].tet);  // j == n - 2
+        success = true;
+      }      
+      // The other tets in 'recuroldtets' are still in 'oldtets'.
+      delete [] recuroldtets;
+      break;
+    } // if (doflip)
+  } // for (i = 0; i < n; i++)
+  
+  return success;
+}
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// lawsonflip()    Flip non-locally Delaunay faces by primitive flips.       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::lawsonflip3d(int flipflag)
+{ 
+  triface fliptets[5], baktets[2];
+  triface fliptet, neightet, *parytet;
+  face checksh, checkseg;
+  point *pt, pd, pe;
+  REAL sign, ori;
+  long flipcount;
+  bool bflag; // for flipflag = 3.
+  int n, i;
+
+  int *iptr;
+
+  // for flipflag = 2.
+  point pa, pb, ppa, ppb;
+  int ecount;
+
+  if (b->verbose > 1) {
+    printf("    Lawson flip %ld faces.\n", flippool->items);
+    flipcount = flip23count + flip32count;
+  }
+
+  ecount = 0; // Initialize the counter.
+
+  while (futureflip != (badface *) NULL) {
+
+    // Pop a face from the stack.
+    fliptet = futureflip->tt;  // abcd (may be a hull tet)
+    pd = futureflip->foppo;  // The new vertex.
+    futureflip = futureflip->nextitem;
+
+    // Skip it if it is a dead tet.
+    if (fliptet.tet[4] == NULL) continue;
+    // Skip it if it is not the same tet as we saved.
+    if (oppo(fliptet) != pd) continue;
+
+    // Get its opposite tet.
+    fliptet.ver = 4;
+    symedge(fliptet, neightet);
+
+    if ((point) neightet.tet[7] == dummypoint) {
+      // A hull tet. Check if its base face is visible by d.
+      pt = (point *) neightet.tet;
+      ori = orient3d(pt[4], pt[5], pt[6], pd); orient3dcount++;
+      if (ori < 0) {
+        // Visible! Found a 2-to-3 flip on abc.
+        fliptets[0] = fliptet;
+        fliptets[1] = neightet;
+        flip23(fliptets, 1, flipflag); // flip a hull tet.
+        recenttet = fliptets[0];
+      } else if (ori == 0) {
+        // Handle degenerate case ori == 0.
+        if (oppo(fliptet) == oppo(neightet)) {
+          // Two hull tets (fliptet and neightet) have the same base face.
+          for (i = 0; i < 3; i++) {
+            fnext(fliptet, fliptets[0]);
+            fnext(neightet, fliptets[1]);
+            bond(fliptets[0], fliptets[1]);
+            if (i == 0) {
+              // apex(fliptets[0]) is the new point. The opposite face may
+              // be not locally Delaunay. Put it in flip stack.
+              // assert(apex(fliptets[0]) == pd); // SELF_CHECK
+              enext0fnextself(fliptets[0]);
+              futureflip = flippush(futureflip, &(fliptets[0]), pd);
+              // assert(apex(fliptets[1]) == pd); // SELF_CHECK
+              enext0fnextself(fliptets[1]);
+              futureflip = flippush(futureflip, &(fliptets[1]), pd);
+            }
+            enextself(fliptet);
+            enext2self(neightet);
+          }
+          // Delete the two tets.
+          tetrahedrondealloc(fliptet.tet);
+          tetrahedrondealloc(neightet.tet);
+          // Update the hull size.
+          hullsize -= 2;
+        }
+      }
+      continue;
+    }
+
+    pe = oppo(neightet);
+    pt = (point *) fliptet.tet;
+    // assert((point) fliptet.tet[7] != dummypoint); // SELF_CHECK
+
+    sign = insphere_sos(pt[4], pt[5], pt[6], pt[7], pe);
+
+    if (b->verbose > 2) {
+      printf("  Insphere: (%d, %d, %d) %d, %d\n", pointmark(org(fliptet)),
+        pointmark(dest(fliptet)), pointmark(apex(fliptet)),
+        pointmark(oppo(fliptet)), pointmark(pe));
+    }
+     
+    // Flip it if it is not locally Delaunay.
+    if (sign < 0) {
+      // Check the convexity of its three edges.
+      fliptet.ver = 0;
+      for (i = 0; i < 3; i++) {
+        ori = orient3d(org(fliptet), dest(fliptet), pd, pe); orient3dcount++;
+        if (ori <= 0) break;
+        enextself(fliptet);
+      }
+      if (i == 3) {
+        // A 2-to-3 flip is found.
+        if (flipflag == 3) {
+          // Do not flip a subface.
+          tspivot(fliptet, checksh);
+          bflag = (checksh.sh == NULL);
+        } else {
+          bflag = true;
+        }
+        if (bflag) {
+          fliptets[0] = fliptet; // tet abcd, d is the new vertex.
+          symedge(fliptets[0], fliptets[1]); // tet bace.
+          flip23(fliptets, 0, flipflag);
+          recenttet = fliptets[0]; // for point location.
+        }
+      } else {
+        // A 3-to-2 or 4-to-4 may possible.
+        if (flipflag == 3) {
+          // Do not flip a subsegment.
+          tsspivot(fliptet, checkseg);
+          bflag = (checkseg.sh == NULL);
+        } else {
+          bflag = true;
+        }
+        if (bflag) {
+          enext0fnext(fliptet, fliptets[0]);
+          esymself(fliptets[0]); // tet badc, d is the new vertex.
+          n = 0;
+          do {
+            fnext(fliptets[n], fliptets[n + 1]);
+            n++;
+          } while ((fliptets[n].tet != fliptet.tet) && (n < 5));
+          if (n == 3) {
+            // Found a 3-to-2 flip.
+            flip32(fliptets, 0, flipflag);
+            recenttet = fliptets[0]; // for point location.
+            if (flipflag == 2) {
+              ecount = 0; // Clear the counter.
+            }
+          } else if ((n == 4) && (ori == 0)) {
+            // Find a 4-to-4 flip.
+            flipnmcount++;
+            // First do a 2-to-3 flip.
+            fliptets[0] = fliptet; // tet abcd, d is the new vertex.
+            baktets[0] = fliptets[2];
+            baktets[1] = fliptets[3];
+            flip23(fliptets, 1, flipflag); // hull tet may involve.
+            // Then do a 3-to-2 flip. 
+            enextfnextself(fliptets[0]);  // fliptets[0] is edab.
+            enextself(fliptets[0]);
+            esymself(fliptets[0]);  // tet badc, d is the new vertex.
+            fliptets[1] = baktets[0];
+            fliptets[2] = baktets[1];
+            flip32(fliptets, 1, flipflag); // hull tet may involve.
+            recenttet = fliptets[0]; // for point location.
+            if (flipflag == 2) {
+              ecount = 0; // Clear the counter.
+            }
+          } else {
+            // An unflipable face. Will be flipped later.
+            if (flipflag == 2) { // if (flipflag > 1) {
+              // Queue all other faces at the edge for flipping.
+              if (b->verbose > 1) {
+                printf("    Queue an N32 edge (%d, %d)", 
+                  pointmark(org(fliptets[0])), pointmark(dest(fliptets[0])));
+              }
+              pe = apex(fliptets[0]);
+              fliptets[1] = fliptets[0];
+              while (1) {
+                if (b->verbose > 1) {
+                  printf("  %d", pointmark(apex(fliptets[1])));
+                }
+                pd = oppo(fliptets[1]);
+                futureflip = flippush(futureflip, &fliptets[1], pd);
+                fnextself(fliptets[1]);
+                if (apex(fliptets[1]) == pe) break;
+              }
+              if (b->verbose > 1) {
+                printf("\n");
+              }
+              ecount++; // Increase the counter.
+              if (ecount >= 1000) {
+                // assert(0); // A flip deadlock.
+                // Dump the dead lock case.
+                pa = org(fliptets[0]);
+                pb = dest(fliptets[0]);
+                if (ecount == 1000) {
+                  printf("-- Flip failed after inserting point %ld.\n", 
+                    pointpool->items);
+                  ppa = pa;  // Bakup the startiing loop edge.
+                  ppb = pb;
+                } else {
+                  if (((ppa == pa) && (ppb == pb)) ||
+                      ((ppa == pb) && (ppb == pa))) {
+                    // Dump the current mesh and exit.
+                    outnodes(0);
+                    outelements(0);
+                    exit(1);
+                  }                      
+                }
+                printf("p:draw_subseg(%d, %d)\n",pointmark(pa),pointmark(pb));
+                printf("p:draw_subface(%d, %d, %d)\n", pointmark(org(fliptet)),
+                  pointmark(dest(fliptet)), pointmark(apex(fliptet)));
+                printf("p:draw_tet(%d, %d, %d, %d)\n", pointmark(org(fliptet)),
+                  pointmark(dest(fliptet)), pointmark(apex(fliptet)),
+                  pointmark(oppo(fliptet)));
+                symedge(fliptet, fliptets[1]);  
+                printf("p:draw_tet(%d, %d, %d, %d)\n", 
+                  pointmark(org(fliptets[1])),
+                  pointmark(dest(fliptets[1])), 
+                  pointmark(apex(fliptets[1])),
+                  pointmark(oppo(fliptets[1])));
+                pe = apex(fliptets[0]);
+                fliptets[1] = fliptets[0];
+                while (1) {
+                  pd = oppo(fliptets[1]);
+                  printf("  -- p:draw_tet(%d, %d, %d, %d)\n", pointmark(pa),
+                    pointmark(pb),pointmark(apex(fliptets[1])),pointmark(pd));
+                  fnextself(fliptets[1]);
+                  if (apex(fliptets[1]) == pe) break;
+                }
+              } // if (ecount >= 1000)
+            }
+          }
+        } // bflag
+      } // if (i == 3)
+    } // if (sign < 0)
+  }
+
+  if (b->verbose > 1) {
+    printf("    %ld faces stacked, %ld flips.\n", flippool->items, 
+      flip23count + flip32count - flipcount);
+  }
+
+  flippool->restart();
+}
+
+#endif // #ifndef flipCXX
\ No newline at end of file
diff --git a/contrib/TetgenNew/geom.cxx b/contrib/TetgenNew/geom.cxx
new file mode 100644
index 0000000000..275df658dd
--- /dev/null
+++ b/contrib/TetgenNew/geom.cxx
@@ -0,0 +1,4517 @@
+#ifndef geomCXX
+#define geomCXX
+
+#include "tetgen.h"
+
+REAL tetgenmesh::PI = 3.14159265358979323846264338327950288419716939937510582;
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tri_edge_2d()    Triangle-edge coplanar intersection test.                //
+//                                                                           //
+// This routine takes a triangle T (with vertices A, B, C) and an edge E (P, //
+// Q) in a plane in 3D, and tests if they intersect each other.  Return 1 if //
+// they are intersected, i.e., T \cap E is not empty, otherwise, return 0.   //
+//                                                                           //
+// If the point 'R' is not NULL, it lies strictly above T [A, B, C].         //
+//                                                                           //
+// If T1 and T2 intersect each other (return 1), they may intersect in diff- //
+// erent ways. If 'level' > 0, their intersection type will be reported in   //
+// combinations of 'types' and 'pos'.                                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::tri_edge_2d(point A, point B, point C, point P, point Q, 
+  point R, int level, int *types, int *pos)
+{
+  point U[3], V[3];  // The permuted vectors of points.
+  int pu[3], pv[3];  // The original positions of points.
+  REAL sA, sB, sC;
+  REAL s1, s2, s3, s4;
+  int z1;
+
+  if (R == NULL) {
+    REAL n[3], len;
+    // Calculate a lift point, saved in dummypoint.
+    facenormal(A, B, C, n, 1);
+    len = sqrt(DOT(n, n));
+    n[0] /= len;
+    n[1] /= len;
+    n[2] /= len;
+    len = DIST(A, B);
+    len += DIST(B, C);
+    len += DIST(C, A);
+    len /= 3.0;
+    R = dummypoint;
+    R[0] = A[0] + len * n[0];
+    R[1] = A[1] + len * n[1];
+    R[2] = A[2] + len * n[2];
+  }
+
+  // Test A's, B's, and C's orientations wrt plane PQR. 
+  sA = orient3d(P, Q, R, A);
+  sB = orient3d(P, Q, R, B);
+  sC = orient3d(P, Q, R, C);
+  orient3dcount+=3;
+
+  if (b->epsilon) {
+    // Re-evaluate the sign with respect to the tolerance.
+    if ((sA != 0) && iscoplanar(P, Q, R, A, sA)) sA = 0;
+    if ((sB != 0) && iscoplanar(P, Q, R, B, sB)) sB = 0;
+    if ((sC != 0) && iscoplanar(P, Q, R, C, sC)) sC = 0;
+  }
+
+  if (b->verbose > 2) {
+    printf("      Tri-edge-2d (%d %d %d)-(%d %d)-(%d) (%c%c%c)", pointmark(A),
+      pointmark(B), pointmark(C), pointmark(P), pointmark(Q), pointmark(R),
+      sA > 0 ? '+' : (sA < 0 ? '-' : '0'), sB>0 ? '+' : (sB<0 ? '-' : '0'),
+      sC>0 ? '+' : (sC<0 ? '-' : '0'));
+  }
+  triedgcopcount++;
+
+  if (sA < 0) {
+    if (sB < 0) {
+      if (sC < 0) { // (---).
+        return 0; 
+      } else {
+        if (sC > 0) { // (--+).
+          // All points are in the right positions.
+          SETVECTOR3(U, A, B, C);  // I3
+          SETVECTOR3(V, P, Q, R);  // I2
+          SETVECTOR3(pu, 0, 1, 2);
+          SETVECTOR3(pv, 0, 1, 2);
+          z1 = 0;
+        } else { // (--0).
+          SETVECTOR3(U, A, B, C);  // I3
+          SETVECTOR3(V, P, Q, R);  // I2
+          SETVECTOR3(pu, 0, 1, 2);
+          SETVECTOR3(pv, 0, 1, 2);
+          z1 = 1;
+        }
+      }
+    } else { 
+      if (sB > 0) {
+        if (sC < 0) { // (-+-).
+          SETVECTOR3(U, C, A, B);  // PT = ST
+          SETVECTOR3(V, P, Q, R);  // I2
+          SETVECTOR3(pu, 2, 0, 1);
+          SETVECTOR3(pv, 0, 1, 2);
+          z1 = 0;
+        } else {
+          if (sC > 0) { // (-++).
+            SETVECTOR3(U, B, C, A);  // PT = ST x ST
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 1, 2, 0);
+            SETVECTOR3(pv, 1, 0, 2);
+            z1 = 0;
+          } else { // (-+0).
+            SETVECTOR3(U, C, A, B);  // PT = ST
+            SETVECTOR3(V, P, Q, R);  // I2
+            SETVECTOR3(pu, 2, 0, 1);
+            SETVECTOR3(pv, 0, 1, 2);
+            z1 = 2;
+          }
+        }
+      } else {
+        if (sC < 0) { // (-0-).
+          SETVECTOR3(U, C, A, B);  // PT = ST
+          SETVECTOR3(V, P, Q, R);  // I2
+          SETVECTOR3(pu, 2, 0, 1);
+          SETVECTOR3(pv, 0, 1, 2);
+          z1 = 1;
+        } else {
+          if (sC > 0) { // (-0+).
+            SETVECTOR3(U, B, C, A);  // PT = ST x ST
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 1, 2, 0);
+            SETVECTOR3(pv, 1, 0, 2);
+            z1 = 2;
+          } else { // (-00).
+            SETVECTOR3(U, B, C, A);  // PT = ST x ST
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 1, 2, 0);
+            SETVECTOR3(pv, 1, 0, 2);
+            z1 = 3; 
+          }
+        }
+      }
+    }
+  } else {
+    if (sA > 0) {
+      if (sB < 0) {
+        if (sC < 0) { // (+--).
+          SETVECTOR3(U, B, C, A);  // PT = ST x ST
+          SETVECTOR3(V, P, Q, R);  // I2
+          SETVECTOR3(pu, 1, 2, 0);
+          SETVECTOR3(pv, 0, 1, 2);
+          z1 = 0;
+        } else {
+          if (sC > 0) { // (+-+).
+            SETVECTOR3(U, C, A, B);  // PT = ST
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 2, 0, 1);
+            SETVECTOR3(pv, 1, 0, 2);
+            z1 = 0;
+          } else { // (+-0).
+            SETVECTOR3(U, C, A, B);  // PT = ST
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 2, 0, 1);
+            SETVECTOR3(pv, 1, 0, 2);
+            z1 = 2;
+          }
+        }
+      } else { 
+        if (sB > 0) {
+          if (sC < 0) { // (++-).
+            SETVECTOR3(U, A, B, C);  // I3
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 0, 1, 2);
+            SETVECTOR3(pv, 1, 0, 2);
+            z1 = 0;
+          } else {
+            if (sC > 0) { // (+++).
+              return 0; 
+            } else { // (++0).
+              SETVECTOR3(U, A, B, C);  // I3
+              SETVECTOR3(V, Q, P, R);  // PL = SL
+              SETVECTOR3(pu, 0, 1, 2);
+              SETVECTOR3(pv, 1, 0, 2);
+              z1 = 1; 
+            }
+          }
+        } else { // (+0#)
+          if (sC < 0) { // (+0-).
+            SETVECTOR3(U, B, C, A);  // PT = ST x ST
+            SETVECTOR3(V, P, Q, R);  // I2
+            SETVECTOR3(pu, 1, 2, 0);
+            SETVECTOR3(pv, 0, 1, 2);
+            z1 = 2;
+          } else {
+            if (sC > 0) { // (+0+).
+              SETVECTOR3(U, C, A, B);  // PT = ST
+              SETVECTOR3(V, Q, P, R);  // PL = SL
+              SETVECTOR3(pu, 2, 0, 1);
+              SETVECTOR3(pv, 1, 0, 2);
+              z1 = 1;
+            } else { // (+00).
+              SETVECTOR3(U, B, C, A);  // PT = ST x ST
+              SETVECTOR3(V, P, Q, R);  // I2
+              SETVECTOR3(pu, 1, 2, 0);
+              SETVECTOR3(pv, 0, 1, 2);
+              z1 = 3; 
+            }
+          }
+        }
+      }
+    } else { 
+      if (sB < 0) {
+        if (sC < 0) { // (0--).
+          SETVECTOR3(U, B, C, A);  // PT = ST x ST
+          SETVECTOR3(V, P, Q, R);  // I2
+          SETVECTOR3(pu, 1, 2, 0);
+          SETVECTOR3(pv, 0, 1, 2);
+          z1 = 1;
+        } else {
+          if (sC > 0) { // (0-+).
+            SETVECTOR3(U, A, B, C);  // I3
+            SETVECTOR3(V, P, Q, R);  // I2
+            SETVECTOR3(pu, 0, 1, 2);
+            SETVECTOR3(pv, 0, 1, 2);
+            z1 = 2;
+          } else { // (0-0).
+            SETVECTOR3(U, C, A, B);  // PT = ST
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 2, 0, 1);
+            SETVECTOR3(pv, 1, 0, 2);
+            z1 = 3; 
+          }
+        }
+      } else { 
+        if (sB > 0) {
+          if (sC < 0) { // (0+-).
+            SETVECTOR3(U, A, B, C);  // I3
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 0, 1, 2);
+            SETVECTOR3(pv, 1, 0, 2);
+            z1 = 2;
+          } else {
+            if (sC > 0) { // (0++).
+              SETVECTOR3(U, B, C, A);  // PT = ST x ST
+              SETVECTOR3(V, Q, P, R);  // PL = SL
+              SETVECTOR3(pu, 1, 2, 0);
+              SETVECTOR3(pv, 1, 0, 2);
+              z1 = 1;
+            } else { // (0+0).
+              SETVECTOR3(U, C, A, B);  // PT = ST
+              SETVECTOR3(V, P, Q, R);  // I2
+              SETVECTOR3(pu, 2, 0, 1);
+              SETVECTOR3(pv, 0, 1, 2);
+              z1 = 3; 
+            }
+          }
+        } else { // (00#)
+          if (sC < 0) { // (00-).
+            SETVECTOR3(U, A, B, C);  // I3
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 0, 1, 2);
+            SETVECTOR3(pv, 1, 0, 2);
+            z1 = 3; 
+          } else {
+            if (sC > 0) { // (00+).
+              SETVECTOR3(U, A, B, C);  // I3
+              SETVECTOR3(V, P, Q, R);  // I2
+              SETVECTOR3(pu, 0, 1, 2);
+              SETVECTOR3(pv, 0, 1, 2);
+              z1 = 3; 
+            } else { // (000)
+              // Not possible unless ABC is degenerate.
+              z1 = 4;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  s1 = orient3d(U[0], U[2], R, V[1]);  // A, C, R, Q
+  s2 = orient3d(U[1], U[2], R, V[0]);  // B, C, R, P
+  orient3dcount+=2;
+
+  if (b->epsilon) {
+    if ((s1 != 0) && iscoplanar(U[0], U[2], R, V[1], s1)) s1 = 0;
+    if ((s2 != 0) && iscoplanar(U[1], U[2], R, V[0], s2)) s2 = 0;
+  }
+
+  if (b->verbose > 2) {
+    printf("      Tri-edge-2d (%d %d %d)-(%d %d %d) (%d) (%c%c)\n",
+      pointmark(U[0]), pointmark(U[1]), pointmark(U[2]), pointmark(V[0]),
+      pointmark(V[1]), pointmark(V[2]), z1, s1>0 ? '+' : (s1<0 ? '-' : '0'),
+      s2>0 ? '+' : (s2<0 ? '-' : '0'));
+  }
+  assert(z1 != 4); // SELF_CHECK
+
+  if (s1 > 0) {
+    return 0;
+  }
+  if (s2 < 0) {
+    return 0;
+  }
+
+  if (level == 0) {
+    return 1;  // They are intersected.
+  }
+
+  if (z1 == 1) {
+    if (s1 == 0) {  // (0###)
+      // C = Q.
+      types[0] = (int) SHAREVERT;
+      pos[0] = pu[2]; // C
+      pos[1] = pv[1]; // Q
+      types[1] = (int) DISJOINT;
+    } else {
+      if (s2 == 0) { // (#0##)
+        // C = P.
+        types[0] = (int) SHAREVERT;
+        pos[0] = pu[2]; // C
+        pos[1] = pv[0]; // P
+        types[1] = (int) DISJOINT;
+      } else { // (-+##)
+        // C in [P, Q].
+        types[0] = (int) ACROSSVERT;
+        pos[0] = pu[2]; // C
+        pos[1] = pv[0]; // [P, Q]
+        types[1] = (int) DISJOINT;
+      }
+    }
+    return 1;
+  }
+
+  s3 = orient3d(U[0], U[2], R, V[0]);  // A, C, R, P
+  s4 = orient3d(U[1], U[2], R, V[1]);  // B, C, R, Q
+  orient3dcount+=2;
+      
+  if (b->epsilon) {
+    if ((s3 != 0) && iscoplanar(U[0], U[2], R, V[0], s3)) s3 = 0;
+    if ((s4 != 0) && iscoplanar(U[1], U[2], R, V[1], s4)) s4 = 0;
+  }
+
+  if (z1 == 0) {  // (tritri-03)
+    if (s1 < 0) {
+      if (s3 > 0) {
+        assert(s2 > 0); // SELF_CHECK
+        if (s4 > 0) {
+          // [P, Q] overlaps [k, l] (-+++).
+          types[0] = (int) ACROSSEDGE;
+          pos[0] = pu[2]; // [C, A]
+          pos[1] = pv[0]; // [P, Q]
+          types[1] = (int) TOUCHFACE;
+          pos[2] = 3;     // [A, B, C]
+          pos[3] = pv[1]; // Q
+        } else {
+          if (s4 == 0) {
+            // Q = l, [P, Q] contains [k, l] (-++0).
+            types[0] = (int) ACROSSEDGE;
+            pos[0] = pu[2]; // [C, A]
+            pos[1] = pv[0]; // [P, Q]
+            types[1] = (int) TOUCHEDGE;
+            pos[2] = pu[1]; // [B, C]
+            pos[3] = pv[1]; // Q
+          } else { // s4 < 0
+            // [P, Q] contains [k, l] (-++-).
+            types[0] = (int) ACROSSEDGE;
+            pos[0] = pu[2]; // [C, A]
+            pos[1] = pv[0]; // [P, Q]
+            types[1] = (int) ACROSSEDGE;
+            pos[2] = pu[1]; // [B, C]
+            pos[3] = pv[0]; // [P, Q]
+          }
+        }
+      } else {
+        if (s3 == 0) {
+          assert(s2 > 0); // SELF_CHECK
+          if (s4 > 0) {
+            // P = k, [P, Q] in [k, l] (-+0+).
+            types[0] = (int) TOUCHEDGE;
+            pos[0] = pu[2]; // [C, A]
+            pos[1] = pv[0]; // P
+            types[1] = (int) TOUCHFACE;
+            pos[2] = 3;     // [A, B, C]
+            pos[3] = pv[1]; // Q
+          } else {
+            if (s4 == 0) {
+              // [P, Q] = [k, l] (-+00).
+              types[0] = (int) TOUCHEDGE;
+              pos[0] = pu[2]; // [C, A]
+              pos[1] = pv[0]; // P
+              types[1] = (int) TOUCHEDGE;
+              pos[2] = pu[1]; // [B, C]
+              pos[3] = pv[1]; // Q
+            } else {
+              // P = k, [P, Q] contains [k, l] (-+0-).
+              types[0] = (int) TOUCHEDGE;
+              pos[0] = pu[2]; // [C, A]
+              pos[1] = pv[0]; // P
+              types[1] = (int) ACROSSEDGE;
+              pos[2] = pu[1]; // [B, C]
+              pos[3] = pv[0]; // [P, Q]
+            }
+          }
+        } else { // s3 < 0
+          if (s2 > 0) {
+            if (s4 > 0) {
+              // [P, Q] in [k, l] (-+-+).
+              types[0] = (int) TOUCHFACE;
+              pos[0] = 3;     // [A, B, C]
+              pos[1] = pv[0]; // P
+              types[1] = (int) TOUCHFACE;
+              pos[2] = 3;     // [A, B, C]
+              pos[3] = pv[1]; // Q
+            } else {
+              if (s4 == 0) {
+                // Q = l, [P, Q] in [k, l] (-+-0).
+                types[0] = (int) TOUCHFACE;
+                pos[0] = 3;     // [A, B, C]
+                pos[1] = pv[0]; // P
+                types[1] = (int) TOUCHEDGE;
+                pos[2] = pu[1]; // [B, C]
+                pos[3] = pv[1]; // Q
+              } else { // s4 < 0
+                // [P, Q] overlaps [k, l] (-+--).
+                types[0] = (int) TOUCHFACE;
+                pos[0] = 3;     // [A, B, C]
+                pos[1] = pv[0]; // P
+                types[1] = (int) ACROSSEDGE;
+                pos[2] = pu[1]; // [B, C]
+                pos[3] = pv[0]; // [P, Q]
+              }
+            }
+          } else { // s2 == 0
+            // P = l (#0##).
+            types[0] = (int) TOUCHEDGE;
+            pos[0] = pu[1]; // [B, C]
+            pos[1] = pv[0]; // P
+            types[1] = (int) DISJOINT;
+          }
+        }
+      }
+    } else { // s1 == 0
+      // Q = k (0####)
+      types[0] = (int) TOUCHEDGE;
+      pos[0] = pu[2]; // [C, A]
+      pos[1] = pv[1]; // Q
+      types[1] = (int) DISJOINT;
+    }
+  } else if (z1 == 2) {  // (tritri-23)
+    if (s1 < 0) {
+      if (s3 > 0) {
+        assert(s2 > 0); // SELF_CHECK
+        if (s4 > 0) {
+          // [P, Q] overlaps [A, l] (-+++).
+          types[0] = (int) ACROSSVERT;
+          pos[0] = pu[0]; // A
+          pos[1] = pv[0]; // [P, Q]
+          types[1] = (int) TOUCHFACE;
+          pos[2] = 3;     // [A, B, C]
+          pos[3] = pv[1]; // Q
+        } else {
+          if (s4 == 0) {
+            // Q = l, [P, Q] contains [A, l] (-++0).
+            types[0] = (int) ACROSSVERT;
+            pos[0] = pu[0]; // A
+            pos[1] = pv[0]; // [P, Q]
+            types[1] = (int) TOUCHEDGE;
+            pos[2] = pu[1]; // [B, C]
+            pos[3] = pv[1]; // Q
+          } else { // s4 < 0
+            // [P, Q] contains [A, l] (-++-).
+            types[0] = (int) ACROSSVERT;
+            pos[0] = pu[0]; // A
+            pos[1] = pv[0]; // [P, Q]
+            types[1] = (int) ACROSSEDGE;
+            pos[2] = pu[1]; // [B, C]
+            pos[3] = pv[0]; // [P, Q]
+          }
+        }
+      } else {
+        if (s3 == 0) {
+          assert(s2 > 0); // SELF_CHECK
+          if (s4 > 0) {
+            // P = A, [P, Q] in [A, l] (-+0+).
+            types[0] = (int) SHAREVERT;
+            pos[0] = pu[0]; // A
+            pos[1] = pv[0]; // P
+            types[1] = (int) TOUCHFACE;
+            pos[2] = 3;     // [A, B, C]
+            pos[3] = pv[1]; // Q
+          } else {
+            if (s4 == 0) {
+              // [P, Q] = [A, l] (-+00).
+              types[0] = (int) SHAREVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = pv[0]; // P
+              types[1] = (int) TOUCHEDGE;
+              pos[2] = pu[1]; // [B, C]
+              pos[3] = pv[1]; // Q
+            } else { // s4 < 0
+              // Q = l, [P, Q] in [A, l] (-+0-).
+              types[0] = (int) SHAREVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = pv[0]; // P
+              types[1] = (int) ACROSSEDGE;
+              pos[2] = pu[1]; // [B, C]
+              pos[3] = pv[0]; // [P, Q]
+            }
+          }
+        } else { // s3 < 0
+          if (s2 > 0) {
+            if (s4 > 0) {
+              // [P, Q] in [A, l] (-+-+).
+              types[0] = (int) TOUCHFACE;
+              pos[0] = 3;     // [A, B, C]
+              pos[1] = pv[0]; // P
+              types[0] = (int) TOUCHFACE;
+              pos[0] = 3;     // [A, B, C]
+              pos[1] = pv[1]; // Q
+            } else {
+              if (s4 == 0) {
+                // Q = l, [P, Q] in [A, l] (-+-0).
+                types[0] = (int) TOUCHFACE;
+                pos[0] = 3;     // [A, B, C]
+                pos[1] = pv[0]; // P
+                types[0] = (int) TOUCHEDGE;
+                pos[0] = pu[1]; // [B, C]
+                pos[1] = pv[1]; // Q
+              } else { // s4 < 0
+                // [P, Q] overlaps [A, l] (-+--).
+                types[0] = (int) TOUCHFACE;
+                pos[0] = 3;     // [A, B, C]
+                pos[1] = pv[0]; // P
+                types[0] = (int) ACROSSEDGE;
+                pos[0] = pu[1]; // [B, C]
+                pos[1] = pv[0]; // [P, Q]
+              }
+            }
+          } else { // s2 == 0
+            // P = l (#0##).
+            types[0] = (int) TOUCHEDGE;
+            pos[0] = pu[1]; // [B, C]
+            pos[1] = pv[0]; // P
+            types[1] = (int) DISJOINT;
+          }
+        }
+      }
+    } else { // s1 == 0
+      // Q = A (0###).
+      types[0] = (int) SHAREVERT;
+      pos[0] = pu[0]; // A
+      pos[1] = pv[1]; // Q
+      types[1] = (int) DISJOINT;
+    }
+  } else if (z1 == 3) {  // (tritri-33)
+    if (s1 < 0) {
+      if (s3 > 0) {
+        assert(s2 > 0); // SELF_CHECK
+        if (s4 > 0) {
+          // [P, Q] overlaps [A, B] (-+++).
+          types[0] = (int) ACROSSVERT;
+          pos[0] = pu[0]; // A
+          pos[1] = pv[0]; // [P, Q]
+          types[1] = (int) TOUCHEDGE;
+          pos[2] = pu[0]; // [A, B]
+          pos[3] = pv[1]; // Q
+        } else {
+          if (s4 == 0) {
+            // Q = B, [P, Q] contains [A, B] (-++0).
+            types[0] = (int) ACROSSVERT;
+            pos[0] = pu[0]; // A
+            pos[1] = pv[0]; // [P, Q]
+            types[1] = (int) SHAREVERT;
+            pos[2] = pu[1]; // B
+            pos[3] = pv[1]; // Q
+          } else { // s4 < 0
+            // [P, Q] contains [A, B] (-++-).
+            types[0] = (int) ACROSSVERT;
+            pos[0] = pu[0]; // A
+            pos[1] = pv[0]; // [P, Q]
+            types[1] = (int) ACROSSVERT;
+            pos[2] = pu[1]; // B
+            pos[3] = pv[0]; // [P, Q]
+          }
+        }
+      } else {
+        if (s3 == 0) {
+          assert(s2 > 0); // SELF_CHECK
+          if (s4 > 0) {
+            // P = A, [P, Q] in [A, B] (-+0+).
+            types[0] = (int) SHAREVERT;
+            pos[0] = pu[0]; // A
+            pos[1] = pv[0]; // P
+            types[1] = (int) TOUCHEDGE;
+            pos[2] = pu[0]; // [A, B]
+            pos[3] = pv[1]; // Q
+          } else {
+            if (s4 == 0) {
+              // [P, Q] = [A, B] (-+00).
+              types[0] = (int) SHAREEDGE;
+              pos[0] = pu[0]; // [A, B]
+              pos[1] = pv[0]; // [P, Q]
+              types[1] = (int) DISJOINT;
+            } else { // s4 < 0
+              // P= A, [P, Q] in [A, B] (-+0-).
+              types[0] = (int) SHAREVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = pv[0]; // P
+              types[1] = (int) ACROSSVERT;
+              pos[2] = pu[1]; // B
+              pos[3] = pv[0]; // [P, Q]
+            }
+          }
+        } else { // s3 < 0
+          if (s2 > 0) {
+            if (s4 > 0) {
+              // [P, Q] in [A, B] (-+-+).
+              types[0] = (int) TOUCHEDGE;
+              pos[0] = pu[0]; // [A, B]
+              pos[1] = pv[0]; // P
+              types[1] = (int) TOUCHEDGE;
+              pos[2] = pu[0]; // [A, B]
+              pos[3] = pv[1]; // Q
+            } else {
+              if (s4 == 0) {
+                // Q = B, [P, Q] in [A, B] (-+-0).
+                types[0] = (int) TOUCHEDGE;
+                pos[0] = pu[0]; // [A, B]
+                pos[1] = pv[0]; // P
+                types[1] = (int) SHAREVERT;
+                pos[2] = pu[1]; // B
+                pos[3] = pv[1]; // Q
+              } else { // s4 < 0
+                // [P, Q] overlaps [A, B] (-+--).
+                types[0] = (int) TOUCHEDGE;
+                pos[0] = pu[0]; // [A, B]
+                pos[1] = pv[0]; // P
+                types[1] = (int) ACROSSVERT;
+                pos[2] = pu[1]; // B
+                pos[3] = pv[0]; // [P, Q]
+              }
+            }
+          } else { // s2 == 0
+            // P = B (#0##).
+            types[0] = (int) SHAREVERT;
+            pos[0] = pu[1]; // B
+            pos[1] = pv[0]; // P
+            types[1] = (int) DISJOINT;
+          }
+        }
+      }
+    } else { // s1 == 0
+      // Q = A (0###).
+      types[0] = (int) SHAREVERT;
+      pos[0] = pu[0]; // A
+      pos[1] = pv[1]; // Q
+      types[1] = (int) DISJOINT;
+    }
+  }
+
+  return 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tri_edge_test()    Triangle-edge intersection test.                       //
+//                                                                           //
+// This routine takes a triangle T (with vertices A, B, C) and an edge E (P, //
+// Q) in 3D, and tests if they intersect each other.  Return 1 if they are   //
+// intersected, i.e., T \cap E is not empty, otherwise, return 0.            //
+//                                                                           //
+// If the point 'R' is not NULL, it lies strictly above the plane defined by //
+// A, B, C. It is used in test when T and E are coplanar.                    //
+//                                                                           //
+// If T1 and T2 intersect each other (return 1), they may intersect in diff- //
+// erent ways. If 'level' > 0, their intersection type will be reported in   //
+// combinations of 'types' and 'pos'.                                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::tri_edge_test(point A, point B, point C, point P, point Q, 
+  point R, int level, int *types, int *pos)
+{
+  point U[3], V[3], Ptmp;
+  int pu[3], pv[3], itmp;
+  REAL sP, sQ, s1, s2, s3;
+  int z1;
+
+  // Test the locations of P and Q with respect to ABC.
+  sP = orient3d(A, B, C, P);
+  sQ = orient3d(A, B, C, Q);
+  orient3dcount+=2;
+
+  if (b->epsilon > 0) {
+    if ((sP != 0) && iscoplanar(A, B, C, P, sP)) sP = 0;
+    if ((sQ != 0) && iscoplanar(A, B, C, Q, sQ)) sQ = 0;
+  }
+
+  if (b->verbose > 2) {
+    printf("      Tri-edge (%d %d %d)-(%d %d) (%c%c).\n", pointmark(A),
+      pointmark(B), pointmark(C), pointmark(P), pointmark(Q),
+      sP>0 ? '+' : (sP<0 ? '-' : '0'), sQ>0 ? '+' : (sQ<0 ? '-' : '0'));
+  }
+  triedgcount++;
+
+  if (sP < 0) {
+    if (sQ < 0) { // (--) disjoint
+      return 0;
+    } else {
+      if (sQ > 0) { // (-+)
+        SETVECTOR3(U, A, B, C);
+        SETVECTOR3(V, P, Q, R);
+        SETVECTOR3(pu, 0, 1, 2);
+        SETVECTOR3(pv, 0, 1, 2);
+        z1 = 0;
+      } else { // (-0)
+        SETVECTOR3(U, A, B, C);
+        SETVECTOR3(V, P, Q, R);
+        SETVECTOR3(pu, 0, 1, 2);
+        SETVECTOR3(pv, 0, 1, 2);
+        z1 = 1;
+      }
+    }
+  } else {
+    if (sP > 0) { // (+-)
+      if (sQ < 0) {
+        SETVECTOR3(U, A, B, C);
+        SETVECTOR3(V, Q, P, R);  // P and Q are flipped.
+        SETVECTOR3(pu, 0, 1, 2);
+        SETVECTOR3(pv, 1, 0, 2);
+        z1 = 0;
+      } else {
+        if (sQ > 0) { // (++) disjoint
+          return 0;
+        } else { // (+0)
+          SETVECTOR3(U, B, A, C); // A and B are flipped.
+          SETVECTOR3(V, P, Q, R);
+          SETVECTOR3(pu, 1, 0, 2);
+          SETVECTOR3(pv, 0, 1, 2);
+          z1 = 1;
+        }
+      }
+    } else { // sP == 0
+      if (sQ < 0) { // (0-)
+        SETVECTOR3(U, A, B, C);
+        SETVECTOR3(V, Q, P, R);  // P and Q are flipped.
+        SETVECTOR3(pu, 0, 1, 2);
+        SETVECTOR3(pv, 1, 0, 2);
+        z1 = 1;
+      } else {
+        if (sQ > 0) { // (0+)
+          SETVECTOR3(U, B, A, C);  // A and B are flipped.
+          SETVECTOR3(V, Q, P, R);  // P and Q are flipped.
+          SETVECTOR3(pu, 1, 0, 2);
+          SETVECTOR3(pv, 1, 0, 2);
+          z1 = 1;
+        } else { // (00)
+          // A, B, C, P, and Q are coplanar.
+          z1 = 2;
+        }
+      }
+    }
+  }
+
+  if (z1 == 2) {
+    // The triangle and the edge are coplanar.
+    return tri_edge_2d(A, B, C, P, Q, R, level, types, pos);
+  }
+
+  s1 = orient3d(U[0], U[1], V[0], V[1]); orient3dcount++;
+  if (b->epsilon) {
+    if ((s1 != 0) && iscoplanar(U[0], U[1], V[0], V[1], s1)) s1 = 0;
+  }
+  if (s1 < 0) {
+    return 0;
+  }
+
+  s2 = orient3d(U[1], U[2], V[0], V[1]); orient3dcount++;
+  if (b->epsilon) {
+    if ((s2 != 0) && iscoplanar(U[1], U[2], V[0], V[1], s2)) s2 = 0;
+  }
+  if (s2 < 0) {
+    return 0;
+  }
+
+  s3 = orient3d(U[2], U[0], V[0], V[1]); orient3dcount++;
+  if (b->epsilon) {
+    if ((s3 != 0) && iscoplanar(U[2], U[0], V[0], V[1], s3)) s3 = 0;
+  }
+  if (s3 < 0) {
+    return 0;
+  }
+
+  if (b->verbose > 2) {
+    printf("      Tri-edge (%d %d %d)-(%d %d) (%c%c%c).\n", pointmark(U[0]),
+      pointmark(U[1]), pointmark(U[2]), pointmark(V[0]), pointmark(V[1]),
+      s1>0 ? '+' : (s1<0 ? '-' : '0'), s2>0 ? '+' : (s2<0 ? '-' : '0'),
+      s3>0 ? '+' : (s3<0 ? '-' : '0'));
+  }
+
+  if (level == 0) {
+    return 1;  // The are intersected.
+  }
+
+  types[1] = (int) DISJOINT; // No second intersection point.
+
+  if (z1 == 0) {
+    if (s1 > 0) {
+      if (s2 > 0) {
+        if (s3 > 0) { // (+++)
+          // [P, Q] passes interior of [A, B, C].
+          types[0] = (int) ACROSSFACE;
+          pos[0] = 3;  // interior of [A, B, C]
+          pos[1] = 0;  // [P, Q]
+        } else { // s3 == 0 (++0)
+          // [P, Q] intersects [C, A].
+          types[0] = (int) ACROSSEDGE;
+          pos[0] = pu[2];  // [C, A]
+          pos[1] = 0;  // [P, Q]
+        }
+      } else { // s2 == 0
+        if (s3 > 0) { // (+0+)
+          // [P, Q] intersects [B, C].
+          types[0] = (int) ACROSSEDGE;
+          pos[0] = pu[1];  // [B, C]
+          pos[1] = 0;  // [P, Q]
+        } else { // s3 == 0 (+00)
+          // [P, Q] passes C.
+          types[0] = (int) ACROSSVERT;
+          pos[0] = pu[2];  // C
+          pos[1] = 0;  // [P, Q]
+        }
+      }
+    } else { // s1 == 0
+      if (s2 > 0) {
+        if (s3 > 0) { // (0++)
+          // [P, Q] intersects [A, B].
+          types[0] = (int) ACROSSEDGE;
+          pos[0] = pu[0];  // [A, B]
+          pos[1] = 0;  // [P, Q]
+        } else { // s3 == 0 (0+0)
+          // [P, Q] passes A.
+          types[0] = (int) ACROSSVERT;
+          pos[0] = pu[0];  // A
+          pos[1] = 0;  // [P, Q]
+        }
+      } else { // s2 == 0
+        if (s3 > 0) { // (00+)
+          // [P, Q] passes B.
+          types[0] = (int) ACROSSVERT;
+          pos[0] = pu[1];  // B
+          pos[1] = 0;  // [P, Q]
+        } else { // s3 == 0 (000)
+          // Impossible.
+          assert(0);
+        }
+      }
+    }
+  } else { // z1 == 1
+    if (s1 > 0) {
+      if (s2 > 0) {
+        if (s3 > 0) { // (+++)
+          // Q lies in [A, B, C].
+          types[0] = (int) TOUCHFACE;
+          pos[0] = 0; // [A, B, C]
+          pos[1] = pv[1]; // Q
+        } else { // s3 == 0 (++0)
+          // Q lies on [C, A].
+          types[0] = (int) TOUCHEDGE;
+          pos[0] = pu[2]; // [C, A]
+          pos[1] = pv[1]; // Q
+        }
+      } else { // s2 == 0
+        if (s3 > 0) { // (+0+)
+          // Q lies on [B, C].
+          types[0] = (int) TOUCHEDGE;
+          pos[0] = pu[1]; // [B, C]
+          pos[1] = pv[1]; // Q
+        } else { // s3 == 0 (+00)
+          // Q = C.
+          types[0] = (int) SHAREVERT;
+          pos[0] = pu[2]; // C
+          pos[1] = pv[1]; // Q
+        }
+      }
+    } else { // s1 == 0
+      if (s2 > 0) {
+        if (s3 > 0) { // (0++)
+          // Q lies on [A, B].
+          types[0] = (int) TOUCHEDGE;
+          pos[0] = pu[0]; // [A, B]
+          pos[1] = pv[1]; // Q
+        } else { // s3 == 0 (0+0)
+          // Q = A.
+          types[0] = (int) SHAREVERT;
+          pos[0] = pu[0]; // A
+          pos[1] = pv[1]; // Q
+        }
+      } else { // s2 == 0
+        if (s3 > 0) { // (00+)
+          // Q = B.
+          types[0] = (int) SHAREVERT;
+          pos[0] = pu[1]; // B
+          pos[1] = pv[1]; // Q
+        } else { // s3 == 0 (000)
+          // Impossible.
+          assert(0);
+        }
+      }
+    }
+  }
+
+  return 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tri_tri_2d()    Triangle-triangle coplanar intersection test.             //
+//                                                                           //
+// This routine takes two triangles T1 (with vertices A, B, C) and T2 (with  //
+// vertices P, Q, R) in 3D, and T1 and T2 are coplanar, and tests if they    //
+// intersect each other.  Return 1 if they intersect, ie., T1 \cap T2 is not //
+// empty, otherwise, return 0.                                               //
+//                                                                           //
+// If 'O' is not NULL, it lies strictly above A, B, C.                       //
+//                                                                           //
+// If T1 and T2 intersect (return 1) and if 'level' > 0,                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::tri_tri_2d(point A, point B, point C, point P, point Q, 
+  point R, point O, int level, int *types, int *pos)
+{
+  point U[3], V[3];
+  int pu[3], pv[3], pe[3];
+  REAL s1, s2, s3, s4;
+  REAL s5, s6 ,s7, s8, s9;
+  int z1;
+
+  if (O == NULL) {
+    REAL n[3], len;
+    // Calculate a lift point, saved in dummypoint.
+    facenormal(A, B, C, n, 1);
+    len = sqrt(DOT(n, n));
+    n[0] /= len;
+    n[1] /= len;
+    n[2] /= len;
+    len = DIST(A, B);
+    len += DIST(B, C);
+    len += DIST(C, A);
+    len /= 3.0;
+    O = dummypoint;
+    O[0] = A[0] + len * n[0];
+    O[1] = A[1] + len * n[1];
+    O[2] = A[2] + len * n[2];
+  }
+
+  s1 = orient3d(A, B, O, P);
+  s2 = orient3d(B, C, O, P);
+  s3 = orient3d(C, A, O, P);
+  orient3dcount+=3;
+
+  if (b->epsilon) {
+    if ((s1 != 0) && iscoplanar(A, B, O, P, s1)) s1 = 0;
+    if ((s2 != 0) && iscoplanar(B, C, O, P, s2)) s2 = 0;
+    if ((s3 != 0) && iscoplanar(C, A, O, P, s3)) s3 = 0;
+  }
+
+  if (b->verbose > 2) {
+    printf("      Tri-tri-2d (%d %d %d)-(%d %d %d) (%c%c%c)\n", pointmark(A),
+      pointmark(B), pointmark(C), pointmark(P), pointmark(Q), pointmark(R),
+      s1>0 ? '+' : (s1 < 0 ? '-' : '0'), s2>0 ? '+' : (s2<0 ? '-' : '0'),
+      s3>0 ? '+' : (s3<0 ? '-' : '0'));
+  }
+
+  if (s1 < 0) {
+    if (s2 < 0) {
+      if (s3 < 0) { // (---)
+        assert(0); // Not possible.
+      } else {
+        if (s3 > 0) { // (--+)
+          SETVECTOR3(U, B, C, A);  // PT = ST x ST
+          SETVECTOR3(pu, 1, 2, 0);
+          z1 = 2;
+        } else { // (--0)
+          assert(0); // Not possible.
+        }
+      }
+    } else {
+      if (s2 > 0) {
+        if (s3 < 0) { // (-+-)
+          SETVECTOR3(U, A, B, C);  // I3
+          SETVECTOR3(pu, 0, 1, 2);
+          z1 = 2;
+        } else {
+          if (s3 > 0) { // (-++)
+            SETVECTOR3(U, A, B, C);  // I3
+            SETVECTOR3(pu, 0, 1, 2);
+            z1 = 1;
+          } else { // (-+0)
+            SETVECTOR3(U, A, B, C);  // I3
+            SETVECTOR3(pu, 0, 1, 2);
+            z1 = 4;
+          }
+        }
+      } else { // s2 == 0
+        if (s3 < 0) { //(-0-)
+          assert(0); // Not possible
+        } else {
+          if (s3 > 0) { // (-0+)
+            SETVECTOR3(U, B, C, A);  // PT = ST x ST
+            SETVECTOR3(pu, 1, 2, 0);
+            z1 = 3;
+          } else { // (-00)
+            assert(0); // Not possible
+          }
+        }
+      }
+    }
+  } else {
+    if (s1 > 0) {
+      if (s2 < 0) {
+        if (s3 < 0) { // (+--)
+          SETVECTOR3(U, C, A, B);  // PT = ST
+          SETVECTOR3(pu, 2, 0, 1);
+          z1 = 2;
+        } else {
+          if (s3 > 0) { // (+-+)
+            SETVECTOR3(U, B, C, A);  // PT = ST x ST
+            SETVECTOR3(pu, 1, 2, 0);
+            z1 = 1;
+          } else { // (+-0)
+            SETVECTOR3(U, C, A, B);  // PT = ST
+            SETVECTOR3(pu, 2, 0, 1);
+            z1 = 3;
+          }
+        }
+      } else { 
+        if (s2 > 0) {
+          if (s3 < 0) { // (++-)
+            SETVECTOR3(U, C, A, B);  // PT = ST
+            SETVECTOR3(pu, 2, 0, 1);
+            z1 = 1;
+          } else {
+            if (s3 > 0) { // (+++)
+              SETVECTOR3(U, A, B, C);  // I3
+              SETVECTOR3(pu, 0, 1, 2);
+              z1 = 7;
+            } else { // (++0)
+              SETVECTOR3(U, C, A, B);  // PT = ST
+              SETVECTOR3(pu, 2, 0, 1);
+              z1 = 5;
+            }
+          }
+        } else { // s2 == 0
+          if (s3 < 0) { // (+0-)
+            SETVECTOR3(U, B, C, A);  // PT = ST x ST
+            SETVECTOR3(pu, 1, 2, 0);
+            z1 = 4;
+          } else {
+            if (s3 > 0) { // (+0+)
+              SETVECTOR3(U, B, C, A);  // PT = ST x ST
+              SETVECTOR3(pu, 1, 2, 0);
+              z1 = 5;
+            } else { // (+00)
+              SETVECTOR3(U, C, A, B);  // PT = ST
+              SETVECTOR3(pu, 2, 0, 1);
+              z1 = 6;
+            }
+          }
+        }
+      }
+    } else { // s1 == 0
+      if (s2 < 0) {
+        if (s3 < 0) { // (0--)
+          assert(0); // Not possible
+        } else {
+          if (s3 > 0) { // (0-+)
+            SETVECTOR3(U, B, C, A);  // PT = ST x ST
+            SETVECTOR3(pu, 1, 2, 0);
+            z1 = 4;
+          } else { // (0-0)
+            assert(0); // Not possible
+          }
+        }
+      } else {
+        if (s2 > 0) {
+          if (s3 < 0) { // (0+-)
+            SETVECTOR3(U, A, B, C);  // I3
+            SETVECTOR3(pu, 0, 1, 2);
+            z1 = 3;
+          } else {
+            if (s3 > 0) { // (0++)
+              SETVECTOR3(U, A, B, C);  // I3
+              SETVECTOR3(pu, 0, 1, 2);
+              z1 = 5;
+            } else { // (0+0)
+              SETVECTOR3(U, A, B, C);  // I3
+              SETVECTOR3(pu, 0, 1, 2);
+              z1 = 6;
+            }
+          }
+        } else { // s2 == 0
+          if (s3 < 0) { // (00-)
+            assert(0); // Not possible
+          } else {
+            if (s3 > 0) { // (00+)
+              SETVECTOR3(U, B, C, A);  // PT = ST x ST
+              SETVECTOR3(pu, 1, 2, 0);
+              z1 = 6;
+            } else { // (000)
+              assert(0); // Not possible
+            }
+          }
+        }
+      }
+    }
+  }
+
+  if (b->verbose > 2) {
+    printf("      Tri-tri-2d (%d %d %d)-(%d) z1(%d)\n", pointmark(U[0]), 
+      pointmark(U[1]), pointmark(U[2]), pointmark(P), z1);
+  }
+
+  if (z1 == 5) { // P in [A, B]
+    if (level > 0) {
+      s4 = orient3d(U[0], U[1], O, V[1]); // A, B, Q
+      if (s4 < 0) {
+        s5 = orient3d(U[0], U[1], O, V[2]); // A, B, R
+        if (s5 < 0) {
+          // P touches [A, B]
+          types[0] = (int) TOUCHEDGE;
+          pos[0] = pu[0]; // [A, B]
+          pos[1] = 0; // P
+          types[1] = (int) DISJOINT;
+        } else { // s5 >= 0
+          // [R, P] intersects [A, B, C]
+          types[0] = (int) EDGETRIINT;
+          pos[0] = 3; // [A, B, C]
+          pos[1] = 2; // [R, P]
+          types[1] = (int) DISJOINT;
+        }
+      } else { // s4 >= 0
+        // [P, Q] intersects [A, B, C]
+        types[0] = (int) EDGETRIINT;
+        pos[0] = 3; // [A, B, C]
+        pos[1] = 0; // [P, Q]
+        types[1] = (int) DISJOINT;
+      }
+    }
+    return 1;
+  }
+
+  if (z1 == 7) { // P in [A, B, C]
+    if (level > 0) {
+      // [P, Q] intersects [A, B, C]
+      types[0] = (int) EDGETRIINT;
+      pos[0] = 3; // [A, B, C]
+      pos[1] = 0; // [P, Q]
+      types[1] = (int) DISJOINT;
+    }
+    return 1;
+  }
+
+  // Orient P, Q, R to be CCW wrt O, keep P as origin
+  s4 = orient3d(P, Q, R, O);
+  orient3dcount++;
+  if (b->epsilon) {
+    if ((s4 != 0) && iscoplanar(P, Q, R, O, s4)) s4 = 0;
+  }
+
+  assert(s4 != 0);
+  if (s4 < 0) {
+    SETVECTOR3(V, P, Q, R);
+    SETVECTOR3(pv, 0, 1, 2);
+    SETVECTOR3(pe, 0, 1, 2);
+  } else {
+    SETVECTOR3(V, P, R, Q);
+    SETVECTOR3(pv, 0, 2, 1);
+    SETVECTOR3(pe, 2, 1, 0);
+  }
+
+  //////////////////////////// z1 == 1 ///////////////////////////////////////
+
+  if (z1 == 1) {
+
+    s5 = orient3d(U[0], U[1], O, V[1]); // A, B, Q
+    if (s5 < 0) {
+      s6 = orient3d(U[0], U[1], O, V[2]); // A, B, R
+      if (s6 < 0) {
+        return 0;
+      } else { // s6 >= 0
+        s7 = orient3d(V[1], V[2], O, U[0]); // Q, R, A
+        if (s7 < 0) {
+          return 0;
+        } else { // s7 >= 0
+          s8 = orient3d(V[0], U[1], O, V[2]); // P, B, R
+          if (s8 >= 0) { 
+            // z2 = 1;
+          } else {
+            return 0;
+          }
+          // NOTE: in the reference, the above two cases are reversed.
+          // It should be an error by the authors.
+        }
+      }
+    } else { // s5 >= 0
+      s6 = orient3d(U[0], V[0], O, V[1]); // A, P, Q
+      if (s6 < 0) {
+        return 0;
+      } else { // s6 >= 0
+        s7 = orient3d(V[0], U[1], O, V[1]); // P, B, Q
+        if (s7 < 0) {
+          s8 = orient3d(V[0], U[1], O, V[2]); // P, B, R
+          if (s8 < 0) {
+            return 0;
+          } else { // s8 >= 0
+            s9 = orient3d(V[1], V[2], O, U[1]); // Q, R, B
+            if (s9 < 0) {
+              return 0;
+            } else { // s9 >= 0
+              // z2 = 2;
+            }
+          }
+        } else { // s7 >= 0
+          // z2 = 3;
+        }
+      }
+    }
+
+    if (level == 0) {
+      return 1;
+    }
+
+    if (s5 < 0) {
+      if (s6 > 0) { // (tritri2d-R1-1)
+        if (s7 > 0) {
+          if (s8 > 0) {
+            // [A, B] intersects [P, Q, R]
+            types[0] = (int) EDGETRIINT;
+            pos[0] = pu[0]; // [A, B]
+            pos[1] = 3; // [P, Q, R]
+            types[1] = (int) DISJOINT;
+          } else { // s8 == 0
+            // [R, P] passes B
+            types[0] = (int) ACROSSVERT;
+            pos[0] = pu[1]; // B
+            pos[1] = pe[2]; // [R, P]
+            types[1] = (int) DISJOINT;
+          }
+        } else { // s7 == 0
+          assert(s8 > 0);
+          // [Q, R] passes A.
+          types[0] = (int) ACROSSVERT;
+          pos[0] = pu[0]; // A
+          pos[1] = pe[1]; // [Q, R]
+          types[1] = (int) DISJOINT;
+        }
+      } else { // s6 == 0 // (tritri2d-R1-1a)
+        if (s7 > 0) {
+          if (s8 > 0) {
+            // R touches [A, B]
+            types[0] = (int) TOUCHEDGE;
+            pos[0] = pu[0]; // [A, B]
+            pos[1] = pv[2]; // R
+            types[1] = (int) DISJOINT;
+          } else { // s8 == 0
+            // R = B
+            types[0] = (int) SHAREVERT;
+            pos[0] = pu[1]; // B
+            pos[1] = pv[2]; // R
+            types[1] = (int) DISJOINT;
+          }
+        } else { // s7 == 0
+          assert(s8 > 0);
+          // R = A
+          types[0] = (int) SHAREVERT;
+          pos[0] = pu[0]; // A
+          pos[1] = pv[2]; // R
+          types[1] = (int) DISJOINT;
+        }
+      }
+    } else { // s5 >= 0
+      if (s5 > 0) {
+        if (s6 > 0) {
+          if (s7 < 0) { // (tritri2d-R1-2)
+            if (s8 > 0) {
+              if (s9 > 0) {
+                // [A, B] intersects [P, Q, R]
+                types[0] = (int) EDGETRIINT;
+                pos[0] = pu[0]; // [A, B]
+                pos[1] = 3; // [P, Q, R]
+                types[1] = (int) DISJOINT;
+              } else { // s9 == 0
+                // [Q, R] passes B
+                types[0] = (int) ACROSSVERT;
+                pos[0] = pu[1]; // B
+                pos[1] = pe[1]; // [Q, R]
+                types[1] = (int) DISJOINT;
+              }
+            } else { // s8 == 0
+              if (s9 > 0) {
+                // [R, P] passes B
+                types[0] = (int) ACROSSVERT;
+                pos[0] = pu[1]; // B
+                pos[1] = pe[2]; // [R, P]
+                types[1] = (int) DISJOINT;
+              } else { // s9 == 0
+                // R = B
+                types[0] = (int) SHAREVERT;
+                pos[0] = pu[1]; // B
+                pos[1] = pv[2]; // R
+                types[1] = (int) DISJOINT;
+              }
+            }
+          } else { // s7 >= 0 (tritri2d-R1-3)
+            if (s7 > 0) {
+              // [P, Q] intersects [A, B, C]
+              // [A, B] intersects [P, Q, R]
+              types[0] = (int) EDGETRIINT;
+              pos[0] = pu[0]; // [A, B]
+              pos[1] = 3; // [P, Q, R]
+              types[1] = (int) DISJOINT;
+            } else { // s7 == 0
+              // [P, Q] passes B
+              // [A, B] intersects [P, Q, R]
+              types[0] = (int) EDGETRIINT;
+              pos[0] = pu[0]; // [A, B]
+              pos[1] = 3; // [P, Q, R]
+              types[1] = (int) DISJOINT;
+            }
+          }
+        } else { // s6 == 0 (tritri2d-R1-3 bottom)
+          // [P, Q] passes A
+          types[0] = (int) ACROSSVERT;
+          pos[0] = pu[0]; // A
+          pos[1] = pe[0]; // [P, Q]
+          types[1] = (int) DISJOINT;
+        }
+      } else { // s5 == 0
+        if (s6 > 0) {
+          if (s7 < 0) { // (tritri2d-R1-2a)
+            if (s8 > 0) {
+              assert(s9 > 0);
+              // [A, B] intersects [P, Q, R]
+              types[0] = (int) EDGETRIINT;
+              pos[0] = pu[0]; // [A, B]
+              pos[1] = 3; // [P, Q, R]
+              types[1] = (int) DISJOINT;
+            } else { // s8 == 0
+              assert(s9 > 0);
+              // [R, P] passes B
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[1]; // B
+              pos[1] = pe[2]; // [R, P]
+              types[1] = (int) DISJOINT;
+            }
+          } else { // s7 >= 0 (tritri2d-R1-3a)
+            if (s7 > 0) {
+              // [A, B] intersects [P, Q, R]
+              types[0] = (int) EDGETRIINT;
+              pos[0] = pu[0]; // [A, B]
+              pos[1] = 3; // [P, Q, R]
+              types[1] = (int) DISJOINT;
+            } else { // s7 == 0
+              s8 = orient3d(U[0], U[1], O, V[2]); // A, B, R
+              if (s8 < 0) {
+                // Q = B
+                types[0] = (int) SHAREVERT;
+                pos[0] = pu[1]; // B
+                pos[1] = pv[1]; // Q
+                types[1] = (int) DISJOINT;
+              } else {
+                if (s8 > 0) {
+                  // [A, B] intersects [P, Q, R]
+                  types[0] = (int) EDGETRIINT;
+                  pos[0] = pu[0]; // [A, B]
+                  pos[1] = 3; // [P, Q, R]
+                  types[1] = (int) DISJOINT;
+                } else { // s8 == 0
+                  s9 = orient3d(U[0], V[0], O, V[2]); // A, P, R
+                  if (s9 != 0) {
+                    // [Q, R] intersects [A, B, C]
+                    // [A, B] intersects [P, Q, R]
+                    types[0] = (int) EDGETRIINT;
+                    pos[0] = pu[0]; // [A, B]
+                    pos[1] = 3; // [P, Q, R]
+                    types[1] = (int) DISJOINT;
+                  } else { // s9 == 0
+                    // [Q, R] = [A, B]
+                    types[0] = (int) SHAREEDGE;
+                    pos[0] = pu[0]; // [A, B]
+                    pos[1] = pe[1]; // [Q, R]
+                    types[1] = (int) DISJOINT;
+                  }
+                }
+              }
+            }
+          }
+        } else { // s6 == 0 (tritri2d-R1-3b)
+          // Q = A
+          types[0] = (int) SHAREVERT;
+          pos[0] = pu[0]; // A
+          pos[1] = pv[1]; // Q
+          types[1] = (int) DISJOINT;
+        }
+      }
+    }
+
+    return 1;
+  } // z1 == 1
+
+  //////////////////////////// z1 == 2, 3, 4 /////////////////////////////////
+
+  if ((z1 == 2) || (z1 == 3) || (z1 == 4)) {
+
+    s5 = orient3d(U[0], U[1], O, V[1]); // A, B, Q
+    if (s5 < 0) {
+      s6 = orient3d(U[0], U[1], O, V[2]); // A, B, R
+      if (s6 < 0) {
+        return 0;
+      } else { // s6 >= 0
+        s7 = orient3d(V[1], V[2], O, U[0]); // Q, R, A
+        if (s7 < 0) {
+          s8 = orient3d(V[1], V[2], O, U[2]); // Q, R, C
+          if (s8 < 0) {
+            return 0;
+          } else {
+            s9 = orient3d(U[2], U[0], O, V[2]); // C, A, R
+            if (s9 < 0) {
+              return 0;
+            } else {
+              // z2 = 1;
+            }
+          }
+        } else { // s7 >= 0
+          s8 = orient3d(V[2], V[0], O, U[1]); // R, P, B
+          if (s8 < 0) {
+            return 0;
+          } else {
+            // z2 = 2;
+          }
+        }
+      }
+    } else { // s5 >= 0
+      s6 = orient3d(U[2], U[0], O, V[1]); // C, A, Q
+      if (s6 < 0) {
+        s7 = orient3d(V[0], U[2], O, V[1]); // P, C, Q
+        if (s7 > 0) { 
+          // Comments! To my analysis, it should be s7 >= 0.
+          // See fig. tritri2d-R2-3a
+          return 0;
+        } else { // s7 <= 0
+          s8 = orient3d(U[2], U[0], O, V[2]); // C, A, R
+          if (s8 < 0) {
+            return 0;
+          } else { // s8 >= 0
+            s9 = orient3d(V[1], V[2], O, U[2]); // Q, R, C
+            if (s9 < 0) {
+              return 0;
+            } else {
+              // z2 = 3;
+            }
+          }
+        }
+      } else { // s6 >= 0
+        s7 = orient3d(V[0], U[1], O, V[1]); // P, B, Q
+        if (s7 < 0) {
+          s8 = orient3d(V[0], U[1], O, V[2]); // P, B, R
+          if (s8 < 0) {
+            return 0;
+          } else { // s8 >= 0
+            s9 = orient3d(U[0], U[1], O, V[2]); // A, B, R
+            if (s9 < 0) {
+              return 0;
+            } else {
+              // z2 = 4;
+            }
+          }
+        } else { // s7 >= 0
+          s8 = orient3d(V[0], U[2], O, V[1]); // P, C, Q
+          if (s8 > 0) {
+            return 0;
+          } else { // s8 <= 0
+            // z2 = 5;
+          }
+        }
+      }
+    }
+
+    if (level == 0) {
+      return 1;
+    }
+
+    if (s5 < 0) { 
+      if (s6 > 0) {
+        if (s7 < 0) { // (tritri2d-R2-1)
+          if (s8 > 0) {
+            if (s9 > 0) { // top-left
+              // [Q, R] intersects [A, B, C]
+              types[0] = (int) TRIEDGEINT;
+              pos[0] = 3; // [A, B, C]
+              pos[1] = pe[1]; // [Q, R]
+              types[1] = (int) DISJOINT;
+            } else { // s9 == 0 top-right
+              // R touches [C, A]
+              types[0] = (int) TOUCHEDGE;
+              pos[0] = pu[2]; // [C, A]
+              pos[1] = pv[2]; // R
+              types[1] = (int) DISJOINT;
+            }
+          } else { // s8 == 0 
+            if (s9 > 0) { // bot-left
+              // [Q, R] passes C.
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[2]; // C
+              pos[1] = pe[1]; // [Q, R]
+              types[1] = (int) DISJOINT;
+            } else { // s9 == 0 bot-right
+              // R = C
+              types[0] = (int) SHAREVERT;
+              pos[0] = pu[2]; // C
+              pos[1] = pv[2]; // R
+              types[1] = (int) DISJOINT;
+            }
+          }
+        } else { // s7 >= 0 (tritri2d-R2-2)
+          if (s7 > 0) {
+            if (s8 > 0) { 
+              // [A, B] intersects [P, Q, R]
+              types[0] = (int) EDGETRIINT;
+              pos[0] = pu[0]; // [A, B]
+              pos[1] = 3; // [P, Q, R]
+              types[1] = (int) DISJOINT;
+            } else { // s8 == 0 (s6 > 0) R != B (top-right)
+              if ((z1 == 2) || (z1 == 4)) {
+                // [R, P] passes B
+                types[0] = (int) ACROSSVERT;
+                pos[0] = pu[1]; // B
+                pos[1] = pe[2]; // [R, P]
+                types[1] = (int) DISJOINT;
+              } else { // z1 == 3 (tritri2d-R3-2)
+                // [R, P] intersects [A, B, C]
+                // [A, B] intersects [P, Q, R]
+                types[0] = (int) EDGETRIINT;
+                pos[0] = pu[0]; // [A, B]
+                pos[1] = 3; // [P, Q, R]
+                types[1] = (int) DISJOINT;
+              }
+            }
+          } else { // s7 == 0 (s6 > 0) R != A (bottom)
+            assert(s8 > 0); 
+            s9 = orient3d(V[1], V[2], O, U[2]); // Q, R, C
+            // Note: if z1 == 4, it must be s9 < 0.
+            if (s9 < 0) {
+              // [Q, R] passes A
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = pe[1]; // [Q, R]
+              types[1] = (int) DISJOINT;
+            } else { // s9 >= 0
+              // [A, C] intersects [P, Q, R]
+              types[0] = (int) EDGETRIINT;
+              pos[0] = pu[2]; // [C, A]
+              pos[1] = 3; // [P, Q, R]
+              types[1] = (int) DISJOINT;
+            }
+          }
+        }
+      } else { // s6 == 0 (tritri2d-R2-2a)
+        assert(s7 >= 0); // s7 < 0 is not possible
+        if (s7 > 0) {
+          if ((z1 == 2) || (z1 == 4)) {
+            if (s8 > 0) {
+              // R touches [A, B]
+              types[0] = (int) TOUCHEDGE;
+              pos[0] = pu[0]; // [A, B]
+              pos[1] = pv[2]; // R
+              types[1] = (int) DISJOINT;
+            } else { // s8 == 0
+              // R = B
+              types[0] = (int) SHAREVERT;
+              pos[0] = pu[1]; // B
+              pos[1] = pv[2]; // R
+              types[1] = (int) DISJOINT;
+            }
+          } else { // z1 == 3 (tritri2d-R3-2a)
+            // [R, P] intersects [A, B, C]
+            // [A, B] intersects [P, Q, R]
+            types[0] = (int) EDGETRIINT;
+            pos[0] = pu[0]; // [A, B]
+            pos[1] = 3; // [P, Q, R]
+            types[1] = (int) DISJOINT;
+          }
+        } else { // s7 == 0
+          // R = A
+          types[0] = (int) SHAREVERT;
+          pos[0] = pu[0]; // A
+          pos[1] = pv[2]; // R
+          types[1] = (int) DISJOINT;
+        }
+      }
+    } else { // s5 >= 0
+      if (s5 > 0) {
+        if (s6 < 0) {
+          if (s7 < 0) { // (tritri2d-R2-3)
+            if (s8 > 0) {
+              if (s9 > 0) { 
+                // [C, A] intersects [P, Q, R]
+                types[0] = (int) EDGETRIINT;
+                pos[0] = pu[2]; // [C, A]
+                pos[1] = 3; // [P, Q, R]
+                types[1] = (int) DISJOINT;
+              } else { // s9 == 0
+                // [Q, R] passes C
+                types[0] = (int) ACROSSVERT;
+                pos[0] = pu[2]; // C
+                pos[1] = pe[1]; // [Q, R]
+                types[1] = (int) DISJOINT;
+              }
+            } else { // s8 == 0
+              if (s9 > 0) {
+                // R touches [C, A]
+                types[0] = (int) TOUCHEDGE;
+                pos[0] = pu[2]; // [C, A]
+                pos[1] = pv[2]; // R
+                types[1] = (int) DISJOINT;
+              } else { // s9 == 0
+                // R = C
+                types[0] = (int) SHAREVERT;
+                pos[0] = pu[2]; // C
+                pos[1] = pv[2]; // R
+                types[1] = (int) DISJOINT;
+              }
+            }
+          } else { // s7 == 0 (see tritri2d-R2-3a)
+            // Not possible be intersecting!
+            assert(0);
+          }
+        } else { // s6 >= 0
+          if (s6 > 0) {
+            if (s7 < 0) { // (tritri2d-R2-4)
+              if (s8 > 0) { // (top-left)
+                // [A, B] intersects [P, Q, R]
+                types[0] = (int) EDGETRIINT;
+                pos[0] = pu[0]; // [A, B]
+                pos[1] = 3; // [P, Q, R]
+                types[1] = (int) DISJOINT;
+              } else { // s8 == 0
+                if (s9 > 0) { // (top-right)
+                  // [R, P] passes B
+                  types[0] = (int) ACROSSVERT;
+                  pos[0] = pu[1]; // B
+                  pos[1] = pe[2]; // [R, P]
+                  types[1] = (int) DISJOINT;
+                } else { // s9 == 0 (bot-left)
+                  // R = B
+                  types[0] = (int) SHAREVERT;
+                  pos[0] = pu[1]; // B
+                  pos[1] = pv[2]; // R
+                  types[1] = (int) DISJOINT;
+                }
+              }
+            } else { // s7 >= 0
+              if (s7 > 0) { // (tritri2d-R2-5)
+                if (s8 < 0) { // (top-left)
+                  // [P, Q] intersects [A, B, C]
+                  types[0] = (int) TRIEDGEINT;
+                  pos[0] = 3; // [A, B, C]
+                  pos[1] = pe[0]; // [P, Q]
+                  types[1] = (int) DISJOINT;
+                } else { // s8 == 0 (top-right)
+                  if ((z1 == 2) || (z1 == 3)) {
+                    // [P, Q] passes C
+                    types[0] = (int) ACROSSVERT;
+                    pos[0] = pu[2]; // C
+                    pos[1] = pe[0]; // [P, Q]
+                    types[1] = (int) DISJOINT;
+                  } else { // z1 == 4 (tritri2d-R4-5)
+                    // [P, Q] intersects [A, B, C]
+                    // [C, A] intersects [P, Q, R]
+                    types[0] = (int) EDGETRIINT;
+                    pos[0] = pu[2]; // [C, A]
+                    pos[1] = 3; // [P, Q, R]
+                    types[1] = (int) DISJOINT;
+                  }
+                }
+              } else { // s7 == 0 (bot-left)
+                // [A, B] intersects [P, Q, R]
+                types[0] = (int) EDGETRIINT;
+                pos[0] = pu[0]; // [A, B]
+                pos[1] = 3; // [P, Q, R]
+                types[1] = (int) DISJOINT;
+              }
+            }
+          } else { // s6 == 0 (tritri2d-R2-5a)
+            if ((z1 == 2) || (z1 == 3)) {
+              if (s7 > 0) {
+                if (s8 < 0) {
+                  // Q touches [C, A]
+                  types[0] = (int) TOUCHEDGE;
+                  pos[0] = pu[2]; // [C, A]
+                  pos[1] = pv[1]; // Q
+                  types[1] = (int) DISJOINT;
+                } else { // s8 == 0
+                  // Q = C
+                  types[0] = (int) SHAREVERT;
+                  pos[0] = pu[2]; // C
+                  pos[1] = pv[1]; // Q
+                  types[1] = (int) DISJOINT;
+                }
+              } else { // s7 == 0
+                assert(0); // Not possible
+              }
+            } else { // z1 == 4 (tritri2d-R4-5a)
+              // [P, Q] intersects [A, B, C]
+              // [C, A] intersects [P, Q, R]
+              types[0] = (int) EDGETRIINT;
+              pos[0] = pu[2]; // [C, A]
+              pos[1] = 3; // [P, Q, R]
+              types[1] = (int) DISJOINT;
+            }
+          }
+        }
+      } else { // s5 == 0
+        if (s6 < 0) { // (tritri2d-R2-3b)
+          if (s7 < 0) {
+            if (s8 > 0) {
+              if (s9 > 0) {
+                // [C, A] intersects [P, Q, R]
+                types[0] = (int) EDGETRIINT;
+                pos[0] = pu[2]; // [C, A]
+                pos[1] = 3; // [P, Q, R]
+                types[1] = (int) DISJOINT;
+              } else { // s9 == 0
+                // [Q, R] passes C
+                types[0] = (int) ACROSSVERT;
+                pos[0] = pu[2]; // C
+                pos[1] = pe[1]; // [Q, R]
+                types[1] = (int) DISJOINT;
+              }
+            } else { // s8 == 0
+              if (s9 > 0) {
+                // R touches [C, A]
+                types[0] = (int) TOUCHEDGE;
+                pos[0] = pu[2]; // [C, A]
+                pos[1] = pv[2]; // R
+                types[1] = (int) DISJOINT;
+              } else { // s9 == 0
+                // R = C
+                types[0] = (int) SHAREVERT;
+                pos[0] = pu[2]; // C
+                pos[1] = pv[2]; // R
+                types[1] = (int) DISJOINT;
+              }
+            }
+          } else { // s7 == 0 (see tritri2d-R2-3c)
+            assert(0); // To my analysis should be disjoint. 
+          }
+        } else {
+          if (s6 > 0) {
+            if (s7 < 0) { // (tritri2d-R2-4a)
+              if (s8 > 0) {
+                if (s9 > 0) {
+                  // [A, B] intersects [P, Q, R]
+                  types[0] = (int) EDGETRIINT;
+                  pos[0] = pu[0]; // [A, B]
+                  pos[1] = 3; // [P, Q, R]
+                  types[1] = (int) DISJOINT;
+                } else { // s9 == 0
+                  // [A, B] intersects [P, Q, R]
+                  types[0] = (int) EDGETRIINT;
+                  pos[0] = pu[0]; // [A, B]
+                  pos[1] = 3; // [P, Q, R]
+                  types[1] = (int) DISJOINT;
+                }
+              } else { // s8 == 0
+                if (s9 > 0) {
+                  // [R, P] passes B
+                  types[0] = (int) ACROSSVERT;
+                  pos[0] = pu[1]; // B
+                  pos[1] = pe[2]; // [R, P]
+                  types[1] = (int) DISJOINT;
+                } else { // s9 == 0
+                  // R = B
+                  types[0] = (int) SHAREVERT;
+                  pos[0] = pu[1]; // B
+                  pos[1] = pv[2]; // R
+                  types[1] = (int) DISJOINT;
+                }
+              }
+            } else { // s7 >= 0
+              if (s7 > 0) {
+                assert(0); // Not possible (see tritri2d-R2-5b)
+              } else { // s7 == 0
+                if (z1 == 3) {// (tritri2d-R3-5b)
+                  // [P, Q] intersects [A, B, C]
+                  // [A, B] intersects [P, Q, R]
+                  types[0] = (int) EDGETRIINT;
+                  pos[0] = pu[0]; // [A, B]
+                  pos[1] = 3; // [P, Q, R]
+                  types[1] = (int) DISJOINT;
+                } else { // (tritri2d-R2-5b)
+                  s8 = orient3d(U[0], U[1], O, V[2]); // A, B, R
+                  if (s8 < 0) {
+                    // Q = B 
+                    types[0] = (int) SHAREVERT;
+                    pos[0] = pu[1]; // B
+                    pos[1] = pv[1]; // Q
+                    types[1] = (int) DISJOINT;
+                  } else {
+                    if (s8 > 0) {
+                      // [A, B] intersect [P, Q, R]
+                      types[0] = (int) EDGETRIINT;
+                      pos[0] = pu[0]; // [A, B]
+                      pos[1] = 3; // [P, Q, R]
+                      types[1] = (int) DISJOINT;
+                    } else { // s8 == 0
+                      s9 = orient3d(U[0], U[2], O, V[2]); // A, C, R
+                      if (s9 == 0) {
+                        // [A, B] = [Q, R]
+                        types[0] = (int) SHAREEDGE;
+                        pos[0] = pu[0]; // [A, B]
+                        pos[1] = pe[2]; // [R, P]
+                        types[1] = (int) DISJOINT;
+                      } else {
+                        // [P, Q] intersects [A, B, C]
+                        // [A, B] intersect [P, Q, R]
+                        types[0] = (int) EDGETRIINT;
+                        pos[0] = pu[0]; // [A, B]
+                        pos[1] = 3; // [P, Q, R]
+                        types[1] = (int) DISJOINT;
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          } else { // s6 == 0 (tritri2d-R2-6)
+            // Q = A. Note that R must above P, Q.
+            s7 = orient3d(V[1], V[2], O, U[2]); // Q, R, C
+            // Note: if z1 == 4, it must be s7 > 0
+            if (s7 < 0) {
+              // [Q, R] intersects [A, B, C]
+              types[0] = (int) EDGETRIINT;
+              pos[0] = 3; // [A, B, C]
+              pos[1] = pe[1]; // [Q, R]
+              types[1] = (int) DISJOINT;
+            } else {
+              if (s7 > 0) {
+                // Q = A
+                types[0] = (int) SHAREVERT;
+                pos[0] = pu[0]; // A
+                pos[1] = pv[1]; // Q
+                types[1] = (int) DISJOINT;
+              } else { // s7 == 0
+                s8 = orient3d(V[0], V[2], O, U[2]); // P, R, C
+                if (s8 == 0) {
+                  // [Q, R] = [A, C]
+                  types[0] = (int) SHAREEDGE;
+                  pos[0] = pu[2]; // [C, A]
+                  pos[1] = pe[1]; // [Q, R]
+                  types[1] = (int) DISJOINT;
+                } else { // s8 > 0 || s8 < 0
+                  // [A, C] intersects [P, Q, R]
+                  types[0] = (int) EDGETRIINT;
+                  pos[0] = pu[2]; // [C, A]
+                  pos[1] = 3; // [P, Q, R]
+                  types[1] = (int) DISJOINT;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    return 1;
+  } // z1 == 2 || z1 == 3 || z1 == 4
+
+  if (z1 == 6) { // P = A
+
+    if (level > 0) {
+      s5 = orient3d(U[0], U[1], O, V[1]); // A, B, Q
+      if (s5 < 0) {
+        s6 = orient3d(U[0], U[1], O, V[2]); // A, B, R
+        if (s6 < 0) { // (tritri2d-R6--)
+          // P = A
+          types[0] = (int) SHAREVERT;
+          pos[0] = pu[0]; // A
+          pos[1] = pv[0]; // P
+          types[1] = (int) DISJOINT;
+        } else {
+          if (s6 > 0) { // (tritri2d-R6-+)
+            // Note: it must be orient3d(Q, R, A) > 0.
+            // [P, Q] intersects [A, B, C]
+            types[0] = (int) TRIEDGEINT;
+            pos[0] = 3; // [A, B, C]
+            pos[1] = pe[0]; // [P, Q]
+            types[1] = (int) DISJOINT;
+          } else { // s6 == 0 (tritri2d-R6-0)
+            // Note: it must be orient3d(Q, R, A) > 0.
+            s7 = orient3d(V[1], V[2], O, U[1]); // Q, R, B
+            if (s7 == 0) {
+              // [R, P] = [A, B]
+              types[0] = (int) SHAREEDGE;
+              pos[0] = pu[0]; // [A, B]
+              pos[1] = pe[2]; // [R, P]
+              types[1] = (int) DISJOINT;
+            } else {
+              // [R, P] intersects [A, B, C]
+              // [A, B] intersects [P, Q, R]
+              types[0] = (int) EDGETRIINT;
+              pos[0] = pu[0]; // [A, B]
+              pos[1] = 3; // [P, Q, R]
+              types[1] = (int) DISJOINT;
+            }
+          }
+        }
+      } else { // s5 >= 0
+        if (s5 > 0) {
+          s6 = orient3d(U[0], U[2], O, V[1]); // A, C, Q
+          if (s6 < 0) { // (tritri2d-R6+-)
+            // [P, Q] intersects [A, B, C]
+            types[0] = (int) TRIEDGEINT;
+            pos[0] = 3; // [A, B, C]
+            pos[1] = pe[0]; // [P, Q]
+            types[1] = (int) DISJOINT;
+          } else { // s6 >= 0
+            if (s6 > 0) { // (tritri2d-R6++) (not draw)
+              // P = A
+              types[0] = (int) SHAREVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = pv[0]; // P
+              types[1] = (int) DISJOINT;  
+            } else { // s6 == 0 // (tritri2d-R6+0)
+              s7 = orient3d(V[1], V[2], O, U[2]); // Q, R, O, C
+              if (s7 == 0) {
+                // [P, Q] = [C, A]
+                types[0] = (int) SHAREEDGE;
+                pos[0] = pu[2]; // [C, A]
+                pos[1] = pe[0]; // [P, Q]
+                types[1] = (int) DISJOINT;
+              } else {
+                // [P, Q] intersects [A, B, C]
+                // [A, C] intersects [P, Q, R]
+                types[0] = (int) TRIEDGEINT;
+                pos[0] = 3; // [A, B, C]
+                pos[1] = pe[0]; // [P, Q]
+                types[1] = (int) DISJOINT;
+              }
+            }
+          }
+        } else { // s5 == 0
+          s6 = orient3d(V[1], V[2], O, U[1]); // Q, R, B
+          if (s6 == 0) {
+            // [P, Q] = [A, B]
+            types[0] = (int) SHAREEDGE;
+            pos[0] = pu[0]; // [A, B]
+            pos[1] = pe[0]; // [P, Q]
+            types[1] = (int) DISJOINT;
+          } else {
+            // [P, Q] intersects [A, B, C]
+            // [A, B] intersects [P, Q, R]
+            types[0] = (int) TRIEDGEINT;
+            pos[0] = 3; // [A, B, C]
+            pos[1] = pe[0]; // [P, Q]
+            types[1] = (int) DISJOINT;
+          }
+        }
+      }
+    } // if (level > 0)
+
+    return 1;
+  } // z1 == 6
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tri_tri_test()    Triangle-triangle intersection test.                    //
+//                                                                           //
+// This routine takes two triangles T1 (with vertices A, B, C) and T2 (P, Q  //
+// R) in 3D, and tests if they intersect each other.  Return 1 if they are   //
+// intersected, i.e., T1 \cap T2 is not empty, otherwise, return 0.          //
+//                                                                           //
+// If the point 'O' is not NULL, it lies strictly above the plane defined by //
+// A, B, C. It is used in test when T1 and T2 are coplanar.                  //
+//                                                                           //
+// If T1 and T2 intersect each other (return 1), they may intersect in diff- //
+// erent ways. If 'level' > 0, their intersection type will be reported in   //
+// combinations of 'types' and 'pos'.                                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::tri_tri_test(point A, point B, point C, point P, point Q, 
+  point R, point O, int level, int *types, int *pos)
+{
+  point U[3], V[3], W[3], Ptmp;  // The permuted vectors of points.
+  int pu[3], pv[3], pw[3], iu, iv, itmp; 
+  REAL sA, sB, sC, sP, sQ, sR;
+  REAL s1, s2, s3, s4;
+  int z1, z2;
+
+  // Test A's, B's, and C's orientations wrt plane PQR. 
+  sA = orient3d(P, Q, R, A);
+  sB = orient3d(P, Q, R, B);
+  sC = orient3d(P, Q, R, C);
+  orient3dcount+=3;
+
+  if (b->epsilon) {
+    if ((sA != 0) && iscoplanar(P, Q, R, A, sA)) sA = 0;
+    if ((sB != 0) && iscoplanar(P, Q, R, B, sB)) sB = 0;
+    if ((sC != 0) && iscoplanar(P, Q, R, C, sC)) sC = 0;
+  }
+
+  if (b->verbose > 2) {
+    printf("      Tri-tri (%d %d %d)-(%d %d %d) (%c%c%c)\n", pointmark(A),
+      pointmark(B), pointmark(C), pointmark(P), pointmark(Q), pointmark(R),
+      sA > 0 ? '+' : (sA < 0 ? '-' : '0'), sB>0 ? '+' : (sB<0 ? '-' : '0'),
+      sC>0 ? '+' : (sC<0 ? '-' : '0'));
+  }
+  // tritricount++;
+  iu = iv = 0;
+
+  if (sA < 0) {
+    if (sB < 0) {
+      if (sC < 0) { // (---).
+        return DISJOINT; 
+      } else {
+        if (sC > 0) { // (--+).
+          // All points are in the right positions.
+          SETVECTOR3(U, A, B, C);  // I3
+          SETVECTOR3(V, P, Q, R);  // I2
+          SETVECTOR3(pu, 0, 1, 2);
+          SETVECTOR3(pv, 0, 1, 2);
+          z1 = 0;
+        } else { // (--0).
+          SETVECTOR3(U, A, B, C);  // I3
+          SETVECTOR3(V, P, Q, R);  // I2
+          SETVECTOR3(pu, 0, 1, 2);
+          SETVECTOR3(pv, 0, 1, 2);
+          z1 = 1;
+        }
+      }
+    } else { 
+      if (sB > 0) {
+        if (sC < 0) { // (-+-).
+          SETVECTOR3(U, C, A, B);  // PT = ST
+          SETVECTOR3(V, P, Q, R);  // I2
+          SETVECTOR3(pu, 2, 0, 1);
+          SETVECTOR3(pv, 0, 1, 2);
+          z1 = 0;
+        } else {
+          if (sC > 0) { // (-++).
+            SETVECTOR3(U, B, C, A);  // PT = ST x ST
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 1, 2, 0);
+            SETVECTOR3(pv, 1, 0, 2); iv = 1;
+            z1 = 0;
+          } else { // (-+0).
+            SETVECTOR3(U, C, A, B);  // PT = ST
+            SETVECTOR3(V, P, Q, R);  // I2
+            SETVECTOR3(pu, 2, 0, 1);
+            SETVECTOR3(pv, 0, 1, 2);
+            z1 = 2;
+          }
+        }
+      } else {
+        if (sC < 0) { // (-0-).
+          SETVECTOR3(U, C, A, B);  // PT = ST
+          SETVECTOR3(V, P, Q, R);  // I2
+          SETVECTOR3(pu, 2, 0, 1);
+          SETVECTOR3(pv, 0, 1, 2);
+          z1 = 1;
+        } else {
+          if (sC > 0) { // (-0+).
+            SETVECTOR3(U, B, C, A);  // PT = ST x ST
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 1, 2, 0);
+            SETVECTOR3(pv, 1, 0, 2); iv = 1;
+            z1 = 2;
+          } else { // (-00).
+            SETVECTOR3(U, B, C, A);  // PT = ST x ST
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 1, 2, 0);
+            SETVECTOR3(pv, 1, 0, 2); iv = 1;
+            z1 = 3;
+          }
+        }
+      }
+    }
+  } else {
+    if (sA > 0) {
+      if (sB < 0) {
+        if (sC < 0) { // (+--).
+          SETVECTOR3(U, B, C, A);  // PT = ST x ST
+          SETVECTOR3(V, P, Q, R);  // I2
+          SETVECTOR3(pu, 1, 2, 0);
+          SETVECTOR3(pv, 0, 1, 2);
+          z1 = 0;
+        } else {
+          if (sC > 0) { // (+-+).
+            SETVECTOR3(U, C, A, B);  // PT = ST
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 2, 0, 1);
+            SETVECTOR3(pv, 1, 0, 2); iv = 1;
+            z1 = 0;
+          } else { // (+-0).
+            SETVECTOR3(U, C, A, B);  // PT = ST
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 2, 0, 1);
+            SETVECTOR3(pv, 1, 0, 2); iv = 1;
+            z1 = 2;
+          }
+        }
+      } else { 
+        if (sB > 0) {
+          if (sC < 0) { // (++-).
+            SETVECTOR3(U, A, B, C);  // I3
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 0, 1, 2);
+            SETVECTOR3(pv, 1, 0, 2); iv = 1;
+            z1 = 0;
+          } else {
+            if (sC > 0) { // (+++).
+              return DISJOINT; 
+            } else { // (++0).
+              SETVECTOR3(U, A, B, C);  // I3
+              SETVECTOR3(V, Q, P, R);  // PL = SL
+              SETVECTOR3(pu, 0, 1, 2);
+              SETVECTOR3(pv, 1, 0, 2); iv = 1;
+              z1 = 1; 
+            }
+          }
+        } else {
+          if (sC < 0) { // (+0-).
+            SETVECTOR3(U, B, C, A);  // PT = ST x ST
+            SETVECTOR3(V, P, Q, R);  // I2
+            SETVECTOR3(pu, 1, 2, 0);
+            SETVECTOR3(pv, 0, 1, 2);
+            z1 = 2;
+          } else {
+            if (sC > 0) { // (+0+).
+              SETVECTOR3(U, C, A, B);  // PT = ST
+              SETVECTOR3(V, Q, P, R);  // PL = SL
+              SETVECTOR3(pu, 2, 0, 1);
+              SETVECTOR3(pv, 1, 0, 2); iv = 1;
+              z1 = 1;
+            } else { // (+00).
+              SETVECTOR3(U, B, C, A);  // PT = ST x ST
+              SETVECTOR3(V, P, Q, R);  // I2
+              SETVECTOR3(pu, 1, 2, 0);
+              SETVECTOR3(pv, 0, 1, 2);
+              z1 = 3; 
+            }
+          }
+        }
+      }
+    } else { 
+      if (sB < 0) {
+        if (sC < 0) { // (0--).
+          SETVECTOR3(U, B, C, A);  // PT = ST x ST
+          SETVECTOR3(V, P, Q, R);  // PL = I2
+          SETVECTOR3(pu, 1, 2, 0);
+          SETVECTOR3(pv, 0, 1, 2);
+          z1 = 1;
+        } else {
+          if (sC > 0) { // (0-+).
+            SETVECTOR3(U, A, B, C);  // I3
+            SETVECTOR3(V, P, Q, R);  // I2
+            SETVECTOR3(pu, 0, 1, 2);
+            SETVECTOR3(pv, 0, 1, 2);
+            z1 = 2;
+          } else { // (0-0).
+            SETVECTOR3(U, C, A, B);  // PT = ST
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 2, 0, 1);
+            SETVECTOR3(pv, 1, 0, 2); iv = 1;
+            z1 = 3; 
+          }
+        }
+      } else { 
+        if (sB > 0) {
+          if (sC < 0) { // (0+-).
+            SETVECTOR3(U, A, B, C);  // I3
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 0, 1, 2);
+            SETVECTOR3(pv, 1, 0, 2); iv = 1;
+            z1 = 2;
+          } else {
+            if (sC > 0) { // (0++).
+              SETVECTOR3(U, B, C, A);  // PT = ST x ST
+              SETVECTOR3(V, Q, P, R);  // PL = SL
+              SETVECTOR3(pu, 1, 2, 0);
+              SETVECTOR3(pv, 1, 0, 2); iv = 1;
+              z1 = 1;
+            } else { // (0+0).
+              SETVECTOR3(U, C, A, B);  // PT = ST
+              SETVECTOR3(V, P, Q, R);  // I2
+              SETVECTOR3(pu, 2, 0, 1);
+              SETVECTOR3(pv, 0, 1, 2);
+              z1 = 3; 
+            }
+          }
+        } else {
+          if (sC < 0) { // (00-).
+            SETVECTOR3(U, A, B, C);  // I3
+            SETVECTOR3(V, Q, P, R);  // PL = SL
+            SETVECTOR3(pu, 0, 1, 2);
+            SETVECTOR3(pv, 1, 0, 2); iv = 1;
+            z1 = 3; 
+          } else {
+            if (sC > 0) { // (00+).
+              SETVECTOR3(U, A, B, C);  // I3
+              SETVECTOR3(V, P, Q, R);  // I2
+              SETVECTOR3(pu, 0, 1, 2);
+              SETVECTOR3(pv, 0, 1, 2);
+              z1 = 3; 
+            } else { // (000)
+              // (A, B, C) is coplanar with (P, Q, R).
+              SETVECTOR3(U, A, B, C);  // I3
+              SETVECTOR3(V, P, Q, R);  // I2
+              SETVECTOR3(pu, 0, 1, 2);
+              SETVECTOR3(pv, 0, 1, 2);
+              z1 = -1;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  sP = orient3d(U[0], U[1], U[2], V[0]);
+  sQ = orient3d(U[0], U[1], U[2], V[1]);
+  sR = orient3d(U[0], U[1], U[2], V[2]);
+  orient3dcount+=3;
+
+  if (b->epsilon) {
+    if ((sP != 0) && iscoplanar(U[0], U[1], U[2], V[0], sP)) sP = 0;
+    if ((sQ != 0) && iscoplanar(U[0], U[1], U[2], V[1], sQ)) sQ = 0;
+    if ((sR != 0) && iscoplanar(U[0], U[1], U[2], V[2], sR)) sR = 0;
+  }
+
+  if (b->verbose > 2) {
+    printf("      Tri-tri (%d %d %d)-(%d %d %d) (%c%c%c)\n", pointmark(U[0]),
+      pointmark(U[1]), pointmark(U[2]), pointmark(V[0]), pointmark(V[1]), 
+      pointmark(V[2]), sP>0 ? '+' : (sP<0 ? '-' : '0'), 
+      sQ>0 ? '+' : (sQ<0 ? '-' : '0'), sR>0 ? '+' : (sR<0 ? '-' : '0'));
+  }
+
+  if (sP < 0) {
+    if (sQ < 0) {
+      if (sR < 0) {  // (---)
+        return DISJOINT;
+      } else {
+        if (sR > 0) { // (--+)
+          // P1->Q1 is opposite to A1->B1. Swicth A1 and B1.
+          SETVECTOR3(W, V[0], V[1], V[2]);  // I3
+          SWAP2(U[0], U[1], Ptmp);  // PL = SL
+          SETVECTOR3(pw, pv[0], pv[1], pv[2]);
+          SWAP2(pu[0], pu[1], itmp); iu = 1;
+          z2 = 0;
+        } else {  // (--0)
+          SETVECTOR3(W, V[0], V[1], V[2]);  // I3
+          SWAP2(U[0], U[1], Ptmp);  // PL = SL
+          SETVECTOR3(pw, pv[0], pv[1], pv[2]);
+          SWAP2(pu[0], pu[1], itmp); iu = 1;
+          z2 = 1;
+        }
+      }
+    } else {
+      if (sQ > 0) {
+        if (sR < 0) {  // (-+-)
+          SETVECTOR3(W, V[2], V[0], V[1]);  // PT = ST
+          SWAP2(U[0], U[1], Ptmp);  // PL = SL
+          SETVECTOR3(pw, pv[2], pv[0], pv[1]);
+          SWAP2(pu[0], pu[1], itmp); iu = 1;
+          z2 = 0;
+        } else {
+          if (sR > 0) { // (-++)
+            SETVECTOR3(W, V[1], V[2], V[0]);  // PT = ST x ST
+            SETVECTOR3(pw, pv[1], pv[2], pv[0]);
+            z2 = 0;
+          } else { // (-+0)
+            SETVECTOR3(W, V[2], V[0], V[1]);  // PT = ST
+            SWAP2(U[0], U[1], Ptmp); // PL = SL
+            SETVECTOR3(pw, pv[2], pv[0], pv[1]);
+            SWAP2(pu[0], pu[1], itmp); iu = 1;
+            z2 = 2;
+          }
+        }
+      } else {
+        if (sR < 0) {  // (-0-)
+          SETVECTOR3(W, V[2], V[0], V[1]);  // PT = ST
+          SWAP2(U[0], U[1], Ptmp); // PL = SL
+          SETVECTOR3(pw, pv[2], pv[0], pv[1]);
+          SWAP2(pu[0], pu[1], itmp); iu = 1;
+          z2 = 1;
+        } else {
+          if (sR > 0) {  // (-0+)
+            SETVECTOR3(W, V[1], V[2], V[0]);  // PT = ST x ST
+            SETVECTOR3(pw, pv[1], pv[2], pv[0]);
+            z2 = 2;
+          } else {  // (-00)
+            SETVECTOR3(W, V[1], V[2], V[0]);  // PT = ST x ST
+            SETVECTOR3(pw, pv[1], pv[2], pv[0]);
+            z2 = 3;
+          }
+        }
+      }
+    }
+  } else {
+    if (sP > 0) {
+      if (sQ < 0) {
+        if (sR < 0) {  // (+--)
+          SETVECTOR3(W, V[1], V[2], V[0]);  // PT = ST x ST
+          SWAP2(U[0], U[1], Ptmp); // PL = SL
+          SETVECTOR3(pw, pv[1], pv[2], pv[0]);
+          SWAP2(pu[0], pu[1], itmp); iu = 1;
+          z2 = 0;
+        } else {
+          if (sR > 0) {  // (+-+)
+            SETVECTOR3(W, V[2], V[0], V[1]);  // PT = ST
+            SETVECTOR3(pw, pv[2], pv[0], pv[1]);
+            z2 = 0;
+          } else {  // (+-0)
+            SETVECTOR3(W, V[2], V[0], V[1]);  // PT = ST
+            SETVECTOR3(pw, pv[2], pv[0], pv[1]);
+            z2 = 2;
+          }
+        }
+      } else {
+        if (sQ > 0) {
+          if (sR < 0) {  // (++-)
+            SETVECTOR3(W, V[0], V[1], V[2]);  // I3
+            SETVECTOR3(pw, pv[0], pv[1], pv[2]);
+            z2 = 0;
+          } else {
+            if (sR > 0) {  // (+++)
+              return DISJOINT;
+            } else {  // (++0)
+              SETVECTOR3(W, V[0], V[1], V[2]);  // I3
+              SETVECTOR3(pw, pv[0], pv[1], pv[2]);
+              z2 = 1;
+            }
+          }
+        } else { // sQ == 0
+          if (sR < 0) {  // (+0-)
+            SETVECTOR3(W, V[1], V[2], V[0]);  // PT = ST x ST
+            SWAP2(U[0], U[1], Ptmp); // PL = SL
+            SETVECTOR3(pw, pv[1], pv[2], pv[0]);
+            SWAP2(pu[0], pu[1], itmp); iu = 1;
+            z2 = 2;
+          } else {
+            if (sR > 0) {  // (+0+)
+              SETVECTOR3(W, V[2], V[0], V[1]);  // PT = ST
+              SETVECTOR3(pw, pv[2], pv[0], pv[1]);
+              z2 = 1;
+            } else {  // (+00)
+              SETVECTOR3(W, V[1], V[2], V[0]);  // PT = ST x ST
+              SWAP2(U[0], U[1], Ptmp); // PL = SL
+              SETVECTOR3(pw, pv[1], pv[2], pv[0]);
+              SWAP2(pu[0], pu[1], itmp); iu = 1;
+              z2 = 3;
+            }
+          }
+        }
+      }
+    } else { // sP == 0
+      if (sQ < 0) {
+        if (sR < 0) {  // (0--)
+          SETVECTOR3(W, V[1], V[2], V[0]);  // PT = ST x ST
+          SWAP2(U[0], U[1], Ptmp); // PL = SL
+          SETVECTOR3(pw, pv[1], pv[2], pv[0]);
+          SWAP2(pu[0], pu[1], itmp); iu = 1;
+          z2 = 1;
+        } else {
+          if (sR > 0) {  // (0-+)
+            SETVECTOR3(W, V[0], V[1], V[2]);  // I3
+            SWAP2(U[0], U[1], Ptmp); // PL = SL
+            SETVECTOR3(pw, pv[0], pv[1], pv[2]);
+            SWAP2(pu[0], pu[1], itmp); iu = 1;
+            z2 = 2;
+          } else {  // (0-0)
+            SETVECTOR3(W, V[2], V[0], V[1]);  // PT = ST
+            SETVECTOR3(pw, pv[2], pv[0], pv[1]);
+            z2 = 3;
+          }
+        }
+      } else {
+        if (sQ > 0) {
+          if (sR < 0) {  // (0+-)
+            SETVECTOR3(W, V[0], V[1], V[2]);  // I3
+            SETVECTOR3(pw, pv[0], pv[1], pv[2]);
+            z2 = 2;
+          } else {
+            if (sR > 0) {  // (0++)
+              SETVECTOR3(W, V[1], V[2], V[0]);  // PT = ST x ST
+              SETVECTOR3(pw, pv[1], pv[2], pv[0]);
+              z2 = 1;
+            } else {  // (0+0)
+              SETVECTOR3(W, V[2], V[0], V[1]);  // PT = ST
+              SWAP2(U[0], U[1], Ptmp); // PL = SL
+              SETVECTOR3(pw, pv[2], pv[0], pv[1]);
+              SWAP2(pu[0], pu[1], itmp); iu = 1;
+              z2 = 3;
+            }
+          }
+        } else { // sQ == 0
+          if (sR < 0) {  // (00-)
+            SETVECTOR3(W, V[0], V[1], V[2]);  // I3
+            SETVECTOR3(pw, pv[0], pv[1], pv[2]);
+            z2 = 3;
+          } else {
+            if (sR > 0) {  // (00+)
+              SETVECTOR3(W, V[0], V[1], V[2]);  // I3
+              SWAP2(U[0], U[1], Ptmp); // PL = SL
+              SETVECTOR3(pw, pv[0], pv[1], pv[2]);
+              SWAP2(pu[0], pu[1], itmp); iu = 1;
+              z2 = 3;
+            } else {  // (000)
+              z2 = -1;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  if (z1 == -1) {
+    assert(z2 == -1);  // SELF_CHECK
+    return tri_tri_2d(A, B, C, P, Q, R, O, level, types, pos);
+  }
+
+  if ((iu == 1) && (z1 == 2)) {
+    z1 = 4; // A and B are inverted.
+  }
+
+  if (z2 == 1) {
+    s1 = orient3d(U[0], U[2], W[0], W[2]);  // A, C, P, R
+    s2 = orient3d(U[1], U[2], W[1], W[2]);  // B, C, Q, R
+    orient3dcount+=2;
+    if (b->epsilon > 0) {
+      if ((s1 != 0) && iscoplanar(U[0], U[2], W[0], W[2], s1)) s1 = 0;
+      if ((s2 != 0) && iscoplanar(U[1], U[2], W[1], W[2], s2)) s2 = 0;
+    }
+  } else {
+    s1 = orient3d(U[0], U[2], W[2], W[1]);  // A, C, R, Q
+    s2 = orient3d(U[1], U[2], W[2], W[0]);  // B, C, R, P
+    orient3dcount+=2;
+    if (b->epsilon > 0) {
+      if ((s1 != 0) && iscoplanar(U[0], U[2], W[2], W[1], s1)) s1 = 0;
+      if ((s2 != 0) && iscoplanar(U[1], U[2], W[2], W[0], s2)) s2 = 0;
+    }
+  }
+
+  if (b->verbose > 2) {
+    printf("      Tri-tri (%d %d %d)-(%d %d %d) (%d-%d) (%c%c)\n",
+      pointmark(U[0]), pointmark(U[1]), pointmark(U[2]), pointmark(W[0]), 
+      pointmark(W[1]), pointmark(W[2]), z1, z2,
+      s1>0 ? '+' : (s1<0 ? '-' : '0'), s2>0 ? '+' : (s2<0 ? '-' : '0'));
+  }
+
+  if (z2 == 1) {
+    if (s1 < 0) {
+      return 0;
+    }
+    if (s2 > 0) {
+      return 0;
+    }
+  } else {
+    if (s1 > 0) {
+      return 0;
+    }
+    if (s2 < 0) {
+      return 0;
+    }
+  }
+
+  if (level == 0) {
+    return 1;
+  }
+
+  if (z2 == 1) {
+
+    if (z1 == 0) {  // (01)
+      if (s1 == 0) {
+        // R = k in [A, C] (tritri-010###).
+        types[0] = (int) TOUCHEDGE;
+        pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+        pos[1] = pw[2]; // R
+        types[1] = (int) DISJOINT;
+      } else {
+        if (s2 == 0) {
+          // R = l in [B, C] (tritri-01#0##).
+          types[0] = (int) TOUCHEDGE;
+          pos[0] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+          pos[1] = pw[2]; // R
+          types[1] = (int) DISJOINT;  
+        } else {
+          // R in [k, l] in [A, B, C] (tritri-01+-##).
+          types[0] = (int) TOUCHFACE;
+          pos[0] = 3; // [A, B, C]
+          pos[1] = pw[2]; // R
+          types[1] = (int) DISJOINT;  
+        }
+      }
+    } else if (z1 == 1) {  // (11)
+      assert(s1 == 0); // SELF_CHECK
+      // C = R (tritri-110###).
+      types[0] = (int) SHAREVERT;
+      pos[0] = pu[2]; // C
+      pos[1] = pw[2]; // R
+      types[1] = (int) DISJOINT;  
+    } else if (z1 == 2) {  // (21)
+      if (s1 == 0) {
+        // R = A (tritri-210###).
+        types[0] = (int) SHAREVERT;
+        pos[0] = pu[0]; // A
+        pos[1] = pw[2]; // R
+        types[1] = (int) DISJOINT;  
+      } else {
+        if (s2 == 0) {
+          // R = l, R in [B, C] (tritri-21#0##).
+          types[0] = (int) TOUCHEDGE;
+          pos[0] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+          pos[1] = pw[2]; // R
+          types[1] = (int) DISJOINT;  
+        } else {
+          // R in [k, l] in [A, B, C] (tritri-21+-##).
+          types[0] = (int) TOUCHFACE;
+          pos[0] = 3; // Interior of [A, B, C]
+          pos[1] = pw[2]; // R
+          types[1] = (int) DISJOINT;  
+        }
+      }
+    } else if (z1 == 3) {  // (31)
+      if (s1 == 0) {
+        // R = A (tritri-310###).
+        types[0] = (int) SHAREVERT;
+        pos[0] = pu[0]; // A
+        pos[1] = pw[2]; // R
+        types[1] = (int) DISJOINT;  
+      } else {
+        if (s2 == 0) {
+          // R = B (tritri-31#0##).
+          types[0] = (int) SHAREVERT;
+          pos[0] = pu[1]; // B
+          pos[1] = pw[2]; // R
+          types[1] = (int) DISJOINT;  
+        } else {
+          // R in [A, B] (tritri-31+-##).
+          types[0] = (int) TOUCHEDGE;
+          pos[0] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // [A, B]
+          pos[1] = pw[2]; // R
+          types[1] = (int) DISJOINT;  
+        }
+      }
+    } else if (z1 == 4) { // (41)
+      if (s1 == 0) { // (tritri-410###).
+        // R touches [C, A]
+        types[0] = (int) TOUCHEDGE;
+        pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+        pos[1] = pw[2]; // R
+        types[1] = (int) DISJOINT;
+      } else {
+        if (s2 == 0) { // (tritri-41#0##).
+          // R = B
+          types[0] = (int) SHAREVERT;
+          pos[0] = pu[1]; // B
+          pos[1] = pw[2]; // R
+          types[1] = (int) DISJOINT;
+        } else { // (tritri-41+-##)
+          // R in [k, l]
+          types[0] = (int) TOUCHFACE;
+          pos[0] = 3; // [A, B, C]
+          pos[1] = pw[2]; // R
+          types[1] = (int) DISJOINT;
+        }
+      }
+    }
+
+    return 1;
+  } // z2 == 1
+
+  if (z1 == 1) {
+  
+    if (z2 == 0) { // (10)
+      if (s1 == 0) {
+        // C = j, C in [Q, R] (tritri-100###).
+        types[0] = (int) ACROSSVERT;
+        pos[0] = pu[2]; // C
+        pos[1] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+        types[1] = (int) DISJOINT;  
+      } else {
+        if (s2 == 0) {
+          // C = i, C in [P, R] (tritri-10#0##).
+          types[0] = (int) ACROSSVERT;
+          pos[0] = pu[2]; // C
+          pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+          types[1] = (int) DISJOINT;  
+        } else {
+          // C in [i, j] in [P, Q, R] (tritri-10-+##).
+          types[0] = (int) ACROSSVERT;
+          pos[0] = pu[2]; // C
+          pos[1] = 3; // Interior of [P, Q, R]
+          types[1] = (int) DISJOINT;  
+        }
+      }
+    } else if (z2 == 2) {  // (12)
+      if (s1 == 0) { // 
+        // C = j, C in [Q, R] (tritri-120###).
+        types[0] = (int) ACROSSVERT;
+        pos[0] = pu[2]; // C
+        pos[1] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+        types[1] = (int) DISJOINT;  
+      } else {
+        if (s2 == 0) {
+          // C = P (tritri-12#0##).
+          types[0] = (int) SHAREVERT;
+          pos[0] = pu[2]; // C
+          pos[1] = pw[0]; // P
+          types[1] = (int) DISJOINT;  
+        } else {
+          // C in [i, j] in [P, Q, R] (tritri-12-+##).
+          types[0] = (int) ACROSSVERT;
+          pos[0] = pu[2]; // C
+          pos[1] = 3; // Interior of [P, Q, R]
+          types[1] = (int) DISJOINT;  
+        }
+      }
+    } else if (z2 == 3) {  // (13)
+      if (s1 == 0) {
+        // C = Q (tritri-130###).
+        types[0] = (int) SHAREVERT;
+        pos[0] = pu[2]; // C
+        pos[1] = pw[1]; // Q
+        types[1] = (int) DISJOINT;  
+      } else {
+        if (s2 == 0) {
+          // C = P (tritri-13#0##).
+          types[0] = (int) SHAREVERT;
+          pos[0] = pu[2]; // C
+          pos[1] = pw[0]; // P
+          types[1] = (int) DISJOINT;  
+        } else {
+          // C in [P, Q] (tritri-13-+##).
+          types[0] = (int) ACROSSVERT;
+          pos[0] = pu[2]; // C
+          pos[1] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // [P, Q]
+          types[1] = (int) DISJOINT;  
+        }
+      }
+    }
+
+    return 1;
+  } // if (z1 == 1)
+
+  // Two additional orientation tests are needed.
+  s3 = orient3d(U[0], U[2], W[2], W[0]);  // A, C, R, P
+  s4 = orient3d(U[1], U[2], W[2], W[1]);  // B, C, R, Q
+  orient3dcount+=2;
+  if (b->epsilon > 0) {
+    if ((s3 != 0) && iscoplanar(U[0], U[2], W[2], W[0], s3)) s3 = 0;
+    if ((s4 != 0) && iscoplanar(U[1], U[2], W[2], W[1], s4)) s4 = 0;
+  }
+
+  if (b->verbose > 2) {
+    printf("      (tritri-%d%d%c%c%c%c)\n", z1, z2, 
+      s1>0 ? '+' : (s1<0 ? '-' : '0'), s2>0 ? '+' : (s2<0 ? '-' : '0'), 
+      s3>0 ? '+' : (s3<0 ? '-' : '0'), s4>0 ? '+' : (s4<0 ? '-' : '0'));
+  }
+
+  if (z1 == 0) {
+    
+    if (z2 == 0) {  // (00)
+      if (s1 < 0) {
+        if (s3 > 0) {
+          assert(s2 > 0); // SELF_CHECK.
+          if (s4 > 0) {
+            // [i, j] overlaps [k, l] (tritri-00-+++).
+            types[0] = (int) ACROSSEDGE;
+            pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+            pos[1] = 3;     // [P, Q, R]
+            types[1] = (int) ACROSSFACE;
+            pos[2] = 3;     // [A, B, C]
+            pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+          } else {
+            if (s4 == 0) {
+              // j = l, [i, j] contains [k, l] (tritri-00-++0).
+              types[0] = (int) ACROSSEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = 3;     // [P, Q, R]
+              types[1] = (int) ACROSSEDGE;
+              pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+            } else {
+              // [i, j] contains [k, l] (tritri-00-++-).
+              types[0] = (int) ACROSSEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = 3;     // [P, Q, R]
+              types[1] = (int) ACROSSEDGE;
+              pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[3] = 3;     // [P, Q, R]
+            }
+          }
+        } else {
+          if (s3 == 0) { // (00-+0#)
+            assert(s2 > 0); // SELF_CHECK.
+            if (s4 > 0) {
+              // i = k, [i, j] overlaps [k, l] (tritri-00-+0+).
+              types[0] = (int) ACROSSEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+              types[1] = (int) ACROSSFACE;
+              pos[2] = 3;     // [A, B, C]
+              pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+            } else {
+              if (s4 == 0) {
+                // [i, j] = [k, l] (tritri-00-+00).
+                types[0] = (int) ACROSSEDGE;
+                pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+                pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                types[1] = (int) ACROSSEDGE;
+                pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+              } else {
+                // i = k, [i, j] contains [k, l] (tritri-00-+0-).
+                types[0] = (int) ACROSSEDGE;
+                pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+                pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                types[1] = (int) ACROSSEDGE;
+                pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                pos[3] = 3;     // [P, Q, R] 
+              }
+            }
+          } else { // s3 < 0
+            if (s2 > 0) {
+              if (s4 > 0) {
+                // [i, j] in [k, l] in [A, B, C] (tritri-00-+-+).
+                types[0] = (int) ACROSSFACE;
+                pos[0] = 3;     // [A, B, C]
+                pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                types[1] = (int) ACROSSFACE;
+                pos[2] = 3;     // [A, B, C]
+                pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+              } else {
+                if (s4 == 0) {
+                  // j = l, [i, j] in [k, l] (tritri-00-+-0)
+                  types[0] = (int) ACROSSFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                  types[1] = (int) ACROSSEDGE;
+                  pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                  pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+                } else { // s4 < 0
+                  // [i, j] overlaps [k, l] (tritri-00-+--)
+                  types[0] = (int) ACROSSFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                  types[1] = (int) ACROSSEDGE;
+                  pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                  pos[3] = 3;     // [P, Q, R]
+                }
+              }
+            } else { // s2 == 0
+              assert(s4 < 0); // SELF_CHECK
+              // i = l, [P, R] intersects [B, C] (tritri-00#0##).
+              types[0] = (int) ACROSSEDGE;
+              pos[0] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+              types[1] = (int) DISJOINT;
+            }
+          }
+        }
+      } else { // s1 == 0
+        // j = k, [Q, R] intersects [A, B] (tritri-000###).
+        types[0] = (int) ACROSSEDGE;
+        pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+        pos[1] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+        types[1] = (int) DISJOINT;
+      }
+    } else if (z2 == 2) {  // (02)
+      if (s1 < 0) {
+        if (s3 > 0) { // (02-#+#)
+          assert(s2 > 0); // SELF_CHECK;
+          if (s4 > 0) {
+            // [P, j] overlaps [k, l] (tritri-02-+++).
+            types[0] = (int) ACROSSEDGE;
+            pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+            pos[1] = 3;     // [P, Q, R]
+            types[1] = (int) ACROSSFACE;
+            pos[2] = 3;     // [A, B, C]
+            pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+          } else {
+            if (s4 == 0) {
+              // j = k, [i, j] contains [k, l] (tritri-02-++0).
+              types[0] = (int) ACROSSEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = 3;     // [P, Q, R]
+              types[1] = (int) ACROSSEDGE;
+              pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+            } else { // s4 < 0
+              // [i, j] contains [k, l] (tritri-02-++-).
+              types[0] = (int) ACROSSEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = 3;     // [P, Q, R]
+              types[1] = (int) ACROSSEDGE;
+              pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[3] = 3;     // [P, Q, R]
+            }
+          }
+        } else {
+          if (s3 == 0) { // (02-#0#)
+            assert(s2 > 0); // SELF_CHECK
+            if (s4 > 0) {
+              // P = k, [P, j] in [k, l] (tritri-02-+0+).
+              types[0] = (int) TOUCHEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = pw[0]; // P
+              types[1] = (int) ACROSSFACE;
+              pos[2] = 3;     // [A, B, C]
+              pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+            } else {
+              if (s4 == 0) {
+                // [P, j] = [k, l] (tritri-02-+00).
+                types[0] = (int) TOUCHEDGE;
+                pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+                pos[1] = pw[0]; // P
+                types[1] = (int) ACROSSEDGE;
+                pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+              } else {  // s4 < 0
+                // P = k, [P, j] contains [k, l] (tritri-02-+0-).
+                types[0] = (int) TOUCHEDGE;
+                pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+                pos[1] = pw[0]; // P
+                types[1] = (int) ACROSSEDGE;
+                pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                pos[3] = 3;     // [P, Q, R]
+              }
+            }
+          } else { // s3 < 0.
+            if (s2 > 0) {
+              if (s4 > 0) {
+                // [P, j] in [k, l] in [A, B, C] (tritri-02-+-+).
+                types[0] = (int) TOUCHFACE;
+                pos[0] = 3;     // [A, B, C]
+                pos[1] = pw[0]; // P
+                types[1] = (int) ACROSSFACE;
+                pos[2] = 3;     // [A, B, C]
+                pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+              } else {
+                if (s4 == 0) {
+                  // j = l, [P, j] overlaps [k, l] (tritri-02-+-0).
+                  types[0] = (int) TOUCHFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = pw[0]; // P
+                  types[1] = (int) ACROSSEDGE;
+                  pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                  pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+                } else { // s4 < 0
+                  // [P, j] overlaps [k, l] (tritri-02-+--).
+                  types[0] = (int) TOUCHFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = pw[0]; // P
+                  types[1] = (int) ACROSSEDGE;
+                  pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                  pos[3] = 3;     // [P, Q, R]
+                }
+              }
+            } else {  // s2 == 0
+              assert(s4 < 0); // SELF_CHECK
+              // P = k, P in [B, C] (tritri-02#0##).
+              types[0] = (int) TOUCHEDGE;
+              pos[0] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[1] = pw[0]; // P
+              types[1] = (int) DISJOINT;
+            }
+          }
+        }
+      } else { // s1 == 0
+        // j = k, [Q, R] intersects [A, C] (tritri-020###).
+        types[0] = (int) ACROSSEDGE;
+        pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+        pos[1] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+        types[1] = (int) DISJOINT;
+      }
+    } else if (z2 == 3) {  // (03)
+      if (s1 < 0) {
+        if (s3 > 0) {
+          assert(s2 > 0); // SELF_CHECK
+          if (s4 > 0) {
+            // [P, Q] overlaps [k, l] (tritri-03-+++).
+            types[0] = (int) ACROSSEDGE;
+            pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+            pos[1] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+            types[1] = (int) TOUCHFACE;
+            pos[2] = 3;     // [A, B, C]
+            pos[3] = pw[1]; // Q
+          } else {
+            if (s4 == 0) {
+              // Q = l, [P, Q] contains [k, l] (tritri-03-++0).
+              types[0] = (int) ACROSSEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+              types[1] = (int) TOUCHEDGE;
+              pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[3] = pw[1]; // Q
+            } else { // s4 < 0
+              // [P, Q] contains [k, l] (tritri-03-++-).
+              types[0] = (int) ACROSSEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+              types[1] = (int) ACROSSEDGE;
+              pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[3] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+            }
+          }
+        } else {
+          if (s3 == 0) {
+            assert(s2 > 0);  // SELF_CHECK
+            if (s4 > 0) {
+              // P = k, [P, Q] in [k, l] (tritri-03-+0+).
+              types[0] = (int) TOUCHEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = pw[0]; // P
+              types[1] = (int) TOUCHFACE;
+              pos[2] = 3;     // [A, B, C]
+              pos[3] = pw[1]; // Q
+            } else {
+              if (s4 == 0) {
+                // [P, Q] = [k, l] (tritri-03-+00).
+                types[0] = (int) TOUCHEDGE;
+                pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+                pos[1] = pw[0]; // P
+                types[1] = (int) TOUCHEDGE;
+                pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                pos[3] = pw[1]; // Q
+              } else {  // s4 < 0
+                // P = k, [P, Q] contains [k, l] (tritri-03-+0-).
+                types[0] = (int) TOUCHEDGE;
+                pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+                pos[1] = pw[0]; // P
+                types[1] = (int) ACROSSEDGE;
+                pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                pos[3] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+              }
+            }
+          } else { // s3 < 0
+            if (s2 > 0) {
+              if (s4 > 0) {
+                // [P, Q] in [k, l] (tritri-03-+-+).
+                types[0] = (int) TOUCHFACE;
+                pos[0] = 3;     // [A, B, C]
+                pos[1] = pw[0]; // P
+                types[1] = (int) TOUCHFACE;
+                pos[2] = 3;     // [A, B, C]
+                pos[3] = pw[1]; // Q
+              } else {
+                if (s4 == 0) {
+                  // Q = l, [P, Q] in [k, l] (tritri-03-+-0).
+                  types[0] = (int) TOUCHFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = pw[0]; // P
+                  types[1] = (int) TOUCHEDGE;
+                  pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                  pos[3] = pw[1]; // Q
+                } else { // s4 < 0
+                  // [P, Q] overlaps [k, l] (tritri-03-+--).
+                  types[0] = (int) TOUCHFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = pw[0]; // P
+                  types[1] = (int) ACROSSEDGE;
+                  pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                  pos[3] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+                }
+              }
+            } else {  // s2 == 0
+              // P = l in [B, C] (tritri-03#0##).
+              types[0] = (int) TOUCHEDGE;
+              pos[0] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[1] = pw[0]; // P
+              types[1] = (int) DISJOINT;
+            }
+          }
+        }
+      } else {
+        // Q = k in [A, C] (tritri-030###).
+        types[0] = (int) TOUCHEDGE;
+        pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+        pos[1] = pw[1]; // Q
+        types[1] = (int) DISJOINT;
+      }
+    }
+
+    return 1;
+  } // if (z1 == 0)
+
+  if (z1 == 2) {
+
+    if (z2 == 0) {  // (20)
+      if (s1 < 0) {
+        if (s3 > 0) {
+          assert(s2 > 0);  // SELF_CHECK
+          if (s4 > 0) {
+            // [i, j] overlaps [A, l] (tritri-20-+++).
+            types[0] = (int) ACROSSVERT;
+            pos[0] = pu[0]; // A
+            pos[1] = 3;     // [P, Q, R]
+            types[1] = (int) ACROSSFACE;
+            pos[2] = 3;     // [A, B, C]
+            pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+          } else {
+            if (s4 == 0) {
+              // j = l, [i, j] contains [A, l] (tritri-20-++0).
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = 3;     // [P, Q, R]
+              types[1] = (int) ACROSSEDGE;
+              pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+            } else {  // s4 < 0
+              // [i, j] contains [A, l] (tritri-20-++-).
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = 3;     // [P, Q, R]
+              types[1] = (int) ACROSSEDGE;
+              pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[3] = 3;     // [P, Q, R]
+            }
+          }
+        } else {
+          if (s3 == 0) {
+            assert(s2 > 0); // SELF_CHECK
+            if (s4 > 0) {
+              // i = A, [i, j] overlaps [A, l] (tritri-20-+0+).
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+              types[1] = (int) ACROSSFACE;
+              pos[2] = 3;     // [A, B, C]
+              pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+            } else {
+              if (s4 == 0) {
+                // [i, j] = [A, l] (tritri-20-+00).
+                types[0] = (int) ACROSSVERT;
+                pos[0] = pu[0]; // A
+                pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                types[1] = (int) ACROSSEDGE;
+                pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+              } else { // s4 < 0
+                // i = A, [i, j] contains [A, l] (tritri-20-+0-).
+                types[0] = (int) ACROSSVERT;
+                pos[0] = pu[0]; // A
+                pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                types[1] = (int) ACROSSEDGE;
+                pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                pos[3] = 3;     // [P, Q, R]
+              }
+            }
+          } else { // s3 < 0
+            if (s2 > 0) {
+              if (s4 > 0) {
+                // [i, j] in [A, l] in [A, B, C] (tritri-20-+-+).
+                types[0] = (int) ACROSSFACE;
+                pos[0] = 3;     // [A, B, C]
+                pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                types[1] = (int) ACROSSFACE;
+                pos[2] = 3;     // [A, B, C]
+                pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+              } else {
+                if (s4 == 0) {
+                  // j = l, [i, j] in [A, l] (tritri-20-+-0).
+                  types[0] = (int) ACROSSFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                  types[1] = (int) ACROSSEDGE;
+                  pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                  pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+                } else { // s4 < 0
+                  // [i, j] overlaps [A, l] (tritri-20-+--).
+                  types[0] = (int) ACROSSFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                  types[1] = (int) ACROSSEDGE;
+                  pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                  pos[3] = 3;     // [P, Q, R]
+                }
+              }
+            } else { // s2 == 0
+              // i = l, [P, R] intersects [B, C] (tritri-20#0##).
+              types[0] = (int) ACROSSEDGE;
+              pos[0] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+              types[1] = (int) DISJOINT;
+            }
+          }
+        }
+      } else { // s1 == 0
+        // j = A in [Q, R] (tritri-200###).
+        types[0] = (int) ACROSSVERT;
+        pos[0] = pu[0]; // A
+        pos[1] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+        types[1] = (int) DISJOINT;
+      }
+    } else if (z2 == 2) {  // (22)
+      if (s1 < 0) {
+        if (s3 > 0) {
+          assert(s2 > 0); // SELF_CHECK
+          if (s4 > 0) {
+            // [P, j] overlaps [A, l] (tritri-22-+++).
+            types[0] = (int) ACROSSVERT;
+            pos[0] = pu[0]; // A
+            pos[1] = 3;     // [P, Q, R]
+            types[1] = (int) ACROSSFACE;
+            pos[2] = 3;     // [A, B, C]
+            pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+          } else {
+            if (s4 == 0) {
+              // j = l, [P, j] contains [A, l] (tritri-22-++0).
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = 3;     // [P, Q, R]
+              types[1] = (int) ACROSSEDGE;
+              pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+            } else { // s4 < 0
+              // [P, j] contains [A, l] (tritri-22-++-).
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = 3;     // [P, Q, R]
+              types[1] = (int) ACROSSEDGE;
+              pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[3] = 3;     // [P, Q, R]
+            }
+          }
+        } else {
+          if (s3 == 0) {
+            assert(s2 > 0); // SELF_CHECK
+            if (s4 > 0) {
+              // P = A, [P, j] in [A, l] (tritri-22-+0+).
+              types[0] = (int) SHAREVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = pw[0]; // P
+              types[1] = (int) ACROSSFACE;
+              pos[2] = 3;     // [A, B, C]
+              pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+            } else {
+              if (s4 == 0) {
+                // [P, j] = [A, l] (tritri-22-+00).
+                types[0] = (int) SHAREVERT;
+                pos[0] = pu[0]; // A
+                pos[1] = pw[0]; // P
+                types[1] = (int) ACROSSEDGE;
+                pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+              } else { // s4 < 0
+                // P = A, [P, j] contains [A, l] (tritri-22-+0-).
+                types[0] = (int) SHAREVERT;
+                pos[0] = pu[0]; // A
+                pos[1] = pw[0]; // P
+                types[1] = (int) ACROSSEDGE;
+                pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                pos[3] = 3;     // [P, Q, R]
+              }
+            }
+          } else { // s3 < 0
+            if (s2 > 0) {
+              if (s4 > 0) {
+                // [P, j] in [A, l] in [A, B, C] (tritri-22-+-+).
+                types[0] = (int) TOUCHFACE;
+                pos[0] = 3;     // [A, B, C]
+                pos[1] = pw[0]; // P
+                types[1] = (int) ACROSSFACE;
+                pos[2] = 3;     // [A, B, C]
+                pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+              } else {
+                if (s4 == 0) {
+                  // j = l, [P, j] in [A, l] (tritri-22-+-0).
+                  types[0] = (int) TOUCHFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = pw[0]; // P
+                  types[1] = (int) ACROSSEDGE;
+                  pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                  pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+                } else { // s4 < 0
+                  // P, j] overlaps [A, l] (tritri-22-+--).
+                  types[0] = (int) TOUCHFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = pw[0]; // P
+                  types[1] = (int) ACROSSEDGE;
+                  pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                  pos[3] = 3;     // [P, Q, R]
+                }
+              }
+            } else { // s2 == 0
+              // P = l, P in [B, C] (tritri-22#0##).
+              types[0] = (int) TOUCHEDGE;
+              pos[0] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // Int({[B, C])
+              pos[1] = pw[0]; // P
+              types[1] = (int) DISJOINT;
+            }
+          }
+        }
+      } else {
+        // j = A in [Q, R] (tritri-220###).
+        types[0] = (int) ACROSSVERT;
+        pos[0] = pu[0]; // A
+        pos[1] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+        types[1] = (int) DISJOINT;
+      }
+    } else if (z2 == 3) {  // (23)
+      if (s1 < 0) {
+        if (s3 > 0) {
+          assert(s2 > 0); // SELF_CHECK
+          if (s4 > 0) {
+            // [P, Q] overlaps [A, l] (tritri-23-+++).
+            types[0] = (int) ACROSSVERT;
+            pos[0] = pu[0]; // A
+            pos[1] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+            types[1] = (int) TOUCHFACE;
+            pos[2] = 3;     // [A, B, C]
+            pos[3] = pw[1]; // Q
+          } else {
+            if (s4 == 0) {
+              // Q = l, [P, Q] contains [A, l] (tritri-23-++0).
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+              types[1] = (int) TOUCHEDGE;
+              pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[3] = pw[1]; // Q
+            } else { // s4 < 0
+              // [P, Q] contains [A, l] (tritri-23-++-).
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+              types[1] = (int) ACROSSEDGE;
+              pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[3] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+            }
+          }
+        } else {
+          if (s3 == 0) {
+            assert(s2 > 0); // SELF_CHECK
+            if (s4 > 0) {
+              // P = A, [P, Q] in [A, l] (tritri-23-+0+).
+              types[0] = (int) SHAREVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = pw[0]; // P
+              types[1] = (int) TOUCHFACE;
+              pos[2] = 3;     // [A, B, C]
+              pos[3] = pw[1]; // Q
+            } else {
+              if (s4 == 0) {
+                // [P, Q] = [A, l] (tritri-23-+00).
+                types[0] = (int) SHAREVERT;
+                pos[0] = pu[0]; // A
+                pos[1] = pw[0]; // P
+                types[1] = (int) TOUCHEDGE;
+                pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                pos[3] = pw[1]; // Q
+              } else {  // s4 < 0
+                // [P, Q] contains [A, l] (tritri-23-+0-).
+                types[0] = (int) SHAREVERT;
+                pos[0] = pu[0]; // A
+                pos[1] = pw[0]; // P
+                types[1] = (int) ACROSSEDGE;
+                pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                pos[3] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+              }
+            }
+          } else { // s3 < 0
+            if (s2 > 0) {
+              if (s4 > 0) {
+                // [P, Q] in [A, l] (tritri-23-+-+).
+                types[0] = (int) TOUCHFACE;
+                pos[0] = 3;     // [A, B, C]
+                pos[1] = pw[0]; // P
+                types[1] = (int) TOUCHFACE;
+                pos[2] = 3;     // [A, B, C]
+                pos[3] = pw[1]; // Q
+              } else {
+                if (s4 == 0) {
+                  // Q = l, [P, Q] in [A, l] (tritri-23-+-0).
+                  types[0] = (int) TOUCHFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = pw[0]; // P
+                  types[1] = (int) TOUCHEDGE;
+                  pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                  pos[3] = pw[1]; // Q
+                } else { // s4 < 0
+                  // [P, Q] overlaps [A, l] (tritri-23-+--).
+                  types[0] = (int) TOUCHFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = pw[0]; // P
+                  types[1] = (int) ACROSSEDGE;
+                  pos[2] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+                  pos[3] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+                }
+              }
+            } else { // s2 == 0
+              // P = l in [B, C] (tritri-23#0##).
+              types[0] = (int) TOUCHEDGE;
+              pos[0] = (iu == 0 ? pu[1] : mi1mo3[pu[1]]); // [B, C]
+              pos[1] = pw[0]; // P
+              types[1] = (int) DISJOINT;
+            }
+          }
+        }
+      } else {
+        // Q = A (tritri-230###).
+        types[0] = (int) SHAREVERT;
+        pos[0] = pu[0]; // A
+        pos[1] = pw[1]; // Q
+        types[1] = (int) DISJOINT;
+      }
+    }
+
+    return 1;
+  } // if (z1 == 2)
+
+  if (z1 == 3) {
+
+    if (z2 == 0) {  // (30)
+      if (s1 < 0) {
+        if (s3 > 0) {
+          assert(s2 > 0); // SELF_CHECK
+          if (s4 > 0) {
+            // [i, j] overlaps [A, B] (tritri-30-+++).
+            types[0] = (int) ACROSSVERT;
+            pos[0] = pu[0]; // A
+            pos[1] = 3;     // [P, Q, R]
+            types[1] = (int) ACROSSEDGE;
+            pos[2] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+            pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+          } else {
+            if (s4 == 0) {
+              // j = B, [i, j] contains [A, B] (tritri-30-++0).
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = 3;     // [P, Q, R]
+              types[1] = (int) ACROSSVERT;
+              pos[2] = pu[1]; // B
+              pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+            } else { // s4 < 0
+              // [i, j] contains [A, B] (tritri-30-++-).
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = 3;     // [P, Q, R]
+              types[1] = (int) ACROSSVERT;
+              pos[2] = pu[1]; // B
+              pos[3] = 3;     // [P, Q, R]
+            }
+          }
+        } else {
+          if (s3 == 0) {
+            assert(s2 > 0); // SELF_CHECK
+            if (s4 > 0) {
+              // i = A, [i, j] in [A, B] (tritri-30-+0+).
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+              types[1] = (int) ACROSSEDGE;
+              pos[2] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+              pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+            } else {
+              if (s4 == 0) {
+                // [i, j] = [A, B] (tritri-30-+00).
+                types[0] = (int) ACROSSVERT;
+                pos[0] = pu[0]; // A
+                pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                types[1] = (int) ACROSSVERT;
+                pos[2] = pu[1]; // B
+                pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+              } else { // s4 < 0
+                // i = A, [i, j] contains [A, B] (tritri-30-+0-).
+                types[0] = (int) ACROSSVERT;
+                pos[0] = pu[0]; // A
+                pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                types[1] = (int) ACROSSVERT;
+                pos[2] = pu[1]; // B
+                pos[3] = 3;     // [P, Q, R]
+              }
+            }
+          } else { // s3 < 0
+            if (s2 > 0) {
+              if (s4 > 0) {
+                // [i, j] in [A, B] (tritri-30-+-+).
+                types[0] = (int) ACROSSEDGE;
+                pos[0] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+                pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                types[1] = (int) ACROSSEDGE;
+                pos[2] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+                pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+              } else {
+                if (s4 == 0) {
+                  // j = B, [i, j] in [A, B] (tritri-30-+-0).
+                  types[0] = (int) ACROSSEDGE;
+                  pos[0] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+                  pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                  types[1] = (int) ACROSSVERT;
+                  pos[2] = pu[1]; // B
+                  pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+                } else { // s4 < 0
+                  // [i, j] overlaps [A, B] (tritri-30-+--).
+                  types[0] = (int) ACROSSEDGE;
+                  pos[0] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+                  pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                  types[1] = (int) ACROSSVERT;
+                  pos[2] = pu[1]; // B
+                  pos[3] = 3;     // [P, Q, R]
+                }
+              }
+            } else { // s2 == 0
+              // i = B in [P, R] (tritri-30#0##).
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[1]; // B
+              pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+              types[1] = (int) DISJOINT;
+            }
+          }
+        }
+      } else {
+        // j = A in [Q, R] (tritri-300###).
+        types[0] = (int) ACROSSVERT;
+        pos[0] = pu[0]; // A
+        pos[1] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+        types[1] = (int) DISJOINT;
+      }
+    } else if (z2 == 2) {  // (32)
+      if (s1 < 0) {
+        if (s3 > 0) {
+          assert(s2 > 0); // SELF_CHECK
+          if (s4 > 0) {
+            // [P, j] overlaps [A, B] (tritri-32-+++).
+            types[0] = (int) ACROSSVERT;
+            pos[0] = pu[0]; // A
+            pos[1] = 3;     // [P, Q, R]
+            types[1] = (int) ACROSSEDGE;
+            pos[2] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+            pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+          } else {
+            if (s4 == 0) {
+              // j = B, [P, j] contains [A, B] (tritri-32-++0).
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = 3;     // [P, Q, R]
+              types[1] = (int) ACROSSVERT;
+              pos[2] = pu[1]; // B
+              pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+            } else { // s4 < 0
+              // [P, j] contains [A, B] (tritri-32-++-).
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = 3;     // [P, Q, R]
+              types[1] = (int) ACROSSVERT;
+              pos[2] = pu[1]; // B
+              pos[3] = 3;     // [P, Q, R]
+            }
+          }
+        } else {
+          if (s3 == 0) {
+            assert(s2 > 0); // SELF_CHECK
+            if (s4 > 0) {
+              // P = A, [P, j] in [A, B] (tritri-32-+0+).
+              types[0] = (int) SHAREVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = pw[0]; // P
+              types[1] = (int) ACROSSEDGE;
+              pos[2] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+              pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+            } else {
+              if (s4 == 0) {
+                // [P, j] = [A, B] (tritri-32-+00).
+                types[0] = (int) SHAREVERT;
+                pos[0] = pu[0]; // A
+                pos[1] = pw[0]; // P
+                types[1] = (int) ACROSSVERT;
+                pos[2] = pu[1]; // B
+                pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+              } else { // s4 < 0
+                // P = A, [P, j] contains [A, B] (tritri-32-+0-).
+                types[0] = (int) SHAREVERT;
+                pos[0] = pu[0]; // A
+                pos[1] = pw[0]; // P
+                types[1] = (int) ACROSSVERT;
+                pos[2] = pu[1]; // B
+                pos[3] = 3;     // [P, Q, R]
+              }
+            }
+          } else { // s3 < 0
+            if (s2 > 0) {
+              if (s4 > 0) {
+                // [P, j] in [A, B] (tritri-32-+-+).
+                types[0] = (int) TOUCHEDGE;
+                pos[0] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+                pos[1] = pw[0]; // P
+                types[1] = (int) ACROSSEDGE;
+                pos[2] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+                pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+              } else {
+                if (s4 == 0) {
+                  // j = B, [P, j] in [A, B] (tritri-32-+-0).
+                  types[0] = (int) TOUCHEDGE;
+                  pos[0] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+                  pos[1] = pw[0]; // P
+                  types[1] = (int) ACROSSVERT;
+                  pos[2] = pu[1]; // B
+                  pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+                } else { // s4 < 0
+                  // [P, j] overlaps [A, B] (tritri-32-+--).
+                  types[0] = (int) TOUCHEDGE;
+                  pos[0] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+                  pos[1] = pw[0]; // P
+                  types[1] = (int) ACROSSVERT;
+                  pos[2] = pu[1]; // B
+                  pos[3] = 3;     // [P, Q, R]
+                }
+              }
+            } else { // s2 == 0
+              // P = B (tritri-32#0##).
+              types[0] = (int) SHAREVERT;
+              pos[0] = pu[1]; // B
+              pos[1] = pw[0]; // P
+              types[1] = (int) DISJOINT;
+            }
+          }
+        }
+      } else {
+        // j = A in [Q, R] (tritri-320###).
+        types[0] = (int) ACROSSVERT;
+        pos[0] = pu[0]; // A
+        pos[1] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+        types[1] = (int) DISJOINT;
+      }
+    } else if (z2 == 3) {  // (33)
+      if (s1 < 0) {
+        if (s3 > 0) {
+          assert(s2 > 0); // SELF_CHECK
+          if (s4 > 0) {
+            // [P, Q] overlaps [A, B] (tritri-33-+++).
+            types[0] = (int) ACROSSVERT;
+            pos[0] = pu[0]; // A
+            pos[1] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+            types[1] = (int) TOUCHEDGE;
+            pos[2] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+            pos[3] = pw[1]; // Q
+          } else {
+            if (s4 == 0) {
+              // Q = B, [P, Q] contains [A, B] (tritri-33-++0).
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+              types[1] = (int) SHAREVERT;
+              pos[2] = pu[1]; // B
+              pos[3] = pw[1]; // Q
+            } else { // s4 < 0
+              // [P, Q] contains [A, B] (tritri-33-++-).
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+              types[1] = (int) ACROSSVERT;
+              pos[2] = pu[1]; // B
+              pos[3] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+            }
+          }
+        } else {
+          if (s3 == 0) {
+            assert(s2 > 0); // SELF_CHECK
+            if (s4 > 0) {
+              // P = A, [P, Q] in [A, B] (tritri-33-+0+).
+              types[0] = (int) SHAREVERT;
+              pos[0] = pu[0]; // A
+              pos[1] = pw[0]; // P
+              types[1] = (int) TOUCHEDGE;
+              pos[2] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+              pos[3] = pw[1]; // Q
+            } else {
+              if (s4 == 0) {
+                // [P, Q] = [A, B] (tritri-33-+00).
+                types[0] = (int) SHAREEDGE;
+                pos[0] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+                pos[1] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+                types[1] = DISJOINT;
+              } else { // s4 < 0
+                // P = A, [P, Q] contains [A, B] (tritri-33-+0-).
+                types[0] = (int) SHAREVERT;
+                pos[0] = pu[0]; // A
+                pos[1] = pw[0]; // P
+                types[1] = (int) ACROSSVERT;
+                pos[2] = pu[0]; // A
+                pos[3] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+              }
+            }
+          } else { // s3 < 0
+            if (s2 > 0) {
+              if (s4 > 0) {
+                // [P, Q] in [A, B] (tritri-33-+-+).
+                types[0] = (int) TOUCHEDGE;
+                pos[0] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+                pos[1] = pw[0]; // P
+                types[1] = (int) TOUCHEDGE;
+                pos[2] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+                pos[3] = pw[1]; // Q
+              } else {
+                if (s4 == 0) {
+                  // Q = B, [P, Q] overlaps [A, B] (tritri-33-+-0).
+                  types[0] = (int) TOUCHEDGE;
+                  pos[0] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+                  pos[1] = pw[0]; // P
+                  types[1] = (int) SHAREVERT;
+                  pos[2] = pu[1]; // B
+                  pos[3] = pw[1]; // Q
+                } else { // s4 < 0
+                  // [P, Q] overlaps [A, B] (tritri-33-+--).
+                  types[0] = (int) TOUCHEDGE;
+                  pos[0] = (iu == 0 ? pu[0] : mi1mo3[pu[0]]); // Int([A, B])
+                  pos[1] = pw[0]; // P
+                  types[1] = (int) ACROSSVERT;
+                  pos[2] = pu[1]; // B
+                  pos[3] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+                }
+              }
+            } else { // s2 == 0
+              // P = B (tritri-33#0##).
+              types[0] = (int) SHAREVERT;
+              pos[0] = pu[1]; // B
+              pos[1] = pw[0]; // P
+              types[1] = (int) DISJOINT;
+            }
+          }
+        }
+      } else {
+        // Q = A (tritri-330###).
+        types[0] = (int) SHAREVERT;
+        pos[0] = pu[0]; // A
+        pos[1] = pw[1]; // Q
+        types[1] = (int) DISJOINT;
+      }
+    }
+
+    return 1;
+  } // if (z1 == 3)
+
+  if (z1 == 4) {
+
+    if (z2 == 0) { // (40)
+      if (s1 < 0) {
+        if (s3 > 0) {
+          assert(s2 > 0); // SELF_CHECK
+          if (s4 > 0) {
+            // [i, j] overlaps [k, B] (tritri-40-+++)
+            types[0] = (int) ACROSSEDGE;
+            pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+            pos[1] = 3;     // [P, Q, R]
+            types[1] = (int) ACROSSFACE;
+            pos[2] = 3;     // [A, B, C]
+            pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+          } else {
+            if (s4 == 0) {
+              // j = B, [i, j] overlaps [k, B] (tritri-40-++0)
+              types[0] = (int) ACROSSEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = 3;     // [P, Q, R]
+              types[1] = (int) ACROSSVERT;
+              pos[2] = pu[1]; // B
+              pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+            } else { // s4 < 0
+              // [i, j] contains [k, B] (tritri-40-++-)
+              types[0] = (int) ACROSSEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = 3;     // [P, Q, R]
+              types[1] = (int) ACROSSVERT;
+              pos[2] = pu[1]; // B
+              pos[3] = 3; // [P, Q, R]
+            }
+          }
+        } else {
+          if (s3 == 0) {
+            assert(s2 > 0); // SELF_CHECK
+            if (s4 > 0) {
+              // i = k, [i, j] in [k, B] (tritri-40-+0+)
+              types[0] = (int) ACROSSEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+              types[1] = (int) ACROSSFACE;
+              pos[2] = 3;     // [A, B, C]
+              pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+            } else {
+              if (s4 == 0) {
+                // [i, j] = [k, B] (tritri-40-+00)
+                types[0] = (int) ACROSSEDGE;
+                pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+                pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                types[1] = (int) ACROSSVERT;
+                pos[2] = pu[1]; // B
+                pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+              } else { // s4 < 0
+                // i = k, [i, j] contains [k, B] (tritri-40-+0-)
+                types[0] = (int) ACROSSEDGE;
+                pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+                pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                types[1] = (int) ACROSSVERT;
+                pos[2] = pu[1]; // B
+                pos[3] = 3; // [P, Q, R]
+              }
+            }
+          } else { // s3 < 0
+            if (s2 > 0) {
+              if (s4 > 0) {
+                // [i, j] in [k, B] (tritri-40-+-+)
+                types[0] = (int) ACROSSFACE;
+                pos[0] = 3;     // [A, B, C]
+                pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                types[1] = (int) ACROSSFACE;
+                pos[2] = 3;     // [A, B, C]
+                pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+              } else {
+                if (s4 == 0) {
+                  // j = B, [i, j] in [k, B] (tritri-40-+-0)
+                  types[0] = (int) ACROSSFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                  types[1] = (int) ACROSSVERT;
+                  pos[2] = pu[1]; // B
+                  pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+                } else { // s4 < 0
+                  // [i, j] overlaps [k, B] (tritri-40-+--)
+                  types[0] = (int) ACROSSFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+                  types[1] = (int) ACROSSVERT;
+                  pos[2] = pu[1]; // B
+                  pos[3] = 3;     // [P, Q, R]
+                }
+              }
+            } else { // s2 == 0
+              // assert(s4 < 0); // SELF_CHECK
+              // i = B (tritri-40#0##)
+              types[0] = (int) ACROSSVERT;
+              pos[0] = pu[1]; // B
+              pos[1] = (iv == 0 ? pw[2] : mi1mo3[pw[2]]); // [R, P]
+              types[1] = (int) DISJOINT;
+            }
+          }
+        }
+      } else { // s1 == 0
+        // j = k (tritri-400###)
+        types[0] = (int) ACROSSEDGE;
+        pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+        pos[1] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+        types[1] = (int) DISJOINT;
+      }
+    } else if (z2 == 2) { // (42)
+      if (s1 < 0) {
+        if (s3 > 0) {
+          assert(s2 > 0); // SELF_CHECK
+          if (s4 > 0) {
+            // [P, j] overlaps [k, B] (tritri-42-+++)
+            types[0] = (int) ACROSSEDGE;
+            pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+            pos[1] = 3;     // [P, Q, R]
+            types[1] = (int) ACROSSFACE;
+            pos[2] = 3;     // [A, B, C]
+            pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+          } else {
+            if (s4 == 0) {
+              // j = B, [P, j] contains [k, B] (tritri-42-++0)
+              types[0] = (int) ACROSSEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = 3;     // [P, Q, R]
+              types[1] = (int) ACROSSVERT;
+              pos[2] = pu[1]; // B
+              pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+            } else { // s4 < 0
+              // [P, j] contains [k, B] (tritri-42-++-)
+              types[0] = (int) ACROSSEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = 3;     // [P, Q, R]
+              types[1] = (int) ACROSSVERT;
+              pos[2] = pu[1]; // B
+              pos[3] = 3;     // [P, Q, R]
+            }
+          }
+        } else {
+          if (s3 == 0) {
+            assert(s2 > 0); // SELF_CHECK
+            if (s4 > 0) {
+              // P = k, [P, j] in [k, B] (tritri-42-+0+)
+              types[0] = (int) TOUCHEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = pw[0]; // P
+              types[1] = (int) ACROSSFACE;
+              pos[2] = 3;     // [A, B, C]
+              pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+            } else {
+              if (s4 == 0) {
+                // [P, j] = [k, B] (tritri-42-+00)
+                types[0] = (int) TOUCHEDGE;
+                pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+                pos[1] = pw[0]; // P
+                types[1] = (int) ACROSSVERT;
+                pos[2] = pu[1]; // B
+                pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+              } else { // s4 < 0
+                // P = k, [P, j] in [k, B] (tritri-42-+0-)
+                types[0] = (int) TOUCHEDGE;
+                pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+                pos[1] = pw[0]; // P
+                types[1] = (int) ACROSSVERT;
+                pos[2] = pu[1]; // B
+                pos[3] = 3;     // [P, Q, R]
+              }
+            }
+          } else { // s3 < 0
+            if (s2 > 0) {
+              if (s4 > 0) {
+                // [P, j] in [k, B] (tritri-42-+-+)
+                types[0] = (int) TOUCHFACE;
+                pos[0] = 3;     // [A, B, C]
+                pos[1] = pw[0]; // P
+                types[1] = (int) ACROSSFACE;
+                pos[2] = 3;     // [A, B, C]
+                pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+              } else {
+                if (s4 == 0) {
+                  // j = B, [P, j] in [k, B] (tritri-42-+-0)
+                  types[0] = (int) TOUCHFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = pw[0]; // P
+                  types[1] = (int) ACROSSVERT;
+                  pos[2] = pu[1]; // B
+                  pos[3] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+                } else { // s4 < 0
+                  // [P, j] overlaps [k, B] (tritri-42-+--)
+                  types[0] = (int) TOUCHFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = pw[0]; // P
+                  types[1] = (int) ACROSSVERT;
+                  pos[2] = pu[1]; // B
+                  pos[3] = 3;     // [P, Q, R]
+                }
+              }
+            } else { // s2 == 0
+              // assert(s4 < 0); // SELF_CHECK
+              // P = B (tritri-42#0##)
+              types[0] = (int) SHAREVERT;
+              pos[0] = pu[1]; // B
+              pos[1] = pw[0]; // P
+              types[1] = (int) DISJOINT;
+            }
+          }
+        }
+      } else { // s1 == 0
+        // j = k (tritri-420###)
+        types[0] = (int) ACROSSEDGE;
+        pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+        pos[1] = (iv == 0 ? pw[1] : mi1mo3[pw[1]]); // [Q, R]
+        types[1] = (int) DISJOINT;
+      }
+    } else if (z2 == 3) { // (43)
+      if (s1 < 0) {
+        if (s3 > 0) {
+          assert(s2 > 0); // SELF_CHECK
+          if (s4 > 0) {
+            // [P, Q] overlaps [k, B] (tritri-43-+++)
+            types[0] = (int) ACROSSEDGE;
+            pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+            pos[1] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+            types[1] = (int) TOUCHFACE;
+            pos[2] = 3;     // [A, B, C]
+            pos[3] = pw[1]; // Q
+          } else {
+            if (s4 == 0) {
+              // Q = B, [P, Q] contains [k, B] (tritri-43-++0)
+              types[0] = (int) ACROSSEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+              types[1] = (int) SHAREVERT;
+              pos[2] = pu[1]; // B
+              pos[3] = pw[1]; // Q
+            } else { // s4 < 0
+              // [P, Q] contains [k, B] (tritri-43-++-)
+              types[0] = (int) ACROSSEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+              types[1] = (int) ACROSSVERT;
+              pos[2] = pu[1]; // B
+              pos[3] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+            }
+          }
+        } else {
+          if (s3 == 0) {
+            assert(s2 > 0); // SELF_CHECK
+            if (s4 > 0) {
+              // P = k, [P, Q] in [k, B] (tritri-43-+0+)
+              types[0] = (int) TOUCHEDGE;
+              pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+              pos[1] = pw[0]; // P
+              types[1] = (int) TOUCHFACE;
+              pos[2] = 3;     // [A, B, C]
+              pos[3] = pw[1]; // Q
+            } else {
+              if (s4 == 0) {
+                // [P, Q] = [k, B] (tritri-43-+00)
+                types[0] = (int) TOUCHEDGE;
+                pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+                pos[1] = pw[0]; // P
+                types[1] = (int) SHAREVERT;
+                pos[2] = pu[1]; // B
+                pos[3] = pw[1]; // Q
+              } else { // s4 < 0
+                // P = k, [P, Q] contains [k, B] (tritri-43-+0-)
+                types[0] = (int) TOUCHEDGE;
+                pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+                pos[1] = pw[0]; // P
+                types[1] = (int) ACROSSVERT;
+                pos[2] = pu[1]; // B
+                pos[3] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+              }
+            }
+          } else { // s3 < 0
+            if (s2 > 0) {
+              if (s4 > 0) {
+                // [P, Q] in [k, B] (tritri-43-+-+)
+                types[0] = (int) TOUCHFACE;
+                pos[0] = 3;     // [A, B, C]
+                pos[1] = pw[0]; // P
+                types[1] = (int) TOUCHFACE;
+                pos[2] = 3;     // [A, B, C]
+                pos[3] = pw[1]; // Q
+              } else {
+                if (s4 == 0) {
+                  // Q = B, [P, Q] in [k, B] (tritri-43-+-0)
+                  types[0] = (int) TOUCHFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = pw[0]; // P
+                  types[1] = (int) SHAREVERT;
+                  pos[2] = pu[1]; // B
+                  pos[3] = pw[1]; // Q
+                } else { // s4 < 0
+                  // [P, Q] overlaps [k, B] (tritri-43-+--)
+                  types[0] = (int) TOUCHFACE;
+                  pos[0] = 3;     // [A, B, C]
+                  pos[1] = pw[0]; // P
+                  types[1] = (int) ACROSSVERT;
+                  pos[2] = pu[1]; // B
+                  pos[3] = (iv == 0 ? pw[0] : mi1mo3[pw[0]]); // Int([P, Q])
+                }
+              }
+            } else { // s2 == 0
+              // assert(s4 < 0); // SELF_CHECK
+              // P = B (tritri-43#0##)
+              types[0] = (int) SHAREVERT;
+              pos[0] = pu[1]; // B
+              pos[1] = pw[0]; // P
+              types[1] = (int) DISJOINT;
+            }
+          }
+        }
+      } else { // s1 == 0
+        // Q = k (tritri-430###)
+        types[0] = (int) TOUCHEDGE;
+        pos[0] = (iu == 0 ? pu[2] : mi1mo3[pu[2]]); // [C, A]
+        pos[1] = pw[1]; // Q
+        types[1] = (int) DISJOINT;
+      }
+    }
+
+    return 1;
+  } // if (z1 == 4)
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insphere_sos()    Insphere test with symbolic perturbation.               //
+//                                                                           //
+// Given four points pa, pb, pc, and pd, test if the point pe lies inside or //
+// outside the circumscirbed sphere of the four points.  Here we assume that //
+// the orientation of the sequence {pa, pb, pc, pd} is negative (NOT zero),  //
+// i.e., pd lies at the negative side of the plane defined by pa, pb, and pc.//
+//                                                                           //
+// Return a positive value (> 0) if pe lies outside, a negative value (< 0)  //
+// if pe lies inside the sphere, the returned value will not be zero.        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL tetgenmesh::insphere_sos(point pa, point pb, point pc, point pd, point pe)
+{
+  REAL sign;
+
+  inspherecount++;
+
+  sign = insphere(pa, pb, pc, pd, pe);
+  if (sign != 0.0) {
+    return sign;
+  }
+
+  insphere_sos_count++;
+
+  // Symbolic perturbation.
+  point pt[5], swappt;
+  REAL oriA, oriB;
+  int swaps, count;
+  int n, i;
+
+  pt[0] = pa;
+  pt[1] = pb;
+  pt[2] = pc;
+  pt[3] = pd;
+  pt[4] = pe;
+  
+  // Sort the five points such that their indices are in the increasing
+  //   order. An optimized bubble sort algorithm is used, i.e., it has
+  //   the worst case O(n^2) runtime, but it is usually much faster.
+  swaps = 0; // Record the total number of swaps.
+  n = 5;
+  do {
+    count = 0;
+    n = n - 1;
+    for (i = 0; i < n; i++) {
+      if (pointmark(pt[i]) > pointmark(pt[i+1])) {
+        swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt;
+        count++;
+      }
+    }
+    swaps += count;
+  } while (count > 0); // Continue if some points are swapped.
+
+  oriA = orient3d(pt[1], pt[2], pt[3], pt[4]);
+  if (oriA != 0.0) {
+    // Flip the sign if there are odd number of swaps.
+    if ((swaps % 2) != 0) oriA = -oriA;
+    return oriA;
+  }
+  
+  oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]);
+  assert(oriB != 0.0); // SELF_CHECK
+  // Flip the sign if there are odd number of swaps.
+  if ((swaps % 2) != 0) oriB = -oriB;
+  return oriB;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// isincircle()    Test if d lies inside the circumcircle of abc.            //
+//                                                                           //
+// Return a positive value (> 0) if pd lies outside, a negative value (< 0)  //
+// if pd lies inside the circle, a zero if pd lies on the circle.            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+/*  This version (which uses insphere test) is not save. It may give 
+  undesired result when four points are nearly coplanar.
+  An example is in fig/dump-incircle3d-case1.*/
+
+/*REAL tetgenmesh::incircle3d(point pa, point pb, point pc, point pd)
+{
+  REAL area2[2], n1[3], n2[3], pe[3];
+  REAL sign, L, len;
+
+  // Calculate the areas of the two triangles [a, b, c] and [b, a, d].
+  facenormal(pa, pb, pc, n1, 1);
+  area2[0] = DOT(n1, n1);
+  facenormal(pb, pa, pd, n2, 1);
+  area2[1] = DOT(n2, n2);
+  L = DIST(pa, pb);
+
+  if (area2[0] > area2[1]) {
+    // Choose [a, b, c] as the base triangle.
+    len = sqrt(area2[0]);
+    n1[0] /= len;
+    n1[1] /= len;
+    n1[2] /= len;
+    L += DIST(pb, pc);
+    L += DIST(pc, pa);
+    L /= 3.0;
+    pe[0] = pa[0] + L * n1[0];
+    pe[1] = pa[1] + L * n1[1];
+    pe[2] = pa[2] + L * n1[2];
+    sign = insphere(pa, pb, pc, pe, pd);
+  } else {
+    // Choose [b, a, d] as the base triangle.
+    len = sqrt(area2[1]);
+    n2[0] /= len;
+    n2[1] /= len;
+    n2[2] /= len;
+    L += DIST(pa, pd);
+    L += DIST(pd, pb);
+    L /= 3.0;
+    pe[0] = pa[0] + L * n2[0];
+    pe[1] = pa[1] + L * n2[1];
+    pe[2] = pa[2] + L * n2[2];
+    sign = insphere(pb, pa, pd, pe, pc);
+  }
+
+  return sign;
+}*/
+
+/* This code had problem with file2.poly*/
+REAL tetgenmesh::incircle3d(point pa, point pb, point pc, point pd)
+{
+  REAL area2[2], n1[3], n2[3], c[3];
+  REAL sign, r, d;
+
+  // Calculate the areas of the two triangles [a, b, c] and [b, a, d].
+  facenormal(pa, pb, pc, n1, 1);
+  area2[0] = DOT(n1, n1);
+  facenormal(pb, pa, pd, n2, 1);
+  area2[1] = DOT(n2, n2);
+
+  if (area2[0] > area2[1]) {
+    // Choose [a, b, c] as the base triangle.
+    assert(area2[0] > 0); // SELF_CHECK
+    circumsphere(pa, pb, pc, NULL, c, &r);
+    d = DIST(c, pd);
+  } else {
+    // Choose [b, a, d] as the base triangle.
+    assert(area2[1] > 0); // SELF_CHECK
+    circumsphere(pb, pa, pd, NULL, c, &r);
+    d = DIST(c, pc);
+  }
+
+  sign = d - r;
+  if (fabs(sign) / r < b->epsilon) {
+    sign = 0;
+  }
+
+  return sign;
+}
+
+/*
+REAL tetgenmesh::incircle3d(point pa, point pb, point pc, point pd)
+{
+  point pk, pl, pm, pn;
+  REAL area2[4], n[3], c[3];
+  REAL amax, sign, r, l, q;
+  int imax;
+
+  // Calculate the areas of the four triangles in a, b, c, and d.
+  //   Get the base triangle which has the largest area.
+  facenormal(pa, pb, pc, n, 1);
+  area2[0] = DOT(n, n); 
+  facenormal(pb, pa, pd, n, 1);
+  area2[1] = DOT(n, n);
+  if (area2[0] < area2[1]) {
+    amax = area2[1]; imax = 1;
+  } else {
+    amax = area2[0]; imax = 0;
+  }
+  facenormal(pc, pd, pb, n, 1);
+  area2[2] = DOT(n, n);
+  if (amax < area2[2]) {
+    amax = area2[2]; imax = 2;
+  }
+  facenormal(pd, pc, pa, n, 1);
+  area2[3] = DOT(n, n);
+  if (amax < area2[3]) {
+    amax = area2[3]; imax = 3;
+  }
+
+  // Permute the vertices s. t. the base triangle is (pk, pl, pm).
+  if (imax == 0) {
+    pk = pa; pl = pb; pm = pc; pn = pd; sign = 1.0;
+  } else if (imax == 1) {
+    pk = pb; pl = pa; pm = pd; pn = pc; sign = 1.0;
+  } else if (imax == 2) {
+    pk = pc; pl = pd; pm = pb; pn = pa; sign = -1.0;
+  } else {
+    pk = pd; pl = pc; pm = pa; pn = pb; sign = -1.0;
+  }
+
+  // Make sure that the base triangle is not degenerate.
+  l = DIST(pk, pl);
+  l += DIST(pl, pm);
+  l += DIST(pm, pk);
+  l /= 3.0;
+
+  if (sqrt(amax) > (l * l * b->epsilon)) {
+    // Calculate the circumcenter and radius.
+    circumsphere(pk, pl, pm, NULL, c, &r);
+    l = DIST(c, pn);
+    q = fabs((l - r) / r);
+  } else {
+    // A (nearly) degenerate base triangle.
+    assert(0);  // Not handle yet.
+    q = 0;
+  }
+
+  if (q > b->epsilon) {
+    return (l - r) * sign;  // Adjust the sign.
+  } else {
+    return 0;  // Round to zero.
+  }
+}*/
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// iscoplanar()    Check if four points are approximately coplanar.          //
+//                                                                           //
+// 'tol' is the relative error tolerance.  The coplanarity is determined by  //
+// the equation q < tol, where q = fabs(6 * vol) / L^3, vol is the volume of //
+// the tet klmn, and L is the average edge length of the tet.                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::iscoplanar(point k, point l, point m, point n, REAL ori)
+{
+  REAL L, q;
+
+  L = DIST(k, l);
+  L += DIST(l, m);
+  L += DIST(m, k);
+  L += DIST(k, n);
+  L += DIST(l, n);
+  L += DIST(m, n);
+  assert(L > 0.0);  // SELF_CHECK
+  L /= 6.0;
+
+  q = fabs(ori) / (L * L * L);
+
+  return q <= b->epsilon;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// interiorangle()    Return the interior angle (0 - 2 * PI) between vectors //
+//                    o->p1 and o->p2.                                       //
+//                                                                           //
+// 'n' is the normal of the plane containing face (o, p1, p2).  The interior //
+// angle is the total angle rotating from o->p1 around n to o->p2.  Exchange //
+// the position of p1 and p2 will get the complement angle of the other one. //
+// i.e., interiorangle(o, p1, p2) = 2 * PI - interiorangle(o, p2, p1).  Set  //
+// 'n' be NULL if you only want the interior angle between 0 - PI.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL tetgenmesh::interiorangle(point o, point p1, point p2, REAL* n)
+{
+  REAL v1[3], v2[3], np[3];
+  REAL theta, costheta, lenlen;
+  REAL ori, len1, len2;
+
+  // Get the interior angle (0 - PI) between o->p1, and o->p2.
+  v1[0] = p1[0] - o[0];
+  v1[1] = p1[1] - o[1];
+  v1[2] = p1[2] - o[2];
+  v2[0] = p2[0] - o[0];
+  v2[1] = p2[1] - o[1];
+  v2[2] = p2[2] - o[2];
+  len1 = sqrt(DOT(v1, v1));
+  len2 = sqrt(DOT(v2, v2));
+  lenlen = len1 * len2;
+  assert(lenlen != 0.0);  // SELF_CHECK
+  costheta = DOT(v1, v2) / lenlen;
+  if (costheta > 1.0) {
+    costheta = 1.0; // Roundoff. 
+  } else if (costheta < -1.0) {
+    costheta = -1.0; // Roundoff. 
+  }
+  theta = acos(costheta);
+  if (n != NULL) {
+    // Get a point above the face (o, p1, p2);
+    np[0] = o[0] + n[0];
+    np[1] = o[1] + n[1];
+    np[2] = o[2] + n[2];
+    // Adjust theta (0 - 2 * PI).
+    ori = orient3d(p1, o, np, p2);
+    if (ori > 0.0) {
+      theta = 2 * PI - theta;
+    }
+  }
+
+  return theta;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// facenormal()    Calculate the normal of the face.                         //
+//                                                                           //
+// The normal of the face abc can be calculated by the cross product of 2 of //
+// its 3 edge vectors.  A better choice of two edge vectors will reduce the  //
+// numerical error during the calculation.  Burdakov proved that the optimal //
+// basis problem is equivalent to the minimum spanning tree problem with the //
+// edge length be the functional, see Burdakov, "A greedy algorithm for the  //
+// optimal basis problem", BIT 37:3 (1997), 591-599. If 'pivot' > 0, the two //
+// short edges in abc are chosen for the calculation.                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::facenormal(point pa, point pb, point pc, REAL *n, int pivot)
+{
+  REAL v1[3], v2[3], v3[3], *pv1, *pv2;
+  REAL L1, L2, L3;
+
+  v1[0] = pb[0] - pa[0];  // edge vector v1: a->b
+  v1[1] = pb[1] - pa[1];
+  v1[2] = pb[2] - pa[2];
+  v2[0] = pa[0] - pc[0];  // edge vector v2: c->a
+  v2[1] = pa[1] - pc[1];
+  v2[2] = pa[2] - pc[2];
+
+  // Default, normal is calculated by: v1 x (-v2) (see Fig. fnormal).
+  if (pivot > 0) {
+    // Choose edge vectors by Burdakov's algorithm.
+    v3[0] = pc[0] - pb[0];  // edge vector v3: b->c
+    v3[1] = pc[1] - pb[1];
+    v3[2] = pc[2] - pb[2];
+    L1 = DOT(v1, v1);
+    L2 = DOT(v2, v2);
+    L3 = DOT(v3, v3);
+    // Sort the three edge lengths.
+    if (L1 < L2) {
+      if (L2 < L3) {
+        pv1 = v1; pv2 = v2; // n = v1 x (-v2).
+      } else {
+        pv1 = v3; pv2 = v1; // n = v3 x (-v1).
+      }
+    } else {
+      if (L1 < L3) {
+        pv1 = v1; pv2 = v2; // n = v1 x (-v2).
+      } else {
+        pv1 = v2; pv2 = v3; // n = v2 x (-v3).
+      }
+    }
+  } else {
+    pv1 = v1; pv2 = v2; // n = v1 x (-v2).
+  }
+
+  // Calculate the face normal.
+  CROSS(pv1, pv2, n);
+  // Inverse the direction;
+  n[0] = -n[0];
+  n[1] = -n[1];
+  n[2] = -n[2];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// circumsphere()    Calculate the smallest circumsphere (center and radius) //
+//                   of the given three or four points.                      //
+//                                                                           //
+// The circumsphere of four points (a tetrahedron) is unique if they are not //
+// degenerate. If 'pd == NULL', the smallest circumsphere of three points is //
+// the diametral sphere of the triangle (pa, pb, pc).                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::circumsphere(point pa, point pb, point pc, point pd,
+  REAL* cent, REAL* radius)
+{
+  REAL A[4][4], rhs[4], D;
+  int indx[4];
+
+  // Compute the coefficient matrix A (3x3).
+  A[0][0] = pb[0] - pa[0];
+  A[0][1] = pb[1] - pa[1];
+  A[0][2] = pb[2] - pa[2];
+  A[1][0] = pc[0] - pa[0];
+  A[1][1] = pc[1] - pa[1];
+  A[1][2] = pc[2] - pa[2];
+  if (pd != NULL) {
+    A[2][0] = pd[0] - pa[0];
+    A[2][1] = pd[1] - pa[1]; 
+    A[2][2] = pd[2] - pa[2];
+  } else {
+    CROSS(A[0], A[1], A[2]);
+  }
+
+  // Compute the right hand side vector b (3x1).
+  rhs[0] = 0.5 * DOT(A[0], A[0]);
+  rhs[1] = 0.5 * DOT(A[1], A[1]);
+  if (pd != NULL) {
+    rhs[2] = 0.5 * DOT(A[2], A[2]);
+  } else {
+    rhs[2] = 0.0;
+  }
+
+  // Solve the 3 by 3 equations use LU decomposition with partial pivoting
+  //   and backward and forward substitute..
+  if (!lu_decmp(A, 3, indx, &D, 0)) {
+    assert(0);  // No solution.
+  }
+  lu_solve(A, 3, indx, rhs, 0);
+  if (cent != (REAL *) NULL) {
+    cent[0] = pa[0] + rhs[0];
+    cent[1] = pa[1] + rhs[1];
+    cent[2] = pa[2] + rhs[2];
+  }
+  if (radius != (REAL *) NULL) {
+    *radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// lu_decmp()    Compute the LU decomposition of a matrix.                   //
+//                                                                           //
+// Compute the LU decomposition of a (non-singular) square matrix A using    //
+// partial pivoting and implicit row exchanges.  The result is:              //
+//     A = P * L * U,                                                        //
+// where P is a permutation matrix, L is unit lower triangular, and U is     //
+// upper triangular.  The factored form of A is used in combination with     //
+// 'lu_solve()' to solve linear equations: Ax = b, or invert a matrix.       //
+//                                                                           //
+// The inputs are a square matrix 'lu[N..n+N-1][N..n+N-1]', it's size is 'n'.//
+// On output, 'lu' is replaced by the LU decomposition of a rowwise permuta- //
+// tion of itself, 'ps[N..n+N-1]' is an output vector that records the row   //
+// permutation effected by the partial pivoting, effectively,  'ps' array    //
+// tells the user what the permutation matrix P is; 'd' is output as +1/-1   //
+// depending on whether the number of row interchanges was even or odd,      //
+// respectively.                                                             //
+//                                                                           //
+// Return true if the LU decomposition is successfully computed, otherwise,  //
+// return false in case that A is a singular matrix.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N)
+{
+  REAL scales[4];
+  REAL pivot, biggest, mult, tempf;
+  int pivotindex = 0;
+  int i, j, k;
+
+  *d = 1.0;                                      // No row interchanges yet.
+
+  for (i = N; i < n + N; i++) {                             // For each row.
+    // Find the largest element in each row for row equilibration
+    biggest = 0.0;
+    for (j = N; j < n + N; j++)
+      if (biggest < (tempf = fabs(lu[i][j])))
+        biggest  = tempf;
+    if (biggest != 0.0)
+      scales[i] = 1.0 / biggest;
+    else {
+      scales[i] = 0.0;
+      return false;                            // Zero row: singular matrix.
+    }
+    ps[i] = i;                                 // Initialize pivot sequence.
+  }
+
+  for (k = N; k < n + N - 1; k++) {                      // For each column.
+    // Find the largest element in each column to pivot around.
+    biggest = 0.0;
+    for (i = k; i < n + N; i++) {
+      if (biggest < (tempf = fabs(lu[ps[i]][k]) * scales[ps[i]])) {
+        biggest = tempf;
+        pivotindex = i;
+      }
+    }
+    if (biggest == 0.0) {
+      return false;                         // Zero column: singular matrix.
+    }
+    if (pivotindex != k) {                         // Update pivot sequence.
+      j = ps[k];
+      ps[k] = ps[pivotindex];
+      ps[pivotindex] = j;
+      *d = -(*d);                          // ...and change the parity of d.
+    }
+
+    // Pivot, eliminating an extra variable  each time
+    pivot = lu[ps[k]][k];
+    for (i = k + 1; i < n + N; i++) {
+      lu[ps[i]][k] = mult = lu[ps[i]][k] / pivot;
+      if (mult != 0.0) {
+        for (j = k + 1; j < n + N; j++)
+          lu[ps[i]][j] -= mult * lu[ps[k]][j];
+      }
+    }
+  }
+
+  // (lu[ps[n + N - 1]][n + N - 1] == 0.0) ==> A is singular.
+  return lu[ps[n + N - 1]][n + N - 1] != 0.0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// lu_solve()    Solves the linear equation:  Ax = b,  after the matrix A    //
+//               has been decomposed into the lower and upper triangular     //
+//               matrices L and U, where A = LU.                             //
+//                                                                           //
+// 'lu[N..n+N-1][N..n+N-1]' is input, not as the matrix 'A' but rather as    //
+// its LU decomposition, computed by the routine 'lu_decmp'; 'ps[N..n+N-1]'  //
+// is input as the permutation vector returned by 'lu_decmp';  'b[N..n+N-1]' //
+// is input as the right-hand side vector, and returns with the solution     //
+// vector. 'lu', 'n', and 'ps' are not modified by this routine and can be   //
+// left in place for successive calls with different right-hand sides 'b'.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N)
+{
+  int i, j;
+  REAL X[4], dot;
+
+  for (i = N; i < n + N; i++) X[i] = 0.0;
+
+  // Vector reduction using U triangular matrix.
+  for (i = N; i < n + N; i++) {
+    dot = 0.0;
+    for (j = N; j < i + N; j++)
+      dot += lu[ps[i]][j] * X[j];
+    X[i] = b[ps[i]] - dot;
+  }
+
+  // Back substitution, in L triangular matrix.
+  for (i = n + N - 1; i >= N; i--) {
+    dot = 0.0;
+    for (j = i + 1; j < n + N; j++)
+      dot += lu[ps[i]][j] * X[j];
+    X[i] = (X[i] - dot) / lu[ps[i]][i];
+  }
+
+  for (i = N; i < n + N; i++) b[i] = X[i];
+}
+
+#endif // #ifndef geomCXX
\ No newline at end of file
diff --git a/contrib/TetgenNew/io.cxx b/contrib/TetgenNew/io.cxx
new file mode 100644
index 0000000000..9cf198a6bd
--- /dev/null
+++ b/contrib/TetgenNew/io.cxx
@@ -0,0 +1,3148 @@
+#ifndef tetgenioCXX
+#define tetgenioCXX
+
+#include "tetgen.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// initialize()    Initialize all variables of 'tetgenio'.                   //
+//                                                                           //
+// It is called by the only class constructor 'tetgenio()' implicitly. Thus, //
+// all variables are guaranteed to be initialized. Each array is initialized //
+// to be a 'NULL' pointer, and its length is equal zero. Some variables have //
+// their default value, 'firstnumber' equals zero, 'mesh_dim' equals 3,  and //
+// 'numberofcorners' equals 4.  Another possible use of this routine is to   //
+// call it before to re-use an object.                                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenio::initialize()
+{
+  firstnumber = 0;              // Default item index is numbered from Zero.
+  mesh_dim = 3;                              // Default mesh dimension is 3.
+  useindex = true;
+
+  pointlist = (REAL *) NULL;
+  pointattributelist = (REAL *) NULL;
+  pointmtrlist = (REAL *) NULL;
+  pointmarkerlist = (int *) NULL;
+  numberofpoints = 0;
+  numberofpointattributes = 0;
+  numberofpointmtrs = 0;
+
+  tetrahedronlist = (int *) NULL;
+  tetrahedronattributelist = (REAL *) NULL;
+  tetrahedronvolumelist = (REAL *) NULL;
+  neighborlist = (int *) NULL;
+  numberoftetrahedra = 0;
+  numberofcorners = 4;                   // Default is 4 nodes per element.
+  numberoftetrahedronattributes = 0;
+
+  trifacelist = (int *) NULL;
+  adjtetlist = (int *) NULL;
+  trifacemarkerlist = (int *) NULL;
+  numberoftrifaces = 0; 
+
+  facetlist = (facet *) NULL;
+  facetmarkerlist = (int *) NULL;
+  numberoffacets = 0; 
+
+  edgelist = (int *) NULL;
+  edgemarkerlist = (int *) NULL;
+  numberofedges = 0;
+
+  holelist = (REAL *) NULL;
+  numberofholes = 0;
+
+  regionlist = (REAL *) NULL;
+  numberofregions = 0;
+
+  facetconstraintlist = (REAL *) NULL;
+  numberoffacetconstraints = 0;
+  segmentconstraintlist = (REAL *) NULL;
+  numberofsegmentconstraints = 0;
+
+  pbcgrouplist = (pbcgroup *) NULL;
+  numberofpbcgroups = 0;
+
+  vpointlist = (REAL *) NULL;
+  vedgelist = (voroedge *) NULL;
+  vfacetlist = (vorofacet *) NULL; 
+  vcelllist = (int **) NULL; 
+  numberofvpoints = 0;
+  numberofvedges = 0;
+  numberofvfacets = 0;
+  numberofvcells = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// deinitialize()    Free the memory allocated in 'tetgenio'.                //
+//                                                                           //
+// It is called by the class destructor '~tetgenio()' implicitly. Hence, the //
+// occupied memory by arrays of an object will be automatically released on  //
+// the deletion of the object. However, this routine assumes that the memory //
+// is allocated by C++ memory allocation operator 'new', thus it is freed by //
+// the C++ array deletor 'delete []'. If one uses the C/C++ library function //
+// 'malloc()' to allocate memory for arrays, one has to free them with the   //
+// 'free()' function, and call routine 'initialize()' once to disable this   //
+// routine on deletion of the object.                                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenio::deinitialize()
+{
+  facet *f;
+  polygon *p;
+  pbcgroup *pg;
+  int i, j;
+
+  if (pointlist != (REAL *) NULL) {
+    delete [] pointlist;
+  }
+  if (pointattributelist != (REAL *) NULL) {
+    delete [] pointattributelist;
+  }
+  if (pointmtrlist != (REAL *) NULL) {
+    delete [] pointmtrlist;
+  }
+  if (pointmarkerlist != (int *) NULL) {
+    delete [] pointmarkerlist;
+  }
+
+  if (tetrahedronlist != (int *) NULL) {
+    delete [] tetrahedronlist;
+  }
+  if (tetrahedronattributelist != (REAL *) NULL) {
+    delete [] tetrahedronattributelist;
+  }
+  if (tetrahedronvolumelist != (REAL *) NULL) {
+    delete [] tetrahedronvolumelist;
+  }
+  if (neighborlist != (int *) NULL) {
+    delete [] neighborlist;
+  }
+
+  if (trifacelist != (int *) NULL) {
+    delete [] trifacelist;
+  }
+  if (adjtetlist != (int *) NULL) {
+    delete [] adjtetlist;
+  }
+  if (trifacemarkerlist != (int *) NULL) {
+    delete [] trifacemarkerlist;
+  }
+
+  if (edgelist != (int *) NULL) {
+    delete [] edgelist;
+  }
+  if (edgemarkerlist != (int *) NULL) {
+    delete [] edgemarkerlist;
+  }
+
+  if (facetlist != (facet *) NULL) {
+    for (i = 0; i < numberoffacets; i++) {
+      f = &facetlist[i];
+      for (j = 0; j < f->numberofpolygons; j++) {
+        p = &f->polygonlist[j];
+        delete [] p->vertexlist;
+      }
+      delete [] f->polygonlist;
+      if (f->holelist != (REAL *) NULL) {
+        delete [] f->holelist;
+      }
+    }
+    delete [] facetlist;
+  }
+  if (facetmarkerlist != (int *) NULL) {
+    delete [] facetmarkerlist;
+  }
+
+  if (holelist != (REAL *) NULL) {
+    delete [] holelist;
+  }
+  if (regionlist != (REAL *) NULL) {
+    delete [] regionlist;
+  }
+  if (facetconstraintlist != (REAL *) NULL) {
+    delete [] facetconstraintlist;
+  }
+  if (segmentconstraintlist != (REAL *) NULL) {
+    delete [] segmentconstraintlist;
+  }
+  if (pbcgrouplist != (pbcgroup *) NULL) {
+    for (i = 0; i < numberofpbcgroups; i++) {
+      pg = &(pbcgrouplist[i]);
+      if (pg->pointpairlist != (int *) NULL) {
+        delete [] pg->pointpairlist;
+      }
+    }
+    delete [] pbcgrouplist;
+  }
+  if (vpointlist != (REAL *) NULL) {
+    delete [] vpointlist;
+  }
+  if (vedgelist != (voroedge *) NULL) {
+    delete [] vedgelist;
+  }
+  if (vfacetlist != (vorofacet *) NULL) {
+    for (i = 0; i < numberofvfacets; i++) {
+      delete [] vfacetlist[i].elist;
+    }
+    delete [] vfacetlist;
+  }
+  if (vcelllist != (int **) NULL) {
+    for (i = 0; i < numberofvcells; i++) {
+      delete [] vcelllist[i];
+    }
+    delete [] vcelllist;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_node_call()    Load a list of nodes.                                 //
+//                                                                           //
+// It is a support routine for routines: 'load_nodes()', 'load_poly()', and  //
+// 'load_tetmesh()'.  'infile' is the file handle contains the node list. It //
+// may point to a .node, or .poly or .smesh file.  'markers' indicates each  //
+// node contains an additional marker (integer) or not. 'infilename' is the  //
+// name of the file being read,  it is only appeared in error message.       //
+//                                                                           //
+// The 'firstnumber' (0 or 1) is automatically determined by the number of   //
+// the first index of the first point.                                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_node_call(FILE* infile,int markers,const char* infilename)
+{
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  REAL x, y, z, attrib;
+  int firstnode, currentmarker;
+  int index, attribindex;
+  int i, j;
+
+  // Initialize 'pointlist', 'pointattributelist', and 'pointmarkerlist'.
+  pointlist = new REAL[numberofpoints * 3];
+  if (pointlist == (REAL *) NULL) {
+    printf("Error:  Out of memory.\n");
+    terminatetetgen(1);
+  }
+  if (numberofpointattributes > 0) {
+    pointattributelist = new REAL[numberofpoints * numberofpointattributes];
+    if (pointattributelist == (REAL *) NULL) {
+      printf("Error:  Out of memory.\n");
+      terminatetetgen(1);
+    }
+  }
+  if (markers) {
+    pointmarkerlist = new int[numberofpoints];
+    if (pointmarkerlist == (int *) NULL) {
+      printf("Error:  Out of memory.\n");
+      terminatetetgen(1);
+    }
+  }
+
+  // Read the point section.
+  index = 0;
+  attribindex = 0;
+  for (i = 0; i < numberofpoints; i++) {
+    stringptr = readnumberline(inputline, infile, infilename);
+    if (useindex) {
+      if (i == 0) {
+        firstnode = (int) strtol (stringptr, &stringptr, 0);
+        if ((firstnode == 0) || (firstnode == 1)) {
+          firstnumber = firstnode;
+        }
+      }
+      stringptr = findnextnumber(stringptr);
+    } // if (useindex)
+    if (*stringptr == '\0') {
+      printf("Error:  Point %d has no x coordinate.\n", firstnumber + i);
+      break;
+    }
+    x = (REAL) strtod(stringptr, &stringptr);
+    stringptr = findnextnumber(stringptr);
+    if (*stringptr == '\0') {
+      printf("Error:  Point %d has no y coordinate.\n", firstnumber + i);
+      break;
+    }
+    y = (REAL) strtod(stringptr, &stringptr);
+    if (mesh_dim == 3) {
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  Point %d has no z coordinate.\n", firstnumber + i);
+        break;
+      }
+      z = (REAL) strtod(stringptr, &stringptr);
+    } else {
+      z = 0.0; // mesh_dim == 2;
+    }
+    pointlist[index++] = x;
+    pointlist[index++] = y;
+    pointlist[index++] = z;
+    // Read the point attributes.
+    for (j = 0; j < numberofpointattributes; j++) {
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        attrib = 0.0;
+      } else {
+        attrib = (REAL) strtod(stringptr, &stringptr);
+      }
+      pointattributelist[attribindex++] = attrib;
+    }
+    if (markers) {
+      // Read a point marker.
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        currentmarker = 0;
+      } else {
+        currentmarker = (int) strtol (stringptr, &stringptr, 0);
+      }
+      pointmarkerlist[i] = currentmarker;
+    }
+  }
+  if (i < numberofpoints) {
+    // Failed to read points due to some error.
+    delete [] pointlist;
+    pointlist = (REAL *) NULL;
+    if (markers) {
+      delete [] pointmarkerlist;
+      pointmarkerlist = (int *) NULL;
+    }
+    if (numberofpointattributes > 0) {
+      delete [] pointattributelist;
+      pointattributelist = (REAL *) NULL;
+    }
+    numberofpoints = 0;
+    return false;
+  }
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_node()    Load a list of nodes from a .node file.                    //
+//                                                                           //
+// 'filename' is the inputfile without suffix. The node list is in 'filename.//
+// node'. On completion, the node list is returned in 'pointlist'.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_node(const char* filename)
+{
+  FILE *infile;
+  char innodefilename[FILENAMESIZE];
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  int markers;
+
+  // Assembling the actual file names we want to open.
+  strcpy(innodefilename, filename);
+  strcat(innodefilename, ".node");
+
+  // Try to open a .node file.
+  infile = fopen(innodefilename, "r");
+  if (infile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot access file %s.\n", innodefilename);
+    return false;
+  }
+  printf("Opening %s.\n", innodefilename);  
+  // Read the first line of the file.
+  stringptr = readnumberline(inputline, infile, innodefilename);
+  // Is this list of points generated from rbox?
+  stringptr = strstr(inputline, "rbox");
+  if (stringptr == NULL) {
+    // Read number of points, number of dimensions, number of point
+    //   attributes, and number of boundary markers. 
+    stringptr = inputline;
+    numberofpoints = (int) strtol (stringptr, &stringptr, 0);
+    stringptr = findnextnumber(stringptr);
+    if (*stringptr == '\0') {
+      mesh_dim = 3;
+    } else {
+      mesh_dim = (int) strtol (stringptr, &stringptr, 0);
+    }
+    stringptr = findnextnumber(stringptr);
+    if (*stringptr == '\0') {
+      numberofpointattributes = 0;
+    } else {
+      numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
+    }
+    stringptr = findnextnumber(stringptr);
+    if (*stringptr == '\0') {
+      markers = 0;
+    } else {
+      markers = (int) strtol (stringptr, &stringptr, 0);
+    }
+  } else {
+    // It is a rbox (qhull) input file.
+    stringptr = inputline;
+    // Get the dimension.
+    mesh_dim = (int) strtol (stringptr, &stringptr, 0);
+    // Get the number of points.
+    stringptr = readnumberline(inputline, infile, innodefilename);
+    numberofpoints = (int) strtol (stringptr, &stringptr, 0);
+    // There is no index column.
+    useindex = 0;
+  }
+
+  if (numberofpoints < (mesh_dim + 1)) {
+    printf("Input error:  TetGen needs at least %d points.\n", mesh_dim + 1);
+    fclose(infile);
+    return false;
+  }
+
+  // Load the list of nodes.
+  if (!load_node_call(infile, markers, innodefilename)) {
+    fclose(infile);
+    return false;
+  }
+  fclose(infile);
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_pbc()    Load a list of pbc groups into 'pbcgrouplist'.              //
+//                                                                           //
+// 'filename' is the filename of the original inputfile without suffix. The  //
+// pbc groups are found in file 'filename.pbc'.                              //
+//                                                                           //
+// This routine will be called both in load_poly() and load_tetmesh().       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_pbc(const char* filename)
+{
+  FILE *infile;
+  char pbcfilename[FILENAMESIZE];
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  pbcgroup *pg;
+  int index, p1, p2;
+  int i, j, k;
+
+  // Pbc groups are saved in file "filename.pbc".
+  strcpy(pbcfilename, filename);
+  strcat(pbcfilename, ".pbc");
+  infile = fopen(pbcfilename, "r");
+  if (infile != (FILE *) NULL) {
+    printf("Opening %s.\n", pbcfilename);
+  } else {
+    // No such file. Return.
+    return false;
+  }
+
+  // Read the number of pbc groups.
+  stringptr = readnumberline(inputline, infile, pbcfilename);
+  numberofpbcgroups = (int) strtol (stringptr, &stringptr, 0);
+  if (numberofpbcgroups == 0) {
+    // It looks this file contains no point.
+    fclose(infile);
+    return false; 
+  }
+  // Initialize 'pbcgrouplist';
+  pbcgrouplist = new pbcgroup[numberofpbcgroups];
+
+  // Read the list of pbc groups.
+  for (i = 0; i < numberofpbcgroups; i++) {
+    pg = &(pbcgrouplist[i]);
+    // Initialize pbcgroup i;
+    pg->numberofpointpairs = 0;
+    pg->pointpairlist = (int *) NULL;
+    // Read 'fmark1', 'fmark2'.
+    stringptr = readnumberline(inputline, infile, pbcfilename);
+    if (*stringptr == '\0') break;
+    pg->fmark1 = (int) strtol(stringptr, &stringptr, 0);
+    stringptr = findnextnumber(stringptr);
+    if (*stringptr == '\0') break;
+    pg->fmark2 = (int) strtol(stringptr, &stringptr, 0);
+    // Read 'transmat'.
+    do {
+      stringptr = readline(inputline, infile, NULL);
+    } while ((*stringptr != '[') && (*stringptr != '\0'));
+    if (*stringptr == '\0') break;
+    for (j = 0; j < 4; j++) {
+      for (k = 0; k < 4; k++) {
+        // Read the entry of [j, k].
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          // Try to read another line.
+          stringptr = readnumberline(inputline, infile, pbcfilename);
+          if (*stringptr == '\0') break;
+        }
+        pg->transmat[j][k] = (REAL) strtod(stringptr, &stringptr);
+      }
+      if (k < 4) break; // Not complete!
+    }
+    if (j < 4) break; // Not complete!
+    // Read 'numberofpointpairs'.
+    stringptr = readnumberline(inputline, infile, pbcfilename);
+    if (*stringptr == '\0') break;
+    pg->numberofpointpairs = (int) strtol(stringptr, &stringptr, 0);
+    if (pg->numberofpointpairs > 0) {
+      pg->pointpairlist = new int[pg->numberofpointpairs * 2];
+      // Read the point pairs.
+      index = 0;
+      for (j = 0; j < pg->numberofpointpairs; j++) {
+        stringptr = readnumberline(inputline, infile, pbcfilename);
+        p1 = (int) strtol(stringptr, &stringptr, 0);
+        stringptr = findnextnumber(stringptr);
+        p2 = (int) strtol(stringptr, &stringptr, 0);
+        pg->pointpairlist[index++] = p1;
+        pg->pointpairlist[index++] = p2;
+      }
+    }
+  }
+  fclose(infile);
+
+  if (i < numberofpbcgroups) {
+    // Failed to read to additional points due to some error.
+    delete [] pbcgrouplist;
+    pbcgrouplist = (pbcgroup *) NULL;
+    numberofpbcgroups = 0;
+    return false;
+  }
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_var()    Load variant constraints applied on facets, segments, nodes.//
+//                                                                           //
+// 'filename' is the filename of the original inputfile without suffix. The  //
+// constraints are found in file 'filename.var'.                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_var(const char* filename)
+{
+  FILE *infile;
+  char varfilename[FILENAMESIZE];
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  int index;
+  int i;
+
+  // Variant constraints are saved in file "filename.var".
+  strcpy(varfilename, filename);
+  strcat(varfilename, ".var");
+  infile = fopen(varfilename, "r");
+  if (infile != (FILE *) NULL) {
+    printf("Opening %s.\n", varfilename);
+  } else {
+    // No such file. Return.
+    return false;
+  }
+
+  // Read the facet constraint section.
+  stringptr = readnumberline(inputline, infile, varfilename);
+  if (*stringptr != '\0') {
+    numberoffacetconstraints = (int) strtol (stringptr, &stringptr, 0);
+  } else {
+    numberoffacetconstraints = 0;
+  }
+  if (numberoffacetconstraints > 0) {
+    // Initialize 'facetconstraintlist'.
+    facetconstraintlist = new REAL[numberoffacetconstraints * 2];
+    index = 0;
+    for (i = 0; i < numberoffacetconstraints; i++) {
+      stringptr = readnumberline(inputline, infile, varfilename);
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  facet constraint %d has no facet marker.\n",
+               firstnumber + i);
+        break;
+      } else {
+        facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
+      }
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  facet constraint %d has no maximum area bound.\n",
+               firstnumber + i);
+        break;
+      } else {
+        facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
+      }
+    }
+    if (i < numberoffacetconstraints) {
+      // This must be caused by an error.
+      fclose(infile);
+      return false;
+    }
+  }
+
+  // Read the segment constraint section.
+  stringptr = readnumberline(inputline, infile, varfilename);
+  if (*stringptr != '\0') {
+    numberofsegmentconstraints = (int) strtol (stringptr, &stringptr, 0);
+  } else {
+    numberofsegmentconstraints = 0;
+  }
+  if (numberofsegmentconstraints > 0) {
+    // Initialize 'segmentconstraintlist'.
+    segmentconstraintlist = new REAL[numberofsegmentconstraints * 3];
+    index = 0;
+    for (i = 0; i < numberofsegmentconstraints; i++) {
+      stringptr = readnumberline(inputline, infile, varfilename);
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  segment constraint %d has no frist endpoint.\n",
+               firstnumber + i);
+        break;
+      } else {
+        segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
+      }
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  segment constraint %d has no second endpoint.\n",
+               firstnumber + i);
+        break;
+      } else {
+        segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
+      }
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  segment constraint %d has no maximum length bound.\n",
+               firstnumber + i);
+        break;
+      } else {
+        segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
+      }
+    }
+    if (i < numberofsegmentconstraints) {
+      // This must be caused by an error.
+      fclose(infile);
+      return false;
+    }
+  }
+
+  fclose(infile);
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_mtr()    Load a size specification map from file.                    //
+//                                                                           //
+// 'filename' is the filename of the original inputfile without suffix. The  //
+// size map is found in file 'filename.mtr'.                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_mtr(const char* filename)
+{
+  FILE *infile;
+  char mtrfilename[FILENAMESIZE];
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  REAL mtr;
+  int mtrindex;
+  int i, j;
+
+  strcpy(mtrfilename, filename);
+  strcat(mtrfilename, ".mtr");
+  infile = fopen(mtrfilename, "r");
+  if (infile != (FILE *) NULL) {
+    printf("Opening %s.\n", mtrfilename);
+  } else {
+    // No such file. Return.
+    return false;
+  }
+
+  // Read number of points, number of columns (1, 3, or 6).
+  stringptr = readnumberline(inputline, infile, mtrfilename);
+  stringptr = findnextnumber(stringptr); // Skip number of points.
+  if (*stringptr != '\0') {
+    numberofpointmtrs = (int) strtol (stringptr, &stringptr, 0);
+  }
+  if (numberofpointmtrs == 0) {
+    // Column number doesn't match. Set a default number (1).
+    numberofpointmtrs = 1;
+  }
+
+  // Allocate space for pointmtrlist.
+  pointmtrlist = new REAL[numberofpoints * numberofpointmtrs];
+  if (pointmtrlist == (REAL *) NULL) {
+    printf("Error:  Out of memory.\n");
+    terminatetetgen(1);
+  }
+  mtrindex = 0;
+  for (i = 0; i < numberofpoints; i++) {
+    // Read metrics.
+    stringptr = readnumberline(inputline, infile, mtrfilename);
+    for (j = 0; j < numberofpointmtrs; j++) {
+      if (*stringptr == '\0') {
+        printf("Error:  Metric %d is missing value #%d in %s.\n",
+               i + firstnumber, j + 1, mtrfilename);
+        terminatetetgen(1);
+      }
+      mtr = (REAL) strtod(stringptr, &stringptr);
+      pointmtrlist[mtrindex++] = mtr;
+      stringptr = findnextnumber(stringptr);
+    }
+  }
+
+  fclose(infile);
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_poly()    Load a piecewise linear complex from a .poly or .smesh.    //
+//                                                                           //
+// 'filename' is the inputfile without suffix. The PLC is in 'filename.poly' //
+// or 'filename.smesh', and possibly plus 'filename.node' (when the first    //
+// line of the file starts with a zero).                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_poly(const char* filename)
+{
+  FILE *infile, *polyfile;
+  char innodefilename[FILENAMESIZE];
+  char inpolyfilename[FILENAMESIZE];
+  char insmeshfilename[FILENAMESIZE];
+  char inputline[INPUTLINESIZE];
+  char *stringptr, *infilename;
+  int smesh, markers, currentmarker;
+  int readnodefile, index;
+  int i, j, k;
+
+  // Assembling the actual file names we want to open.
+  strcpy(innodefilename, filename);
+  strcpy(inpolyfilename, filename);
+  strcpy(insmeshfilename, filename);
+  strcat(innodefilename, ".node");
+  strcat(inpolyfilename, ".poly");
+  strcat(insmeshfilename, ".smesh");
+
+  // First assume it is a .poly file.
+  smesh = 0;
+  // Try to open a .poly file.
+  polyfile = fopen(inpolyfilename, "r");
+  if (polyfile == (FILE *) NULL) {
+    // .poly doesn't exist! Try to open a .smesh file.
+    polyfile = fopen(insmeshfilename, "r");
+    if (polyfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot access file %s and %s.\n",
+             inpolyfilename, insmeshfilename);
+      return false;
+    } else {
+      printf("Opening %s.\n", insmeshfilename);
+    }
+    smesh = 1;
+  } else {
+    printf("Opening %s.\n", inpolyfilename);
+  }
+  // Initialize the default values.
+  mesh_dim = 3;  // Three-dimemsional accoordinates.
+  numberofpointattributes = 0;  // no point attribute.
+  markers = 0;  // no boundary marker.
+  // Read number of points, number of dimensions, number of point
+  //   attributes, and number of boundary markers.
+  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
+  stringptr = findnextnumber(stringptr);
+  if (*stringptr != '\0') {
+    mesh_dim = (int) strtol (stringptr, &stringptr, 0);      
+  }
+  stringptr = findnextnumber(stringptr);
+  if (*stringptr != '\0') {
+    numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
+  }
+  stringptr = findnextnumber(stringptr);
+  if (*stringptr != '\0') {
+    markers = (int) strtol (stringptr, &stringptr, 0);
+  }
+  if (numberofpoints > 0) {
+    readnodefile = 0;
+    if (smesh) {
+      infilename = insmeshfilename;
+    } else {
+      infilename = inpolyfilename;
+    } 
+    infile = polyfile;
+  } else {
+    // If the .poly or .smesh file claims there are zero points, that
+    //   means the points should be read from a separate .node file.
+    readnodefile = 1;
+    infilename = innodefilename;
+  }
+
+  if (readnodefile) {
+    // Read the points from the .node file.
+    printf("Opening %s.\n", innodefilename);
+    infile = fopen(innodefilename, "r");
+    if (infile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot access file %s.\n", innodefilename);
+      return false;
+    }
+    // Initialize the default values.
+    mesh_dim = 3;  // Three-dimemsional accoordinates.
+    numberofpointattributes = 0;  // no point attribute.
+    markers = 0;  // no boundary marker.
+    // Read number of points, number of dimensions, number of point
+    //   attributes, and number of boundary markers.
+    stringptr = readnumberline(inputline, infile, innodefilename);
+    numberofpoints = (int) strtol (stringptr, &stringptr, 0);
+    stringptr = findnextnumber(stringptr);
+    if (*stringptr != '\0') {
+      mesh_dim = (int) strtol (stringptr, &stringptr, 0);
+    }
+    stringptr = findnextnumber(stringptr);
+    if (*stringptr != '\0') {
+      numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
+    }
+    stringptr = findnextnumber(stringptr);
+    if (*stringptr != '\0') {
+      markers = (int) strtol (stringptr, &stringptr, 0);
+    }
+  }
+
+  if ((mesh_dim != 3) && (mesh_dim != 2)) {
+    printf("Input error:  TetGen only works for 2D & 3D point sets.\n");
+    fclose(infile);
+    return false;
+  }
+  if (numberofpoints < (mesh_dim + 1)) {
+    printf("Input error:  TetGen needs at least %d points.\n", mesh_dim + 1);
+    fclose(infile);
+    return false;
+  }
+
+  // Load the list of nodes.
+  if (!load_node_call(infile, markers, infilename)) {
+    fclose(infile);
+    return false;
+  }
+
+  if (readnodefile) {
+    fclose(infile);
+  }
+
+  facet *f;
+  polygon *p;
+
+  if (mesh_dim == 3) {
+
+    // Read number of facets and number of boundary markers.
+    stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+    numberoffacets = (int) strtol (stringptr, &stringptr, 0);
+    if (numberoffacets <= 0) {
+      // No facet list, return.
+      fclose(polyfile);
+      return true;
+    }
+    stringptr = findnextnumber(stringptr);
+    if (*stringptr == '\0') {
+      markers = 0;  // no boundary marker.
+    } else {
+      markers = (int) strtol (stringptr, &stringptr, 0);
+    }
+
+    // Initialize the 'facetlist', 'facetmarkerlist'.
+    facetlist = new facet[numberoffacets];
+    if (markers == 1) {
+      facetmarkerlist = new int[numberoffacets];
+    }
+
+    // Read data into 'facetlist', 'facetmarkerlist'.
+    if (smesh == 0) {
+      // Facets are in .poly file format.
+      for (i = 1; i <= numberoffacets; i++) {
+        f = &(facetlist[i - 1]);
+        init(f);
+        f->numberofholes = 0;
+        currentmarker = 0;
+        // Read number of polygons, number of holes, and a boundary marker.
+        stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+        f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr != '\0') {
+          f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
+          if (markers == 1) {
+            stringptr = findnextnumber(stringptr);
+            if (*stringptr != '\0') {
+              currentmarker = (int) strtol(stringptr, &stringptr, 0);
+            }
+          }
+        }
+        // Initialize facetmarker if it needs.
+        if (markers == 1) {
+          facetmarkerlist[i - 1] = currentmarker; 
+        }
+        // Each facet should has at least one polygon.
+        if (f->numberofpolygons <= 0) {
+          printf("Error:  Wrong number of polygon in %d facet.\n", i);
+          break; 
+        }
+        // Initialize the 'f->polygonlist'.
+        f->polygonlist = new polygon[f->numberofpolygons];
+        // Go through all polygons, read in their vertices.
+        for (j = 1; j <= f->numberofpolygons; j++) {
+          p = &(f->polygonlist[j - 1]);
+          init(p);
+          // Read number of vertices of this polygon.
+          stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+          p->numberofvertices = (int) strtol(stringptr, &stringptr, 0);
+          if (p->numberofvertices < 1) {
+            printf("Error:  Wrong polygon %d in facet %d\n", j, i);
+            break;
+          }
+          // Initialize 'p->vertexlist'.
+          p->vertexlist = new int[p->numberofvertices];
+          // Read all vertices of this polygon.
+          for (k = 1; k <= p->numberofvertices; k++) {
+            stringptr = findnextnumber(stringptr);
+            if (*stringptr == '\0') {
+              // Try to load another non-empty line and continue to read the
+              //   rest of vertices.
+              stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+              if (*stringptr == '\0') {
+                printf("Error: Missing %d endpoints of polygon %d in facet %d",
+                       p->numberofvertices - k, j, i);
+                break;
+              }
+            }
+            p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
+          }
+        } 
+        if (j <= f->numberofpolygons) {
+          // This must be caused by an error. However, there're j - 1
+          //   polygons have been read. Reset the 'f->numberofpolygon'.
+          if (j == 1) {
+            // This is the first polygon.
+            delete [] f->polygonlist;
+          }
+          f->numberofpolygons = j - 1;
+          // No hole will be read even it exists.
+          f->numberofholes = 0;
+          break;
+        }
+        // If this facet has hole pints defined, read them.
+        if (f->numberofholes > 0) {
+          // Initialize 'f->holelist'.
+          f->holelist = new REAL[f->numberofholes * 3];
+          // Read the holes' coordinates.
+          index = 0;
+          for (j = 1; j <= f->numberofholes; j++) {
+            stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+            for (k = 1; k <= 3; k++) {
+              stringptr = findnextnumber(stringptr);
+              if (*stringptr == '\0') {
+                printf("Error:  Hole %d in facet %d has no coordinates", j, i);
+                break;
+              }
+              f->holelist[index++] = (REAL) strtod (stringptr, &stringptr);
+            }
+            if (k <= 3) {
+              // This must be caused by an error.
+              break;
+            }
+          }
+          if (j <= f->numberofholes) {
+            // This must be caused by an error.
+            break;
+          }
+        }
+      }
+      if (i <= numberoffacets) {
+        // This must be caused by an error.
+        numberoffacets = i - 1;
+        fclose(polyfile);
+        return false;
+      }
+    } else { // poly == 0
+      // Read the facets from a .smesh file.
+      for (i = 1; i <= numberoffacets; i++) {
+        f = &(facetlist[i - 1]);
+        init(f);
+        // Initialize 'f->facetlist'. In a .smesh file, each facetlist only
+        //   contains exactly one polygon, no hole.
+        f->numberofpolygons = 1;
+        f->polygonlist = new polygon[f->numberofpolygons];
+        p = &(f->polygonlist[0]);
+        init(p);
+        // Read number of vertices of this polygon.
+        stringptr = readnumberline(inputline, polyfile, insmeshfilename);
+        p->numberofvertices = (int) strtol (stringptr, &stringptr, 0);
+        if (p->numberofvertices < 1) {
+          printf("Error:  Wrong number of vertex in facet %d\n", i);
+          break;
+        }
+        // Initialize 'p->vertexlist'.
+        p->vertexlist = new int[p->numberofvertices];
+        for (k = 1; k <= p->numberofvertices; k++) {
+          stringptr = findnextnumber(stringptr);
+          if (*stringptr == '\0') {
+            // Try to load another non-empty line and continue to read the
+            //   rest of vertices.
+            stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+            if (*stringptr == '\0') {
+              printf("Error:  Missing %d endpoints in facet %d",
+                     p->numberofvertices - k, i);
+              break;
+            }
+          }
+          p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
+        }
+        if (k <= p->numberofvertices) {
+          // This must be caused by an error.
+          break;
+        }
+        // Read facet's boundary marker at last.
+        if (markers == 1) {
+          stringptr = findnextnumber(stringptr);
+          if (*stringptr == '\0') {
+            currentmarker = 0;
+          } else {
+            currentmarker = (int) strtol(stringptr, &stringptr, 0);
+          }
+          facetmarkerlist[i - 1] = currentmarker;
+        }
+      }
+      if (i <= numberoffacets) {
+        // This must be caused by an error.
+        numberoffacets = i - 1;
+        fclose(polyfile);
+        return false;
+      }
+    }
+
+    // Read the hole section.
+    stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+    if (*stringptr != '\0') {
+      numberofholes = (int) strtol (stringptr, &stringptr, 0);
+    } else {
+      numberofholes = 0;
+    }
+    if (numberofholes > 0) {
+      // Initialize 'holelist'.
+      holelist = new REAL[numberofholes * 3];
+      for (i = 0; i < 3 * numberofholes; i += 3) {
+        stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Hole %d has no x coord.\n", firstnumber + (i / 3));
+          break;
+        } else {
+          holelist[i] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Hole %d has no y coord.\n", firstnumber + (i / 3));
+          break;
+        } else {
+          holelist[i + 1] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Hole %d has no z coord.\n", firstnumber + (i / 3));
+          break;
+        } else {
+          holelist[i + 2] = (REAL) strtod(stringptr, &stringptr);
+        }
+      }
+      if (i < 3 * numberofholes) {
+        // This must be caused by an error.
+        fclose(polyfile);
+        return false;
+      }
+    }
+
+    // Read the region section.  The 'region' section is optional, if we
+    //   don't reach the end-of-file, try read it in.
+    stringptr = readnumberline(inputline, polyfile, NULL);
+    if (stringptr != (char *) NULL && *stringptr != '\0') {
+      numberofregions = (int) strtol (stringptr, &stringptr, 0);
+    } else {
+      numberofregions = 0;
+    }
+    if (numberofregions > 0) {
+      // Initialize 'regionlist'.
+      regionlist = new REAL[numberofregions * 5];
+      index = 0;
+      for (i = 0; i < numberofregions; i++) {
+        stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Region %d has no x coordinate.\n", firstnumber + i);
+          break;
+        } else {
+          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Region %d has no y coordinate.\n", firstnumber + i);
+          break;
+        } else {
+          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Region %d has no z coordinate.\n", firstnumber + i);
+          break;
+        } else {
+          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Region %d has no region attrib.\n", firstnumber + i);
+          break;
+        } else {
+          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          regionlist[index] = regionlist[index - 1];
+        } else {
+          regionlist[index] = (REAL) strtod(stringptr, &stringptr);
+        }
+        index++;
+      }
+      if (i < numberofregions) {
+        // This must be caused by an error.
+        fclose(polyfile);
+        return false;
+      }
+    }
+
+    /*// Read the edge (segment) section.  This section is optional, if we
+    //   don't reach the end-of-file, try read it in.
+    stringptr = readnumberline(inputline, polyfile, NULL);
+    if (stringptr != (char *) NULL && *stringptr != '\0') {
+      numberofedges = (int) strtol (stringptr, &stringptr, 0);
+    } else {
+      numberofedges = 0;
+    }
+    if (numberofedges > 0) {
+      // Initialize 'edgelist'.
+      edgelist = new int[numberofedges * 2];
+      edgemarkerlist = new int[numberofedges];
+      index = 0;
+      for (i = 0; i < numberofedges; i++) {
+        stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+        for (j = 0; j < 2; j++) {
+          stringptr = findnextnumber(stringptr);
+          if (*stringptr == '\0') {
+            printf("Error:  Segment %d has no endpoint.\n", firstnumber + i);
+            break;
+          } else {
+            edgelist[index++] = (int) strtol(stringptr, &stringptr, 0);
+          }
+        }
+        if (j < 2) break;
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          edgemarkerlist[i] = 0;  // Set a default segment marker.
+        } else {
+          edgemarkerlist[i] = (int) strtol(stringptr, &stringptr, 0);
+        }
+      }
+      if (i < numberofedges) {
+        // This must be caused by an error.
+        fclose(polyfile);
+        return false;
+      }
+    }
+    */
+
+  } else {
+
+    // Read a PSLG from Triangle's poly file.
+    assert(mesh_dim == 2);
+    // A PSLG is a facet of a PLC.
+    numberoffacets = 1;
+    // Initialize the 'facetlist'.
+    facetlist = new facet[numberoffacets];
+    facetmarkerlist = (int *) NULL; // No facet markers.
+    f = &(facetlist[0]);
+    init(f);
+    // Read number of segments.
+    stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+    // Segments are degenerate polygons.
+    f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
+    if (f->numberofpolygons > 0) {
+      f->polygonlist = new polygon[f->numberofpolygons];
+    }
+    // Go through all segments, read in their vertices.
+    for (j = 0; j < f->numberofpolygons; j++) {
+      p = &(f->polygonlist[j]);
+      init(p);
+      // Read in a segment.
+      stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+      stringptr = findnextnumber(stringptr); // Skip its index.
+      p->numberofvertices = 2; // A segment always has two vertices.
+      p->vertexlist = new int[p->numberofvertices];
+      p->vertexlist[0] = (int) strtol (stringptr, &stringptr, 0);
+      stringptr = findnextnumber(stringptr);
+      p->vertexlist[1] = (int) strtol (stringptr, &stringptr, 0);
+    }
+    // Read number of holes.
+    stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+    f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
+    if (f->numberofholes > 0) {
+      // Initialize 'f->holelist'.
+      f->holelist = new REAL[f->numberofholes * 3];
+      // Read the holes' coordinates.
+      for (j = 0; j < f->numberofholes; j++) {
+        // Read a 2D hole point.
+        stringptr = readnumberline(inputline, polyfile, inpolyfilename);
+        stringptr = findnextnumber(stringptr); // Skip its index.
+        f->holelist[j * 3] = (REAL) strtod (stringptr, &stringptr);
+        stringptr = findnextnumber(stringptr);
+        f->holelist[j * 3 + 1] = (REAL) strtod (stringptr, &stringptr);
+        f->holelist[j * 3 + 2] = 0.0; // The z-coord.
+      }
+    }
+    // The regions are skipped.
+
+  }
+
+  // End of reading poly/smesh file.
+  fclose(polyfile);
+
+  // Try to load a .var file if it exists.
+  load_var(filename);
+  // Try to load a .mtr file if it exists.
+  load_mtr(filename);
+  // Try to read a .pbc file if it exists.
+  load_pbc(filename);
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_off()    Load a polyhedron described in a .off file.                 //
+//                                                                           //
+// The .off format is one of file formats of the Geomview, an interactive    //
+// program for viewing and manipulating geometric objects.  More information //
+// is available form: http://www.geomview.org.                               //
+//                                                                           //
+// 'filename' is a input filename with extension .off or without extension ( //
+// the .off will be added in this case). On completion, the polyhedron is    //
+// returned in 'pointlist' and 'facetlist'.                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_off(const char* filename)
+{
+  FILE *fp;
+  tetgenio::facet *f;
+  tetgenio::polygon *p;
+  char infilename[FILENAMESIZE];
+  char buffer[INPUTLINESIZE];
+  char *bufferp;
+  double *coord;
+  int nverts = 0, iverts = 0;
+  int nfaces = 0, ifaces = 0;
+  int nedges = 0;
+  int line_count = 0, i;
+
+  strncpy(infilename, filename, 1024 - 1);
+  infilename[FILENAMESIZE - 1] = '\0';
+  if (infilename[0] == '\0') {
+    printf("Error:  No filename.\n");
+    return false;
+  }
+  if (strcmp(&infilename[strlen(infilename) - 4], ".off") != 0) {
+    strcat(infilename, ".off");
+  }
+
+  if (!(fp = fopen(infilename, "r"))) {
+    printf("File I/O Error:  Unable to open file %s\n", infilename);
+    return false;
+  }
+  printf("Opening %s.\n", infilename);
+
+  // OFF requires the index starts from '0'.
+  firstnumber = 0;
+
+  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
+    // Check section
+    if (nverts == 0) {
+      // Read header 
+      bufferp = strstr(bufferp, "OFF");
+      if (bufferp != NULL) {
+        // Read mesh counts
+        bufferp = findnextnumber(bufferp); // Skip field "OFF".
+        if (*bufferp == '\0') {
+          // Read a non-empty line.
+          bufferp = readline(buffer, fp, &line_count);
+        }
+        if ((sscanf(bufferp, "%d%d%d", &nverts, &nfaces, &nedges) != 3) 
+            || (nverts == 0)) {
+          printf("Syntax error reading header on line %d in file %s\n",
+                 line_count, infilename);
+          fclose(fp);
+          return false;
+        }
+        // Allocate memory for 'tetgenio'
+        if (nverts > 0) {
+          numberofpoints = nverts;
+          pointlist = new REAL[nverts * 3];
+        }
+        if (nfaces > 0) {        
+          numberoffacets = nfaces;
+          facetlist = new tetgenio::facet[nfaces];
+        }
+      }
+    } else if (iverts < nverts) {
+      // Read vertex coordinates
+      coord = &pointlist[iverts * 3];
+      for (i = 0; i < 3; i++) {
+        if (*bufferp == '\0') {
+          printf("Syntax error reading vertex coords on line %d in file %s\n",
+                 line_count, infilename);
+          fclose(fp);
+          return false;
+        }
+        coord[i] = (REAL) strtod(bufferp, &bufferp);
+        bufferp = findnextnumber(bufferp);
+      }
+      iverts++;
+    } else if (ifaces < nfaces) {
+      // Get next face
+      f = &facetlist[ifaces];
+      init(f);      
+      // In .off format, each facet has one polygon, no hole.
+      f->numberofpolygons = 1;
+      f->polygonlist = new tetgenio::polygon[1];
+      p = &f->polygonlist[0];
+      init(p);
+      // Read the number of vertices, it should be greater than 0.
+      p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
+      if (p->numberofvertices == 0) {
+        printf("Syntax error reading polygon on line %d in file %s\n",
+               line_count, infilename);
+        fclose(fp);
+        return false;
+      }
+      // Allocate memory for face vertices
+      p->vertexlist = new int[p->numberofvertices];
+      for (i = 0; i < p->numberofvertices; i++) {
+        bufferp = findnextnumber(bufferp);
+        if (*bufferp == '\0') {
+          printf("Syntax error reading polygon on line %d in file %s\n",
+                 line_count, infilename);
+          fclose(fp);
+          return false;
+        }
+        p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
+      }
+      ifaces++;
+    } else {
+      // Should never get here
+      printf("Found extra text starting at line %d in file %s\n", line_count,
+             infilename);
+      break;
+    }
+  }
+
+  // Close file
+  fclose(fp);
+
+  // Check whether read all points
+  if (iverts != nverts) {
+    printf("Expected %d vertices, but read only %d vertices in file %s\n",
+           nverts, iverts, infilename);
+    return false;
+  }
+
+  // Check whether read all faces
+  if (ifaces != nfaces) {
+    printf("Expected %d faces, but read only %d faces in file %s\n",
+           nfaces, ifaces, infilename);
+    return false;
+  }
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_ply()    Load a polyhedron described in a .ply file.                 //
+//                                                                           //
+// 'filename' is the file name with extension .ply or without extension (the //
+// .ply will be added in this case).                                         //
+//                                                                           //
+// This is a simplified version of reading .ply files, which only reads the  //
+// set of vertices and the set of faces. Other informations (such as color,  //
+// material, texture, etc) in .ply file are ignored. Complete routines for   //
+// reading and writing ,ply files are available from:                        //
+//       http://www.cc.gatech.edu/projects/large_models/ply.html             //
+// Except the header section,ply file format has exactly the same format for //
+// listing vertices and polygons as off file format.                         //
+//                                                                           //
+// On completion, 'pointlist' and 'facetlist' together return the polyhedron.//
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_ply(const char* filename)
+{
+  FILE *fp;
+  tetgenio::facet *f;
+  tetgenio::polygon *p;
+  char infilename[FILENAMESIZE];
+  char buffer[INPUTLINESIZE];
+  char *bufferp, *str;
+  double *coord;
+  int endheader = 0, format = 0;
+  int nverts = 0, iverts = 0;
+  int nfaces = 0, ifaces = 0;
+  int line_count = 0, i;
+
+  strncpy(infilename, filename, FILENAMESIZE - 1);
+  infilename[FILENAMESIZE - 1] = '\0';
+  if (infilename[0] == '\0') {
+    printf("Error:  No filename.\n");
+    return false;
+  }
+  if (strcmp(&infilename[strlen(infilename) - 4], ".ply") != 0) {
+    strcat(infilename, ".ply");
+  }
+
+  if (!(fp = fopen(infilename, "r"))) {
+    printf("Error:  Unable to open file %s\n", infilename);
+    return false;
+  }
+  printf("Opening %s.\n", infilename);
+
+  // PLY requires the index starts from '0'.
+  firstnumber = 0;
+
+  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
+    if (!endheader) {
+      // Find if it is the keyword "end_header".
+      str = strstr(bufferp, "end_header");
+      // strstr() is case sensitive.
+      if (!str) str = strstr(bufferp, "End_header");
+      if (!str) str = strstr(bufferp, "End_Header");
+      if (str) {
+        // This is the end of the header section.
+        endheader = 1; 
+        continue;
+      }
+      // Parse the number of vertices and the number of faces.
+      if (nverts == 0 || nfaces == 0) {
+        // Find if it si the keyword "element".
+        str = strstr(bufferp, "element");
+        if (!str) str = strstr(bufferp, "Element");
+        if (str) {
+          bufferp = findnextfield(str);
+          if (*bufferp == '\0') {
+            printf("Syntax error reading element type on line%d in file %s\n",
+                   line_count, infilename);
+            fclose(fp);
+            return false;
+          }
+          if (nverts == 0) {
+            // Find if it is the keyword "vertex".
+            str = strstr(bufferp, "vertex");
+            if (!str) str = strstr(bufferp, "Vertex");
+            if (str) {
+              bufferp = findnextnumber(str);
+              if (*bufferp == '\0') {
+                printf("Syntax error reading vertex number on line");
+                printf(" %d in file %s\n", line_count, infilename);
+                fclose(fp);
+                return false;
+              }
+              nverts = (int) strtol(bufferp, &bufferp, 0);
+              // Allocate memory for 'tetgenio'
+              if (nverts > 0) {
+                numberofpoints = nverts;
+                pointlist = new REAL[nverts * 3];
+              }
+            }
+          }
+          if (nfaces == 0) {
+            // Find if it is the keyword "face".
+            str = strstr(bufferp, "face");
+            if (!str) str = strstr(bufferp, "Face");
+            if (str) {
+              bufferp = findnextnumber(str);
+              if (*bufferp == '\0') {
+                printf("Syntax error reading face number on line");
+                printf(" %d in file %s\n", line_count, infilename);
+                fclose(fp);
+                return false;
+              }
+              nfaces = (int) strtol(bufferp, &bufferp, 0);
+              // Allocate memory for 'tetgenio'
+              if (nfaces > 0) {        
+                numberoffacets = nfaces;
+                facetlist = new tetgenio::facet[nfaces];
+              }
+            }
+          }
+        } // It is not the string "element". 
+      }
+      if (format == 0) {
+        // Find the keyword "format".
+        str = strstr(bufferp, "format");
+        if (!str) str = strstr(bufferp, "Format");
+        if (str) {
+          format = 1;
+          bufferp = findnextfield(str);
+          // Find if it is the string "ascii".
+          str = strstr(bufferp, "ascii");
+          if (!str) str = strstr(bufferp, "ASCII");
+          if (!str) {
+            printf("This routine only reads ascii format of ply files.\n");
+            printf("Hint: You can convert the binary to ascii format by\n");
+            printf("  using the provided ply tools:\n");
+            printf("  ply2ascii < %s > ascii_%s\n", infilename, infilename);
+            fclose(fp);
+            return false;
+          }
+        }
+      }
+    } else if (iverts < nverts) {
+      // Read vertex coordinates
+      coord = &pointlist[iverts * 3];
+      for (i = 0; i < 3; i++) {
+        if (*bufferp == '\0') {
+          printf("Syntax error reading vertex coords on line %d in file %s\n",
+                 line_count, infilename);
+          fclose(fp);
+          return false;
+        }
+        coord[i] = (REAL) strtod(bufferp, &bufferp);
+        bufferp = findnextnumber(bufferp);
+      }
+      iverts++;
+    } else if (ifaces < nfaces) {
+      // Get next face
+      f = &facetlist[ifaces];
+      init(f);      
+      // In .off format, each facet has one polygon, no hole.
+      f->numberofpolygons = 1;
+      f->polygonlist = new tetgenio::polygon[1];
+      p = &f->polygonlist[0];
+      init(p);
+      // Read the number of vertices, it should be greater than 0.
+      p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
+      if (p->numberofvertices == 0) {
+        printf("Syntax error reading polygon on line %d in file %s\n",
+               line_count, infilename);
+        fclose(fp);
+        return false;
+      }
+      // Allocate memory for face vertices
+      p->vertexlist = new int[p->numberofvertices];
+      for (i = 0; i < p->numberofvertices; i++) {
+        bufferp = findnextnumber(bufferp);
+        if (*bufferp == '\0') {
+          printf("Syntax error reading polygon on line %d in file %s\n",
+                 line_count, infilename);
+          fclose(fp);
+          return false;
+        }
+        p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
+      }
+      ifaces++;
+    } else {
+      // Should never get here
+      printf("Found extra text starting at line %d in file %s\n", line_count,
+             infilename);
+      break;
+    }
+  }
+
+  // Close file
+  fclose(fp);
+
+  // Check whether read all points
+  if (iverts != nverts) {
+    printf("Expected %d vertices, but read only %d vertices in file %s\n",
+           nverts, iverts, infilename);
+    return false;
+  }
+
+  // Check whether read all faces
+  if (ifaces != nfaces) {
+    printf("Expected %d faces, but read only %d faces in file %s\n",
+           nfaces, ifaces, infilename);
+    return false;
+  }
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_stl()    Load a surface mesh described in a .stl file.               //
+//                                                                           //
+// 'filename' is the file name with extension .stl or without extension (the //
+// .stl will be added in this case).                                         //
+//                                                                           //
+// The .stl or stereolithography format is an ASCII or binary file used in   //
+// manufacturing.  It is a list of the triangular surfaces that describe a   //
+// computer generated solid model. This is the standard input for most rapid //
+// prototyping machines.                                                     //
+//                                                                           //
+// On completion, 'pointlist' and 'facetlist' together return the polyhedron.//
+// Note: After load_stl(), there exist many duplicated points in 'pointlist'.//
+// They will be unified during the Delaunay tetrahedralization process.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_stl(const char* filename)
+{
+  FILE *fp;
+  facet *f;
+  polygon *p;
+  char infilename[FILENAMESIZE];
+  char buffer[INPUTLINESIZE];
+  char *bufferp, *str;
+  double *tmplist, *coord;
+  int solid = 0;
+  int maxverts = 1024, nverts = 0, iverts = 0;
+  int nfaces = 0;
+  int line_count = 0, i;
+
+  strncpy(infilename, filename, FILENAMESIZE - 1);
+  infilename[FILENAMESIZE - 1] = '\0';
+  if (infilename[0] == '\0') {
+    printf("Error:  No filename.\n");
+    return false;
+  }
+  if (strcmp(&infilename[strlen(infilename) - 4], ".stl") != 0) {
+    strcat(infilename, ".stl");
+  }
+
+  if (!(fp = fopen(infilename, "r"))) {
+    printf("Error:  Unable to open file %s\n", infilename);
+    return false;
+  }
+  printf("Opening %s.\n", infilename);
+
+  // STL file has no number of points available. Use a list to read points.
+  tmplist = (double *) malloc(sizeof(double) * 3 * maxverts); 
+
+  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
+    // The ASCII .stl file must start with the lower case keyword solid and
+    //   end with endsolid.
+    if (solid == 0) {
+      // Read header 
+      bufferp = strstr(bufferp, "solid");
+      if (bufferp != NULL) {
+        solid = 1;
+      }
+    } else {
+      // We're inside the block of the solid.
+      str = bufferp;
+      // Is this the end of the solid.
+      bufferp = strstr(bufferp, "endsolid");
+      if (bufferp != NULL) {
+        solid = 0;
+      } else {
+        // Read the XYZ coordinates if it is a vertex.
+        bufferp = str;
+        bufferp = strstr(bufferp, "vertex");
+        if (bufferp != NULL) {
+	  // Check if we have enough memory.
+	  if (nverts == maxverts) {
+	    maxverts += 1024;
+	    tmplist = (double *) realloc(tmplist, sizeof(double)*3*maxverts);
+	  }
+          coord = &(tmplist[nverts * 3]);
+          for (i = 0; i < 3; i++) {
+            bufferp = findnextnumber(bufferp);
+            if (*bufferp == '\0') {
+              printf("Syntax error reading vertex coords on line %d\n",
+                     line_count);
+              free(tmplist);
+              fclose(fp);
+              return false;
+            }
+            coord[i] = (REAL) strtod(bufferp, &bufferp);
+          }
+	  nverts++;
+        }
+      }
+    }
+  }
+  fclose(fp);
+
+  // nverts should be an integer times 3 (every 3 vertices denote a face).
+  if (nverts == 0 || (nverts % 3 != 0)) {
+    printf("Error:  Wrong number of vertices in file %s.\n", infilename);
+    free(tmplist);
+    return false;
+  }
+  numberofpoints = nverts;
+  pointlist = new REAL[nverts * 3];
+  for (i = 0; i < nverts; i++) {
+    coord = &(tmplist[i * 3]);
+    iverts = i * 3;
+    pointlist[iverts] = (REAL) coord[0];
+    pointlist[iverts + 1] = (REAL) coord[1];
+    pointlist[iverts + 2] = (REAL) coord[2];
+  }
+
+  nfaces = (int) (nverts / 3);
+  numberoffacets = nfaces;
+  facetlist = new facet[nfaces];
+
+  // Default use '1' as the array starting index.
+  firstnumber = 1;
+  iverts = firstnumber;
+  for (i = 0; i < nfaces; i++) {
+    f = &facetlist[i];
+    init(f);      
+    // In .stl format, each facet has one polygon, no hole.
+    f->numberofpolygons = 1;
+    f->polygonlist = new polygon[1];
+    p = &f->polygonlist[0];
+    init(p);
+    // Each polygon has three vertices.
+    p->numberofvertices = 3;
+    p->vertexlist = new int[p->numberofvertices];
+    p->vertexlist[0] = iverts;
+    p->vertexlist[1] = iverts + 1;
+    p->vertexlist[2] = iverts + 2;
+    iverts += 3;
+  }
+
+  free(tmplist);
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_medit()    Load a surface mesh described in .mesh file.              //
+//                                                                           //
+// 'filename' is the file name with extension .mesh or without entension (   //
+// the .mesh will be added in this case). .mesh is the file format of Medit, //
+// a user-friendly interactive mesh viewing program.                         //
+//                                                                           //
+// This routine ONLY reads the sections containing vertices, triangles, and  //
+// quadrilaters. Other sections (such as tetrahedra, edges, ...) are ignored.//
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_medit(const char* filename)
+{
+  FILE *fp;
+  tetgenio::facet *tmpflist, *f;
+  tetgenio::polygon *p;
+  char infilename[FILENAMESIZE];
+  char buffer[INPUTLINESIZE];
+  char *bufferp, *str;
+  double *coord;
+  int *tmpfmlist;
+  int dimension = 0;
+  int nverts = 0;
+  int nfaces = 0;
+  int line_count = 0;
+  int corners = 0; // 3 (triangle) or 4 (quad).
+  int i, j;
+
+  strncpy(infilename, filename, FILENAMESIZE - 1);
+  infilename[FILENAMESIZE - 1] = '\0';
+  if (infilename[0] == '\0') {
+    printf("Error:  No filename.\n");
+    return false;
+  }
+  if (strcmp(&infilename[strlen(infilename) - 5], ".mesh") != 0) {
+    strcat(infilename, ".mesh");
+  }
+  
+  if (!(fp = fopen(infilename, "r"))) {
+    printf("Error:  Unable to open file %s\n", infilename);
+    return false;
+  }
+  printf("Opening %s.\n", infilename);
+
+  // Default uses the index starts from '1'.
+  firstnumber = 1;
+
+  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
+    if (*bufferp == '#') continue;  // A comment line is skipped.
+    if (dimension == 0) {
+      // Find if it is the keyword "Dimension".
+      str = strstr(bufferp, "Dimension");
+      if (!str) str = strstr(bufferp, "dimension");
+      if (!str) str = strstr(bufferp, "DIMENSION");
+      if (str) {
+        // Read the dimensions
+        bufferp = findnextnumber(str); // Skip field "Dimension".
+        if (*bufferp == '\0') {
+          // Read a non-empty line.
+          bufferp = readline(buffer, fp, &line_count);
+        }
+        dimension = (int) strtol(bufferp, &bufferp, 0);
+        if (dimension != 2 && dimension != 3) {
+          printf("Unknown dimension in file on line %d in file %s\n",
+                 line_count, infilename);
+          fclose(fp);
+          return false;
+        }
+        mesh_dim = dimension;
+      }
+    }
+    if (nverts == 0) {
+      // Find if it is the keyword "Vertices".
+      str = strstr(bufferp, "Vertices");
+      if (!str) str = strstr(bufferp, "vertices");
+      if (!str) str = strstr(bufferp, "VERTICES");
+      if (str) {
+        // Read the number of vertices.
+        bufferp = findnextnumber(str); // Skip field "Vertices".
+        if (*bufferp == '\0') {
+          // Read a non-empty line.
+          bufferp = readline(buffer, fp, &line_count);
+        }
+        nverts = (int) strtol(bufferp, &bufferp, 0);
+        // Allocate memory for 'tetgenio'
+        if (nverts > 0) {
+          numberofpoints = nverts;
+          pointlist = new REAL[nverts * 3];
+        }
+        // Read the follwoing node list.
+        for (i = 0; i < nverts; i++) {
+          bufferp = readline(buffer, fp, &line_count);
+          if (bufferp == NULL) {
+            printf("Unexpected end of file on line %d in file %s\n",
+                   line_count, infilename);
+            fclose(fp);
+            return false;
+          }
+          // Read vertex coordinates
+          coord = &pointlist[i * 3];
+          for (j = 0; j < 3; j++) {
+            if (*bufferp == '\0') {
+              printf("Syntax error reading vertex coords on line");
+              printf(" %d in file %s\n", line_count, infilename);
+              fclose(fp);
+              return false;
+            }
+            if ((j < 2) || (dimension == 3)) {
+              coord[j] = (REAL) strtod(bufferp, &bufferp);
+            } else {
+              assert((j == 2) && (dimension == 2));
+              coord[j] = 0.0;
+            }
+            bufferp = findnextnumber(bufferp);
+          }
+        }
+        continue;
+      }
+    } 
+    if (nfaces == 0) {
+      // Find if it is the keyword "Triangles" or "Quadrilaterals".
+      corners = 0;
+      str = strstr(bufferp, "Triangles");
+      if (!str) str = strstr(bufferp, "triangles");
+      if (!str) str = strstr(bufferp, "TRIANGLES");
+      if (str) {
+        corners = 3;
+      } else {
+        str = strstr(bufferp, "Quadrilaterals");
+        if (!str) str = strstr(bufferp, "quadrilaterals");
+        if (!str) str = strstr(bufferp, "QUADRILATERALS");
+        if (str) {
+          corners = 4;
+        }
+      }
+      if (corners == 3 || corners == 4) {
+        // Read the number of triangles (or quadrilaterals).
+        bufferp = findnextnumber(str); // Skip field "Triangles".
+        if (*bufferp == '\0') {
+          // Read a non-empty line.
+          bufferp = readline(buffer, fp, &line_count);
+        }
+        nfaces = strtol(bufferp, &bufferp, 0);
+        // Allocate memory for 'tetgenio'
+        if (nfaces > 0) {
+          if (numberoffacets > 0) {
+            // facetlist has already been allocated. Enlarge arrays.
+            tmpflist = new tetgenio::facet[numberoffacets + nfaces];
+            tmpfmlist = new int[numberoffacets + nfaces];
+            // Copy the data of old arrays into new arrays.
+            for (i = 0; i < numberoffacets; i++) {
+              f = &(tmpflist[i]);
+              tetgenio::init(f);
+              *f = facetlist[i];
+              tmpfmlist[i] = facetmarkerlist[i];
+            }
+            // Release old arrays.
+            delete [] facetlist;
+            delete [] facetmarkerlist;
+            // Remember the new arrays.
+            facetlist = tmpflist;
+            facetmarkerlist = tmpfmlist;
+          } else {
+            // This is the first time to allocate facetlist.
+            facetlist = new tetgenio::facet[nfaces];
+            facetmarkerlist = new int[nfaces];
+          }
+        }
+        // Read the following list of faces.
+        for (i = numberoffacets; i < numberoffacets + nfaces; i++) {
+          bufferp = readline(buffer, fp, &line_count);
+          if (bufferp == NULL) {
+            printf("Unexpected end of file on line %d in file %s\n",
+                   line_count, infilename);
+            fclose(fp);
+            return false;
+          }
+          f = &facetlist[i];
+          tetgenio::init(f);
+          // In .mesh format, each facet has one polygon, no hole.
+          f->numberofpolygons = 1;
+          f->polygonlist = new tetgenio::polygon[1];
+          p = &f->polygonlist[0];
+          tetgenio::init(p);
+          p->numberofvertices = corners;
+          // Allocate memory for face vertices
+          p->vertexlist = new int[p->numberofvertices];
+          // Read the vertices of the face.
+          for (j = 0; j < corners; j++) {
+            if (*bufferp == '\0') {
+              printf("Syntax error reading face on line %d in file %s\n",
+                     line_count, infilename);
+              fclose(fp);
+              return false;
+            }
+            p->vertexlist[j] = (int) strtol(bufferp, &bufferp, 0);
+            if (firstnumber == 1) {
+              // Check if a '0' index appears.
+              if (p->vertexlist[j] == 0) {
+                // The first index is set to be 0.
+                firstnumber = 0;
+              }
+            }
+            bufferp = findnextnumber(bufferp);
+          }
+          // Read the marker of the face if it exists.
+          facetmarkerlist[i] = 0;
+          if (*bufferp != '\0') {
+            facetmarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
+          }
+        }
+        // Have read in a list of triangles/quads.
+        numberoffacets += nfaces;
+        nfaces = 0;
+      }
+    }
+    // if (nverts > 0 && nfaces > 0) break; // Ignore other data.
+  }
+
+  // Close file
+  fclose(fp);
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_vtk()    Load VTK surface mesh from file (.vtk ascii or binary).     //
+//                                                                           //
+// 'filename' is a string containing the file name with or without suffix.   //
+//                                                                           //
+// This function is contributed by user: Bryn Lloyd (May 7, 2007).           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void swapBytes(unsigned char* var, int size)
+{
+  int i = 0;
+  int j = size - 1;
+  char c;
+
+  while (i < j) {
+    c = var[i]; var[i] = var[j]; var[j] = c;
+    i++, j--;
+  }
+}
+
+bool testIsBigEndian()
+{
+  short word = 0x4321;
+  if((*(char *)& word) != 0x21)
+    return true;
+  else 
+    return false;
+}
+
+bool tetgenio::load_vtk(const char* filename)
+{
+  FILE *fp;
+  tetgenio::facet *f;
+  tetgenio::polygon *p;
+  char infilename[FILENAMESIZE];
+  char line[INPUTLINESIZE];
+  char mode[128], id[256], fmt[64];
+  char *bufferp;
+  double *coord;
+  float _x, _y, _z;
+  int nverts = 0;
+  int nfaces = 0;
+  int line_count = 0;
+  int dummy;
+  int id1, id2, id3;
+  int nn = -1;
+  int nn_old = -1;
+  int i, j;
+  bool ImALittleEndian = !testIsBigEndian();
+
+  strncpy(infilename, filename, FILENAMESIZE - 1);
+  infilename[FILENAMESIZE - 1] = '\0';
+  if (infilename[0] == '\0') {
+    printf("Error:  No filename.\n");
+    return false;
+  }
+  if (strcmp(&infilename[strlen(infilename) - 4], ".vtk") != 0) {
+    strcat(infilename, ".vtk");
+  }
+  if (!(fp = fopen(infilename, "r"))) {
+    printf("Error:  Unable to open file %s\n", infilename);
+    return false;
+  }
+  printf("Opening %s.\n", infilename);
+
+  // Default uses the index starts from '0'.
+  firstnumber = 0;
+  strcpy(mode, "BINARY");
+
+  while((bufferp = readline(line, fp, &line_count)) != NULL) {
+    if(strlen(line) == 0) continue;
+    //swallow lines beginning with a comment sign or white space
+    if(line[0] == '#' || line[0]=='\n' || line[0] == 10 || line[0] == 13 || 
+       line[0] == 32) continue;
+
+    sscanf(line, "%s", id);
+    if(!strcmp(id, "ASCII")) {
+      strcpy(mode, "ASCII");
+    }
+
+    if(!strcmp(id, "POINTS")) {
+      sscanf(line, "%s %d %s", id, &nverts, fmt);
+      if (nverts > 0) {
+        numberofpoints = nverts;
+        pointlist = new REAL[nverts * 3];
+      }
+
+      if(!strcmp(mode, "BINARY")) {
+        for(i = 0; i < nverts; i++) {
+          coord = &pointlist[i * 3];
+          if(!strcmp(fmt, "double")) {
+            fread((char*)(&(coord[0])), sizeof(double), 1, fp);
+            fread((char*)(&(coord[1])), sizeof(double), 1, fp);
+            fread((char*)(&(coord[2])), sizeof(double), 1, fp);
+            if(ImALittleEndian){
+              swapBytes((unsigned char *) &(coord[0]), sizeof(coord[0]));
+              swapBytes((unsigned char *) &(coord[1]), sizeof(coord[1]));
+              swapBytes((unsigned char *) &(coord[2]), sizeof(coord[2]));
+            }
+          } else if(!strcmp(fmt, "float")) {
+            fread((char*)(&_x), sizeof(float), 1, fp);
+            fread((char*)(&_y), sizeof(float), 1, fp);
+            fread((char*)(&_z), sizeof(float), 1, fp);
+            if(ImALittleEndian){
+              swapBytes((unsigned char *) &_x, sizeof(_x));
+              swapBytes((unsigned char *) &_y, sizeof(_y));
+              swapBytes((unsigned char *) &_z, sizeof(_z));
+            }
+            coord[0] = double(_x);
+            coord[1] = double(_y);
+            coord[2] = double(_z);
+          } else {
+            printf("Error: Only float or double formats are supported!\n");
+            return false;
+          }
+        }
+      } else if(!strcmp(mode, "ASCII")) {
+        for(i = 0; i < nverts; i++){
+          bufferp = readline(line, fp, &line_count);
+          if (bufferp == NULL) {
+            printf("Unexpected end of file on line %d in file %s\n",
+                   line_count, infilename);
+            fclose(fp);
+            return false;
+          }
+          // Read vertex coordinates
+          coord = &pointlist[i * 3];
+          for (j = 0; j < 3; j++) {
+            if (*bufferp == '\0') {
+              printf("Syntax error reading vertex coords on line");
+              printf(" %d in file %s\n", line_count, infilename);
+              fclose(fp);
+              return false;
+            }
+            coord[j] = (REAL) strtod(bufferp, &bufferp);
+            bufferp = findnextnumber(bufferp);
+          }
+        }
+      }
+      continue;
+    }
+
+    if(!strcmp(id, "POLYGONS")) {
+      sscanf(line, "%s %d  %d", id, &nfaces, &dummy);
+      if (nfaces > 0) {
+        numberoffacets = nfaces;
+        facetlist = new tetgenio::facet[nfaces];
+      }
+
+      if(!strcmp(mode, "BINARY")) {
+        for(i = 0; i < nfaces; i++){
+          fread((char*)(&nn), sizeof(int), 1, fp);
+          if(ImALittleEndian){
+            swapBytes((unsigned char *) &nn, sizeof(nn));
+          }
+          if (i == 0)
+            nn_old = nn;
+          if (nn != nn_old) {
+            printf("Error:  No mixed cells are allowed.\n");
+            return false;
+          }
+
+          if(nn == 3){
+            fread((char*)(&id1), sizeof(int), 1, fp);
+            fread((char*)(&id2), sizeof(int), 1, fp);
+            fread((char*)(&id3), sizeof(int), 1, fp);
+            if(ImALittleEndian){
+              swapBytes((unsigned char *) &id1, sizeof(id1));
+              swapBytes((unsigned char *) &id2, sizeof(id2));
+              swapBytes((unsigned char *) &id3, sizeof(id3));
+            }
+            f = &facetlist[i];
+            init(f);
+            // In .off format, each facet has one polygon, no hole.
+            f->numberofpolygons = 1;
+            f->polygonlist = new tetgenio::polygon[1];
+            p = &f->polygonlist[0];
+            init(p);
+            // Set number of vertices
+            p->numberofvertices = 3;
+            // Allocate memory for face vertices
+            p->vertexlist = new int[p->numberofvertices];
+            p->vertexlist[0] = id1;
+            p->vertexlist[1] = id2;
+            p->vertexlist[2] = id3;
+          } else {
+            printf("Error: Only triangles are supported\n");
+            return false;
+          }
+        }
+      } else if(!strcmp(mode, "ASCII")) {
+        for(i = 0; i < nfaces; i++) {
+          bufferp = readline(line, fp, &line_count);
+          nn = (int) strtol(bufferp, &bufferp, 0);
+          if (i == 0)
+            nn_old = nn;
+          if (nn != nn_old) {
+            printf("Error:  No mixed cells are allowed.\n");
+            return false;
+          }
+
+          if (nn == 3) {
+            bufferp = findnextnumber(bufferp); // Skip the first field.
+            id1 = (int) strtol(bufferp, &bufferp, 0);
+            bufferp = findnextnumber(bufferp);
+            id2 = (int) strtol(bufferp, &bufferp, 0);
+            bufferp = findnextnumber(bufferp);
+            id3 = (int) strtol(bufferp, &bufferp, 0);
+            f = &facetlist[i];
+            init(f);
+            // In .off format, each facet has one polygon, no hole.
+            f->numberofpolygons = 1;
+            f->polygonlist = new tetgenio::polygon[1];
+            p = &f->polygonlist[0];
+            init(p);
+            // Set number of vertices
+            p->numberofvertices = 3;
+            // Allocate memory for face vertices
+            p->vertexlist = new int[p->numberofvertices];
+            p->vertexlist[0] = id1;
+            p->vertexlist[1] = id2;
+            p->vertexlist[2] = id3;
+          } else {
+            printf("Error:  Only triangles are supported.\n");
+            return false;
+          }
+        }
+      }
+
+      fclose(fp);
+      return true;
+    }
+
+    if(!strcmp(id,"LINES") || !strcmp(id,"CELLS")){
+      printf("Warning:  load_vtk(): cannot read formats LINES, CELLS.\n");
+    }
+  } // while ()
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_plc()    Load a piecewise linear complex from file.                  //
+//                                                                           //
+// This is main entrance for loading plcs from different file formats into   //
+// tetgenio.  'filename' is the input file name without extention. 'object'  //
+// indicates which file format is used to describ the plc.                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_plc(const char* filename, int object)
+{
+  enum tetgenbehavior::objecttype type;
+
+  type = (enum tetgenbehavior::objecttype) object;
+  switch (type) {
+  case tetgenbehavior::NODES:
+    return load_node(filename);
+  case tetgenbehavior::POLY:
+    return load_poly(filename);
+  case tetgenbehavior::OFF:
+    return load_off(filename);
+  case tetgenbehavior::PLY:
+    return load_ply(filename);
+  case tetgenbehavior::STL:
+    return load_stl(filename);
+  case tetgenbehavior::MEDIT:
+    return load_medit(filename);
+  case tetgenbehavior::VTK:
+    return load_vtk(filename);
+  default:
+    return load_poly(filename);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_tetmesh()    Load a tetrahedral mesh from files.                     //
+//                                                                           //
+// 'filename' is the inputfile without suffix.  The nodes of the tetrahedral //
+// mesh is in "filename.node",  the elements is in "filename.ele", if the    //
+// "filename.face" and "filename.vol" exists, they will also be read.        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_tetmesh(const char* filename)
+{
+  FILE *infile;
+  char innodefilename[FILENAMESIZE];
+  char inelefilename[FILENAMESIZE];
+  char infacefilename[FILENAMESIZE];
+  char inedgefilename[FILENAMESIZE];
+  char involfilename[FILENAMESIZE];
+  char inputline[INPUTLINESIZE];
+  char *stringptr, *infilename;
+  REAL attrib, volume;
+  int volelements;
+  int markers, corner;
+  int index, attribindex;
+  int i, j;
+
+  // Assembling the actual file names we want to open.
+  strcpy(innodefilename, filename);
+  strcpy(inelefilename, filename);
+  strcpy(infacefilename, filename);
+  strcpy(inedgefilename, filename);
+  strcpy(involfilename, filename);
+  strcat(innodefilename, ".node");
+  strcat(inelefilename, ".ele");
+  strcat(infacefilename, ".face");
+  strcat(inedgefilename, ".edge");
+  strcat(involfilename, ".vol");
+
+  // Read the points from a .node file.
+  infilename = innodefilename;
+  printf("Opening %s.\n", infilename);
+  infile = fopen(infilename, "r");
+  if (infile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot access file %s.\n", infilename);
+    return false;
+  }
+  // Read the first line of the file.
+  stringptr = readnumberline(inputline, infile, infilename); 
+  // Is this list of points generated from rbox?
+  stringptr = strstr(inputline, "rbox");
+  if (stringptr == NULL) {
+    // Read number of points, number of dimensions, number of point
+    //   attributes, and number of boundary markers.
+    stringptr = inputline;
+    numberofpoints = (int) strtol (stringptr, &stringptr, 0);
+    stringptr = findnextnumber(stringptr);
+    if (*stringptr == '\0') {
+      mesh_dim = 3;
+    } else {
+      mesh_dim = (int) strtol (stringptr, &stringptr, 0);
+    }
+    stringptr = findnextnumber(stringptr);
+    if (*stringptr == '\0') {
+      numberofpointattributes = 0;
+    } else {
+      numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
+    }
+    stringptr = findnextnumber(stringptr);
+    if (*stringptr == '\0') {
+      markers = 0;  // Default value.
+    } else {
+      markers = (int) strtol (stringptr, &stringptr, 0);
+    }
+  } else {
+    // It is a rbox (qhull) input file.
+    stringptr = inputline;
+    // Get the dimension.
+    mesh_dim = (int) strtol (stringptr, &stringptr, 0);
+    // Get the number of points.
+    stringptr = readnumberline(inputline, infile, infilename);
+    numberofpoints = (int) strtol (stringptr, &stringptr, 0);
+    // There is no index column.
+    useindex = 0;
+  }
+
+  // Load the list of nodes.
+  if (!load_node_call(infile, markers, infilename)) {
+    fclose(infile);
+    return false;
+  }
+  fclose(infile);
+
+  // Read the elements from an .ele file.
+  if (mesh_dim == 3) {
+    infilename = inelefilename;
+    infile = fopen(infilename, "r");
+    if (infile != (FILE *) NULL) {
+      printf("Opening %s.\n", infilename);
+      // Read number of elements, number of corners (4 or 10), number of
+      //   element attributes.
+      stringptr = readnumberline(inputline, infile, infilename);
+      numberoftetrahedra = (int) strtol (stringptr, &stringptr, 0);
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        numberofcorners = 4;  // Default read 4 nodes per element.
+      } else {
+        numberofcorners = (int) strtol(stringptr, &stringptr, 0);
+      }
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        numberoftetrahedronattributes = 0; // Default no attribute.
+      } else {
+        numberoftetrahedronattributes = (int) strtol(stringptr, &stringptr, 0);
+      }
+      if (numberofcorners != 4 && numberofcorners != 10) {
+        printf("Error:  Wrong number of corners %d (should be 4 or 10).\n", 
+               numberofcorners);
+        fclose(infile);
+        return false;
+      }
+      // Allocate memory for tetrahedra.
+      if (numberoftetrahedra > 0) {
+        tetrahedronlist = new int[numberoftetrahedra * numberofcorners]; 
+        if (tetrahedronlist == (int *) NULL) {
+          printf("Error:  Out of memory.\n");
+          terminatetetgen(1);
+        }
+        // Allocate memory for output tetrahedron attributes if necessary.
+        if (numberoftetrahedronattributes > 0) {
+          tetrahedronattributelist = new REAL[numberoftetrahedra *
+                                          numberoftetrahedronattributes];
+          if (tetrahedronattributelist == (REAL *) NULL) {
+            printf("Error:  Out of memory.\n");
+            terminatetetgen(1);
+          }
+        }
+      }
+      // Read the list of tetrahedra.
+      index = 0;
+      attribindex = 0;
+      for (i = 0; i < numberoftetrahedra; i++) {
+        // Read tetrahedron index and the tetrahedron's corners.
+        stringptr = readnumberline(inputline, infile, infilename);
+        for (j = 0; j < numberofcorners; j++) {
+          stringptr = findnextnumber(stringptr);
+          if (*stringptr == '\0') {
+            printf("Error:  Tetrahedron %d is missing vertex %d in %s.\n",
+                   i + firstnumber, j + 1, infilename);
+            terminatetetgen(1);
+          }
+          corner = (int) strtol(stringptr, &stringptr, 0);
+          if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
+            printf("Error:  Tetrahedron %d has an invalid vertex index.\n",
+                   i + firstnumber);
+            terminatetetgen(1);
+          }
+          tetrahedronlist[index++] = corner;
+        }
+        // Read the tetrahedron's attributes.
+        for (j = 0; j < numberoftetrahedronattributes; j++) {
+          stringptr = findnextnumber(stringptr);
+          if (*stringptr == '\0') {
+            attrib = 0.0;
+          } else {
+            attrib = (REAL) strtod(stringptr, &stringptr);
+          }
+          tetrahedronattributelist[attribindex++] = attrib;
+        }
+      }
+      fclose(infile);
+    }
+  } // if (meshdim == 3)
+  
+  // Read the hullfaces or subfaces from a .face file if it exists.
+  if (mesh_dim == 3) {
+    infilename = infacefilename;
+  } else {
+    infilename = inelefilename;
+  }
+  infile = fopen(infilename, "r");
+  if (infile != (FILE *) NULL) {
+    printf("Opening %s.\n", infilename);
+    // Read number of faces, boundary markers.
+    stringptr = readnumberline(inputline, infile, infilename);
+    numberoftrifaces = (int) strtol (stringptr, &stringptr, 0);
+    stringptr = findnextnumber(stringptr);
+    if (mesh_dim == 2) {
+      // Skip a number.
+      stringptr = findnextnumber(stringptr);
+    }
+    if (*stringptr == '\0') {
+      markers = 0;  // Default there is no marker per face.
+    } else {
+      markers = (int) strtol (stringptr, &stringptr, 0);
+    }
+    if (numberoftrifaces > 0) {
+      trifacelist = new int[numberoftrifaces * 3];
+      if (trifacelist == (int *) NULL) {
+        printf("Error:  Out of memory.\n");
+        terminatetetgen(1);
+      }
+      if (markers) {
+        trifacemarkerlist = new int[numberoftrifaces * 3];
+        if (trifacemarkerlist == (int *) NULL) {
+          printf("Error:  Out of memory.\n");
+          terminatetetgen(1);
+        }
+      }
+    }
+    // Read the list of faces.
+    index = 0;
+    for (i = 0; i < numberoftrifaces; i++) {
+      // Read face index and the face's three corners.
+      stringptr = readnumberline(inputline, infile, infilename);
+      for (j = 0; j < 3; j++) {
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Face %d is missing vertex %d in %s.\n",
+                 i + firstnumber, j + 1, infilename);
+          terminatetetgen(1);
+        }
+        corner = (int) strtol(stringptr, &stringptr, 0);
+        if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
+          printf("Error:  Face %d has an invalid vertex index.\n",
+                 i + firstnumber);
+          terminatetetgen(1);
+        }
+        trifacelist[index++] = corner;
+      }
+      // Read the boundary marker if it exists.
+      if (markers) {
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          attrib = 0.0;
+        } else {
+          attrib = (REAL) strtod(stringptr, &stringptr);
+        }
+        trifacemarkerlist[i] = (int) attrib;
+      }
+    }
+    fclose(infile);
+  }
+
+  // Read the boundary edges from a .edge file if it exists.
+  infilename = inedgefilename;
+  infile = fopen(infilename, "r");
+  if (infile != (FILE *) NULL) {
+    printf("Opening %s.\n", infilename);
+    // Read number of boundary edges.
+    stringptr = readnumberline(inputline, infile, infilename);
+    numberofedges = (int) strtol (stringptr, &stringptr, 0);
+    if (numberofedges > 0) {
+      edgelist = new int[numberofedges * 2];
+      if (edgelist == (int *) NULL) {
+        printf("Error:  Out of memory.\n");
+        terminatetetgen(1);
+      }
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        markers = 0;  // Default value.
+      } else {
+        markers = (int) strtol (stringptr, &stringptr, 0);
+      }
+      if (markers > 0) {
+        edgemarkerlist = new int[numberofedges];
+      }
+    }
+    // Read the list of faces.
+    index = 0;
+    for (i = 0; i < numberofedges; i++) {
+      // Read face index and the edge's two endpoints.
+      stringptr = readnumberline(inputline, infile, infilename);
+      for (j = 0; j < 2; j++) {
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Edge %d is missing vertex %d in %s.\n",
+                 i + firstnumber, j + 1, infilename);
+          terminatetetgen(1);
+        }
+        corner = (int) strtol(stringptr, &stringptr, 0);
+        if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
+          printf("Error:  Edge %d has an invalid vertex index.\n",
+                 i + firstnumber);
+          terminatetetgen(1);
+        }
+        edgelist[index++] = corner;
+      }
+      // Read the edge marker if it has.
+      if (markers) {
+        stringptr = findnextnumber(stringptr);
+        edgemarkerlist[i] = (int) strtol(stringptr, &stringptr, 0);
+      }
+    }
+    fclose(infile);
+  }
+
+  // Read the volume constraints from a .vol file if it exists.
+  infilename = involfilename;
+  infile = fopen(infilename, "r");
+  if (infile != (FILE *) NULL) {
+    printf("Opening %s.\n", infilename);
+    // Read number of tetrahedra.
+    stringptr = readnumberline(inputline, infile, infilename);
+    volelements = (int) strtol (stringptr, &stringptr, 0);
+    if (volelements != numberoftetrahedra) {
+      printf("Warning:  %s and %s disagree on number of tetrahedra.\n",
+             inelefilename, involfilename);
+      volelements = 0;
+    }
+    if (volelements > 0) {
+      tetrahedronvolumelist = new REAL[volelements];
+      if (tetrahedronvolumelist == (REAL *) NULL) {
+        printf("Error:  Out of memory.\n");
+        terminatetetgen(1);
+      }
+    }
+    // Read the list of volume constraints.
+    for (i = 0; i < volelements; i++) {
+      stringptr = readnumberline(inputline, infile, infilename);
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        volume = -1.0; // No constraint on this tetrahedron.
+      } else {
+        volume = (REAL) strtod(stringptr, &stringptr);
+      }
+      tetrahedronvolumelist[i] = volume;
+    }
+    fclose(infile);
+  }
+
+  // Try to load a .mtr file if it exists.
+  load_mtr(filename);
+  // Try to read a .pbc file if it exists.
+  load_pbc(filename);
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_voronoi()    Load a Voronoi diagram from files.                      //
+//                                                                           //
+// 'filename' is the inputfile without suffix.  The Voronoi diagram is read  //
+// from files: filename.v.node, filename.v.edge, and filename.v.face.        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_voronoi(const char* filename)
+{
+  FILE *infile;
+  char innodefilename[FILENAMESIZE];
+  char inedgefilename[FILENAMESIZE];
+  char inputline[INPUTLINESIZE];
+  char *stringptr, *infilename;
+  voroedge *vedge;
+  REAL x, y, z;
+  int firstnode, corner;
+  int index;
+  int i, j;
+
+  // Assembling the actual file names we want to open.
+  strcpy(innodefilename, filename);
+  strcpy(inedgefilename, filename);
+  strcat(innodefilename, ".v.node");
+  strcat(inedgefilename, ".v.edge");
+
+  // Read the points from a .v.node file.
+  infilename = innodefilename;
+  printf("Opening %s.\n", infilename);
+  infile = fopen(infilename, "r");
+  if (infile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot access file %s.\n", infilename);
+    return false;
+  }
+  // Read the first line of the file.
+  stringptr = readnumberline(inputline, infile, infilename); 
+  // Is this list of points generated from rbox?
+  stringptr = strstr(inputline, "rbox");
+  if (stringptr == NULL) {
+    // Read number of points, number of dimensions, number of point
+    //   attributes, and number of boundary markers.
+    stringptr = inputline;
+    numberofvpoints = (int) strtol (stringptr, &stringptr, 0);
+    stringptr = findnextnumber(stringptr);
+    if (*stringptr == '\0') {
+      mesh_dim = 3;  // Default.
+    } else {
+      mesh_dim = (int) strtol (stringptr, &stringptr, 0);
+    }
+    useindex = 1;  // There is an index column.
+  } else {
+    // It is a rbox (qhull) input file.
+    stringptr = inputline;
+    // Get the dimension.
+    mesh_dim = (int) strtol (stringptr, &stringptr, 0);
+    // Get the number of points.
+    stringptr = readnumberline(inputline, infile, infilename);
+    numberofvpoints = (int) strtol (stringptr, &stringptr, 0);
+    useindex = 0;  // No index column.
+  }
+  // Initialize 'vpointlist'.
+  vpointlist = new REAL[numberofvpoints * 3];
+  if (vpointlist == (REAL *) NULL) {
+    printf("Error:  Out of memory.\n");
+    terminatetetgen(1);
+  }
+  // Read the point section.
+  index = 0;
+  for (i = 0; i < numberofvpoints; i++) {
+    stringptr = readnumberline(inputline, infile, infilename);
+    if (useindex) {
+      if (i == 0) {
+        firstnode = (int) strtol (stringptr, &stringptr, 0);
+        if ((firstnode == 0) || (firstnode == 1)) {
+          firstnumber = firstnode;
+        }
+      }
+      stringptr = findnextnumber(stringptr);
+    } // if (useindex)
+    if (*stringptr == '\0') {
+      printf("Error:  Point %d has no x coordinate.\n", firstnumber + i);
+      terminatetetgen(1);
+    }
+    x = (REAL) strtod(stringptr, &stringptr);
+    stringptr = findnextnumber(stringptr);
+    if (*stringptr == '\0') {
+      printf("Error:  Point %d has no y coordinate.\n", firstnumber + i);
+      terminatetetgen(1);
+    }
+    y = (REAL) strtod(stringptr, &stringptr);
+    if (mesh_dim == 3) {
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  Point %d has no z coordinate.\n", firstnumber + i);
+        terminatetetgen(1);
+      }
+      z = (REAL) strtod(stringptr, &stringptr);
+    } else {
+      z = 0.0; // mesh_dim == 2;
+    }
+    vpointlist[index++] = x;
+    vpointlist[index++] = y;
+    vpointlist[index++] = z;
+  }
+  fclose(infile);
+
+  // Read the Voronoi edges from a .v.edge file if it exists.
+  infilename = inedgefilename;
+  infile = fopen(infilename, "r");
+  if (infile != (FILE *) NULL) {
+    printf("Opening %s.\n", infilename);
+    // Read number of boundary edges.
+    stringptr = readnumberline(inputline, infile, infilename);
+    numberofvedges = (int) strtol (stringptr, &stringptr, 0);
+    if (numberofvedges > 0) {
+      vedgelist = new voroedge[numberofvedges];
+    }
+    // Read the list of faces.
+    index = 0;
+    for (i = 0; i < numberofvedges; i++) {
+      // Read edge index and the edge's two endpoints.
+      stringptr = readnumberline(inputline, infile, infilename);
+      vedge = &(vedgelist[i]);
+      for (j = 0; j < 2; j++) {
+        stringptr = findnextnumber(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Edge %d is missing vertex %d in %s.\n",
+                 i + firstnumber, j + 1, infilename);
+          terminatetetgen(1);
+        }
+        corner = (int) strtol(stringptr, &stringptr, 0);
+        j == 0 ? vedge->v1 = corner : vedge->v2 = corner;
+      }
+      if (vedge->v2 < 0) {
+        for (j = 0; j < mesh_dim; j++) {
+          stringptr = findnextnumber(stringptr);
+          if (*stringptr == '\0') {
+            printf("Error:  Edge %d is missing normal in %s.\n",
+                   i + firstnumber, infilename);
+            terminatetetgen(1);
+          }
+          vedge->vnormal[j] = (REAL) strtod(stringptr, &stringptr);
+        }
+        if (mesh_dim == 2) {
+          vedge->vnormal[2] = 0.0;
+        }
+      } else {
+        vedge->vnormal[0] = 0.0;
+        vedge->vnormal[1] = 0.0;
+        vedge->vnormal[2] = 0.0;
+      }
+    }
+    fclose(infile);
+  }
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// save_nodes()    Save points to a .node file.                              //
+//                                                                           //
+// 'filename' is a string containing the file name without suffix.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenio::save_nodes(const char* filename)
+{
+  FILE *fout;
+  char outnodefilename[FILENAMESIZE];
+  char outmtrfilename[FILENAMESIZE];
+  int i, j;
+
+  sprintf(outnodefilename, "%s.node", filename);
+  printf("Saving nodes to %s\n", outnodefilename);
+  fout = fopen(outnodefilename, "w");
+  fprintf(fout, "%d  %d  %d  %d\n", numberofpoints, mesh_dim,
+          numberofpointattributes, pointmarkerlist != NULL ? 1 : 0);
+  for (i = 0; i < numberofpoints; i++) {
+    if (mesh_dim == 2) {
+      fprintf(fout, "%d  %.16g  %.16g", i + firstnumber, pointlist[i * 3],
+              pointlist[i * 3 + 1]);
+    } else {
+      fprintf(fout, "%d  %.16g  %.16g  %.16g", i + firstnumber,
+              pointlist[i * 3], pointlist[i * 3 + 1], pointlist[i * 3 + 2]);
+    }
+    for (j = 0; j < numberofpointattributes; j++) {
+      fprintf(fout, "  %.16g", 
+              pointattributelist[i * numberofpointattributes + j]);
+    }
+    if (pointmarkerlist != NULL) {
+      fprintf(fout, "  %d", pointmarkerlist[i]);
+    }
+    fprintf(fout, "\n");
+  }
+  fclose(fout);
+
+  // If the point metrics exist, output them to a .mtr file.
+  if ((numberofpointmtrs > 0) && (pointmtrlist != (REAL *) NULL)) {
+    sprintf(outmtrfilename, "%s.mtr", filename);
+    printf("Saving metrics to %s\n", outmtrfilename);
+    fout = fopen(outmtrfilename, "w");
+    fprintf(fout, "%d  %d\n", numberofpoints, numberofpointmtrs);
+    for (i = 0; i < numberofpoints; i++) {
+      for (j = 0; j < numberofpointmtrs; j++) {
+        fprintf(fout, "%.16g ", pointmtrlist[i * numberofpointmtrs + j]);
+      }
+      fprintf(fout, "\n");
+    }
+    fclose(fout);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// save_elements()    Save elements to a .ele file.                          //
+//                                                                           //
+// 'filename' is a string containing the file name without suffix.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenio::save_elements(const char* filename)
+{
+  FILE *fout;
+  char outelefilename[FILENAMESIZE];
+  int i, j;
+
+  sprintf(outelefilename, "%s.ele", filename);
+  printf("Saving elements to %s\n", outelefilename);
+  fout = fopen(outelefilename, "w");
+  if (mesh_dim == 3) {
+    fprintf(fout, "%d  %d  %d\n", numberoftetrahedra, numberofcorners,
+            numberoftetrahedronattributes);
+    for (i = 0; i < numberoftetrahedra; i++) {
+      fprintf(fout, "%d", i + firstnumber);
+      for (j = 0; j < numberofcorners; j++) {
+        fprintf(fout, "  %5d", tetrahedronlist[i * numberofcorners + j]);
+      }
+      for (j = 0; j < numberoftetrahedronattributes; j++) {
+        fprintf(fout, "  %g",
+          tetrahedronattributelist[i * numberoftetrahedronattributes + j]);
+      }
+      fprintf(fout, "\n");
+    }
+  } else {
+    // Save a two-dimensional mesh.
+    fprintf(fout, "%d  %d  %d\n", numberoftrifaces,3,trifacemarkerlist ? 1:0);
+    for (i = 0; i < numberoftrifaces; i++) {
+      fprintf(fout, "%d", i + firstnumber);
+      for (j = 0; j < 3; j++) {
+        fprintf(fout, "  %5d", trifacelist[i * 3 + j]);
+      }
+      if (trifacemarkerlist != NULL) {
+        fprintf(fout, "  %d", trifacemarkerlist[i]);
+      }
+      fprintf(fout, "\n");
+    }
+  }
+
+  fclose(fout);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// save_faces()    Save faces to a .face file.                               //
+//                                                                           //
+// 'filename' is a string containing the file name without suffix.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenio::save_faces(const char* filename)
+{
+  FILE *fout;
+  char outfacefilename[FILENAMESIZE];
+  int i;
+
+  sprintf(outfacefilename, "%s.face", filename);
+  printf("Saving faces to %s\n", outfacefilename);
+  fout = fopen(outfacefilename, "w");
+  fprintf(fout, "%d  %d\n", numberoftrifaces, 
+          trifacemarkerlist != NULL ? 1 : 0);
+  for (i = 0; i < numberoftrifaces; i++) {
+    fprintf(fout, "%d  %5d  %5d  %5d", i + firstnumber, trifacelist[i * 3],
+            trifacelist[i * 3 + 1], trifacelist[i * 3 + 2]);
+    if (trifacemarkerlist != NULL) {
+      fprintf(fout, "  %d", trifacemarkerlist[i]);
+    }
+    fprintf(fout, "\n");
+  }
+
+  fclose(fout);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// save_edges()    Save egdes to a .edge file.                               //
+//                                                                           //
+// 'filename' is a string containing the file name without suffix.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenio::save_edges(const char* filename)
+{
+  FILE *fout;
+  char outedgefilename[FILENAMESIZE];
+  int i;
+
+  sprintf(outedgefilename, "%s.edge", filename);
+  printf("Saving edges to %s\n", outedgefilename);
+  fout = fopen(outedgefilename, "w");
+  fprintf(fout, "%d  %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
+  for (i = 0; i < numberofedges; i++) {
+    fprintf(fout, "%d  %4d  %4d", i + firstnumber, edgelist[i * 2],
+            edgelist[i * 2 + 1]);
+    if (edgemarkerlist != NULL) {
+      fprintf(fout, "  %d", edgemarkerlist[i]);
+    }
+    fprintf(fout, "\n");
+  }
+
+  fclose(fout);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// save_neighbors()    Save egdes to a .neigh file.                          //
+//                                                                           //
+// 'filename' is a string containing the file name without suffix.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenio::save_neighbors(const char* filename)
+{
+  FILE *fout;
+  char outneighborfilename[FILENAMESIZE];
+  int i;
+
+  sprintf(outneighborfilename, "%s.neigh", filename);
+  printf("Saving neighbors to %s\n", outneighborfilename);
+  fout = fopen(outneighborfilename, "w");
+  fprintf(fout, "%d  %d\n", numberoftetrahedra, mesh_dim + 1);
+  for (i = 0; i < numberoftetrahedra; i++) {
+    if (mesh_dim == 2) {
+      fprintf(fout, "%d  %5d  %5d  %5d", i + firstnumber,  neighborlist[i * 3],
+              neighborlist[i * 3 + 1], neighborlist[i * 3 + 2]);
+    } else {
+      fprintf(fout, "%d  %5d  %5d  %5d  %5d", i + firstnumber,
+              neighborlist[i * 4], neighborlist[i * 4 + 1],
+              neighborlist[i * 4 + 2], neighborlist[i * 4 + 3]);
+    }
+    fprintf(fout, "\n");
+  }
+
+  fclose(fout);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// save_poly()    Save segments or facets to a .poly file.                   //
+//                                                                           //
+// 'filename' is a string containing the file name without suffix.  It only  //
+// save the facets, holes and regions.  The nodes are saved in a .node file  //
+// by routine save_nodes().                                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenio::save_poly(const char* filename)
+{
+  FILE *fout;
+  facet *f;
+  polygon *p;
+  char outpolyfilename[FILENAMESIZE];
+  int i, j, k;
+
+  sprintf(outpolyfilename, "%s.poly", filename);
+  printf("Saving poly to %s\n", outpolyfilename);
+  fout = fopen(outpolyfilename, "w");
+
+  // The zero indicates that the vertices are in a separate .node file.
+  //   Followed by number of dimensions, number of vertex attributes,
+  //   and number of boundary markers (zero or one).
+  fprintf(fout, "%d  %d  %d  %d\n", 0, mesh_dim, numberofpointattributes,
+          pointmarkerlist != NULL ? 1 : 0);
+
+  // Save segments or facets.
+  if (mesh_dim == 2) {
+    // Number of segments, number of boundary markers (zero or one).
+    fprintf(fout, "%d  %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
+    for (i = 0; i < numberofedges; i++) {
+      fprintf(fout, "%d  %4d  %4d", i + firstnumber, edgelist[i * 2],
+              edgelist[i * 2 + 1]);
+      if (edgemarkerlist != NULL) {
+        fprintf(fout, "  %d", edgemarkerlist[i]);
+      }
+      fprintf(fout, "\n");
+    }
+  } else {
+    // Number of facets, number of boundary markers (zero or one).
+    fprintf(fout, "%d  %d\n", numberoffacets, facetmarkerlist != NULL ? 1 : 0);
+    for (i = 0; i < numberoffacets; i++) {
+      f = &(facetlist[i]);
+      fprintf(fout, "%d  %d  %d  # %d\n", f->numberofpolygons,f->numberofholes,
+            facetmarkerlist != NULL ? facetmarkerlist[i] : 0, i + firstnumber);
+      // Output polygons of this facet.
+      for (j = 0; j < f->numberofpolygons; j++) {
+        p = &(f->polygonlist[j]);
+        fprintf(fout, "%d  ", p->numberofvertices);
+        for (k = 0; k < p->numberofvertices; k++) {
+          if (((k + 1) % 10) == 0) {
+            fprintf(fout, "\n  ");
+          }
+          fprintf(fout, "  %d", p->vertexlist[k]);
+        }
+        fprintf(fout, "\n");
+      }
+      // Output holes of this facet.
+      for (j = 0; j < f->numberofholes; j++) {
+        fprintf(fout, "%d  %.12g  %.12g  %.12g\n", j + firstnumber,
+           f->holelist[j * 3], f->holelist[j * 3 + 1], f->holelist[j * 3 + 2]);
+      }
+    }
+  }
+
+  // Save holes.
+  fprintf(fout, "%d\n", numberofholes);
+  for (i = 0; i < numberofholes; i++) {
+    // Output x, y coordinates.
+    fprintf(fout, "%d  %.12g  %.12g", i + firstnumber, holelist[i * mesh_dim],
+            holelist[i * mesh_dim + 1]);
+    if (mesh_dim == 3) {
+      // Output z coordinate.
+      fprintf(fout, "  %.12g", holelist[i * mesh_dim + 2]);
+    }
+    fprintf(fout, "\n");
+  }
+
+  // Save regions.
+  fprintf(fout, "%d\n", numberofregions);
+  for (i = 0; i < numberofregions; i++) {
+    if (mesh_dim == 2) {
+      // Output the index, x, y coordinates, attribute (region number)
+      //   and maximum area constraint (maybe -1).
+      fprintf(fout, "%d  %.12g  %.12g  %.12g  %.12g\n", i + firstnumber,
+              regionlist[i * 4], regionlist[i * 4 + 1],
+              regionlist[i * 4 + 2], regionlist[i * 4 + 3]);
+    } else {
+      // Output the index, x, y, z coordinates, attribute (region number)
+      //   and maximum volume constraint (maybe -1).
+      fprintf(fout, "%d  %.12g  %.12g  %.12g  %.12g  %.12g\n", i + firstnumber,
+              regionlist[i * 5], regionlist[i * 5 + 1],
+              regionlist[i * 5 + 2], regionlist[i * 5 + 3],
+              regionlist[i * 5 + 4]);
+    }
+  }
+
+  fclose(fout);  
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// readline()   Read a nonempty line from a file.                            //
+//                                                                           //
+// A line is considered "nonempty" if it contains something more than white  //
+// spaces.  If a line is considered empty, it will be dropped and the next   //
+// line will be read, this process ends until reaching the end-of-file or a  //
+// non-empty line.  Return NULL if it is the end-of-file, otherwise, return  //
+// a pointer to the first non-whitespace character of the line.              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+char* tetgenio::readline(char *string, FILE *infile, int *linenumber)
+{
+  char *result;
+
+  // Search for a non-empty line.
+  do {
+    result = fgets(string, INPUTLINESIZE - 1, infile);
+    if (linenumber) (*linenumber)++;
+    if (result == (char *) NULL) {
+      return (char *) NULL;
+    }
+    // Skip white spaces.
+    while ((*result == ' ') || (*result == '\t')) result++;
+    // If it's end of line, read another line and try again.
+  } while (*result == '\0');
+  return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// findnextfield()   Find the next field of a string.                        //
+//                                                                           //
+// Jumps past the current field by searching for whitespace or a comma, then //
+// jumps past the whitespace or the comma to find the next field.            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+char* tetgenio::findnextfield(char *string)
+{
+  char *result;
+
+  result = string;
+  // Skip the current field.  Stop upon reaching whitespace or a comma.
+  while ((*result != '\0') && (*result != ' ') &&  (*result != '\t') && 
+         (*result != ',') && (*result != ';')) {
+    result++;
+  }
+  // Now skip the whitespace or the comma, stop at anything else that looks
+  //   like a character, or the end of a line. 
+  while ((*result == ' ') || (*result == '\t') || (*result == ',') ||
+         (*result == ';')) {
+    result++;
+  }
+  return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// readnumberline()   Read a nonempty number line from a file.               //
+//                                                                           //
+// A line is considered "nonempty" if it contains something that looks like  //
+// a number.  Comments (prefaced by `#') are ignored.                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+char* tetgenio::readnumberline(char *string, FILE *infile, 
+  const char *infilename)
+{
+  char *result;
+
+  // Search for something that looks like a number.
+  do {
+    result = fgets(string, INPUTLINESIZE, infile);
+    if (result == (char *) NULL) {
+      if (infilename != (char *) NULL) {
+        printf("  Error:  Unexpected end of file in %s.\n", infilename);
+        terminatetetgen(1);
+      }
+      return result;
+    }
+    // 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;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// findnextnumber()   Find the next field of a number string.                //
+//                                                                           //
+// Jumps past the current field by searching for whitespace or a comma, then //
+// jumps past the whitespace or the comma to find the next field that looks  //
+// like a number.                                                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+char* tetgenio::findnextnumber(char *string)
+{
+  char *result;
+
+  result = string;
+  // Skip the current field.  Stop upon reaching whitespace or a comma.
+  while ((*result != '\0') && (*result != '#') && (*result != ' ') && 
+         (*result != '\t') && (*result != ',')) {
+    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;
+}
+
+#endif // #ifndef tetgenioCXX
\ No newline at end of file
diff --git a/contrib/TetgenNew/main.cxx b/contrib/TetgenNew/main.cxx
new file mode 100644
index 0000000000..82edf9afd5
--- /dev/null
+++ b/contrib/TetgenNew/main.cxx
@@ -0,0 +1,387 @@
+#ifndef mainCXX
+#define mainCXX
+
+#include "tetgen.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// test_tri_tri()    Triangle-triangle intersection tests.                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void test_tri_tri(tetgenbehavior *b, tetgenio *in)
+{
+  tetgenmesh m;
+  tetgenmesh::face s1, s2;
+  tetgenmesh::point U[3], V[3], T1[3], T2[3];
+  tetgenmesh::intersection dir;
+  int types[2], pos[4];
+  int i, j;
+
+  m.b = b;
+  m.in = in;
+  exactinit();
+  m.initializepools();
+  m.transfernodes();
+  m.meshsurface();
+
+  m.subfacepool->traversalinit();
+  s1.sh = m.shellfacetraverse(m.subfacepool);
+  s2.sh = m.shellfacetraverse(m.subfacepool);
+
+  V[0] = (tetgenmesh::point) s1.sh[3]; // P
+  V[1] = (tetgenmesh::point) s1.sh[4]; // Q
+  V[2] = (tetgenmesh::point) s1.sh[5]; // R
+
+  U[0] = (tetgenmesh::point) s2.sh[3]; // A
+  U[1] = (tetgenmesh::point) s2.sh[4]; // B
+  U[2] = (tetgenmesh::point) s2.sh[5]; // C
+
+  // The permuations of {0, 1, 2}
+  int perm[6][3] = { 
+    {0, 1, 2}, 
+    {2, 0, 1}, 
+    {1, 2, 0},
+    {1, 0, 2}, 
+    {2, 1, 0}, 
+    {0, 2, 1}};
+
+  b->epsilon = 0;
+  b->verbose = 3;
+
+  for (j = 0; j < 36; j++) {
+
+    // Get the permuation of the vertices.
+    T1[0] = U[perm[j/6][0]];
+    T1[1] = U[perm[j/6][1]];
+    T1[2] = U[perm[j/6][2]];
+    
+    T2[0] = V[perm[j%6][0]];
+    T2[1] = V[perm[j%6][1]];
+    T2[2] = V[perm[j%6][2]];
+
+    i = m.tri_tri_test(T1[0], T1[1], T1[2], T2[0], T2[1], T2[2], NULL, 1, 
+                       types, pos);
+    if (i == 0) {
+      printf("  [%d] DISJOINT.\n", j);
+      continue;
+    }
+
+    // Report the intersection types and positions.
+    for (i = 0; i < 2; i++) {
+      dir = (enum tetgenmesh::intersection) types[i];
+      switch (dir) {
+      case tetgenmesh::DISJOINT: 
+        printf("  [%d] DISJOINT\n", j); break;
+      case tetgenmesh::SHAREVERT: 
+        printf("  [%d] SHAREVERT %d %d\n", j, pos[i*2], pos[i*2+1]); break;
+      case tetgenmesh::SHAREEDGE: 
+        printf("  [%d] SHAREEDGE %d %d\n", j, pos[i*2], pos[i*2+1]); break;
+      case tetgenmesh::SHAREFACE: 
+        printf("  [%d] SHAREFACE\n", j); break;
+      case tetgenmesh::TOUCHEDGE: 
+        printf("  [%d] TOUCHEDGE %d %d\n", j, pos[i*2], pos[i*2+1]); break;
+      case tetgenmesh::TOUCHFACE: 
+        printf("  [%d] TOUCHFACE %d %d\n", j, pos[i*2], pos[i*2+1]); break;
+      case tetgenmesh::ACROSSVERT: 
+        printf("  [%d] ACROSSVERT %d %d\n", j, pos[i*2], pos[i*2+1]); break;
+      case tetgenmesh::ACROSSEDGE: 
+        printf("  [%d] ACROSSEDGE %d %d\n", j, pos[i*2], pos[i*2+1]); break;
+      case tetgenmesh::ACROSSFACE: 
+        printf("  [%d] ACROSSFACE %d %d\n", j, pos[i*2], pos[i*2+1]); break;
+      case tetgenmesh::ACROSSTET: 
+        printf("  [%d] ACROSSTET\n", j); break;
+      case tetgenmesh::TRIEDGEINT:
+        printf("  [%d] TRIEDGEINT %d %d\n", j, pos[i*2], pos[i*2+1]); break;
+      case tetgenmesh::EDGETRIINT:
+        printf("  [%d] EDGETRIINT %d %d\n", j, pos[i*2], pos[i*2+1]); break;
+      }
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetrahedralize()    The interface for users using TetGen library to       //
+//                     generate tetrahedral meshes with all features.        //
+//                                                                           //
+// 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 vertices from a file and either                                //
+//   - tetrahedralize them (no -r), or                                       //
+//   - read an old mesh from files and reconstruct it (-r).                  //
+// - Insert the PLC segments and facets (-p).                                //
+// - Read the holes (-p), regional attributes (-pA), and regional volume     //
+//   constraints (-pa).  Carve the holes and concavities, and spread the     //
+//   regional attributes and volume constraints.                             //
+// - Enforce the constraints on minimum quality bound (-q) and maximum       //
+//   volume (-a). Also enforce the conforming Delaunay property (-q and -a). //
+// - Promote the mesh's linear tetrahedra to higher order elements (-o).     //
+// - Write the output files and print the statistics.                        //
+// - Check the consistency and Delaunay property of the mesh (-C).           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
+  tetgenio *addin, tetgenio *bgmin)
+{
+  tetgenmesh m;
+  // Variables for timing the performance of TetGen (defined in time.h).
+  clock_t tv[17];
+
+  tv[0] = clock();
+
+  m.b = b;
+  m.in = in;
+  exactinit();
+  m.initializepools();
+  m.transfernodes();
+
+  tv[1] = clock();
+
+  if (b->refine) {
+    // m.reconstructmesh();
+  } else {
+    m.incrementaldelaunay();
+  }
+
+  tv[2] = clock();
+
+  if (!b->quiet) {
+    if (b->refine) {
+      printf("Mesh reconstruction seconds:");
+    } else {
+      printf("Delaunay seconds:");
+    }
+    printf("  %g\n", (tv[2] - tv[1]) / (REAL) CLOCKS_PER_SEC);
+  }
+
+  if (b->plc) { // if has -p option
+    m.meshsurface();
+  }
+
+  tv[3] = clock();
+
+  if (!b->quiet) {
+    if (b->plc) {
+      printf("Surface meshing seconds:  %g\n", 
+        (tv[3] - tv[2]) / (REAL) CLOCKS_PER_SEC);
+    }
+  }
+
+  if (b->plc) { // if has -p option
+    m.formskeleton();
+  }
+  
+  tv[4] = clock();
+
+  if (!b->quiet) {
+    if (b->plc) {
+      if (b->diagnose != 1) {
+        printf("Boundary recovery ");
+      } else {
+        printf("Intersection "); 
+      }
+      printf("seconds:  %g\n", (tv[4] - tv[3]) / (REAL) CLOCKS_PER_SEC);
+    }
+  }
+  
+  if (b->quality) {
+    m.enforcequality();
+  }
+
+  tv[5] = clock();
+
+  if (!b->quiet) {
+    if (b->quality) {
+      printf("Quality seconds:  %g\n", (tv[5] - tv[4])/(REAL) CLOCKS_PER_SEC);
+    }
+  }
+
+  if (b->plc) {
+    if (b->convexity == 0) { // if has no -c option.
+      m.carveholes();
+    }
+  }
+
+  tv[6] = clock();
+
+  if (!b->quiet) {
+    if (b->plc) {
+      if (b->convexity == 0) { // if has no -c option.
+        printf("Holes and region seconds:  %g\n", 
+          (tv[6] - tv[5]) / (REAL) CLOCKS_PER_SEC);
+      }
+    }
+  }
+
+  printf("\n");
+
+  if (out != (tetgenio *) NULL) {
+    out->firstnumber = in->firstnumber;
+    out->mesh_dim = in->mesh_dim;
+  }
+
+  if (b->nonodewritten || b->noiterationnum) {
+    if (!b->quiet) {
+      printf("NOT writing a .node file.\n");
+    }
+  } else {
+    m.outnodes(out);
+  }
+
+  if (b->noelewritten == 1) {
+    if (!b->quiet) {
+      printf("NOT writing an .ele file.\n");
+    }
+    m.numberedges();
+  } else {
+    m.outelements(out);
+  }
+
+  if (b->nofacewritten) {
+    if (!b->quiet) {
+      printf("NOT writing an .face file.\n");
+    }
+    if (b->plc || b->refine) {
+      m.numbersubedges();
+    }
+  } else {
+    if (b->facesout) {
+      if (m.tetrahedronpool->items > 0l) {
+        m.outfaces(out);  // Output all faces.
+      }
+      if (b->plc || b->refine) {
+        m.numberedges();
+      }
+    } else {
+      if (b->plc || b->refine) {
+        if (m.subfacepool->items > 0l) {
+          m.outsubfaces(out); // Output boundary faces.
+        }
+      } else {
+        if (m.tetrahedronpool->items > 0l) {
+          m.outhullfaces(out); // Output convex hull faces.
+        }
+      }
+    }
+  }
+
+  if (b->edgesout) {
+    if (b->edgesout > 1) {
+      m.outedges(out); // -ee, output all mesh edges. 
+    } else {
+      m.outsubsegments(out); // -e, only output subsegments.
+    }
+  }
+
+  if (b->neighout) {
+    m.outneighbors(out);
+  }
+
+  if (b->voroout) {
+    // m.outvoronoi(out);
+  }
+
+  tv[6] = clock();
+
+  if (!b->quiet) {
+    printf("\nOutput seconds:  %g\n",
+           (tv[6] - tv[5]) / (REAL) CLOCKS_PER_SEC);
+    printf("Total running seconds:  %g\n\n",
+           (tv[6] - tv[0]) / (REAL) CLOCKS_PER_SEC);
+  }
+
+  if (b->docheck) {
+    if (b->plc) {
+      if (m.checkshells(1) > 0) assert(0);
+      if (m.checksegments() > 0) assert(0);
+    }
+    if (m.checkdelaunay(b->plc) > 0) assert(0);
+  }
+
+  if (!b->quiet) {
+    m.statistics();
+  }
+}
+
+#ifndef TETLIBRARY
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// main()    The entrance for running TetGen from command line.              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int main(int argc, char *argv[])
+
+#else // with TETLIBRARY
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetrahedralize()    The entrance for calling TetGen from another program. //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
+  tetgenio *addin, tetgenio *bgmin)
+
+#endif // not TETLIBRARY
+
+{
+  tetgenbehavior b;
+
+#ifndef TETLIBRARY
+
+  tetgenio in, addin, bgmin;
+  
+  if (!b.parse_commandline(argc, argv)) {
+    terminatetetgen(1);
+  }
+  if (b.refine) {
+    if (!in.load_tetmesh(b.infilename)) {
+      terminatetetgen(1);
+    }
+  } else {
+    if (!in.load_plc(b.infilename, (int) b.object)) {
+      terminatetetgen(1);
+    }
+  }
+  if (b.insertaddpoints) {
+    if (!addin.load_node(b.addinfilename)) {
+      addin.numberofpoints = 0l;
+    }
+  }
+  if (b.metric) {
+    if (!bgmin.load_tetmesh(b.bgmeshfilename)) {
+      bgmin.numberoftetrahedra = 0l;
+    }
+  }
+
+  // FOR DEBUG -S1 option.
+  if (b.steinerleft > 0) {
+    test_tri_tri(&b, &in);
+    terminatetetgen(0);
+  }
+
+  if (bgmin.numberoftetrahedra > 0l) {
+    tetrahedralize(&b, &in, NULL, &addin, &bgmin);
+  } else {
+    tetrahedralize(&b, &in, NULL, &addin, NULL);
+  }
+
+  return 0;
+
+#else // with TETLIBRARY
+
+  if (!b.parse_commandline(switches)) {
+    terminatetetgen(1);
+  }
+  tetrahedralize(&b, in, out, addin, bgmin);
+
+#endif // not TETLIBRARY
+}
+
+#endif // #ifndef mainCXX
\ No newline at end of file
diff --git a/contrib/TetgenNew/memorypool.cxx b/contrib/TetgenNew/memorypool.cxx
new file mode 100644
index 0000000000..21a0ff623e
--- /dev/null
+++ b/contrib/TetgenNew/memorypool.cxx
@@ -0,0 +1,981 @@
+#ifndef memorypoolCXX
+#define memorypoolCXX
+
+#include "tetgen.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// restart()    Deallocate all objects in this pool.                         //
+//                                                                           //
+// The pool returns to a fresh state, like after it was initialized, except  //
+// that no memory is freed to the operating system.  Rather, the previously  //
+// allocated blocks are ready to be used.                                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::arraypool::restart()
+{
+  objects = 0l;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// poolinit()    Initialize an arraypool for allocation of objects.          //
+//                                                                           //
+// Before the pool may be used, it must be initialized by this procedure.    //
+// After initialization, memory can be allocated and freed in this pool.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::arraypool::poolinit(int sizeofobject, int log2objperblk)
+{
+  // Each object must be at least one byte long.
+  objectbytes = sizeofobject > 1 ? sizeofobject : 1;
+
+  log2objectsperblock = log2objperblk;
+  // Compute the number of objects in each block.
+  objectsperblock = ((int) 1) << log2objectsperblock;
+
+  // No memory has been allocated.
+  totalmemory = 0l;
+  // The top array has not been allocated yet.
+  toparray = (char **) NULL;
+  toparraylen = 0;
+
+  // Ready all indices to be allocated.
+  restart();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// arraypool()    The constructor and destructor.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+tetgenmesh::arraypool::arraypool(int sizeofobject, int log2objperblk)
+{
+  poolinit(sizeofobject, log2objperblk);
+}
+
+tetgenmesh::arraypool::~arraypool()
+{
+  int i;
+
+  // Has anything been allocated at all?
+  if (toparray != (char **) NULL) {
+    // Walk through the top array.
+    for (i = 0; i < toparraylen; i++) {
+      // Check every pointer; NULLs may be scattered randomly.
+      if (toparray[i] != (char *) NULL) {
+        // Free an allocated block.
+        free((void *) toparray[i]);
+      }
+    }
+    // Free the top array.
+    free((void *) toparray);
+  }
+
+  // The top array is no longer allocated.
+  toparray = (char **) NULL;
+  toparraylen = 0;
+  objects = 0;
+  totalmemory = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// getblock()    Return (and perhaps create) the block containing the object //
+//               with a given index.                                         //
+//                                                                           //
+// This function takes care of allocating or resizing the top array if nece- //
+// ssary, and of allocating the block if it hasn't yet been allocated.       //
+//                                                                           //
+// Return a pointer to the beginning of the block (NOT the object).          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+char* tetgenmesh::arraypool::getblock(int objectindex)
+{
+  char **newarray;
+  char *block;
+  int newsize;
+  int topindex;
+  int i;
+
+  // Compute the index in the top array (upper bits).
+  topindex = objectindex >> log2objectsperblock;
+  // Does the top array need to be allocated or resized?
+  if (toparray == (char **) NULL) {
+    // Allocate the top array big enough to hold 'topindex', and NULL out
+    //   its contents.
+    newsize = topindex + 128;
+    toparray = (char **) malloc((size_t) (newsize * sizeof(char *)));
+    toparraylen = newsize;
+    for (i = 0; i < newsize; i++) {
+      toparray[i] = (char *) NULL;
+    }
+    // Account for the memory.
+    totalmemory = newsize * (unsigned long) sizeof(char *);
+  } else if (topindex >= toparraylen) {
+    // Resize the top array, making sure it holds 'topindex'.
+    newsize = 3 * toparraylen;
+    if (topindex >= newsize) {
+      newsize = topindex + 128;
+    }
+    // Allocate the new array, copy the contents, NULL out the rest, and
+    //   free the old array.
+    newarray = (char **) malloc((size_t) (newsize * sizeof(char *)));
+    for (i = 0; i < toparraylen; i++) {
+      newarray[i] = toparray[i];
+    }
+    for (i = toparraylen; i < newsize; i++) {
+      newarray[i] = (char *) NULL;
+    }
+    free(toparray);
+    // Account for the memory.
+    totalmemory += (newsize - toparraylen) * sizeof(char *);
+    toparray = newarray;
+    toparraylen = newsize;
+  }
+
+  // Find the block, or learn that it hasn't been allocated yet.
+  block = toparray[topindex];
+  if (block == (char *) NULL) {
+    // Allocate a block at this index.
+    block = (char *) malloc((size_t) (objectsperblock * objectbytes));
+    toparray[topindex] = block;
+    // Account for the memory.
+    totalmemory += objectsperblock * objectbytes;
+  }
+
+  // Return a pointer to the block.
+  return block;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// lookup()    Return the pointer to the object with a given index, or NULL  //
+//             if the object's block doesn't exist yet.                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void* tetgenmesh::arraypool::lookup(int objectindex)
+{
+  char *block;
+  int topindex;
+
+  // Has the top array been allocated yet?
+  if (toparray == (char **) NULL) {
+    return (void *) NULL;
+  }
+
+  // Compute the index in the top array (upper bits).
+  topindex = objectindex >> log2objectsperblock;
+  // Does the top index fit in the top array?
+  if (topindex >= toparraylen) {
+    return (void *) NULL;
+  }
+
+  // Find the block, or learn that it hasn't been allocated yet.
+  block = toparray[topindex];
+  if (block == (char *) NULL) {
+    return (void *) NULL;
+  }
+
+  // Compute a pointer to the object with the given index.  Note that
+  //   'objectsperblock' is a power of two, so the & operation is a bit mask
+  //   that preserves the lower bits.
+  return (void *)(block + (objectindex & (objectsperblock - 1)) * objectbytes);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// newindex()    Allocate space for a fresh object from the pool.            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::arraypool::newindex(void **newptr)
+{
+  void *newobject;
+  int newindex;
+
+  // Allocate an object at index 'firstvirgin'.
+  newindex = objects;
+  newobject = (void *) (getblock(objects) +
+    (objects & (objectsperblock - 1)) * objectbytes);
+  objects++;
+
+  // If 'newptr' is not NULL, use it to return a pointer to the object.
+  if (newptr != (void **) NULL) {
+    *newptr = newobject;
+  }
+  return newindex;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// restart()   Deallocate all items in this 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 tetgenmesh::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;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// alloc()   Allocate space for an item.                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void* tetgenmesh::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 **) malloc(itemsperblock * itembytes + sizeof(void *) 
+                                    + alignbytes);
+        if (newblock == (void **) NULL) {
+          printf("Error:  Out of memory.\n");
+          terminatetetgen(1);
+        }
+        *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 *) ((REAL *) 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 tetgenmesh::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 tetgenmesh::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.  It can usually be done more space-efficiently by //
+// a routine that knows something about the structure of the item.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void* tetgenmesh::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 *) ((REAL *) pathitem + itemwords);
+  }
+  pathitemsleft--;
+  return newitem;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// poolinit()    Initialize a pool of memory for allocation of items.        //
+//                                                                           //
+// A 'pool' is created whose records have size at least 'bytecount'.  Items  //
+// will be allocated 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 `alignment'-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.                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::memorypool::poolinit(int bytecount, int itemcount,
+  enum wordtype wtype, int alignment)
+{
+  int wordsize;
+
+  // Initialize values in the pool.
+  itemwordtype = wtype;
+  wordsize = (itemwordtype == POINTER) ? sizeof(void *) : sizeof(REAL);
+  // 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 ((int) sizeof(void *) > alignbytes) {
+    alignbytes = (int) 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 **) malloc(itemsperblock * itembytes + sizeof(void *)
+                                + alignbytes); 
+  if (firstblock == (void **) NULL) {
+    printf("Error:  Out of memory.\n");
+    terminatetetgen(1);
+  }
+  // Set the next block pointer to NULL.
+  *(firstblock) = (void *) NULL;
+  restart();
+}
+
+tetgenmesh::memorypool::memorypool(int bytecount, int itemcount,
+  enum wordtype wtype, int alignment)
+{
+  poolinit(bytecount, itemcount, wtype, alignment);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// ~memorypool()   Free to the operating system all memory taken by a pool.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+tetgenmesh::memorypool::~memorypool()
+{
+  while (firstblock != (void **) NULL) {
+    nowblock = (void **) *(firstblock);
+    free(firstblock);
+    firstblock = nowblock;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// initializepools()    Initialize pools of mesh elements.                   //
+//                                                                           //
+// The sizes of the tetrahedron, shellface, and point will be calculated.    //
+// Some class variables, such as 'pointmarkindex', 'elemmarkindex', 'volume- //
+// boundindex', 'dummypoint', etc, are initialized. The pools of tetrahedra, //
+// points, subfaces, and segments are allocated.                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::initializepools()
+{
+  enum wordtype wtype;
+  int ptsize, elesize, shsize;
+
+  // A point contains 3 coordinates, 1 weight, plus 'n' attributes in REALs,
+  //   and other fields, such as pointers, boundary markers, etc. The total
+  //   size (in byte) of a point is calcualted below.
+  ptsize = (4 + in->numberofpointattributes) * sizeof(REAL);
+  // The index within each point at which an element pointer is found, where
+  //   the index is measured in pointers. Ensure the index is aligned to a
+  //   sizeof(tetrahedron)-byte address.
+  point2tetindex = (ptsize + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
+  // Increase the point size by two pointers, which are
+  //   - a pointer to a tet, read by point2tet(), or
+  //   - a pointer to a parent point, read by point2ppt().
+  ptsize = (point2tetindex + 2) * sizeof(tetrahedron);
+  // The index within each point at which the boundary marker is found,
+  //   Ensure the marker is aligned to a sizeof(int)-byte address.
+  pointmarkindex = (ptsize + sizeof(int) - 1) / sizeof(int);
+  // Increase the point size by two integers, which are:
+  //   - an integer for boundary marker, read by pointmark();
+  //   - an integer for vertex type, read by pointtype();
+  ptsize = (pointmarkindex + 2) * sizeof(int);
+  // Decide the wordtype used in point pool.
+  wtype = (sizeof(REAL) >= sizeof(tetrahedron)) ? FLOATINGPOINT : POINTER;
+  // Initialize the pool of vertices.
+  pointpool = new memorypool(ptsize, VERPERBLOCK, wtype, 0);
+  
+  // Initialize spaces for 'dummypoint'.
+  dummypoint = new REAL[(ptsize + sizeof(REAL) - 1) / sizeof(REAL)];
+  dummypoint[0] = dummypoint[1] = dummypoint[2] = dummypoint[3] = 0.0;
+  pointmark(dummypoint) = -1;
+
+  // The number of bytes occupied by a tetrahedron.  There are 4 pointers
+  //   to other tetrahedra, 4 pointers to corners, and possibly 1 pointers
+  //   to an array of subfaces/subsegments.
+  elesize = (8 + (b->useshelles ? 2 : 0)) * sizeof(tetrahedron);
+  // The index within each element at which its attributes are found, where
+  //   the index is measured in REALs. 
+  elemattribindex = (elesize + sizeof(REAL) - 1) / sizeof(REAL);
+  // The index within each element at which the maximum voulme bound is
+  //   found, where the index is measured in REALs.  Note that if the
+  //   `b->regionattrib' flag is set, an additional attribute will be added.
+  volumeboundindex = elemattribindex + in->numberoftetrahedronattributes
+                   + (b->regionattrib > 0);
+  // If element attributes or an constraint are needed, increase the number
+  //   of bytes occupied by an element.
+  elesize = (volumeboundindex + (b->varvolume > 0)) * sizeof(REAL);
+  // The index within each element at which its marker is found, where the
+  //   index is measured in ints.
+  elemmarkerindex = (elesize + sizeof(int) - 1) / sizeof(int);
+  // Increase the size by one interger.
+  elesize = (elemmarkerindex + 1) * sizeof(int);
+  // If -o2 switch is used, an additional pointer pointed to the list of
+  //   higher order nodes is allocated for each element.
+  highorderindex = (elesize + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
+  if (b->order == 2) {
+    elesize = (highorderindex + 1) * sizeof(tetrahedron);
+  }
+  // Having determined the memory size of an element, initialize the pools.
+  tetrahedronpool = new memorypool(elesize, ELEPERBLOCK, POINTER, 16);
+
+  if (b->useshelles) {
+    // The number of bytes occupied by a subface.  The list of pointers
+    //   stored in a subface are: three to other subfaces, three to corners,
+    //   three to subsegments, one to an adjacent tetrahedron.
+    shsize = 10 * sizeof(shellface);
+    // The index within each subface at which the maximum area bound is
+    //   found, where the index is measured in REALs.
+    areaboundindex = (shsize + sizeof(REAL) - 1) / sizeof(REAL);
+    // If -q switch is in use, increase the number of bytes occupied by
+    //   a subface for saving maximum area bound.
+    if (b->quality && checkconstraints) {
+      shsize = (areaboundindex + 1) * sizeof(REAL);
+    } else {
+      shsize = areaboundindex * sizeof(REAL);
+    }
+    // The index within subface at which the facet marker is found. Ensure
+    //   the marker is aligned to a sizeof(int)-byte address.
+    shmarkindex = (shsize + sizeof(int) - 1) / sizeof(int);
+    // Increase the number of bytes by two or three integers, one for facet
+    //   marker, one for shellface type, and optionally one for pbc group.
+    shsize = (shmarkindex + 2 + checkpbcs) * sizeof(int);
+    // Initialize the pool of subfaces. Each subface record is eight-byte
+    //   aligned so it has room to store an edge version (from 0 to 5) in
+    //   the least three bits.
+    subfacepool = new memorypool(shsize, SUBPERBLOCK, POINTER, 8);
+    // Initialize the pool of subsegments.
+    subsegpool = new memorypool(shsize, SUBPERBLOCK, POINTER, 8);
+
+    // Initialize the pool for tet-subseg connections.
+    tet2segpool = new memorypool(6*sizeof(shellface), SUBPERBLOCK, POINTER, 0);
+    // Initialize the pool for tet-subface connections.
+    tet2subpool = new memorypool(4*sizeof(shellface), SUBPERBLOCK, POINTER, 0);
+
+    // Initialize arraypools for segment & facet recovery.
+    subsegstack = new arraypool(sizeof(face), 10);
+    subfacstack = new arraypool(sizeof(face), 10);
+
+    // Initialize arraypools for surface Bowyer-Watson algorithm.
+    caveshlist = new arraypool(sizeof(face), 8);
+    caveshbdlist = new arraypool(sizeof(face), 8);
+  }
+
+  // Initialize the pool for flips.
+  flippool = new memorypool(sizeof(badface), 1024, POINTER, 0);
+
+  // Initialize the arraypools for Bowyer-Watson algorithm.
+  cavetetlist = new arraypool(sizeof(triface), 10);
+  cavebdrylist = new arraypool(sizeof(triface), 10);
+  caveoldtetlist = new arraypool(sizeof(triface), 10);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetrahedrondealloc()    Deallocate space for a tet, marking it dead.      //
+//                                                                           //
+// Set the first vertex of 'dyingtet' to NULL. So we can detect dead tets    //
+// when when traversing the list of all tetrahedra.                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::tetrahedrondealloc(tetrahedron *dyingtet)
+{
+  // Mark it as a dead tet.
+  dyingtet[4] = (tetrahedron) NULL;
+
+  if (b->useshelles) {
+    // Dealloc the space to subfaces/subsegments.
+    if (dyingtet[8] != NULL) {
+      tet2segpool->dealloc((shellface *) dyingtet[8]);
+    }
+    if (dyingtet[9] != NULL) {
+      tet2subpool->dealloc((shellface *) dyingtet[9]);
+    }
+  }
+
+  // Actually pool->dealloc();
+  *((void **) (dyingtet)) = tetrahedronpool->deaditemstack;
+  tetrahedronpool->deaditemstack = (void *) (dyingtet);
+  tetrahedronpool->items--;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetrahedrontraverse()    Traverse the tetrahedra, skipping dead ones.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+tetgenmesh::tetrahedron* tetgenmesh::tetrahedrontraverse()
+{
+  tetrahedron *newtetrahedron;
+
+  // Skip dead and hull tetrahedra.
+  do {
+    newtetrahedron = (tetrahedron *) tetrahedronpool->traverse();
+    if (newtetrahedron == (tetrahedron *) NULL) {
+      return (tetrahedron *) NULL;
+    }
+  } while ((newtetrahedron[4] == (tetrahedron) NULL) ||
+    ((point) newtetrahedron[7] == dummypoint)); 
+  return newtetrahedron;
+}
+
+tetgenmesh::tetrahedron* tetgenmesh::alltetrahedrontraverse()
+{
+  tetrahedron *newtetrahedron;
+
+  do {
+    newtetrahedron = (tetrahedron *) tetrahedronpool->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.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::shellfacedealloc(memorypool *pool, shellface *dyingsh)
+{
+  dyingsh[3] = (shellface) NULL;
+  pool->dealloc((void *) dyingsh);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// shellfacetraverse()    Traverse the subfaces, skipping dead ones.         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+tetgenmesh::shellface* tetgenmesh::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;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// badfacedealloc()    Deallocate space for a badface, marking it dead.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::badfacedealloc(memorypool *pool, badface *dying)
+{
+  dying->forg = (point) NULL;
+  pool->dealloc((void *) dying);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// badfacetraverse()    Traverse the pools, skipping dead ones.              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+tetgenmesh::badface* tetgenmesh::badfacetraverse(memorypool *pool)
+{
+  badface *newsh;
+
+  do {
+    newsh = (badface *) pool->traverse();
+    if (newsh == (badface *) NULL) {
+      return (badface *) NULL;
+    }
+  } while (newsh->forg == (point) NULL); // Skip dead ones.
+  return newsh;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// pointdealloc()    Deallocate space for a point, marking it dead.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::pointdealloc(point dyingpoint)
+{
+  setpointtype(dyingpoint, DEADVERTEX);
+  pointpool->dealloc((void *) dyingpoint);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// pointtraverse()    Traverse the points, skipping dead ones.               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+tetgenmesh::point tetgenmesh::pointtraverse()
+{
+  point newpoint;
+
+  do {
+    newpoint = (point) pointpool->traverse();
+    if (newpoint == (point) NULL) {
+      return (point) NULL;
+    }
+  } while (getpointtype(newpoint) == DEADVERTEX); // Skip dead ones.
+  return newpoint;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// maketetrahedron()    Create a new tetrahedron.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::maketetrahedron(triface *newtet)
+{
+  int i;
+
+  newtet->tet = (tetrahedron *) tetrahedronpool->alloc();
+  for (i = 0; i < 8; i++) {
+    newtet->tet[i] = (tetrahedron) NULL;
+  }
+  if (b->useshelles) {
+    newtet->tet[8] = (tetrahedron) NULL;
+    newtet->tet[9] = (tetrahedron) NULL;
+  }
+  for (i = 0; i < in->numberoftetrahedronattributes; i++) {
+    setelemattribute(newtet->tet, i, 0);
+  }
+  if (b->varvolume) {
+    setvolumebound(newtet->tet, -1.0);
+  }
+  elemmarker(newtet->tet) = 0;
+  newtet->loc = 0;
+  newtet->ver = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// makeshellface()    Create a new shellface and initialize its data fields. //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::makeshellface(memorypool* pool, face* newsh)
+{
+  int i;
+
+  newsh->sh = (shellface *) pool->alloc();
+  for (i = 0; i < 10; i++) {
+    newsh->sh[i] = (shellface) NULL;
+  }
+  if (checkconstraints) {
+    areabound(*newsh) = 0.0;
+  }
+  // setshelltype(*newsh, NSHARP);
+  // if (checkpbcs) {
+    // setshellpbcgroup(*newsh, -1);
+  // }
+  ((int *) (newsh->sh))[shmarkindex] = 0;
+  // Initialize the version to be Zero.
+  newsh->shver = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// makepoint()    Create a new point.                                        //
+//                                                                           //
+// The new point is indexed (starting from 'in->firstnumber'). It's type is  //
+// initialized as UNUSEDVERTEX.                                              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::makepoint(point* pnewpt)
+{
+  int i;
+
+  *pnewpt = (point) pointpool->alloc();
+  // Initialize the list of coordinates and user-defined attributes.
+  for (i = 0; i < 4 + in->numberofpointattributes; i++) {
+    (*pnewpt)[i] = 0.0;
+  }
+  // Initialize the point marker (starting from in->firstnumber).
+  pointmark(*pnewpt) = (int) pointpool->items - (in->firstnumber ? 0 : 1);
+  point2tet(*pnewpt) = NULL;
+  setpointtype(*pnewpt, UNUSEDVERTEX);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// makeindex2pointmap()    Make a map from indices to points.                //
+//                                                                           //
+// The first index of the point is 'in->firstnumber' (0 or 1). '*pidx2ptmap' //
+// return this map. NOTE: it is allocated but not deleted in this function.  //
+// The caller has to deleted it.                                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::makeindex2pointmap(point*& idx2ptmap)
+{
+  point pt;
+  int idx;
+
+  if (b->verbose> 1) {
+    printf("  Making a map from indices to points.\n");
+  }
+
+  idx2ptmap = new point[pointpool->items + 1];
+  pointpool->traversalinit();
+  idx = in->firstnumber;
+  pt = pointtraverse();
+  while (pt != NULL) {
+    idx2ptmap[idx++] = pt;
+    pt = pointtraverse();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// makesubfacemap()    Create a map from vertex to subfaces incident at it.  //
+//                                                                           //
+// The map is returned in two arrays 'idx2faclist' and 'facperverlist'.  All //
+// subfaces incident at i-th vertex (i is counted from 0) are found in the   //
+// array facperverlist[j], where idx2faclist[i] <= j < idx2faclist[i + 1].   //
+// Each entry in facperverlist[j] is a subface whose origin is the vertex.   //
+//                                                                           //
+// NOTE: These two arrays will be created inside this routine, don't forget  //
+// to free them after using.                                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::makepoint2submap(memorypool* pool, int*& idx2faclist,
+  face*& facperverlist)
+{
+  face shloop;
+  int i, j, k;
+
+  if (b->verbose > 1) {
+    printf("  Making a map from points to subfaces.\n");
+  }
+
+  // Initialize 'idx2faclist'.
+  idx2faclist = new int[pointpool->items + 1];
+  for (i = 0; i < pointpool->items + 1; i++) idx2faclist[i] = 0;
+
+  // Loop all subfaces, counter the number of subfaces incident at a vertex.
+  pool->traversalinit();
+  shloop.sh = shellfacetraverse(pool);
+  while (shloop.sh != (shellface *) NULL) {
+    // Increment the number of incident subfaces for each vertex.
+    j = pointmark((point) shloop.sh[3]) - in->firstnumber;
+    idx2faclist[j]++;
+    j = pointmark((point) shloop.sh[4]) - in->firstnumber;
+    idx2faclist[j]++;
+    // Skip the third corner if it is a segment.
+    if (shloop.sh[5] != NULL) {
+      j = pointmark((point) shloop.sh[5]) - in->firstnumber;
+      idx2faclist[j]++;
+    }
+    shloop.sh = shellfacetraverse(pool);
+  }
+
+  // Calculate the total length of array 'facperverlist'.
+  j = idx2faclist[0];
+  idx2faclist[0] = 0;  // Array starts from 0 element.
+  for (i = 0; i < pointpool->items; i++) {
+    k = idx2faclist[i + 1];
+    idx2faclist[i + 1] = idx2faclist[i] + j;
+    j = k;
+  }
+
+  // The total length is in the last unit of idx2faclist.
+  facperverlist = new face[idx2faclist[i]];
+
+  // Loop all subfaces again, remember the subfaces at each vertex.
+  pool->traversalinit();
+  shloop.sh = shellfacetraverse(pool);
+  while (shloop.sh != (shellface *) NULL) {
+    j = pointmark((point) shloop.sh[3]) - in->firstnumber;
+    shloop.shver = 0; // save the origin.
+    facperverlist[idx2faclist[j]] = shloop;
+    idx2faclist[j]++;
+    // Is it a subface or a subsegment?
+    if (shloop.sh[5] != NULL) {
+      j = pointmark((point) shloop.sh[4]) - in->firstnumber;
+      shloop.shver = 2; // save the origin.
+      facperverlist[idx2faclist[j]] = shloop;
+      idx2faclist[j]++;
+      j = pointmark((point) shloop.sh[5]) - in->firstnumber;
+      shloop.shver = 4; // save the origin.
+      facperverlist[idx2faclist[j]] = shloop;
+      idx2faclist[j]++;
+    } else {
+      j = pointmark((point) shloop.sh[4]) - in->firstnumber;
+      shloop.shver = 1; // save the origin.
+      facperverlist[idx2faclist[j]] = shloop;
+      idx2faclist[j]++;
+    }
+    shloop.sh = shellfacetraverse(pool);
+  }
+
+  // Contents in 'idx2faclist' are shifted, now shift them back.
+  for (i = pointpool->items - 1; i >= 0; i--) {
+    idx2faclist[i + 1] = idx2faclist[i];
+  }
+  idx2faclist[0] = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// makepoint2tetmap()    Make a map from points to tetrahedra.               //
+//                                                                           //
+// Traverses all the tetrahedra,  provides each corner of each tetrahedron   //
+// with a pointer to that tetrahedera.  Some pointers will be overwritten by //
+// other pointers because each point may be a corner of several tetrahedra,  //
+// but in the end every point will point to a tetrahedron that contains it.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::makepoint2tetmap()
+{
+  tetrahedron *tptr;
+  point *pt;
+
+  if (b->verbose > 1) {
+    printf("  Making a map from points to tetrahedra.\n");
+  }
+
+  tetrahedronpool->traversalinit();
+  tptr = tetrahedrontraverse();
+  while (tptr != (tetrahedron *) NULL) {
+    pt  = (point *) tptr;
+    point2tet(pt[4]) = (tetrahedron) tptr;
+    point2tet(pt[5]) = (tetrahedron) tptr;
+    point2tet(pt[6]) = (tetrahedron) tptr;
+    point2tet(pt[7]) = (tetrahedron) tptr;
+    tptr = tetrahedrontraverse();
+  }
+}
+
+#endif // #ifndef memorypoolCXX
\ No newline at end of file
diff --git a/contrib/TetgenNew/meshio.cxx b/contrib/TetgenNew/meshio.cxx
new file mode 100644
index 0000000000..db3b038d6a
--- /dev/null
+++ b/contrib/TetgenNew/meshio.cxx
@@ -0,0 +1,1237 @@
+#ifndef meshioCXX
+#define meshioCXX
+
+#include "tetgen.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// transfernodes()    Transfer points from 'in->pointlist' to 'pointpool'.   //
+//                                                                           //
+// While transfering the points, the size of the bounding box (xmax, ....,   //
+// zmin) is caclulated.                                                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::transfernodes()
+{
+  point pointloop;
+  REAL x, y, z;
+  int coordindex;
+  int attribindex;
+  int i, j;
+
+  // Read the points.
+  coordindex = 0;
+  attribindex = 0;
+  for (i = 0; i < in->numberofpoints; i++) {
+    makepoint(&pointloop);
+    // Read the point coordinates.
+    x = pointloop[0] = in->pointlist[coordindex++];
+    y = pointloop[1] = in->pointlist[coordindex++];
+    z = pointloop[2] = in->pointlist[coordindex++];
+    // Read the point attributes.
+    for (j = 0; j < in->numberofpointattributes; j++) {
+      pointloop[4 + j] = in->pointattributelist[attribindex++];
+    }
+    // Determine the smallest and largests x, y and z 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 < zmin) ? z : zmin;
+      zmax = (z > zmax) ? z : zmax;
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// jettisonnodes()    Jettison unused or duplicated vertices.                //
+//                                                                           //
+// Unused points are those input points which are outside the mesh domain or //
+// have no connection (isolated) to the mesh.  Duplicated points exist for   //
+// example if the input PLC is read from a .stl mesh file (marked during the //
+// Delaunay tetrahedralization step. This routine remove these points from   //
+// points list. All existing points are reindexed.                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::jettisonnodes()
+{
+  point pointloop;
+  bool jetflag;
+  int oldidx, newidx;
+  int remcount;
+
+  if (!b->quiet) {
+    printf("Jettisoning redundants points.\n");
+  }
+
+  pointpool->traversalinit();
+  pointloop = pointtraverse();
+  oldidx = newidx = 0; // in->firstnumber;
+  remcount = 0;
+  while (pointloop != (point) NULL) {
+    jetflag = (getpointtype(pointloop) == DUPLICATEDVERTEX) || 
+      (getpointtype(pointloop) == UNUSEDVERTEX);
+    jetflag = (getpointtype(pointloop) == DUPLICATEDVERTEX);
+    if (jetflag) {
+      // It is a duplicated point, delete it.
+      pointdealloc(pointloop);
+      remcount++;
+    } else {
+      // Re-index it.
+      pointmark(pointloop) = newidx + in->firstnumber;
+      if (in->pointmarkerlist != (int *) NULL) {
+        if (oldidx < in->numberofpoints) {
+          // Re-index the point marker as well.
+          in->pointmarkerlist[newidx] = in->pointmarkerlist[oldidx];
+        }
+      }
+      newidx++;
+    }
+    oldidx++;
+    if (oldidx == in->numberofpoints) {
+      // Update the numbe of input points (Because some were removed).
+      in->numberofpoints -= remcount;
+      // Remember this number for output original input nodes.
+      // jettisoninverts = remcount;
+    }
+    pointloop = pointtraverse();
+  }
+  if (b->verbose) {
+    printf("  %d duplicated vertices have been removed.\n", dupverts);
+    // printf("  %d unused vertices have been removed.\n", unuverts);
+  }
+  dupverts = 0; 
+  // unuverts = 0;
+
+  // The following line ensures that dead items in the pool of nodes cannot
+  //   be allocated for the new created nodes. This ensures that the input
+  //   nodes will occur earlier in the output files, and have lower indices.
+  pointpool->deaditemstack = (void *) NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// numberedges()    Count the number of mesh edges (in 'meshedges').         //
+//                                                                           //
+// The edges will be automatically counted in routine 'outelements()'.  This //
+// routine is needed only -E option is used.                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::numberedges()
+{
+  triface worktet, spintet;
+  int i;
+
+  meshedges = 0l;
+  tetrahedronpool->traversalinit();
+  worktet.tet = tetrahedrontraverse();
+  while (worktet.tet != NULL) {
+    // Count the number of Voronoi faces. Look at the six edges of this
+    //   tet. Count an edge only if this tet's pointer is smaller than
+    //   those of other non-hull tets which share this edge.
+    for (i = 0; i < 6; i++) {
+      worktet.loc = edge2locver[i][0];
+      worktet.ver = edge2locver[i][1];
+      fnext(worktet, spintet);
+      do {
+        if ((point) spintet.tet[7] != dummypoint) {
+          if (spintet.tet < worktet.tet) break;
+        }
+        fnextself(spintet);
+      } while (spintet.tet != worktet.tet);
+      // Count this edge if no adjacent tets are smaller than this tet.
+      if (spintet.tet == worktet.tet) {
+        meshedges++;
+      }
+    }
+    worktet.tet = tetrahedrontraverse();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// numbersubedges()    Count the number of boundary mesh edges (in           //
+//                     'meshsubedges').                                      //
+//                                                                           //
+// The number of boundary edges will be automatically counted in routine     //
+// 'outsubfaces()'.  This routine is needed only -F option is used.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::numbersubedges()
+{
+  face faceloop, spinsh;
+  int i;
+
+  shellface sptr;
+
+  meshsubedges = 0l;
+  subfacepool->traversalinit();
+  faceloop.sh = shellfacetraverse(subfacepool);
+  while (faceloop.sh != NULL) {
+    // Count the number of boundary edges. Look at all subfaces sharing at 
+    //   this edge. Count it only if this subface's pointer is the smallest.
+    faceloop.shver = 0;
+    for (i = 0; i < 3; i++) {
+      spivot(faceloop, spinsh);
+      if (spinsh.sh != NULL) {
+        while (spinsh.sh != faceloop.sh) {
+          if ((unsigned long) spinsh.sh < (unsigned long) faceloop.sh) break;
+          spivotself(spinsh);
+        }
+        if (spinsh.sh == faceloop.sh) {
+          meshsubedges++;
+        }
+      } else {
+        meshsubedges++;
+      }
+      senextself(faceloop);
+    }
+    faceloop.sh = shellfacetraverse(subfacepool);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outnodes()    Output the points to a .node file or a tetgenio structure.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outnodes(tetgenio* out)
+{
+  FILE *outfile;
+  char outnodefilename[FILENAMESIZE];
+  point pointloop;
+  int nextras, bmark, marker;
+  int coordindex, attribindex;
+  int pointnumber, firstindex;
+  int index, i;
+  
+  if (out == (tetgenio *) NULL) {
+    strcpy(outnodefilename, b->outfilename);
+    strcat(outnodefilename, ".node");
+  }
+  
+  if (!b->quiet) {
+    if (out == (tetgenio *) NULL) {
+      printf("Writing %s.\n", outnodefilename);
+    } else {
+      printf("Writing nodes.\n");
+    }
+  }
+
+  nextras = in->numberofpointattributes;
+  bmark = !b->nobound && in->pointmarkerlist;
+
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(outnodefilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", outnodefilename);
+      terminatetetgen(1);
+    }
+    // Number of pointpool, number of dimensions, number of point attributes,
+    //   and number of boundary markers (zero or one).
+    fprintf(outfile, "%ld  %d  %d  %d\n", pointpool->items, 3, nextras, bmark);
+  } else {
+    // Allocate space for 'pointlist';
+    out->pointlist = new REAL[pointpool->items * 3];
+    if (out->pointlist == (REAL *) NULL) {
+      printf("Error:  Out of memory.\n");
+      terminatetetgen(1);
+    }
+    // Allocate space for 'pointattributelist' if necessary;
+    if (nextras > 0) {
+      out->pointattributelist = new REAL[pointpool->items * nextras];
+      if (out->pointattributelist == (REAL *) NULL) {
+        printf("Error:  Out of memory.\n");
+        terminatetetgen(1);
+      }
+    }
+    // Allocate space for 'pointmarkerlist' if necessary;
+    if (bmark) {
+      out->pointmarkerlist = new int[pointpool->items];
+      if (out->pointmarkerlist == (int *) NULL) {
+        printf("Error:  Out of memory.\n");
+        terminatetetgen(1);
+      }
+    }
+    out->numberofpoints = pointpool->items;
+    out->numberofpointattributes = nextras;
+    coordindex = 0;
+    attribindex = 0;
+  }
+  
+  // Determine the first index (0 or 1).
+  firstindex = b->zeroindex ? 0 : in->firstnumber;
+
+  pointpool->traversalinit();
+  pointloop = pointtraverse();
+  pointnumber = firstindex; // in->firstnumber;
+  index = 0;
+  while (pointloop != (point) NULL) {
+    if (bmark) {
+      // Default the vertex has a zero marker.
+      marker = 0;
+      // Is it an input vertex?
+      if (index < in->numberofpoints) {
+        // Input point's marker is directly copied to output.
+        marker = in->pointmarkerlist[index];
+      }
+    }
+    if (out == (tetgenio *) NULL) {
+      // Point number, x, y and z coordinates.
+      fprintf(outfile, "%4d    %.17g  %.17g  %.17g", pointnumber,
+              pointloop[0], pointloop[1], pointloop[2]);
+      for (i = 0; i < nextras; i++) {
+        // Write an attribute.
+        fprintf(outfile, "  %.17g", pointloop[4 + i]);
+      }
+      if (bmark) {
+        // Write the boundary marker.
+        fprintf(outfile, "    %d", marker);
+      }
+      fprintf(outfile, "\n");
+    } else {
+      // X, y, and z coordinates.
+      out->pointlist[coordindex++] = pointloop[0];
+      out->pointlist[coordindex++] = pointloop[1];
+      out->pointlist[coordindex++] = pointloop[2];
+      // Point attributes.
+      for (i = 0; i < nextras; i++) {
+        // Output an attribute.
+        out->pointattributelist[attribindex++] = pointloop[4 + i];
+      }
+      if (bmark) {
+        // Output the boundary marker.  
+        out->pointmarkerlist[index] = marker;
+      }
+    }
+    pointloop = pointtraverse();
+    pointnumber++; 
+    index++;
+  }
+
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outelements()    Output tetrahedra to an .ele file or a tetgenio object.  //
+//                                                                           //
+// The total number of mesh edges 'meshedges' (the number of Voronoi faces)  //
+// are counted in this function.                                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outelements(tetgenio* out)
+{
+  FILE *outfile;
+  char outelefilename[FILENAMESIZE];
+  tetrahedron* tptr;
+  triface worktet, spintet;
+  point p1, p2, p3, p4;
+  point *extralist;
+  REAL *talist;
+  int *tlist;
+  long ntets;
+  int firstindex, shift;
+  int pointindex, attribindex;
+  int elementnumber;
+  int eextras;
+  int i;
+
+  if (out == (tetgenio *) NULL) {
+    strcpy(outelefilename, b->outfilename);
+    strcat(outelefilename, ".ele");
+  }
+
+  if (!b->quiet) {
+    if (out == (tetgenio *) NULL) {
+      printf("Writing %s.\n", outelefilename);
+    } else {
+      printf("Writing elements.\n");
+    }
+  }
+
+  // The number of tets excluding hull tets.
+  ntets = tetrahedronpool->items - hullsize;
+
+  eextras = in->numberoftetrahedronattributes;
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(outelefilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", outelefilename);
+      terminatetetgen(1);
+    }
+    // Number of tetras, points per tetra, attributes per tetra.
+    fprintf(outfile, "%ld  %d  %d\n", ntets, b->order == 1 ? 4 : 10, eextras);
+  } else {
+    // Allocate memory for output tetrahedra.
+    out->tetrahedronlist = new int[ntets * (b->order == 1 ? 4 : 10)];
+    if (out->tetrahedronlist == (int *) NULL) {
+      printf("Error:  Out of memory.\n");
+      terminatetetgen(1);
+    }
+    // Allocate memory for output tetrahedron attributes if necessary.
+    if (eextras > 0) {
+      out->tetrahedronattributelist = new REAL[ntets * eextras];
+      if (out->tetrahedronattributelist == (REAL *) NULL) {
+        printf("Error:  Out of memory.\n");
+        terminatetetgen(1);
+      }
+    }
+    out->numberoftetrahedra = ntets;
+    out->numberofcorners = b->order == 1 ? 4 : 10;
+    out->numberoftetrahedronattributes = eextras;
+    tlist = out->tetrahedronlist;
+    talist = out->tetrahedronattributelist;
+    pointindex = 0;
+    attribindex = 0;
+  }
+
+  // Determine the first index (0 or 1).
+  firstindex = b->zeroindex ? 0 : in->firstnumber;
+  shift = 0; // Default no shiftment.
+  if ((in->firstnumber == 1) && (firstindex == 0)) {
+    shift = 1; // Shift the output indices by 1.
+  }
+
+  // Count the total edge numbers.
+  meshedges = 0l;
+
+  tetrahedronpool->traversalinit();
+  tptr = tetrahedrontraverse();
+  elementnumber = firstindex; // in->firstnumber;
+  while (tptr != (tetrahedron *) NULL) {
+    // Reverse the orientation so that Orient3D() > 0.
+    p1 = (point) tptr[5];
+    p2 = (point) tptr[4];
+    p3 = (point) tptr[6];
+    p4 = (point) tptr[7];
+    if (out == (tetgenio *) NULL) {
+      // Tetrahedron number, indices for four points.
+      fprintf(outfile, "%5d   %5d %5d %5d %5d", elementnumber,
+              pointmark(p1) - shift, pointmark(p2) - shift,
+              pointmark(p3) - shift, pointmark(p4) - shift);
+      if (b->order == 2) {
+        extralist = (point *) tptr[highorderindex];
+        // Tetrahedron number, indices for four points plus six extra points.
+        fprintf(outfile, "  %5d %5d %5d %5d %5d %5d",
+          pointmark(extralist[0]) - shift, pointmark(extralist[1]) - shift,
+          pointmark(extralist[2]) - shift, pointmark(extralist[3]) - shift,
+          pointmark(extralist[4]) - shift, pointmark(extralist[5]) - shift);
+      }
+      for (i = 0; i < eextras; i++) {
+        fprintf(outfile, "    %.17g", elemattribute(tptr, i));
+      }
+      fprintf(outfile, "\n");
+    } else {
+      tlist[pointindex++] = pointmark(p1) - shift;
+      tlist[pointindex++] = pointmark(p2) - shift;
+      tlist[pointindex++] = pointmark(p3) - shift;
+      tlist[pointindex++] = pointmark(p4) - shift;
+      if (b->order == 2) {
+        extralist = (point *) tptr[highorderindex];
+        tlist[pointindex++] = pointmark(extralist[0]) - shift;
+        tlist[pointindex++] = pointmark(extralist[1]) - shift;
+        tlist[pointindex++] = pointmark(extralist[2]) - shift;
+        tlist[pointindex++] = pointmark(extralist[3]) - shift;
+        tlist[pointindex++] = pointmark(extralist[4]) - shift;
+        tlist[pointindex++] = pointmark(extralist[5]) - shift;
+      }
+      for (i = 0; i < eextras; i++) {
+        talist[attribindex++] = elemattribute(tptr, i);
+      }
+    }
+    if (b->neighout) {
+      // Remember the index of this element.
+      * (int *) (tptr + elemmarkerindex) = elementnumber;
+    }
+    // Count the number of Voronoi faces. Look at the six edges of this
+    //   tet. Count an edge only if this tet's pointer is smaller than
+    //   those of other non-hull tets which share this edge.
+    worktet.tet = tptr;
+    for (i = 0; i < 6; i++) {
+      worktet.loc = edge2locver[i][0];
+      worktet.ver = edge2locver[i][1];
+      fnext(worktet, spintet);
+      do {
+        if ((point) spintet.tet[7] != dummypoint) {
+          if (spintet.tet < worktet.tet) break;
+        }
+        fnextself(spintet);
+      } while (spintet.tet != worktet.tet);
+      // Count this edge if no adjacent tets are smaller than this tet.
+      if (spintet.tet == worktet.tet) {
+        meshedges++;
+      }
+    }
+    tptr = tetrahedrontraverse();
+    elementnumber++;
+  }
+
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outfaces()    Output all faces to a .face file or a tetgenio object.      //
+//                                                                           //
+// The total number of faces f can be calculated as following:  Let t be the //
+// total number of tets. Since each tet has 4 faces, the number t * 4 counts //
+// each interior face twice and each hull face once. So f = (t * 4 + h) / 2, //
+// where h is the total number of hull faces (which is known).               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outfaces(tetgenio* out)
+{
+  FILE *outfile;
+  char facefilename[FILENAMESIZE];
+  triface tface, tsymface;
+  face checkmark;
+  point torg, tdest, tapex;
+  long ntets, faces;
+  int *elist, *emlist;
+  int neigh1, neigh2;
+  int bmark, faceid, marker;
+  int firstindex, shift;
+  int facenumber;
+  int index;
+
+  if (out == (tetgenio *) NULL) {
+    strcpy(facefilename, b->outfilename);
+    strcat(facefilename, ".face");
+  }
+
+  if (!b->quiet) {
+    if (out == (tetgenio *) NULL) {
+      printf("Writing %s.\n", facefilename);
+    } else {
+      printf("Writing faces.\n");
+    }
+  }
+
+  ntets = tetrahedronpool->items - hullsize;
+  faces = (ntets * 4l + hullsize) / 2l;
+  bmark = !b->nobound && in->facetmarkerlist;
+
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(facefilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", facefilename);
+      terminatetetgen(1);
+    }
+    fprintf(outfile, "%ld  %d\n", faces, bmark);
+  } else {
+    // Allocate memory for 'trifacelist'.
+    out->trifacelist = new int[faces * 3];
+    if (out->trifacelist == (int *) NULL) {
+      printf("Error:  Out of memory.\n");
+      terminatetetgen(1);
+    }
+    // Allocate memory for 'trifacemarkerlist' if necessary.
+    if (bmark) {
+      out->trifacemarkerlist = new int[faces];
+      if (out->trifacemarkerlist == (int *) NULL) {
+        printf("Error:  Out of memory.\n");
+        terminatetetgen(1);
+      }
+    }
+    if (b->neighout > 1) {
+      // '-nn' switch.
+      out->adjtetlist = new int[faces * 2];
+      if (out->adjtetlist == (int *) NULL) {
+        printf("Error:  Out of memory.\n");
+        terminatetetgen(1);
+      }
+    }
+    out->numberoftrifaces = faces;
+    elist = out->trifacelist;
+    emlist = out->trifacemarkerlist;
+    index = 0;
+  }
+
+  // Determine the first index (0 or 1).
+  firstindex = b->zeroindex ? 0 : in->firstnumber;
+  shift = 0; // Default no shiftment.
+  if ((in->firstnumber == 1) && (firstindex == 0)) {
+    shift = 1; // Shift the output indices by 1.
+  }
+
+  tetrahedronpool->traversalinit();
+  tface.tet = tetrahedrontraverse();
+  facenumber = firstindex; // in->firstnumber;
+  // To loop over the set of faces, loop over all tetrahedra, and look at
+  //   the four faces of each one. If its adjacent tet is a hull tet,
+  //   operate on the face, otherwise, operate on the face only if the
+  //   current tet has a smaller pointer than its neighbor.
+  while (tface.tet != (tetrahedron *) NULL) {
+    for (tface.loc = 0; tface.loc < 4; tface.loc ++) {
+      sym(tface, tsymface);
+      if (((point) tsymface.tet[7] == dummypoint) || 
+          (tface.tet < tsymface.tet)) {
+        torg = org(tface);
+        tdest = dest(tface);
+        tapex = apex(tface);
+        if (bmark) {
+          // Get the boundary marker of this face. If it is an inner face,
+          //   it has no boundary marker, set it be zero.
+          if (b->useshelles) {
+            // Shell face is used.
+            // tspivot(tface, checkmark);
+            if (checkmark.sh == NULL) {
+              marker = 0;  // It is an inner face.
+            } else {
+              faceid = getshellmark(checkmark) - 1;
+              marker = in->facetmarkerlist[faceid];
+            }
+          } else {
+            // Shell face is not used, only distinguish outer and inner face.
+            marker = tsymface.tet != NULL ? 1 : 0;
+          }
+        }
+        if (b->neighout > 1) {
+          // '-nn' switch. Output adjacent tets indices.
+          neigh1 = * (int *)(tface.tet + elemmarkerindex);
+          if (tsymface.tet != NULL) {
+            neigh2 = * (int *)(tsymface.tet + elemmarkerindex);
+          } else {
+            neigh2 = -1;  
+          }
+        }
+        if (out == (tetgenio *) NULL) {
+          // Face number, indices of three vertices.
+          fprintf(outfile, "%5d   %4d  %4d  %4d", facenumber,
+                  pointmark(torg) - shift, pointmark(tdest) - shift,
+                  pointmark(tapex) - shift);
+          if (bmark) {
+            // Output a boundary marker.
+            fprintf(outfile, "  %d", marker);
+          }
+          if (b->neighout > 1) {
+            fprintf(outfile, "    %5d  %5d", neigh1, neigh2);
+          }
+          fprintf(outfile, "\n");
+        } else {
+          // Output indices of three vertices.
+          elist[index++] = pointmark(torg) - shift;
+          elist[index++] = pointmark(tdest) - shift;
+          elist[index++] = pointmark(tapex) - shift;
+          if (bmark) {
+            emlist[facenumber - in->firstnumber] = marker;
+          }
+          if (b->neighout > 1) {
+            out->adjtetlist[(facenumber - in->firstnumber) * 2]     = neigh1;
+            out->adjtetlist[(facenumber - in->firstnumber) * 2 + 1] = neigh2;
+          }
+        }
+        facenumber++;
+      }
+    }
+    tface.tet = tetrahedrontraverse();
+  }
+
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outhullfaces()    Output hull faces to a .face file or a tetgenio object. //
+//                                                                           //
+// The normal of each face is pointing to the outside of the domain.         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outhullfaces(tetgenio* out)
+{
+  FILE *outfile;
+  char facefilename[FILENAMESIZE];
+  triface hulltet;
+  point torg, tdest, tapex;
+  int *elist;
+  int firstindex, shift;
+  int facenumber;
+  int index;
+
+  if (out == (tetgenio *) NULL) {
+    strcpy(facefilename, b->outfilename);
+    strcat(facefilename, ".face");
+  }
+
+  if (!b->quiet) {
+    if (out == (tetgenio *) NULL) {
+      printf("Writing %s.\n", facefilename);
+    } else {
+      printf("Writing faces.\n");
+    }
+  }
+
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(facefilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", facefilename);
+      terminatetetgen(1);
+    }
+    fprintf(outfile, "%ld  0\n", hullsize);
+  } else {
+    // Allocate memory for 'trifacelist'.
+    out->trifacelist = new int[hullsize * 3];
+    if (out->trifacelist == (int *) NULL) {
+      printf("Error:  Out of memory.\n");
+      terminatetetgen(1);
+    }
+    out->numberoftrifaces = hullsize;
+    elist = out->trifacelist;
+    index = 0;
+  }
+
+  // Determine the first index (0 or 1).
+  firstindex = b->zeroindex ? 0 : in->firstnumber;
+  shift = 0; // Default no shiftment.
+  if ((in->firstnumber == 1) && (firstindex == 0)) {
+    shift = 1; // Shift the output indices by 1.
+  }
+
+  tetrahedronpool->traversalinit();
+  hulltet.tet = alltetrahedrontraverse();
+  facenumber = firstindex;
+  while (hulltet.tet != (tetrahedron *) NULL) {
+    if ((point) hulltet.tet[7] == dummypoint) {
+      torg = (point) hulltet.tet[4];
+      tdest = (point) hulltet.tet[5];
+      tapex = (point) hulltet.tet[6];
+      if (out == (tetgenio *) NULL) {
+        // Face number, indices of three vertices.
+        fprintf(outfile, "%5d   %4d  %4d  %4d", facenumber,
+          pointmark(torg) - shift, pointmark(tdest) - shift,
+          pointmark(tapex) - shift);
+        fprintf(outfile, "\n");
+      } else {
+        // Output indices of three vertices.
+        elist[index++] = pointmark(torg) - shift;
+        elist[index++] = pointmark(tdest) - shift;
+        elist[index++] = pointmark(tapex) - shift;
+      }
+      facenumber++;
+    }
+    hulltet.tet = alltetrahedrontraverse();
+  }
+  
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outsubfaces()    Output subfaces to a .face file or a tetgenio object.    //
+//                                                                           //
+// The number of mesh boundary edges ('meshsubedges') will be counted.       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outsubfaces(tetgenio* out)
+{
+  FILE *outfile;
+  char facefilename[FILENAMESIZE];
+  int *elist;
+  int *emlist;
+  int index, index1 = 0, index2 = 0;
+  triface abuttingtet;
+  face faceloop, spinsh;
+  point torg, tdest, tapex;
+  int bmark, faceid, marker;
+  int firstindex, shift;
+  int neigh1, neigh2;
+  int facenumber, i;
+
+  shellface sptr;
+
+  if (out == (tetgenio *) NULL) {
+    strcpy(facefilename, b->outfilename);
+    strcat(facefilename, ".face");
+  }
+
+  if (!b->quiet) {
+    if (out == (tetgenio *) NULL) {
+      printf("Writing %s.\n", facefilename);
+    } else {
+      printf("Writing faces.\n");
+    }
+  }
+
+  bmark = !b->nobound && in->facetmarkerlist;
+
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(facefilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", facefilename);
+      terminatetetgen(1);
+    }
+    // Number of subfaces.
+    fprintf(outfile, "%ld  %d\n", subfacepool->items, bmark);
+  } else {
+    // Allocate memory for 'trifacelist'.
+    out->trifacelist = new int[subfacepool->items * 3];
+    if (out->trifacelist == (int *) NULL) {
+      printf("Error:  Out of memory.\n");
+      terminatetetgen(1);
+    }
+    if (bmark) {
+      // Allocate memory for 'trifacemarkerlist'.
+      out->trifacemarkerlist = new int[subfacepool->items];
+      if (out->trifacemarkerlist == (int *) NULL) {
+        printf("Error:  Out of memory.\n");
+        terminatetetgen(1);
+      }
+    }
+    if (b->neighout > 1) {
+      // '-nn' switch.
+      out->adjtetlist = new int[subfacepool->items * 2];
+      if (out->adjtetlist == (int *) NULL) {
+        printf("Error:  Out of memory.\n");
+        terminatetetgen(1);
+      }
+    }
+    out->numberoftrifaces = subfacepool->items;
+    elist = out->trifacelist;
+    emlist = out->trifacemarkerlist;
+  }
+
+  // Determine the first index (0 or 1).
+  firstindex = b->zeroindex ? 0 : in->firstnumber;
+  shift = 0; // Default no shiftment.
+  if ((in->firstnumber == 1) && (firstindex == 0)) {
+    shift = 1; // Shift the output indices by 1.
+  }
+
+  meshsubedges = 0l;
+
+  subfacepool->traversalinit();
+  faceloop.sh = shellfacetraverse(subfacepool);
+  facenumber = firstindex; // in->firstnumber;
+  while (faceloop.sh != (shellface *) NULL) {
+    abuttingtet.tet = NULL; // stpivot(faceloop, abuttingtet);
+    if (abuttingtet.tet != NULL) {
+      // There is a tetrahedron containing this subface, orient it.
+      abuttingtet.ver = 0;
+      torg = org(abuttingtet);
+      tdest = dest(abuttingtet);
+      tapex = apex(abuttingtet);
+    } else {
+      // This may happen when only a surface mesh be generated.
+      torg = sorg(faceloop);
+      tdest = sdest(faceloop);
+      tapex = sapex(faceloop);
+    }
+    if (bmark) {
+      faceid = getshellmark(faceloop) - 1;
+      marker = in->facetmarkerlist[faceid];
+    }
+    if (b->neighout > 1) {
+      // '-nn' switch. Output adjacent tets indices.
+      neigh1 = -1;
+      // stpivot(faceloop, abuttingtet);
+      if (abuttingtet.tet != NULL) {
+        neigh1 = * (int *)(abuttingtet.tet + elemmarkerindex);
+      }
+      neigh2 = -1;
+      sesymself(faceloop);
+      // stpivot(faceloop, abuttingtet);
+      if (abuttingtet.tet != NULL) {
+        neigh2 = * (int *)(abuttingtet.tet + elemmarkerindex);
+      }
+    }
+    if (out == (tetgenio *) NULL) {
+      fprintf(outfile, "%5d   %4d  %4d  %4d", facenumber,
+              pointmark(torg) - shift, pointmark(tdest) - shift,
+              pointmark(tapex) - shift);
+      if (bmark) {
+        fprintf(outfile, "    %d", marker);
+      }
+      if (b->neighout > 1) {
+        fprintf(outfile, "    %5d  %5d", neigh1, neigh2);
+      }
+      fprintf(outfile, "\n");
+    } else {
+      // Output three vertices of this face;
+      elist[index++] = pointmark(torg) - shift;
+      elist[index++] = pointmark(tdest) - shift;
+      elist[index++] = pointmark(tapex) - shift;
+      if (bmark) {
+        emlist[index1++] = marker;
+      }
+      if (b->neighout > 1) {
+        out->adjtetlist[index2++] = neigh1;
+        out->adjtetlist[index2++] = neigh2;
+      }
+    }
+    // Count the number of boundary edges. Look at all subfaces sharing at 
+    //   this edge. Count it only if this subface's pointer is the smallest.
+    faceloop.shver = 0;
+    for (i = 0; i < 3; i++) {
+      spivot(faceloop, spinsh);
+      if (spinsh.sh != NULL) {
+        while (spinsh.sh != faceloop.sh) {
+          if ((unsigned long) spinsh.sh < (unsigned long) faceloop.sh) break;
+          spivotself(spinsh);
+        }
+        if (spinsh.sh == faceloop.sh) {
+          meshsubedges++;
+        }
+      } else {
+        meshsubedges++;
+      }
+      senextself(faceloop);
+    }
+    facenumber++;
+    faceloop.sh = shellfacetraverse(subfacepool);
+  }
+
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outedges()    Output all edges to a .edge file or a tetgenio object.      //
+//                                                                           //
+// Note: This routine must be called after outelements(),  so that the total //
+// number of edges 'meshedges' has been counted.                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outedges(tetgenio* out)
+{
+  FILE *outfile;
+  char edgefilename[FILENAMESIZE];
+  triface tetloop, worktet, spintet;
+  point torg, tdest;
+  int *elist, *emlist;
+  int firstindex, shift;
+  int edgenumber;
+  int index;
+  int i;
+
+  if (out == (tetgenio *) NULL) {
+    strcpy(edgefilename, b->outfilename);
+    strcat(edgefilename, ".edge");
+  }
+
+  if (!b->quiet) {
+    if (out == (tetgenio *) NULL) {
+      printf("Writing %s.\n", edgefilename);
+    } else {
+      printf("Writing edges.\n");
+    }
+  }
+
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(edgefilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", edgefilename);
+      terminatetetgen(1);
+    }
+    // Write the number of edges, boundary markers (0 or 1).
+    fprintf(outfile, "%ld  %d\n", meshedges, !b->nobound);
+  } else {
+    // Allocate memory for 'edgelist'.
+    out->edgelist = new int[meshedges * 2];
+    if (out->edgelist == (int *) NULL) {
+      printf("Error:  Out of memory.\n");
+      terminatetetgen(1);
+    }
+    if (!b->nobound) {
+      out->edgemarkerlist = new int[meshedges];
+    }
+    out->numberofedges = meshedges;
+    elist = out->edgelist;
+    emlist = out->edgemarkerlist;
+    index = 0;
+  }
+
+  // Determine the first index (0 or 1).
+  firstindex = b->zeroindex ? 0 : in->firstnumber;
+  shift = 0; // Default no shiftment.
+  if ((in->firstnumber == 1) && (firstindex == 0)) {
+    shift = 1; // Shift (reduce) the output indices by 1.
+  }
+
+  tetrahedronpool->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  edgenumber = firstindex; // in->firstnumber;
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    // Count the number of Voronoi faces. Look at the six edges of this
+    //   tet. Count an edge only if this tet's pointer is smaller than
+    //   those of other non-hull tets which share this edge.
+    worktet.tet = tetloop.tet;
+    for (i = 0; i < 6; i++) {
+      worktet.loc = edge2locver[i][0];
+      worktet.ver = edge2locver[i][1];
+      fnext(worktet, spintet);
+      do {
+        if ((point) spintet.tet[7] != dummypoint) {
+          if (spintet.tet < worktet.tet) break;
+        }
+        fnextself(spintet);
+      } while (spintet.tet != worktet.tet);
+      // Count this edge if no adjacent tets are smaller than this tet.
+      if (spintet.tet == worktet.tet) {
+        torg = org(worktet);
+        tdest = dest(worktet);
+        if (out == (tetgenio *) NULL) {
+          fprintf(outfile, "%5d   %4d  %4d", edgenumber,
+                  pointmark(torg) - shift, pointmark(tdest) - shift);
+        } else {
+          // Output three vertices of this face;
+          elist[index++] = pointmark(torg) - shift;
+          elist[index++] = pointmark(tdest) - shift;
+        }
+        /*
+        if (!b->nobound) {
+          // Check if the edge is a segment.
+          tsspivot(&worktet, &checkseg);
+          if (checkseg.sh != dummysh) {
+            marker = shellmark(checkseg);
+            if (marker == 0) {  // Does it have no marker?
+              marker = 1;  // Set the default marker for this segment.
+            }
+          } else {
+            marker = 0;  // It's not a segment.
+          }
+          if (out == (tetgenio *) NULL) {
+            fprintf(outfile, "  %d", marker);
+          } else {
+            emlist[index1++] = marker;
+          }
+        }
+        */
+        if (out == (tetgenio *) NULL) {
+          fprintf(outfile, "\n");
+        }
+        edgenumber++;
+      }
+    }
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outsubsegments()    Output subsegments into an .edge file or an object.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outsubsegments(tetgenio* out)
+{
+  FILE *outfile;
+  char edgefilename[FILENAMESIZE];
+  int *elist;
+  int index;
+  face edgeloop;
+  point torg, tdest;
+  int firstindex, shift;
+  int edgenumber;
+
+  if (out == (tetgenio *) NULL) {
+    strcpy(edgefilename, b->outfilename);
+    strcat(edgefilename, ".edge");
+  }
+
+  if (!b->quiet) {
+    if (out == (tetgenio *) NULL) {
+      printf("Writing %s.\n", edgefilename);
+    } else {
+      printf("Writing edges.\n");
+    }
+  }
+
+  // Avoid compile warnings.
+  outfile = (FILE *) NULL;
+  elist = (int *) NULL;
+  index = 0;  
+
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(edgefilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", edgefilename);
+      terminatetetgen(1);
+    }
+    // Number of subsegments.
+    fprintf(outfile, "%ld\n", subsegpool->items);
+  } else {
+    // Allocate memory for 'edgelist'.
+    out->edgelist = new int[subsegpool->items * 2];
+    if (out->edgelist == (int *) NULL) {
+      printf("Error:  Out of memory.\n");
+      terminatetetgen(1);
+    }
+    out->numberofedges = subsegpool->items;
+    elist = out->edgelist;
+  }
+
+  // Determine the first index (0 or 1).
+  firstindex = b->zeroindex ? 0 : in->firstnumber;
+  shift = 0; // Default no shiftment.
+  if ((in->firstnumber == 1) && (firstindex == 0)) {
+    shift = 1; // Shift the output indices by 1.
+  }
+
+  subsegpool->traversalinit();
+  edgeloop.sh = shellfacetraverse(subsegpool);
+  edgenumber = firstindex; // in->firstnumber;
+  while (edgeloop.sh != (shellface *) NULL) {
+    torg = sorg(edgeloop);
+    tdest = sdest(edgeloop);
+    if (out == (tetgenio *) NULL) {
+      fprintf(outfile, "%5d   %4d  %4d\n", edgenumber,
+              pointmark(torg) - shift, pointmark(tdest) - shift);
+    } else {
+      // Output three vertices of this face;
+      elist[index++] = pointmark(torg) - shift;
+      elist[index++] = pointmark(tdest) - shift;
+    }
+    edgenumber++;
+    edgeloop.sh = shellfacetraverse(subsegpool);
+  }
+
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outneighbors()    Output tet neighbors to a .neigh file or an object.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outneighbors(tetgenio* out)
+{
+  FILE *outfile;
+  char neighborfilename[FILENAMESIZE];
+  int *nlist;
+  int index;
+  triface tetloop, tetsym;
+  int neighbor1, neighbor2, neighbor3, neighbor4;
+  int firstindex;
+  int elementnumber;
+  long ntets;
+
+  if (out == (tetgenio *) NULL) {
+    strcpy(neighborfilename, b->outfilename);
+    strcat(neighborfilename, ".neigh");
+  }
+
+  if (!b->quiet) {
+    if (out == (tetgenio *) NULL) {
+      printf("Writing %s.\n", neighborfilename);
+    } else {
+      printf("Writing neighbors.\n");
+    }
+  }
+
+  ntets = tetrahedronpool->items - hullsize;
+
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(neighborfilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", neighborfilename);
+      terminatetetgen(1);
+    }
+    // Number of tetrahedra, four faces per tetrahedron.
+    fprintf(outfile, "%ld  %d\n", ntets, 4);
+  } else {
+    // Allocate memory for 'neighborlist'.
+    out->neighborlist = new int[ntets * 4];
+    if (out->neighborlist == (int *) NULL) {
+      printf("Error:  Out of memory.\n");
+      terminatetetgen(1);
+    }
+    nlist = out->neighborlist;
+  }
+
+  // Determine the first index (0 or 1).
+  firstindex = b->zeroindex ? 0 : in->firstnumber;
+
+  tetrahedronpool->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  elementnumber = firstindex; // in->firstnumber;
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    tetloop.loc = 2;
+    sym(tetloop, tetsym);
+    if ((point) tetsym.tet[7] != dummypoint) {
+      neighbor1 = * (int *) (tetsym.tet + elemmarkerindex);
+    } else {
+      neighbor1 = -1;
+    }
+    tetloop.loc = 3;
+    sym(tetloop, tetsym);
+    if ((point) tetsym.tet[7] != dummypoint) {
+      neighbor2 = * (int *) (tetsym.tet + elemmarkerindex);
+    } else {
+      neighbor1 = -1;
+    }
+    tetloop.loc = 1;
+    sym(tetloop, tetsym);
+    if ((point) tetsym.tet[7] != dummypoint) {
+      neighbor3 = * (int *) (tetsym.tet + elemmarkerindex);
+    } else {
+      neighbor1 = -1;
+    }
+    tetloop.loc = 0;
+    sym(tetloop, tetsym);
+    if ((point) tetsym.tet[7] != dummypoint) {
+      neighbor4 = * (int *) (tetsym.tet + elemmarkerindex);
+    } else {
+      neighbor1 = -1;
+    }
+    if (out == (tetgenio *) NULL) {
+      // Tetrahedra number, neighboring tetrahedron numbers.
+      fprintf(outfile, "%4d    %4d  %4d  %4d  %4d\n", elementnumber,
+              neighbor1, neighbor2, neighbor3, neighbor4);
+    } else {
+      nlist[index++] = neighbor1;
+      nlist[index++] = neighbor2;
+      nlist[index++] = neighbor3;
+      nlist[index++] = neighbor4;
+    }
+    tetloop.tet = tetrahedrontraverse();
+    elementnumber++;
+  }
+
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+}
+
+#endif // #ifndef meshioCXX
diff --git a/contrib/TetgenNew/meshstat.cxx b/contrib/TetgenNew/meshstat.cxx
new file mode 100644
index 0000000000..c5c0c992c1
--- /dev/null
+++ b/contrib/TetgenNew/meshstat.cxx
@@ -0,0 +1,1764 @@
+#ifndef meshstatCXX
+#define meshstatCXX
+
+#include "tetgen.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Initialize fast look-up tables.                                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::ve[6] = { 2, 5, 4, 1, 0, 3 };
+int tetgenmesh::ve2[6] = { 4, 3, 0, 5, 2, 1 };
+
+int tetgenmesh::vo[6] = { 0, 1, 1, 2, 2, 0 };
+int tetgenmesh::vd[6] = { 1, 0, 2, 1, 0, 2 };
+int tetgenmesh::va[6] = { 2, 2, 0, 0, 1, 1 };
+
+int tetgenmesh::verver2zero[6][6] = {
+  {0, 0, 2, 2, 4, 4},
+  {0, 0, 2, 2, 4, 4},
+  {2, 2, 4, 4, 0, 0},
+  {2, 2, 4, 4, 0, 0},
+  {4, 4, 0, 0, 2, 2},
+  {4, 4, 0, 0, 2, 2}
+};
+
+int tetgenmesh::ver2zero[6] = {0, 0, 2, 2, 4, 4};
+
+int tetgenmesh::zero2ver[6][6] = {
+  {0, 0, 2, 2, 4, 4}, 
+  {0, 0, 2, 2, 4, 4},
+  {4, 4, 0, 0, 2, 2},
+  {4, 4, 0, 0, 2, 2},
+  {2, 2, 4, 4, 0, 0},
+  {2, 2, 4, 4, 0, 0}
+};
+
+int tetgenmesh::locver2org[4][6]  = {
+  {0, 1, 1, 2, 2, 0},
+  {0, 3, 3, 1, 1, 0},
+  {1, 3, 3, 2, 2, 1},
+  {2, 3, 3, 0, 0, 2} 
+};
+
+int tetgenmesh::locver2dest[4][6] = { 
+  {1, 0, 2, 1, 0, 2},
+  {3, 0, 1, 3, 0, 1},
+  {3, 1, 2, 3, 1, 2},
+  {3, 2, 0, 3, 2, 0}
+};
+
+int tetgenmesh::locver2apex[4][6] = { 
+  {2, 2, 0, 0, 1, 1},
+  {1, 1, 0, 0, 3, 3},
+  {2, 2, 1, 1, 3, 3},
+  {0, 0, 2, 2, 3, 3}
+};
+
+int tetgenmesh::loc2oppo[4] = { 3, 2, 0, 1 };
+
+int tetgenmesh::locver2nextf[32] = {
+  1, 5, 2, 5, 3, 5, 0, 0,
+  3, 3, 2, 1, 0, 1, 0, 0,
+  1, 3, 3, 1, 0, 3, 0, 0,
+  2, 3, 1, 1, 0, 5, 0, 0
+};
+
+int tetgenmesh::locver2edge[4][6] = {
+  {0, 0, 1, 1, 2, 2},
+  {3, 3, 4, 4, 0, 0},
+  {4, 4, 5, 5, 1, 1},
+  {5, 5, 3, 3, 2, 2}
+};
+
+int tetgenmesh::edge2locver[6][2] = {
+  {0, 0}, // 0  v0 -> v1
+  {0, 2}, // 1  v1 -> v2
+  {0, 4}, // 2  v2 -> v0
+  {1, 0}, // 3  v0 -> v3
+  {1, 2}, // 4  v1 -> v3
+  {2, 2}  // 5  v2 -> v3
+};
+
+int tetgenmesh::locpivot[4][3] = {
+  {1, 2, 3},
+  {0, 2, 3},
+  {0, 1, 3},
+  {0, 1, 2}
+};
+
+int tetgenmesh::locverpivot[4][6][2] = {
+  {{2, 3}, {2, 3}, {1, 3}, {1, 3}, {1, 2}, {1, 2}},
+  {{0, 2}, {0, 2}, {0, 3}, {0, 3}, {2, 3}, {2, 3}},
+  {{0, 3}, {0, 3}, {0, 1}, {0, 1}, {1, 3}, {1, 3}},
+  {{0, 1}, {0, 1}, {0, 2}, {0, 2}, {1, 2}, {1, 2}}
+};
+
+int tetgenmesh::mi1mo3[3] = {2, 0, 1};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkmesh()    Test mesh for geometrical and topological consistencies.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checkmesh()
+{
+  triface tetloop;
+  triface neightet, symtet;
+  point pa, pb, pc, pd;
+  REAL ori;
+  int horrors, i;
+
+  if (!b->quiet) {
+    printf("  Checking consistency of mesh...\n");
+  }
+
+  horrors = 0;
+  tetloop.ver = 0;
+  // Run through the list of tetrahedra, checking each one.
+  tetrahedronpool->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    // Check all four faces of the tetrahedron.
+    for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
+      pa = org(tetloop);
+      pb = dest(tetloop);
+      pc = apex(tetloop);
+      pd = oppo(tetloop);
+      if (tetloop.loc == 0) {  // Only test for inversion once.
+        if (pd != dummypoint) {  // Only do test if it is not a hull tet.
+          ori = orient3d(pa, pb, pc, pd);
+          if (ori >= 0.0) {
+            printf("  !! !! %s ", ori > 0.0 ? "Inverted" : "Degenerated");
+            printf("  (%d, %d, %d, %d) (ori = %.17g)\n", pointmark(pa),
+              pointmark(pb), pointmark(pc), pointmark(pd), ori);
+            horrors++;
+          }
+        }
+        if (infected(tetloop)) { 
+          // This may be a bug. Report it.
+          printf("  !! (%d, %d, %d, %d) is infected.\n", pointmark(pa),
+            pointmark(pb), pointmark(pc), pointmark(pd));
+        }
+        if (marktested(tetloop)) {
+          // This may be a bug. Report it.
+          printf("  !! (%d, %d, %d, %d) is marked.\n", pointmark(pa),
+            pointmark(pb), pointmark(pc), pointmark(pd));
+        }
+      }
+      if (tetloop.tet[tetloop.loc] == NULL) {
+        printf("  !! !! No neighbor at face (%d, %d, %d).\n", pointmark(pa),
+            pointmark(pb), pointmark(pc));
+        horrors++;
+      } else {
+        // Find the neighboring tetrahedron on this face.
+        symedge(tetloop, neightet);
+        // Check that the tetrahedron's neighbor knows it's a neighbor.
+        sym(neightet, symtet);
+        if ((tetloop.tet != symtet.tet) || (tetloop.loc != symtet.loc)) {
+          printf("  !! !! Asymmetric tetra-tetra bond:\n");
+          if (tetloop.tet == symtet.tet) {
+            printf("   (Right tetrahedron, wrong orientation)\n");
+          }
+          printf("    First:  (%d, %d, %d, %d)\n", pointmark(pa),
+            pointmark(pb), pointmark(pc), pointmark(pd));
+          printf("    Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
+            pointmark(dest(neightet)), pointmark(apex(neightet)),
+            pointmark(oppo(neightet)));
+          horrors++;
+        }
+        // Check if they have the same edge (the bond() operation).
+        if ((org(neightet) != pb) || (dest(neightet) != pa)) {
+          printf("  !! !! Wrong edge-edge bond:\n");
+          printf("    First:  (%d, %d, %d, %d)\n", pointmark(pa),
+            pointmark(pb), pointmark(pc), pointmark(pd));
+          printf("    Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
+            pointmark(dest(neightet)), pointmark(apex(neightet)),
+            pointmark(oppo(neightet)));
+          horrors++;
+        }
+        // Check if they have the same apex.
+        if (apex(neightet) != pc) {
+          printf("  !! !! Wrong face-face bond:\n");
+          printf("    First:  (%d, %d, %d, %d)\n", pointmark(pa),
+            pointmark(pb), pointmark(pc), pointmark(pd));
+          printf("    Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
+            pointmark(dest(neightet)), pointmark(apex(neightet)),
+            pointmark(oppo(neightet)));
+          horrors++;
+        }
+        // Check if they have the same opposite.
+        if (oppo(neightet) == pd) {
+          printf("  !! !! Two identical tetra:\n");
+          printf("    First:  (%d, %d, %d, %d)\n", pointmark(pa),
+            pointmark(pb), pointmark(pc), pointmark(pd));
+          printf("    Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
+            pointmark(dest(neightet)), pointmark(apex(neightet)),
+            pointmark(oppo(neightet)));
+          horrors++;
+        }
+      }
+      if (facemarked(tetloop)) {
+        // This may be a bug. Report it.
+        printf("  !! tetface (%d, %d, %d) %d is marked.\n", pointmark(pa),
+          pointmark(pb), pointmark(pc), pointmark(pd));
+      }
+    }
+    // Check the six edges of this tet.
+    for (i = 0; i < 6; i++) {
+      tetloop.loc = edge2locver[i][0];
+      tetloop.ver = edge2locver[i][1];
+      if (edgemarked(tetloop)) {
+        // This may be a bug. Report it.
+        printf("  !! tetedge (%d, %d) %d, %d is marked.\n", 
+          pointmark(org(tetloop)), pointmark(dest(tetloop)), 
+          pointmark(apex(tetloop)), pointmark(oppo(tetloop)));
+      }
+    }
+    tetloop.tet = tetrahedrontraverse();
+  }
+  if (horrors == 0) {
+    if (!b->quiet) {
+      printf("  In my studied opinion, the mesh appears to be consistent.\n");
+    }
+  } else {
+    printf("  !! !! !! !! %d %s witnessed.\n", horrors, 
+      horrors > 1 ? "abnormity" : "abnormities");
+  }
+
+  return horrors;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkshells()    Test the surface mesh for consistencies.                 //
+//                                                                           //
+// If 'sub2tet' > 0, it also checks the subface-to-tet connections.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checkshells(int sub2tet)
+{
+  triface neightet, symtet;
+  face shloop, spinsh, nextsh;
+  face checkseg;
+  point pa, pb, *ppt;
+  int count;
+  int horrors, i;
+
+  tetrahedron ptr;
+
+  if (!b->quiet) {
+    printf("  Checking consistency of the mesh boundary...\n");
+  }
+  horrors = 0;
+
+  void **bakpathblock = subfacepool->pathblock;
+  void *bakpathitem = subfacepool->pathitem;
+  int bakpathitemsleft = subfacepool->pathitemsleft;
+  int bakalignbytes = subfacepool->alignbytes;
+
+  subfacepool->traversalinit();
+  shloop.sh = shellfacetraverse(subfacepool);
+  while (shloop.sh != NULL) {
+    shloop.shver = 0;
+    for (i = 0; i < 3; i++) {
+      // Check the face ring at this edge.
+      pa = sorg(shloop);
+      pb = sdest(shloop);
+      spinsh = shloop;
+      spivot(spinsh, nextsh);
+      while ((nextsh.sh != NULL) && (nextsh.sh != shloop.sh)) {
+        // check if they have the same edge.
+        if (!((sorg(nextsh) == pa) && (sdest(nextsh) == pb) ||
+             (sorg(nextsh) == pb) && (sdest(nextsh) == pa))) {
+           printf("  !! !! Wrong subface-subface connection.\n");
+           printf("    First: x%lx (%d, %d, %d).\n", (unsigned long) spinsh.sh,
+             pmark(sorg(spinsh)), pmark(sdest(spinsh)), pmark(sapex(spinsh)));
+           printf("    Scond: x%lx (%d, %d, %d).\n", (unsigned long) nextsh.sh,
+             pmark(sorg(nextsh)), pmark(sdest(nextsh)), pmark(sapex(nextsh)));
+           horrors++;
+        }
+        spinsh = nextsh;
+        spivot(spinsh, nextsh);
+      }
+      // Check subface-subseg bond.
+      sspivot(shloop, checkseg);
+      if (checkseg.sh != NULL) {
+        if (!((sorg(checkseg) == pa) && (sdest(checkseg) == pb) ||
+             (sorg(checkseg) == pb) && (sdest(checkseg) == pa))) {
+          printf("  !! !! Wrong subface-subseg connection.\n");
+          printf("    Sub: x%lx (%d, %d, %d).\n", (unsigned long) shloop.sh,
+            pmark(sorg(shloop)), pmark(sdest(shloop)), pmark(sapex(shloop)));
+          printf("    Seg: x%lx (%d, %d).\n", (unsigned long) checkseg.sh,
+            pmark(sorg(checkseg)), pmark(sdest(checkseg)));
+          horrors++;
+        }
+      }
+      senextself(shloop);
+    }
+    if (sub2tet > 0) {
+      // Check the tet-subface connections.
+      stpivot(shloop, neightet);
+      if (neightet.tet != NULL) {
+        // Check if the tet and subface have the same vertices.
+        ppt = (point *) shloop.sh;
+        for (i = 0; i < 3; i++) {
+          pinfect(ppt[3 + i]); // Infect the subface vertices.
+        }
+        ppt = (point *) neightet.tet;
+        count = 0;  // Count the infected vertices of this tet.
+        for (i = 0; i < 4; i++) {
+          if (pinfected(ppt[4 + i])) count++; 
+        }
+        ppt = (point *) shloop.sh;
+        for (i = 0; i < 3; i++) {
+          puninfect(ppt[3 + i]); // Uninfect the subface vertices.
+        }
+        if (count != 3) {
+          printf("  !! !! Wrong tet-sub connection (face does not match).\n");
+          printf("    Sub: x%lx (%d, %d, %d).\n", (unsigned long) shloop.sh,
+            pmark(sorg(shloop)), pmark(sdest(shloop)), pmark(sapex(shloop)));
+          printf("    Tet: x%lx (%d, %d, %d, %d).\n", 
+            (unsigned long) neightet.tet, pmark(org(neightet)), 
+            pmark(dest(neightet)), pmark(apex(neightet)), 
+            pmark(oppo(neightet)));
+          horrors++;
+        }
+        tspivot(neightet, spinsh);
+        if (spinsh.sh != shloop.sh) {
+          printf("  !! !! Wrong tet-sub connection (wrong subfaces).\n");
+          printf("    Sub: x%lx (%d, %d, %d).\n", (unsigned long) shloop.sh,
+            pmark(sorg(shloop)), pmark(sdest(shloop)), pmark(sapex(shloop)));
+          printf("    Tet: x%lx (%d, %d, %d, %d).\n", 
+            (unsigned long) neightet.tet, pmark(org(neightet)), 
+            pmark(dest(neightet)), pmark(apex(neightet)), 
+            pmark(oppo(neightet)));
+          horrors++;
+        } else {
+          symself(neightet);
+          tspivot(neightet, spinsh);
+          if (spinsh.sh != shloop.sh) {
+            printf("  !! !! Wrong tet-sub connection (wrong subfaces).\n");
+            printf("    Sub: x%lx (%d, %d, %d).\n", (unsigned long) shloop.sh,
+              pmark(sorg(shloop)), pmark(sdest(shloop)), pmark(sapex(shloop)));
+            printf("    Tet: x%lx (%d, %d, %d, %d).\n", 
+              (unsigned long) neightet.tet, pmark(org(neightet)), 
+              pmark(dest(neightet)), pmark(apex(neightet)), 
+              pmark(oppo(neightet)));
+            horrors++;
+          }
+        }
+      } else {
+        // printf("  !! A dangling subface.\n");
+        // printf("    Sub: x%lx (%d, %d, %d).\n", (unsigned long) shloop.sh,
+        //   pmark(sorg(shloop)), pmark(sdest(shloop)), pmark(sapex(shloop)));
+        // horrors++;
+      }
+    }
+    if (sinfected(shloop)) {
+      // This may be a bug. report it.
+      printf("  !! A infected subface: (%d, %d, %d).\n", pmark(sorg(shloop)),
+        pmark(sdest(shloop)), pmark(sapex(shloop)));
+    }
+    if (smarktested(shloop)) {
+      // This may be a bug. report it.
+      printf("  !! A marked subface: (%d, %d, %d).\n", pmark(sorg(shloop)), 
+        pmark(sdest(shloop)), pmark(sapex(shloop)));
+    }
+    shloop.sh = shellfacetraverse(subfacepool);
+  }
+
+  if (horrors == 0) {
+    if (!b->quiet) {
+      printf("  Mesh boundaries connected correctly.\n");
+    }
+  } else {
+    printf("  !! !! !! !! %d boundary connection viewed with horror.\n",
+           horrors);
+  }
+
+  subfacepool->pathblock = bakpathblock;
+  subfacepool->pathitem = bakpathitem;
+  subfacepool->pathitemsleft = bakpathitemsleft;
+  subfacepool->alignbytes = bakalignbytes;
+
+  return horrors;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkdelaunay()    Ensure that the mesh is (constrained) Delaunay.        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checkdelaunay(int constrained)
+{
+  triface tetloop;
+  triface symtet;
+  face checksh;
+  point pa, pb, pc, pd, pe;
+  REAL sign;
+  int horrors;
+
+  if (!b->quiet) {
+    printf("  Checking %s property of the mesh...\n",  constrained > 0 ? 
+      "constrained Delaunay" : "Delaunay");
+  }
+  
+  horrors = 0;
+  tetloop.ver = 0;
+  // Run through the list of triangles, checking each one.
+  tetrahedronpool->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    // Check all four faces of the tetrahedron.
+    for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
+      sym(tetloop, symtet);
+      // Only do test if its adjoining tet is not a hull tet or its pointer
+      //   is larger (to ensure that each pair isn't tested twice).
+      if (((point) symtet.tet[7] != dummypoint)&&(tetloop.tet < symtet.tet)) {
+        pa = org(tetloop);
+        pb = dest(tetloop);
+        pc = apex(tetloop);
+        pd = oppo(tetloop);
+        pe = oppo(symtet);
+        sign = insphere_sos(pa, pb, pc, pd, pe);
+        if (sign < 0.0) {
+          if (constrained > 0) {
+            tspivot(tetloop, checksh);
+          }
+          if ((constrained == 0) || 
+             ((constrained > 0) && (checksh.sh == NULL))) {
+            printf("  !! Non-locally Delaunay (%d, %d, %d) - %d, %d\n",
+              pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd),
+              pointmark(pe));
+            horrors++;
+          }
+        }
+      }
+    }
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  if (horrors == 0) {
+    if (!b->quiet) {
+      printf("  The mesh is %s.\n", constrained > 0 ? "constrained Delaunay" 
+        : "Delaunay");
+    }
+  } else {
+    printf("  !! !! !! !! Found %d non-Delaunay faces.\n", horrors);
+  }
+
+  return horrors;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checksegments()    Check the connections between tetrahedra and segments. //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checksegments()
+{
+  triface tetloop, neightet;
+  shellface *segs;
+  face sseg, checkseg;
+  point pa, pb;
+  int horrors, i;
+
+  if (!b->quiet) {
+    printf("  Checking tet-seg connections...\n");
+  }
+
+  horrors = 0;
+  tetrahedronpool->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != NULL) {
+    // Loop the six edges of the tet.
+    if (tetloop.tet[8] != NULL) {
+      segs = (shellface *) tetloop.tet[8];
+      for (i = 0; i < 6; i++) {
+        sdecode(segs[i], sseg);
+        if (sseg.sh != NULL) {
+          // Get the edge of the tet.
+          tetloop.loc = edge2locver[i][0];
+          tetloop.ver = edge2locver[i][1];
+          // Check if they are the same edge.
+          pa = (point) sseg.sh[3];
+          pb = (point) sseg.sh[4];
+          if (!(((org(tetloop) == pa) && (dest(tetloop) == pb)) ||
+                ((org(tetloop) == pb) && (dest(tetloop) == pa)))) {
+            printf("  !! Wrong tet-seg connection.\n");
+            printf("    Tet: x%lx (%d, %d, %d, %d) - Seg: x%lx (%d, %d).\n", 
+              (unsigned long) tetloop.tet, pointmark(org(tetloop)),
+              pointmark(dest(tetloop)), pointmark(apex(tetloop)),
+              pointmark(oppo(tetloop)), (unsigned long) sseg.sh,
+              pointmark(pa), pointmark(pb));
+            horrors++;
+          } else {
+            // Loop all tets sharing at this edge.
+            neightet = tetloop;
+            do {
+              tsspivot(neightet, checkseg);
+              if (checkseg.sh != sseg.sh) {
+                printf("  !! Wrong tet->seg connection.\n");
+                printf("    Tet: x%lx (%d, %d, %d, %d) - ", 
+                  (unsigned long) neightet.tet, pointmark(org(neightet)),
+                  pointmark(dest(neightet)), pointmark(apex(neightet)),
+                  pointmark(oppo(neightet)));
+                if (checkseg.sh != NULL) {
+                  printf("Seg x%lx (%d, %d).\n", (unsigned long) checkseg.sh,
+                  pointmark(sorg(checkseg)), pointmark(sdest(checkseg))); 
+                } else {
+                  printf("Seg: NULL.\n");
+                }
+                horrors++;
+              }
+              fnextself(neightet);
+            } while (neightet.tet != tetloop.tet);
+          }
+          // Check the seg->tet pointer.
+          stpivot(sseg, neightet);
+          if (neightet.tet == NULL) {
+            printf("  !! Wrong seg->tet connection (A NULL tet).\n");
+            horrors++;
+          } else {
+            if (!(((org(neightet) == pa) && (dest(neightet) == pb)) ||
+                ((org(neightet) == pb) && (dest(neightet) == pa)))) {
+              printf("  !! Wrong seg->tet connection (Wrong edge).\n");
+              printf("    Tet: x%lx (%d, %d, %d, %d) - Seg: x%lx (%d, %d).\n", 
+                (unsigned long) neightet.tet, pointmark(org(neightet)),
+                pointmark(dest(neightet)), pointmark(apex(neightet)),
+                pointmark(oppo(neightet)), (unsigned long) sseg.sh,
+                pointmark(pa), pointmark(pb));
+              horrors++;
+            }
+          }
+        }
+      }
+    }
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  if (horrors == 0) {
+    printf("  Segments are connected properly.\n");
+  } else {
+    printf("  !! !! !! !! Found %d missing connections.\n", horrors);
+  }
+
+  return horrors;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkconforming()    Check if the mesh is boundary conforming Delaunay.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checkconforming()
+{
+  face shloop;
+  int horrors;
+
+  horrors = 0;
+
+  // Find all encroached segments.
+  subsegpool->traversalinit();
+  shloop.shver = 0;
+  shloop.sh = shellfacetraverse(subsegpool);
+  while (shloop.sh != NULL) {
+    if (checkedge4encroach(shloop, NULL, 0)) {
+      printf("  !! Segment x%lx (%d, %d) is encroached.\n", 
+        (unsigned long) shloop.sh, pointmark(sorg(shloop)),
+        pointmark(sdest(shloop)));
+      horrors++;
+    }
+    shloop.sh = shellfacetraverse(subsegpool);
+  }
+
+  if (horrors == 0) {
+    printf("  Segments are boundary conforming Delaunay.\n");
+  } else {
+    printf("  !! !! !! !! Found %d encroached segments.\n", horrors);
+  }
+
+  return horrors;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// algorithmstatistics()    Report algorithmic performances.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::algorithmstatistics()
+{
+  /*// Report memory usages.
+    unsigned long totalmeshbytes;
+    printf("Memory allocation statistics:\n\n");
+    printf("  Maximum number of vertices: %ld\n", pointpool->maxitems);
+    totalmeshbytes = pointpool->maxitems * pointpool->itembytes;
+    printf("  Maximum number of tetrahedra: %ld\n", tetrahedronpool->maxitems);
+    totalmeshbytes += tetrahedronpool->maxitems * tetrahedronpool->itembytes;
+    if (subfacepool != (memorypool *) NULL) {
+      printf("  Maximum number of subfaces: %ld\n", subfacepool->maxitems);
+      totalmeshbytes += subfacepool->maxitems * subfacepool->itembytes;
+    }
+    if (subsegpool != (memorypool *) NULL) {
+      printf("  Maximum number of segments: %ld\n", subsegpool->maxitems);
+      totalmeshbytes += subsegpool->maxitems * subsegpool->itembytes;
+    }
+    printf("  Heap memory used by the mesh (K bytes): %g\n\n",
+           ((double) totalmeshbytes) / 1024.0);
+  */
+
+  printf("Algorithmic statistics:\n\n");
+
+  printf("  Number of orient3d tests: %ld\n", orient3dcount);
+  printf("  Number of insphere tests: %ld\n", inspherecount);
+  printf("  Number of symbolic insphere tests: %ld\n", insphere_sos_count);
+  printf("  Number of visited tets in point location: %ld\n", ptloc_count);
+  printf("  Maximal number of tets per point location: %ld\n",ptloc_max_count);
+  printf("  Number of 1-to-4 flips: %ld\n", flip14count);
+  printf("  Number of 2-to-6 flips: %ld\n", flip26count);
+  printf("  Number of n-t-2n flips: %ld\n", flipn2ncount);
+
+  if (!b->plc) {
+    if (b->bowyerwatson) {
+      printf("  Number of deleted tets: %ld\n", totaldeadtets);
+      printf("  Number of created tets: %ld\n", totalbowatcavsize);
+      printf("  Maximum number of tets per new point: %ld\n", maxbowatcavsize);
+      printf("  Number of 3-to-2 flips: %ld\n", flip32count);
+    } else {
+      printf("  Number of 3-to-2 flips: %ld\n", flip32count);
+      printf("  Number of 2-to-3 flips: %ld\n", flip23count);
+      printf("  Number of n-to-m flips: %ld\n", flipnmcount);
+      printf("  Total number of primitive flips: %ld\n",
+        flip23count + flip32count);
+    }
+  }
+
+  if (b->plc) {
+    printf("  Number of 2-to-2 flips: %ld\n", flip22count);
+    printf("  Number of tri-edge inter (coplanar) tests: %ld (%ld)\n",
+      triedgcount, triedgcopcount);
+    printf("  Number of crossed faces (edges) in scout segs: %ld (%ld)\n",
+      across_face_count, across_edge_count);
+    printf("  Maximal number of crossed faces per segment: %ld\n",
+      across_max_count);
+    printf("  Number of rule-1 points: %ld\n", r1count);
+    printf("  Number of rule-2 points: %ld\n", r2count);
+    printf("  Number of rule-3 points: %ld\n", r3count);
+    printf("  Maximal size of a missing region: %ld\n", maxregionsize);
+    printf("  Maximal size of a recovered cavity: %ld\n", maxcavsize);
+    printf("  Number of non-Delaunay edges: %ld\n", ndelaunayedgecount);
+    printf("  Number of cavity expansions: %ld\n", cavityexpcount);
+  }
+  
+  // printf("  Total point location time (millisec):  %g\n", tloctime * 1e+3);
+  // printf("  Total point insertion time (millisec):  %g\n",tinserttime*1e+3);
+  // if (b->bowyerwatson == 0) {
+  //   printf("  Total flip time (millisec):  %g\n", tfliptime * 1e+3);
+  // }
+
+  printf("\n");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// statistics()    Print all sorts of cool facts.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::statistics()
+{
+  long tetnumber, facenumber;
+
+  printf("\nStatistics:\n\n");
+  printf("  Input points: %d\n", in->numberofpoints);
+  if (b->refine) {
+    printf("  Input tetrahedra: %d\n", in->numberoftetrahedra);
+  }
+  if (b->plc) {
+    printf("  Input facets: %d\n", in->numberoffacets);
+    printf("  Input segments: %ld\n", insegments);
+    printf("  Input holes: %d\n", in->numberofholes);
+    printf("  Input regions: %d\n", in->numberofregions);
+  }
+
+  tetnumber = tetrahedronpool->items - hullsize;
+  facenumber = (tetnumber * 4l + hullsize) / 2l;
+
+  printf("\n  Mesh points: %ld\n", pointpool->items);
+  printf("  Mesh tetrahedra: %ld\n", tetnumber);
+  printf("  Mesh faces: %ld\n", facenumber);
+  printf("  Mesh edges: %ld\n", meshedges);
+
+  if (b->plc || b->refine) {
+    printf("  Mesh boundary faces: %ld\n", subfacepool->items);
+    printf("  Mesh boundary edges: %ld\n", meshsubedges);
+    printf("  Mesh subsegments: %ld\n", subsegpool->items);
+  } else {
+    printf("  Convex hull faces: %ld\n", hullsize);
+  }
+  printf("\n");
+
+  if (b->verbose > 0) {
+    printf("  Euler characteristic of mesh domain: %ld\n", pointpool->items 
+      - meshedges + facenumber - tetnumber);
+    //printf("  Euler characteristic of boundary: %ld\n", pointpool->items 
+    //  - meshsubedges + subfacepool->items);
+    printf("\n");
+  }
+
+  if (b->verbose > 0) {
+    // qualitystatistics();
+    algorithmstatistics();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// terminatetetgen()    Terminate TetGen with a given exit code.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void terminatetetgen(int x)
+{
+#ifdef TETLIBRARY
+  throw x;
+#else
+  exit(x);
+#endif // #ifdef TETLIBRARY
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Debug functions.                                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// Print the detail informations of a tetrahedron.
+
+void tetgenmesh::ptet(triface* t)
+{
+  triface tmpface, prtface;
+  shellface *shells;
+  face checksh;
+  point *pts, tmppt;
+  REAL ori;
+  int facecount;
+
+  printf("Tetra x%lx with loc(%i) ver(%i):",
+         (unsigned long)(t->tet), t->loc, t->ver);
+  if (t->tet == NULL) {
+    printf("  !! NOT A VALID HANDLE\n");
+    return;
+  }
+  pts = (point *) t->tet;
+  if (pts[4] == NULL) {
+    printf("  !! A DEAD TET\n");
+    return;
+  }
+  if (pts[7] != dummypoint) {
+    ori = orient3d(pts[4], pts[5], pts[6], pts[7]);
+    printf("  ori = %g.\n", ori);
+  } else {
+    printf("  (hull tet).\n");
+  }
+  // Report the status of this tet.
+  printf("      ");
+  if (infected(*t)) {
+    printf("(infected) ");
+  }
+  if (marktested(*t)) {
+    printf("(marktested) ");
+  }
+  if (edgemarked(*t)) {
+    printf("(edgemarked) ");
+  }
+  if (b->regionattrib) {
+    printf("attr(%d)", elemattribute(t->tet, 0));
+  }
+  printf("\n");
+
+  tmpface = *t;
+  facecount = 0;
+  while(facecount < 4) {
+    tmpface.loc = facecount;
+    sym(tmpface, prtface);
+    if (prtface.tet == NULL) {
+      printf("      [%i] Open !!\n", facecount);
+    } else {
+      printf("      [%i] x%lx  loc(%i) ver(%i)", facecount,
+             (unsigned long)(prtface.tet), prtface.loc, prtface.ver);
+      if ((point) prtface.tet[7] == dummypoint) {
+        printf("  (hull tet)");
+      }
+      if (infected(prtface)) {
+        printf(" (infected)");
+      }
+      printf("\n");
+    }
+    facecount++;
+  }
+
+  tmppt = org(*t);
+  if(tmppt == (point) NULL) {
+    printf("      Org [%i] NULL\n", locver2org[t->loc][t->ver]);
+  } else {
+    printf("      Org [%i] x%lx (%.12g,%.12g,%.12g) %d\n",
+           locver2org[t->loc][t->ver], (unsigned long)(tmppt),
+           tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt));
+  }
+  tmppt = dest(*t);
+  if(tmppt == (point) NULL) {
+    printf("      Dest[%i] NULL\n", locver2dest[t->loc][t->ver]);
+  } else {
+    printf("      Dest[%i] x%lx (%.12g,%.12g,%.12g) %d\n",
+           locver2dest[t->loc][t->ver], (unsigned long)(tmppt),
+           tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt));
+  }
+  tmppt = apex(*t);
+  if(tmppt == (point) NULL) {
+    printf("      Apex[%i] NULL\n", locver2apex[t->loc][t->ver]);
+  } else {
+    printf("      Apex[%i] x%lx (%.12g,%.12g,%.12g) %d\n",
+           locver2apex[t->loc][t->ver], (unsigned long)(tmppt),
+           tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt));
+  }
+  tmppt = oppo(*t);
+  if(tmppt == (point) NULL) {
+    printf("      Oppo[%i] NULL\n", loc2oppo[t->loc]);
+  } else {
+    printf("      Oppo[%i] x%lx (%.12g,%.12g,%.12g) %d\n",
+           loc2oppo[t->loc], (unsigned long)(tmppt),
+           tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt));
+  }
+
+  if (checksubsegs) {
+    if (t->tet[8] != NULL) {
+      shells = (shellface *) t->tet[8];
+      for (facecount = 0; facecount < 6; facecount++) {
+        sdecode(shells[facecount], checksh);
+        if (checksh.sh != NULL) {
+          printf("      [%d] x%lx %d.", facecount, (unsigned long) checksh.sh,
+            checksh.shver);
+        } else {
+          printf("      [%d] NULL.", facecount);
+        }
+        if (locver2edge[t->loc][t->ver] == facecount) {
+          printf(" (*)");  // It is the current edge.
+        }
+        printf("\n");
+      }
+    }
+  }
+
+  if (checksubfaces) {
+    if (t->tet[9] != NULL) {
+      shells = (shellface *) t->tet[9];
+      for (facecount = 0; facecount < 4; facecount++) {
+        sdecode(shells[facecount], checksh);
+        if (checksh.sh != NULL) {
+          printf("      [%d] x%lx %d.", facecount, (unsigned long) checksh.sh,
+            checksh.shver);
+        } else {
+          printf("      [%d] NULL.", facecount);
+        }
+        if (t->loc == facecount) {
+          printf(" (*)");  // It is the current face.
+        }
+        printf("\n");
+      }
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Print the detail informations of a shellface.
+
+void tetgenmesh::psh(face *s)
+{
+  face prtsh;
+  triface prttet;
+  point *pt, printpoint;
+  REAL n[3];
+
+  if (s->sh == NULL) {
+    printf("Not a handle.\n");
+    return;
+  }
+
+  if (s->sh[3] == NULL) {
+    printf("A dead subface x%lx.\n", (unsigned long)(s->sh));
+    return;
+  }
+
+  pt = (point *) s->sh;
+  if (s->sh[5] != NULL) {
+    printf("subface x%lx, ver %d, mark %d:\n",(unsigned long)(s->sh),s->shver,
+      getshellmark(*s));
+    facenormal(pt[3], pt[4], pt[5], n, 1);
+    printf("      area %g, edge lengths %g %g %g\n", 0.5 * sqrt(DOT(n, n)),
+      DIST(pt[3], pt[4]), DIST(pt[4], pt[5]), DIST(pt[5], pt[3]));
+  } else {
+    printf("Subsegment x%lx, ver %d, mark %d:\n", (unsigned long)(s->sh),
+      s->shver, getshellmark(*s));
+    printf("      length %g", DIST(pt[3], pt[4]));
+  }
+  if (sinfected(*s)) {
+    printf(" (infected)");
+  }
+  if (smarktested(*s)) {
+    printf(" (marked)");
+  }
+  // if (shell2badface(*sface)) {
+  //   printf(" (queued)");
+  // }
+  // if (checkpbcs) {
+  //   if (shellpbcgroup(*sface) >= 0) {
+  //     printf(" (pbc %d)", shellpbcgroup(*sface));
+  //   }
+  // }
+  printf("\n");
+
+  sdecode(s->sh[0], prtsh);
+  if (prtsh.sh == NULL) {
+    printf("      [0] = No shell\n");
+  } else {
+    printf("      [0] = x%lx  %d\n", (unsigned long)(prtsh.sh), prtsh.shver);
+  }
+  sdecode(s->sh[1], prtsh);
+  if (prtsh.sh == NULL) {
+    printf("      [1] = No shell\n");
+  } else {
+    printf("      [1] = x%lx  %d\n", (unsigned long)(prtsh.sh), prtsh.shver);
+  }
+  sdecode(s->sh[2], prtsh);
+  if (prtsh.sh == NULL) {
+    printf("      [2] = No shell\n");
+  } else {
+    printf("      [2] = x%lx  %d\n", (unsigned long)(prtsh.sh), prtsh.shver);
+  }
+
+  printpoint = sorg(*s);
+  if (printpoint == (point) NULL)
+    printf("      Org [%d] = NULL\n", vo[s->shver]);
+  else
+    printf("      Org [%d] = x%lx  (%.12g,%.12g,%.12g) %d\n",
+           vo[s->shver], (unsigned long)(printpoint), printpoint[0],
+           printpoint[1], printpoint[2], pointmark(printpoint));
+  printpoint = sdest(*s);
+  if (printpoint == (point) NULL)
+    printf("      Dest[%d] = NULL\n", vd[s->shver]);
+  else
+    printf("      Dest[%d] = x%lx  (%.12g,%.12g,%.12g) %d\n",
+           vd[s->shver], (unsigned long)(printpoint), printpoint[0],
+           printpoint[1], printpoint[2], pointmark(printpoint));
+
+  printpoint = sapex(*s);
+  if (printpoint == (point) NULL)
+    printf("      Apex[%d] = NULL\n", va[s->shver]);
+  else
+    printf("      Apex[%d] = x%lx  (%.12g,%.12g,%.12g) %d\n",
+           va[s->shver], (unsigned long)(printpoint), printpoint[0],
+           printpoint[1], printpoint[2], pointmark(printpoint));
+
+  if (s->sh[5] != NULL) {
+    sdecode(s->sh[6], prtsh);
+    if (prtsh.sh == NULL) {
+      printf("      [6] = No subsegment\n");
+    } else {
+      printf("      [6] = x%lx  %d\n", (unsigned long) prtsh.sh, prtsh.shver);
+    }
+    sdecode(s->sh[7], prtsh);
+    if (prtsh.sh == NULL) {
+      printf("      [7] = No subsegment\n");
+    } else {
+      printf("      [7] = x%lx  %d\n", (unsigned long) prtsh.sh, prtsh.shver);
+    }
+    sdecode(s->sh[8], prtsh);
+    if (prtsh.sh == NULL) {
+      printf("      [8] = No subsegment\n");
+    } else {
+      printf("      [8] = x%lx  %d\n", (unsigned long) prtsh.sh, prtsh.shver);
+    }
+  }
+
+  // Print the adjacent tet of this subface or segment.
+  decode(s->sh[9], prttet);
+  if (prttet.tet == NULL) {
+      printf("      [9] = Outer space\n");
+  } else {
+    printf("      [9] = x%lx  (%d, %d, %d, %d)\n",(unsigned long) prttet.tet, 
+      pointmark(org(prttet)), pointmark(dest(prttet)), 
+      pointmark(apex(prttet)), pointmark(oppo(prttet)));
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Find and print the tetrahedron (or face or edge) with the given indices.
+// Do not handle 'dummypoint' (-1).
+
+void tetgenmesh::pteti(int i, int j, int k, int l)
+{
+  triface t;
+  point *pts;
+  int *marklist;
+  int ii;
+
+  marklist = new int[pointpool->items + 1];
+  for (ii = 0; ii < pointpool->items + 1; ii++) marklist[ii] = 0;
+  // Marke the given indices. 
+  marklist[i] = marklist[j] = marklist[k] = marklist[l] = 1;
+
+  t.loc = t.ver = 0;
+  tetrahedronpool->traversalinit();
+  t.tet = tetrahedrontraverse();
+  while (t.tet != NULL) {
+    pts = (point *) t.tet;
+    if (pts[7] != dummypoint) {
+      if ((marklist[pointmark(pts[4])] + marklist[pointmark(pts[5])] +
+           marklist[pointmark(pts[6])] + marklist[pointmark(pts[7])]) == 4) {
+        ptet(&t);  // Find!
+        break;
+      }
+    }
+    t.tet = tetrahedrontraverse();
+  }
+  
+  if (t.tet == NULL) {
+    printf("  !! Not exist.\n");
+  }
+  delete [] marklist;
+}
+
+void tetgenmesh::pface(int i, int j, int k)
+{
+  triface t, t1;
+  point *pts;
+  REAL sign;
+  int *marklist;
+  int ii;
+
+  marklist = new int[pointpool->items + 1];
+  for (ii = 0; ii < pointpool->items + 1; ii++) marklist[ii] = 0;
+  // Marke the given indices. 
+  marklist[i] = marklist[j] = marklist[k] = 1;
+
+  t.ver = t1.ver = 0;
+  tetrahedronpool->traversalinit();
+  t.tet = tetrahedrontraverse();
+  while (t.tet != NULL) {
+    pts = (point *) t.tet;
+    if (pts[7] != dummypoint) {
+      if ((marklist[pointmark(pts[4])] + marklist[pointmark(pts[5])] +
+           marklist[pointmark(pts[6])] + marklist[pointmark(pts[7])]) == 3) {
+        // Find a tet containing the search face.
+        for (t.loc = 0; t.loc < 4; t.loc++) {
+          sym(t, t1);
+          pts = (point *) t1.tet;
+          if ((marklist[pointmark(pts[4])] + marklist[pointmark(pts[5])] +
+              marklist[pointmark(pts[6])] + 
+              (pts[7] != dummypoint ? marklist[pointmark(pts[7])] : 0)) == 3)
+            break;
+        }
+        assert(t.loc < 4);
+        // Now t and t1 share the face.
+        printf("  tet x%lx (%d, %d, %d, %d) %d\n", (unsigned long) t.tet,
+          pointmark(org(t)), pointmark(dest(t)), pointmark(apex(t)), 
+          pointmark(oppo(t)), t.loc);
+        printf("  tet x%lx (%d, %d, %d, %d) %d\n", (unsigned long) t1.tet,
+          pointmark(org(t1)), pointmark(dest(t1)), pointmark(apex(t1)),
+          pointmark(oppo(t1)), t1.loc);
+        if ((point) t1.tet[7] != dummypoint) {
+          pts = (point *) t.tet;
+          sign = insphere(pts[4], pts[5], pts[6], pts[7], oppo(t1));
+          printf("  %s (sign = %.g).\n", sign > 0 ? "Delaunay" :
+            (sign < 0 ? "Non-Delaunay" : "Cosphere"), sign);
+          if (sign == 0) {
+            sign = insphere_sos(pts[4], pts[5], pts[6], pts[7], oppo(t1));
+            printf("  %s (symbolic).\n", sign > 0 ? "Delaunay":"Non-Delaunay");
+          }
+        }
+        break;
+      }
+    }
+    t.tet = tetrahedrontraverse();
+  }
+  
+  if (t.tet == NULL) {
+    printf("  !! Not exist.\n");
+  }
+  delete [] marklist;
+}
+
+bool tetgenmesh::pedge(int i, int j)
+{
+  triface t, t1;
+  face ssub, sseg;
+  int ii;
+
+  t.ver = t1.ver = 0;
+  tetrahedronpool->traversalinit();
+  t.tet = tetrahedrontraverse();
+  while (t.tet != NULL) {
+    for (ii = 0; ii < 6; ii++) {
+      t.loc = edge2locver[ii][0];
+      t.ver = edge2locver[ii][1];
+      if ((pointmark(org(t)) == i && pointmark(dest(t)) == j) ||
+          (pointmark(org(t)) == j && pointmark(dest(t)) == i)) break;
+    }
+    if (ii < 6) {
+      // Now t is the edge (i, j). Find all tets at (i, j).
+      t1 = t;
+      do {
+        printf("  tet x%lx (%d, %d, %d, %d)", (unsigned long) t1.tet,
+          pointmark(org(t1)), pointmark(dest(t1)), pointmark(apex(t1)), 
+          pointmark(oppo(t1)));
+        if (checksubsegs) {
+          tsspivot(t1, sseg);
+          if (sseg.sh != NULL) {
+            printf(" (seg)");
+          }
+        }
+        if (checksubfaces) {
+          tspivot(t1, ssub);
+          if (ssub.sh != NULL) {
+            printf(" (sub)");
+          }
+        } 
+        if (edgemarked(t1)) {
+          printf(" (marked)");
+        }
+        printf("\n");
+        // Go to the next tet.
+        fnextself(t1);
+      } while (t1.tet != t.tet);
+      break;
+    }
+    t.tet = tetrahedrontraverse();
+  }
+  
+  if (t.tet == NULL) {
+    printf("  !! Not exist.\n");
+  }
+  return t.tet != NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Find the subface with indices (i, j, k)
+
+void tetgenmesh::psubface(int i, int j, int k)
+{
+  triface t, t1;
+  face s, s1;
+  point *pts;
+  REAL n[3], sign;
+  int *marklist;
+  int ii;
+
+  void **bakpathblock = subfacepool->pathblock;
+  void *bakpathitem = subfacepool->pathitem;
+  int bakpathitemsleft = subfacepool->pathitemsleft;
+  int bakalignbytes = subfacepool->alignbytes;
+
+  marklist = new int[pointpool->items + 1];
+  for (ii = 0; ii < pointpool->items + 1; ii++) marklist[ii] = 0;
+  // Marke the given indices. 
+  marklist[i] = marklist[j] = marklist[k] = 1;
+
+  s.shver = 0;
+  subfacepool->traversalinit();
+  s.sh = shellfacetraverse(subfacepool);
+  while (s.sh != NULL) {
+    pts = (point *) s.sh;
+    if (pts[3] != NULL) {
+      if ((marklist[pointmark(pts[3])] + marklist[pointmark(pts[4])] +
+           marklist[pointmark(pts[5])]) == 3) {
+        // Found.
+        printf("  sub x%lx (%d, %d, %d) mark=%d\n", (unsigned long) s.sh,
+          pointmark(pts[3]), pointmark(pts[4]), pointmark(pts[5]),
+          getshellmark(s));
+        facenormal(pts[3], pts[4], pts[5], n, 1);
+        printf("    area=%g, lengths: %g, %g, %g\n", 0.5 * sqrt(DOT(n, n)),
+          DIST(pts[3], pts[4]), DIST(pts[4], pts[5]), DIST(pts[5], pts[3]));
+        // Print coplanar adjacent subfaces.
+        s.shver = 0;
+        for (ii = 0; ii < 3; ii++) {
+          sspivot(s, s1);
+          if (s1.sh != NULL) {
+            printf("  seg x%lx (%d, %d)\n", (unsigned long) s1.sh, 
+              pointmark(sorg(s1)), pointmark(sdest(s1)));
+          } else {
+            spivot(s, s1);
+            if (s1.sh != NULL) {
+              printf("  sub x%lx (%d, %d, %d)\n", (unsigned long) s1.sh, 
+          pointmark(sorg(s1)), pointmark(sdest(s1)), pointmark(sapex(s1)));
+            } else {
+              printf("  No seg and sub at (%d, %d)!\n", pointmark(sorg(s)), 
+                pointmark(sdest(s)));
+            }
+          }
+          senextself(s);
+        }
+        stpivot(s, t);
+        if (t.tet != NULL) {
+          // Print two adjacent tets.
+          symedge(t, t1);
+          // Now t and t1 share the face.
+          printf("  tet x%lx (%d, %d, %d, %d) %d\n", (unsigned long) t.tet,
+            pointmark(org(t)), pointmark(dest(t)), pointmark(apex(t)), 
+            pointmark(oppo(t)), t.loc);
+          printf("  tet x%lx (%d, %d, %d, %d) %d\n", (unsigned long) t1.tet,
+            pointmark(org(t1)), pointmark(dest(t1)), pointmark(apex(t1)),
+            pointmark(oppo(t1)), t1.loc);
+          if (((point) t1.tet[7] != dummypoint) && 
+              ((point) t.tet[7] != dummypoint)) {
+            pts = (point *) t.tet;
+            sign = insphere(pts[4], pts[5], pts[6], pts[7], oppo(t1));
+            printf("  %s (sign = %.g).\n", sign > 0 ? "Delaunay" :
+              (sign < 0 ? "Non-Delaunay" : "Cosphere"), sign);
+            if (sign == 0) {
+            sign = insphere_sos(pts[4], pts[5], pts[6], pts[7], oppo(t1));
+            printf("  %s (symbolic).\n", sign > 0 ? "Delaunay":"Non-Delaunay");
+            }
+          }
+        }
+        break;
+      }
+    }
+    s.sh = shellfacetraverse(subfacepool);
+  }
+
+  if (s.sh == NULL) {
+    printf("  !! Not exist.\n");
+  }
+  delete [] marklist;
+
+  subfacepool->pathblock = bakpathblock;
+  subfacepool->pathitem = bakpathitem;
+  subfacepool->pathitemsleft = bakpathitemsleft;
+  subfacepool->alignbytes = bakalignbytes;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Print the information of the subsegment (i, j).
+// Return 1 if seg-to-tet pointer is broken.
+
+int tetgenmesh::psubseg(int i, int j)
+{
+  triface t;
+  face s; //, s1;
+  point forg, fdest;
+  bool bflag;
+
+  bflag = false;
+  s.shver = 0;
+  subsegpool->traversalinit();
+  s.sh = shellfacetraverse(subsegpool);
+  while (s.sh != NULL) {
+    if (pointmark(sorg(s)) == i) {
+      if (pointmark(sdest(s)) == j) {
+        bflag = true;
+      }
+    } else if (pointmark(sorg(s)) == j) {
+      if (pointmark(sdest(s)) == i) {
+        sesymself(s);
+        bflag = true;
+      }
+    }
+    if (bflag) {
+      // Print the original segment containing [i, j]
+      forg = farsorg(s);
+      fdest = farsdest(s);
+      printf("  seg x%lx (%d, %d) < (%d, %d)\n", (unsigned long) s.sh, i, j,
+        pointmark(forg), pointmark(fdest));
+      // Chekc seg-to-tet pointer
+      stpivot(s, t);
+      if (t.tet != NULL) {
+        if (t.tet[4] != NULL) {
+          forg = org(t);
+          fdest = dest(t);
+          if (((pointmark(forg) == i) && (pointmark(fdest) == j)) || 
+              ((pointmark(forg) == j) && (pointmark(fdest) == i))) {
+            printf("  adj tet x%lx (%d, %d, %d, %d)\n", (unsigned long) t.tet,
+              pointmark(forg), pointmark(fdest), pointmark(apex(t)), 
+              pointmark(oppo(t)));
+          } else {
+            printf("  !! Wrong seg-to-tet pointer.\n");
+            return 1;
+          }
+        } else {
+          printf("  !! A DEAD seg-to-tet pointer.\n");
+          return 1;
+        }
+      }
+      /*// Print the adjacent subsegments at i and j.
+      senext2(s, s1);
+      spivotself(s1);
+      if (s1.sh != NULL) {
+        if (sdest(s1) != i) sesymself(s1);
+        printf("  [%d] seg x%lx (%d, %d)\n", i, (unsigned long) s1.sh,
+          pointmark(sorg(s1)), pointmark(sdest(s1))); 
+      } else {
+        printf("  [%d] NULL", i);
+      }
+      senext(s, s1);
+      spivotself(s1);
+      if (s1.sh != NULL) {
+        if (sorg(s1) != j) sesymself(s1);
+        printf("  [%d] seg x%lx (%d, %d)\n", j, (unsigned long) s1.sh,
+          pointmark(sorg(s1)), pointmark(sdest(s1))); 
+      } else {
+        printf("  [%d] NULL", j);
+      }*/
+      break;
+    }
+    s.sh = shellfacetraverse(subsegpool);
+  }
+
+  if (!bflag) {
+    printf("  !! Not exist.\n");
+  }
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Print the index of the point.
+
+int tetgenmesh::pmark(point p)
+{
+  return pointmark(p);
+}
+
+void tetgenmesh::pvert(point pt)
+{
+  triface adjtet;
+  int idx;
+
+  idx = ((int *) (pt))[pointmarkindex];
+  printf("  vertex %d: x%lx\n", idx, (unsigned long) pt);
+  idx = ((int *) (pt))[pointmarkindex + 1];
+  printf("  type: %d (%s infected).\n", idx >> 1, idx & 1 ? " " : "not");
+
+  decode(point2tet(pt), adjtet);
+  if (adjtet.tet != NULL) {
+    printf("  adjtet: x%lx (%d, %d, %d, %d).\n", (unsigned long) adjtet.tet,
+      pointmark(adjtet.tet[4]), pointmark(adjtet.tet[5]),
+      pointmark(adjtet.tet[6]), pointmark(adjtet.tet[7]));
+  } else {
+    printf("  No adjacent tet.\n");
+  }
+}
+
+int tetgenmesh::pverti(int idx)
+{
+  triface adjtet;
+  point pt;
+
+  // Search the vertex.
+  pointpool->traversalinit();
+  pt = pointtraverse();
+  while (pt != NULL) {
+    if (idx == ((int *) (pt))[pointmarkindex]) break;
+    pt = pointtraverse();
+  }
+
+  if (pt == NULL) {
+    printf(" Not exist.\n");
+    return 0;
+  }
+
+  printf("  vertex %d: x%lx\n", idx, (unsigned long) pt);
+  idx = ((int *) (pt))[pointmarkindex + 1];
+  printf("  type: %d (%s infected).\n", idx >> 1, idx & 1 ? " " : "not");
+
+  decode(point2tet(pt), adjtet);
+  if (adjtet.tet == NULL) {
+    printf("  No adjacent tet.\n");
+    return 0;
+  }
+  if (adjtet.tet[4] == NULL) {
+    printf("  !! A DEAD adjacent tet.\n");
+    return 0;
+  }
+  printf("  adjtet: x%lx (%d, %d, %d, %d).\n", (unsigned long) adjtet.tet,
+    pointmark(adjtet.tet[4]), pointmark(adjtet.tet[5]),
+    pointmark(adjtet.tet[6]), pointmark(adjtet.tet[7]));
+
+  if (((point) adjtet.tet[4] == pt) || ((point) adjtet.tet[5] == pt) ||
+      ((point) adjtet.tet[6] == pt) || ((point) adjtet.tet[7] == pt)) {
+    return 0;
+  } else {
+    return 1;  // Bad point-to-tet map.
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Geometrical tests.
+
+REAL tetgenmesh::test_orient3d(int i, int j, int k, int l)
+{
+  point *idx2ptmap;
+  REAL ori;
+  int idx;
+
+  idx = (int) pointpool->items;
+  if ((i > idx) || (j > idx) || (k > idx) || (l > idx)) {
+    printf("Input indices are invalid.\n");
+    return 0;
+  }
+
+  makeindex2pointmap(idx2ptmap);
+  ori = orient3d(idx2ptmap[i], idx2ptmap[j], idx2ptmap[k], idx2ptmap[l]);
+  delete [] idx2ptmap;
+  
+  return ori;
+}
+
+REAL tetgenmesh::test_insphere(int i, int j, int k, int l, int m)
+{
+  point *idx2ptmap;
+  REAL sign;
+  int idx;
+
+  idx = (int) pointpool->items;
+  if ((i > idx) || (j > idx) || (k > idx) || (l > idx) || (m > idx)) {
+    printf("Input indices are invalid.\n");
+    return 0;
+  }
+
+  makeindex2pointmap(idx2ptmap);
+  sign = insphere(idx2ptmap[i], idx2ptmap[j], idx2ptmap[k], idx2ptmap[l],
+                  idx2ptmap[m]);
+  if (sign == 0) {
+    printf("  sign == 0.0! (symbolic perturbed) \n");
+    sign = insphere_sos(idx2ptmap[i], idx2ptmap[j], idx2ptmap[k], idx2ptmap[l],
+                        idx2ptmap[m]);
+  }
+  delete [] idx2ptmap;
+  
+  return sign;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// test_tritri()    Test if two triangles are intersecting.
+
+int tetgenmesh::test_tritri(int a, int b, int c, int p,  int q, int r)
+{
+  point *idx2ptmap;
+  point A, B, C, P, Q, R;
+  enum intersection dir;
+  int ret, types[2], pos[4];
+  int idx, i;
+
+  idx = (int) pointpool->items;
+  if ((a > idx) || (b > idx) || (c > idx) || 
+      (p > idx) || (q > idx) || (r > idx) ||
+      (a<in->firstnumber) || (b<in->firstnumber) || (c<in->firstnumber) || 
+      (p<in->firstnumber) || (q<in->firstnumber) || (r<in->firstnumber)) {
+    printf("Input indices are invalid.\n");
+    return 0;
+  }
+
+  makeindex2pointmap(idx2ptmap);
+  A = idx2ptmap[a];
+  B = idx2ptmap[b];
+  C = idx2ptmap[c];
+  P = idx2ptmap[p];
+  Q = idx2ptmap[q];
+  R = idx2ptmap[r];
+
+  ret = tri_tri_test(A, B, C, P, Q, R, NULL, 1, types, pos);
+
+  // Report the intersection types and positions.
+  for (i = 0; i < 2; i++) {
+    dir = (enum tetgenmesh::intersection) types[i];
+    switch (dir) {
+    case tetgenmesh::DISJOINT: 
+      printf("  DISJOINT\n"); break;
+    case tetgenmesh::SHAREVERT: 
+      printf("  SHAREVERT %d %d\n", pos[i*2], pos[i*2+1]); break;
+    case tetgenmesh::SHAREEDGE: 
+      printf("  SHAREEDGE %d %d\n", pos[i*2], pos[i*2+1]); break;
+    case tetgenmesh::SHAREFACE: 
+      printf("  SHAREFACE\n"); break;
+    case tetgenmesh::TOUCHEDGE: 
+      printf("  TOUCHEDGE %d %d\n", pos[i*2], pos[i*2+1]); break;
+    case tetgenmesh::TOUCHFACE: 
+      printf("  TOUCHFACE %d %d\n", pos[i*2], pos[i*2+1]); break;
+    case tetgenmesh::ACROSSVERT: 
+      printf("  ACROSSVERT %d %d\n", pos[i*2], pos[i*2+1]); break;
+    case tetgenmesh::ACROSSEDGE: 
+      printf("  ACROSSEDGE %d %d\n", pos[i*2], pos[i*2+1]); break;
+    case tetgenmesh::ACROSSFACE: 
+      printf("  ACROSSFACE %d %d\n", pos[i*2], pos[i*2+1]); break;
+    case tetgenmesh::ACROSSTET: 
+      printf("  ACROSSTET\n"); break;
+    case tetgenmesh::TRIEDGEINT:
+      printf("  TRIEDGEINT %d %d\n", pos[i*2], pos[i*2+1]); break;
+    case tetgenmesh::EDGETRIINT:
+      printf("  EDGETRIINT %d %d\n", pos[i*2], pos[i*2+1]); break;
+    }
+  }
+
+  delete [] idx2ptmap;
+  return ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Print an array of tetrahedra (in draw command)
+
+void tetgenmesh::print_cavebdrylist()
+{
+  FILE *fout;
+  triface *cavetet;
+  int i;
+
+  printf("  Dump %ld faces to dump_cavebdry.lua.\n", cavebdrylist->objects);
+
+  fout = fopen("dump_cavebdry.lua", "w");
+  for (i = 0; i < cavebdrylist->objects; i++) {
+    cavetet = (triface *) fastlookup(cavebdrylist, i);
+    fprintf(fout, "p:draw_subface(%d, %d, %d) -- %d\n", 
+      pointmark(org(*cavetet)), pointmark(dest(*cavetet)), 
+      pointmark(apex(*cavetet)), i);
+  }
+  fclose(fout);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Print current faces in flipstack (in draw command)
+
+void tetgenmesh::print_flipstack()
+{
+  badface *traveface;
+  int i;
+
+  traveface = futureflip; 
+  i = 0;
+  while (traveface != NULL) {
+    if (traveface->tt.tet[4] != NULL) {
+      printf("%2d  (%d, %d, %d, %d) - %d\n",i+1,pointmark(org(traveface->tt)),
+        pointmark(dest(traveface->tt)), pointmark(apex(traveface->tt)),
+        pointmark(oppo(traveface->tt)), pointmark(traveface->foppo));
+    }
+    traveface = traveface->nextitem;
+    i++;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Print an array of tetrahedra, faces, subfaces (in draw command)
+// If 'nohulltet' is TRUE, ignore hull tets.
+
+void tetgenmesh::print_tetarray(arraypool *tetarray, bool nohulltet)
+{
+  triface *parytet;
+  int i;
+
+  for (i = 0; i < tetarray->objects; i++) {
+    parytet = (triface *) fastlookup(tetarray, i);
+    if (parytet->tet == NULL) {
+      printf("-- NOT A TET -- %d\n", i + 1); continue;
+    }
+    if (nohulltet) {
+      if ((point) parytet->tet[7] == dummypoint) continue;
+    }
+    if (parytet->tet[4] == NULL) {
+      printf("-- A DEAD TET -- %d\n", i + 1); continue;
+    }
+    if ((point) parytet->tet[7] != dummypoint) {
+      printf("p:draw_tet(%d, %d, %d, %d) -- %d", 
+        pointmark(org(*parytet)), pointmark(dest(*parytet)),
+        pointmark(apex(*parytet)), pointmark(oppo(*parytet)), i + 1);
+    } else {
+      printf("-- p:draw_tet(%d, %d, %d, %d) -- %d (hulltet)", 
+        pointmark(org(*parytet)), pointmark(dest(*parytet)),
+        pointmark(apex(*parytet)), pointmark(oppo(*parytet)), i + 1);
+    }
+    if (marktested(*parytet)) {
+      printf(" (marked)");
+    }
+    if (infected(*parytet)) {
+      printf(" (infect)");
+    }
+    printf("\n");
+  }
+}
+
+void tetgenmesh::print_facearray(arraypool *facearray)
+{
+  triface *parytet;
+  int i;
+
+  for (i = 0; i < facearray->objects; i++) {
+    parytet = (triface *) fastlookup(facearray, i);
+    printf("p:draw_subface(%d, %d, %d) -- %d\n", 
+      pointmark(org(*parytet)), pointmark(dest(*parytet)),
+      pointmark(apex(*parytet)), i + 1);
+  }
+}
+
+void tetgenmesh::print_subfacearray(arraypool *subfacearray)
+{
+  face *parysub;
+  int i;
+
+  for (i = 0; i < subfacearray->objects; i++) {
+    parysub = (face *) fastlookup(subfacearray, i);
+    printf("p:draw_subface(%d, %d, %d) -- %d\n", 
+      pointmark(sorg(*parysub)), pointmark(sdest(*parysub)),
+      pointmark(sapex(*parysub)), i + 1);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// dump the boundary faces of a cavity into file "cavity.lua"
+// 'topfaces' and 'botfaces' are two arrays. 
+// NOTE: hull tets may be included.
+
+void tetgenmesh::dump_cavity(arraypool *topfaces, arraypool *botfaces = NULL)
+{
+  FILE *fout;
+  arraypool *cavfaces;
+  triface *paryface;
+  int i, k;
+
+  printf("  dump %ld topfaces to cavity.lua\n", topfaces->objects);
+  if (botfaces != NULL) {
+    printf("  dump %ld botfaces to cavity.lua\n", botfaces->objects);
+  }
+  fout = fopen("cavity.lua", "w");
+
+  for (k = 0; k < 2; k++) {
+    cavfaces = (k == 0 ? topfaces : botfaces);
+    if (cavfaces != NULL) {
+      for (i = 0; i < cavfaces->objects; i++) {
+        paryface = (triface *) fastlookup(cavfaces, i);
+        fprintf(fout, "p:draw_subface(%d, %d, %d) -- %d\n", 
+          pointmark(org(*paryface)), pointmark(dest(*paryface)),
+          pointmark(apex(*paryface)), i + 1);
+      }
+    }
+  }
+
+  fclose(fout);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// dump a facet containing a given subface s.
+
+void tetgenmesh::dump_facetof(face *pssub, char *filename)
+{
+  FILE *fout;
+  char outfilename[256];
+  arraypool *tmpfaces;
+  face *parysh, *parysh2, s;
+  face checkseg;
+  int ii, jj;
+
+  tmpfaces = new arraypool(sizeof(face), 8);
+
+  smarktest(*pssub);
+  tmpfaces->newindex((void **) &parysh);
+  *parysh = *pssub;
+
+  for (ii = 0; ii < tmpfaces->objects; ii++) {
+    parysh = (face *) fastlookup(tmpfaces, ii);
+    for (jj = 0; jj < 3; jj++) {
+      sspivot(*parysh, checkseg);
+      if (checkseg.sh == NULL) {
+        spivot(*parysh, s);
+        if (s.sh != NULL) {
+          if (!smarktested(s)) {
+            smarktest(s);
+            tmpfaces->newindex((void **) &parysh2);
+            *parysh2 = s;
+          }
+        }
+      }
+      senextself(*parysh);
+    }
+  }
+
+  for (ii = 0; ii < tmpfaces->objects; ii++) {
+    parysh = (face *) fastlookup(tmpfaces, ii);
+    sunmarktest(*parysh);
+  }
+
+  if (filename != NULL) {
+    sprintf(outfilename, filename);
+  } else {
+    sprintf(outfilename, "facet.lua");
+  }
+
+  printf("  dump %ld subfaces to %s\n", tmpfaces->objects, outfilename);
+  fout = fopen(outfilename, "w");
+
+  for (ii = 0; ii < tmpfaces->objects; ii++) {
+    parysh = (face *) fastlookup(tmpfaces, ii);
+    fprintf(fout, "p:draw_subface(%d, %d, %d) -- %d\n", 
+      pointmark(sorg(*parysh)), pointmark(sdest(*parysh)),
+      pointmark(sapex(*parysh)), ii + 1);
+  }
+
+  fclose(fout);
+
+  delete tmpfaces;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Dump the new tets of a cavity (in draw_tet() lua commands)
+
+void tetgenmesh::dump_cavitynewtets()
+{
+  arraypool *newtets;
+  triface searchtet, neightet, *parytet;
+  point *ppt;
+  int i;
+
+  newtets = new arraypool(sizeof(triface), 8);
+
+  // Collect all tets of the DT.
+  marktest(recenttet);
+  newtets->newindex((void **) &parytet);
+  *parytet = recenttet;
+  for (i = 0; i < newtets->objects; i++) {
+    searchtet = * (triface *) fastlookup(newtets, i);
+    for (searchtet.loc = 0; searchtet.loc < 4; searchtet.loc++) {
+      sym(searchtet, neightet);
+      if (!marktested(neightet)) {
+        marktest(neightet);
+        newtets->newindex((void **) &parytet);
+        *parytet = neightet;
+      }
+    }
+  }
+  // Comment: All new tets are marktested.
+
+  // Output the new tets.
+  for (i = 0; i < newtets->objects; i++) {
+    parytet = (triface *) fastlookup(newtets, i);
+    ppt = (point *) parytet->tet;
+    if (ppt[7] != dummypoint) {
+      printf("p:draw_tet(%d, %d, %d, %d) -- %i\n", pointmark(ppt[4]),
+        pointmark(ppt[5]), pointmark(ppt[6]), pointmark(ppt[7]), i);
+    } else {
+      printf("-- p:draw_tet(%d, %d, %d, -1) -- %i\n", pointmark(ppt[4]),
+        pointmark(ppt[5]), pointmark(ppt[6]), i);
+    }
+    unmarktest(*parytet); // Unmarktest it.
+  }
+
+  delete newtets;
+}
+
+#endif // #ifndef meshstatCXX
\ No newline at end of file
diff --git a/contrib/TetgenNew/predicates.cxx b/contrib/TetgenNew/predicates.cxx
new file mode 100644
index 0000000000..bc0bd39f9e
--- /dev/null
+++ b/contrib/TetgenNew/predicates.cxx
@@ -0,0 +1,4187 @@
+/*****************************************************************************/
+/*                                                                           */
+/*  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 <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#ifdef CPU86
+#include <float.h>
+#endif /* CPU86 */
+#ifdef LINUX
+#include <fpu_control.h>
+#endif /* LINUX */
+
+#include "tetgen.h"            // Defines the symbol REAL (float or double).
+
+/* 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 */
+
+/* #define REAL double */                      /* float or double */
+#define REALPRINT doubleprint
+#define REALRAND doublerand
+#define NARROWRAND narrowdoublerand
+#define UNIFORMRAND uniformdoublerand
+
+/* 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)
+
+/* splitter = 2^ceiling(p / 2) + 1.  Used to split floats in half.           */
+static REAL splitter;
+static REAL epsilon;         /* = 2^(-p).  Used to estimate roundoff errors. */
+/* A set of coefficients used to calculate maximum roundoff errors.          */
+static REAL resulterrbound;
+static REAL ccwerrboundA, ccwerrboundB, ccwerrboundC;
+static REAL o3derrboundA, o3derrboundB, o3derrboundC;
+static REAL iccerrboundA, iccerrboundB, iccerrboundC;
+static REAL isperrboundA, isperrboundB, isperrboundC;
+
+/*****************************************************************************/
+/*                                                                           */
+/*  doubleprint()   Print the bit representation of a double.                */
+/*                                                                           */
+/*  Useful for debugging exact arithmetic routines.                          */
+/*                                                                           */
+/*****************************************************************************/
+
+/*
+void doubleprint(number)
+double number;
+{
+  unsigned long long no;
+  unsigned long long sign, expo;
+  int exponent;
+  int i, bottomi;
+
+  no = *(unsigned long long *) &number;
+  sign = no & 0x8000000000000000ll;
+  expo = (no >> 52) & 0x7ffll;
+  exponent = (int) expo;
+  exponent = exponent - 1023;
+  if (sign) {
+    printf("-");
+  } else {
+    printf(" ");
+  }
+  if (exponent == -1023) {
+    printf(
+      "0.0000000000000000000000000000000000000000000000000000_     (   )");
+  } else {
+    printf("1.");
+    bottomi = -1;
+    for (i = 0; i < 52; i++) {
+      if (no & 0x0008000000000000ll) {
+        printf("1");
+        bottomi = i;
+      } else {
+        printf("0");
+      }
+      no <<= 1;
+    }
+    printf("_%d  (%d)", exponent, exponent - 1 - bottomi);
+  }
+}
+*/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  floatprint()   Print the bit representation of a float.                  */
+/*                                                                           */
+/*  Useful for debugging exact arithmetic routines.                          */
+/*                                                                           */
+/*****************************************************************************/
+
+/*
+void floatprint(number)
+float number;
+{
+  unsigned no;
+  unsigned sign, expo;
+  int exponent;
+  int i, bottomi;
+
+  no = *(unsigned *) &number;
+  sign = no & 0x80000000;
+  expo = (no >> 23) & 0xff;
+  exponent = (int) expo;
+  exponent = exponent - 127;
+  if (sign) {
+    printf("-");
+  } else {
+    printf(" ");
+  }
+  if (exponent == -127) {
+    printf("0.00000000000000000000000_     (   )");
+  } else {
+    printf("1.");
+    bottomi = -1;
+    for (i = 0; i < 23; i++) {
+      if (no & 0x00400000) {
+        printf("1");
+        bottomi = i;
+      } else {
+        printf("0");
+      }
+      no <<= 1;
+    }
+    printf("_%3d  (%3d)", exponent, exponent - 1 - bottomi);
+  }
+}
+*/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  expansion_print()   Print the bit representation of an expansion.        */
+/*                                                                           */
+/*  Useful for debugging exact arithmetic routines.                          */
+/*                                                                           */
+/*****************************************************************************/
+
+/*
+void expansion_print(elen, e)
+int elen;
+REAL *e;
+{
+  int i;
+
+  for (i = elen - 1; i >= 0; i--) {
+    REALPRINT(e[i]);
+    if (i > 0) {
+      printf(" +\n");
+    } else {
+      printf("\n");
+    }
+  }
+}
+*/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  doublerand()   Generate a double with random 53-bit significand and a    */
+/*                 random exponent in [0, 511].                              */
+/*                                                                           */
+/*****************************************************************************/
+
+/*
+double doublerand()
+{
+  double result;
+  double expo;
+  long a, b, c;
+  long i;
+
+  a = random();
+  b = random();
+  c = random();
+  result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8);
+  for (i = 512, expo = 2; i <= 131072; i *= 2, expo = expo * expo) {
+    if (c & i) {
+      result *= expo;
+    }
+  }
+  return result;
+}
+*/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  narrowdoublerand()   Generate a double with random 53-bit significand    */
+/*                       and a random exponent in [0, 7].                    */
+/*                                                                           */
+/*****************************************************************************/
+
+/*
+double narrowdoublerand()
+{
+  double result;
+  double expo;
+  long a, b, c;
+  long i;
+
+  a = random();
+  b = random();
+  c = random();
+  result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8);
+  for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) {
+    if (c & i) {
+      result *= expo;
+    }
+  }
+  return result;
+}
+*/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  uniformdoublerand()   Generate a double with random 53-bit significand.  */
+/*                                                                           */
+/*****************************************************************************/
+
+/*
+double uniformdoublerand()
+{
+  double result;
+  long a, b;
+
+  a = random();
+  b = random();
+  result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8);
+  return result;
+}
+*/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  floatrand()   Generate a float with random 24-bit significand and a      */
+/*                random exponent in [0, 63].                                */
+/*                                                                           */
+/*****************************************************************************/
+
+/*
+float floatrand()
+{
+  float result;
+  float expo;
+  long a, c;
+  long i;
+
+  a = random();
+  c = random();
+  result = (float) ((a - 1073741824) >> 6);
+  for (i = 512, expo = 2; i <= 16384; i *= 2, expo = expo * expo) {
+    if (c & i) {
+      result *= expo;
+    }
+  }
+  return result;
+}
+*/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  narrowfloatrand()   Generate a float with random 24-bit significand and  */
+/*                      a random exponent in [0, 7].                         */
+/*                                                                           */
+/*****************************************************************************/
+
+/*
+float narrowfloatrand()
+{
+  float result;
+  float expo;
+  long a, c;
+  long i;
+
+  a = random();
+  c = random();
+  result = (float) ((a - 1073741824) >> 6);
+  for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) {
+    if (c & i) {
+      result *= expo;
+    }
+  }
+  return result;
+}
+*/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  uniformfloatrand()   Generate a float with random 24-bit significand.    */
+/*                                                                           */
+/*****************************************************************************/
+
+/*
+float uniformfloatrand()
+{
+  float result;
+  long a;
+
+  a = random();
+  result = (float) ((a - 1073741824) >> 6);
+  return result;
+}
+*/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  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.                */
+/*                                                                           */
+/*****************************************************************************/
+
+REAL exactinit()
+{
+  REAL half;
+  REAL check, lastcheck;
+  int every_other;
+#ifdef LINUX
+  int cword;
+#endif /* LINUX */
+
+#ifdef CPU86
+#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 /* CPU86 */
+#ifdef LINUX
+#ifdef SINGLE
+  /*  cword = 4223; */
+  cword = 4210;                 /* set FPU control word for single precision */
+#else /* not SINGLE */
+  /*  cword = 4735; */
+  cword = 4722;                 /* set FPU control word for double precision */
+#endif /* not SINGLE */
+  _FPU_SETCW(cword);
+#endif /* LINUX */
+
+  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;
+
+  return epsilon; /* Added by H. Si 30 Juli, 2004. */
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  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;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  orient2dfast()   Approximate 2D orientation test.  Nonrobust.            */
+/*  orient2dexact()   Exact 2D orientation test.  Robust.                    */
+/*  orient2dslow()   Another exact 2D orientation test.  Robust.             */
+/*  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.           */
+/*                                                                           */
+/*  Only the first and last routine should be used; the middle two are for   */
+/*  timings.                                                                 */
+/*                                                                           */
+/*  The last three 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 orient2dfast(REAL *pa, REAL *pb, REAL *pc)
+{
+  REAL acx, bcx, acy, bcy;
+
+  acx = pa[0] - pc[0];
+  bcx = pb[0] - pc[0];
+  acy = pa[1] - pc[1];
+  bcy = pb[1] - pc[1];
+  return acx * bcy - acy * bcx;
+}
+
+REAL orient2dexact(REAL *pa, REAL *pb, REAL *pc)
+{
+  INEXACT REAL axby1, axcy1, bxcy1, bxay1, cxay1, cxby1;
+  REAL axby0, axcy0, bxcy0, bxay0, cxay0, cxby0;
+  REAL aterms[4], bterms[4], cterms[4];
+  INEXACT REAL aterms3, bterms3, cterms3;
+  REAL v[8], w[12];
+  int vlength, wlength;
+
+  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(pa[0], pc[1], axcy1, axcy0);
+  Two_Two_Diff(axby1, axby0, axcy1, axcy0,
+               aterms3, aterms[2], aterms[1], aterms[0]);
+  aterms[3] = aterms3;
+
+  Two_Product(pb[0], pc[1], bxcy1, bxcy0);
+  Two_Product(pb[0], pa[1], bxay1, bxay0);
+  Two_Two_Diff(bxcy1, bxcy0, bxay1, bxay0,
+               bterms3, bterms[2], bterms[1], bterms[0]);
+  bterms[3] = bterms3;
+
+  Two_Product(pc[0], pa[1], cxay1, cxay0);
+  Two_Product(pc[0], pb[1], cxby1, cxby0);
+  Two_Two_Diff(cxay1, cxay0, cxby1, cxby0,
+               cterms3, cterms[2], cterms[1], cterms[0]);
+  cterms[3] = cterms3;
+
+  vlength = fast_expansion_sum_zeroelim(4, aterms, 4, bterms, v);
+  wlength = fast_expansion_sum_zeroelim(vlength, v, 4, cterms, w);
+
+  return w[wlength - 1];
+}
+
+REAL orient2dslow(REAL *pa, REAL *pb, REAL *pc)
+{
+  INEXACT REAL acx, acy, bcx, bcy;
+  REAL acxtail, acytail;
+  REAL bcxtail, bcytail;
+  REAL negate, negatetail;
+  REAL axby[8], bxay[8];
+  INEXACT REAL axby7, bxay7;
+  REAL deter[16];
+  int deterlen;
+
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+  INEXACT REAL c;
+  INEXACT REAL abig;
+  REAL a0hi, a0lo, a1hi, a1lo, bhi, blo;
+  REAL err1, err2, err3;
+  INEXACT REAL _i, _j, _k, _l, _m, _n;
+  REAL _0, _1, _2;
+
+  Two_Diff(pa[0], pc[0], acx, acxtail);
+  Two_Diff(pa[1], pc[1], acy, acytail);
+  Two_Diff(pb[0], pc[0], bcx, bcxtail);
+  Two_Diff(pb[1], pc[1], bcy, bcytail);
+
+  Two_Two_Product(acx, acxtail, bcy, bcytail,
+                  axby7, axby[6], axby[5], axby[4],
+                  axby[3], axby[2], axby[1], axby[0]);
+  axby[7] = axby7;
+  negate = -acy;
+  negatetail = -acytail;
+  Two_Two_Product(bcx, bcxtail, negate, negatetail,
+                  bxay7, bxay[6], bxay[5], bxay[4],
+                  bxay[3], bxay[2], bxay[1], bxay[0]);
+  bxay[7] = bxay7;
+
+  deterlen = fast_expansion_sum_zeroelim(8, axby, 8, bxay, deter);
+
+  return deter[deterlen - 1];
+}
+
+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);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  orient3dfast()   Approximate 3D orientation test.  Nonrobust.            */
+/*  orient3dexact()   Exact 3D orientation test.  Robust.                    */
+/*  orient3dslow()   Another exact 3D orientation test.  Robust.             */
+/*  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.                                                */
+/*                                                                           */
+/*  Only the first and last routine should be used; the middle two are for   */
+/*  timings.                                                                 */
+/*                                                                           */
+/*  The last three 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 orient3dfast(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
+{
+  REAL adx, bdx, cdx;
+  REAL ady, bdy, cdy;
+  REAL adz, bdz, cdz;
+
+  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];
+
+  return adx * (bdy * cdz - bdz * cdy)
+       + bdx * (cdy * adz - cdz * ady)
+       + cdx * (ady * bdz - adz * bdy);
+}
+
+REAL orient3dexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
+{
+  INEXACT REAL axby1, bxcy1, cxdy1, dxay1, axcy1, bxdy1;
+  INEXACT REAL bxay1, cxby1, dxcy1, axdy1, cxay1, dxby1;
+  REAL axby0, bxcy0, cxdy0, dxay0, axcy0, bxdy0;
+  REAL bxay0, cxby0, dxcy0, axdy0, cxay0, dxby0;
+  REAL ab[4], bc[4], cd[4], da[4], ac[4], bd[4];
+  REAL temp8[8];
+  int templen;
+  REAL abc[12], bcd[12], cda[12], dab[12];
+  int abclen, bcdlen, cdalen, dablen;
+  REAL adet[24], bdet[24], cdet[24], ddet[24];
+  int alen, blen, clen, dlen;
+  REAL abdet[48], cddet[48];
+  int ablen, cdlen;
+  REAL deter[96];
+  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], 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(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]);
+
+  templen = fast_expansion_sum_zeroelim(4, cd, 4, da, temp8);
+  cdalen = fast_expansion_sum_zeroelim(templen, temp8, 4, ac, cda);
+  templen = fast_expansion_sum_zeroelim(4, da, 4, ab, temp8);
+  dablen = fast_expansion_sum_zeroelim(templen, temp8, 4, bd, dab);
+  for (i = 0; i < 4; i++) {
+    bd[i] = -bd[i];
+    ac[i] = -ac[i];
+  }
+  templen = fast_expansion_sum_zeroelim(4, ab, 4, bc, temp8);
+  abclen = fast_expansion_sum_zeroelim(templen, temp8, 4, ac, abc);
+  templen = fast_expansion_sum_zeroelim(4, bc, 4, cd, temp8);
+  bcdlen = fast_expansion_sum_zeroelim(templen, temp8, 4, bd, bcd);
+
+  alen = scale_expansion_zeroelim(bcdlen, bcd, pa[2], adet);
+  blen = scale_expansion_zeroelim(cdalen, cda, -pb[2], bdet);
+  clen = scale_expansion_zeroelim(dablen, dab, pc[2], cdet);
+  dlen = scale_expansion_zeroelim(abclen, abc, -pd[2], ddet);
+
+  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
+  cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet);
+  deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, deter);
+
+  return deter[deterlen - 1];
+}
+
+REAL orient3dslow(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
+{
+  INEXACT REAL adx, ady, adz, bdx, bdy, bdz, cdx, cdy, cdz;
+  REAL adxtail, adytail, adztail;
+  REAL bdxtail, bdytail, bdztail;
+  REAL cdxtail, cdytail, cdztail;
+  REAL negate, negatetail;
+  INEXACT REAL axby7, bxcy7, axcy7, bxay7, cxby7, cxay7;
+  REAL axby[8], bxcy[8], axcy[8], bxay[8], cxby[8], cxay[8];
+  REAL temp16[16], temp32[32], temp32t[32];
+  int temp16len, temp32len, temp32tlen;
+  REAL adet[64], bdet[64], cdet[64];
+  int alen, blen, clen;
+  REAL abdet[128];
+  int ablen;
+  REAL deter[192];
+  int deterlen;
+
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+  INEXACT REAL c;
+  INEXACT REAL abig;
+  REAL a0hi, a0lo, a1hi, a1lo, bhi, blo;
+  REAL err1, err2, err3;
+  INEXACT REAL _i, _j, _k, _l, _m, _n;
+  REAL _0, _1, _2;
+
+  Two_Diff(pa[0], pd[0], adx, adxtail);
+  Two_Diff(pa[1], pd[1], ady, adytail);
+  Two_Diff(pa[2], pd[2], adz, adztail);
+  Two_Diff(pb[0], pd[0], bdx, bdxtail);
+  Two_Diff(pb[1], pd[1], bdy, bdytail);
+  Two_Diff(pb[2], pd[2], bdz, bdztail);
+  Two_Diff(pc[0], pd[0], cdx, cdxtail);
+  Two_Diff(pc[1], pd[1], cdy, cdytail);
+  Two_Diff(pc[2], pd[2], cdz, cdztail);
+
+  Two_Two_Product(adx, adxtail, bdy, bdytail,
+                  axby7, axby[6], axby[5], axby[4],
+                  axby[3], axby[2], axby[1], axby[0]);
+  axby[7] = axby7;
+  negate = -ady;
+  negatetail = -adytail;
+  Two_Two_Product(bdx, bdxtail, negate, negatetail,
+                  bxay7, bxay[6], bxay[5], bxay[4],
+                  bxay[3], bxay[2], bxay[1], bxay[0]);
+  bxay[7] = bxay7;
+  Two_Two_Product(bdx, bdxtail, cdy, cdytail,
+                  bxcy7, bxcy[6], bxcy[5], bxcy[4],
+                  bxcy[3], bxcy[2], bxcy[1], bxcy[0]);
+  bxcy[7] = bxcy7;
+  negate = -bdy;
+  negatetail = -bdytail;
+  Two_Two_Product(cdx, cdxtail, negate, negatetail,
+                  cxby7, cxby[6], cxby[5], cxby[4],
+                  cxby[3], cxby[2], cxby[1], cxby[0]);
+  cxby[7] = cxby7;
+  Two_Two_Product(cdx, cdxtail, ady, adytail,
+                  cxay7, cxay[6], cxay[5], cxay[4],
+                  cxay[3], cxay[2], cxay[1], cxay[0]);
+  cxay[7] = cxay7;
+  negate = -cdy;
+  negatetail = -cdytail;
+  Two_Two_Product(adx, adxtail, negate, negatetail,
+                  axcy7, axcy[6], axcy[5], axcy[4],
+                  axcy[3], axcy[2], axcy[1], axcy[0]);
+  axcy[7] = axcy7;
+
+  temp16len = fast_expansion_sum_zeroelim(8, bxcy, 8, cxby, temp16);
+  temp32len = scale_expansion_zeroelim(temp16len, temp16, adz, temp32);
+  temp32tlen = scale_expansion_zeroelim(temp16len, temp16, adztail, temp32t);
+  alen = fast_expansion_sum_zeroelim(temp32len, temp32, temp32tlen, temp32t,
+                                     adet);
+
+  temp16len = fast_expansion_sum_zeroelim(8, cxay, 8, axcy, temp16);
+  temp32len = scale_expansion_zeroelim(temp16len, temp16, bdz, temp32);
+  temp32tlen = scale_expansion_zeroelim(temp16len, temp16, bdztail, temp32t);
+  blen = fast_expansion_sum_zeroelim(temp32len, temp32, temp32tlen, temp32t,
+                                     bdet);
+
+  temp16len = fast_expansion_sum_zeroelim(8, axby, 8, bxay, temp16);
+  temp32len = scale_expansion_zeroelim(temp16len, temp16, cdz, temp32);
+  temp32tlen = scale_expansion_zeroelim(temp16len, temp16, cdztail, temp32t);
+  clen = fast_expansion_sum_zeroelim(temp32len, temp32, temp32tlen, temp32t,
+                                     cdet);
+
+  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
+  deterlen = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, deter);
+
+  return deter[deterlen - 1];
+}
+
+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;
+
+  ////////////////////////////////////////////////////////
+  // To avoid uninitialized warnings reported by valgrind.
+  int i;
+  for (i = 0; i < 8; i++) {
+    adet[i] = bdet[i] = cdet[i] = 0.0;
+  }
+  for (i = 0; i < 16; i++) {
+    abdet[i] = 0.0;
+  }
+  ////////////////////////////////////////////////////////
+
+  REAL adxtail, bdxtail, cdxtail;
+  REAL adytail, bdytail, cdytail;
+  REAL adztail, bdztail, cdztail;
+  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);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  incirclefast()   Approximate 2D incircle test.  Nonrobust.               */
+/*  incircleexact()   Exact 2D incircle test.  Robust.                       */
+/*  incircleslow()   Another exact 2D incircle test.  Robust.                */
+/*  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.          */
+/*                                                                           */
+/*  Only the first and last routine should be used; the middle two are for   */
+/*  timings.                                                                 */
+/*                                                                           */
+/*  The last three 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 incirclefast(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
+{
+  REAL adx, ady, bdx, bdy, cdx, cdy;
+  REAL abdet, bcdet, cadet;
+  REAL alift, blift, clift;
+
+  adx = pa[0] - pd[0];
+  ady = pa[1] - pd[1];
+  bdx = pb[0] - pd[0];
+  bdy = pb[1] - pd[1];
+  cdx = pc[0] - pd[0];
+  cdy = pc[1] - pd[1];
+
+  abdet = adx * bdy - bdx * ady;
+  bcdet = bdx * cdy - cdx * bdy;
+  cadet = cdx * ady - adx * cdy;
+  alift = adx * adx + ady * ady;
+  blift = bdx * bdx + bdy * bdy;
+  clift = cdx * cdx + cdy * cdy;
+
+  return alift * bcdet + blift * cadet + clift * abdet;
+}
+
+REAL incircleexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
+{
+  INEXACT REAL axby1, bxcy1, cxdy1, dxay1, axcy1, bxdy1;
+  INEXACT REAL bxay1, cxby1, dxcy1, axdy1, cxay1, dxby1;
+  REAL axby0, bxcy0, cxdy0, dxay0, axcy0, bxdy0;
+  REAL bxay0, cxby0, dxcy0, axdy0, cxay0, dxby0;
+  REAL ab[4], bc[4], cd[4], da[4], ac[4], bd[4];
+  REAL temp8[8];
+  int templen;
+  REAL abc[12], bcd[12], cda[12], dab[12];
+  int abclen, bcdlen, cdalen, dablen;
+  REAL det24x[24], det24y[24], det48x[48], det48y[48];
+  int xlen, ylen;
+  REAL adet[96], bdet[96], cdet[96], ddet[96];
+  int alen, blen, clen, dlen;
+  REAL abdet[192], cddet[192];
+  int ablen, cdlen;
+  REAL deter[384];
+  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], 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(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]);
+
+  templen = fast_expansion_sum_zeroelim(4, cd, 4, da, temp8);
+  cdalen = fast_expansion_sum_zeroelim(templen, temp8, 4, ac, cda);
+  templen = fast_expansion_sum_zeroelim(4, da, 4, ab, temp8);
+  dablen = fast_expansion_sum_zeroelim(templen, temp8, 4, bd, dab);
+  for (i = 0; i < 4; i++) {
+    bd[i] = -bd[i];
+    ac[i] = -ac[i];
+  }
+  templen = fast_expansion_sum_zeroelim(4, ab, 4, bc, temp8);
+  abclen = fast_expansion_sum_zeroelim(templen, temp8, 4, ac, abc);
+  templen = fast_expansion_sum_zeroelim(4, bc, 4, cd, temp8);
+  bcdlen = fast_expansion_sum_zeroelim(templen, temp8, 4, bd, bcd);
+
+  xlen = scale_expansion_zeroelim(bcdlen, bcd, pa[0], det24x);
+  xlen = scale_expansion_zeroelim(xlen, det24x, pa[0], det48x);
+  ylen = scale_expansion_zeroelim(bcdlen, bcd, pa[1], det24y);
+  ylen = scale_expansion_zeroelim(ylen, det24y, pa[1], det48y);
+  alen = fast_expansion_sum_zeroelim(xlen, det48x, ylen, det48y, adet);
+
+  xlen = scale_expansion_zeroelim(cdalen, cda, pb[0], det24x);
+  xlen = scale_expansion_zeroelim(xlen, det24x, -pb[0], det48x);
+  ylen = scale_expansion_zeroelim(cdalen, cda, pb[1], det24y);
+  ylen = scale_expansion_zeroelim(ylen, det24y, -pb[1], det48y);
+  blen = fast_expansion_sum_zeroelim(xlen, det48x, ylen, det48y, bdet);
+
+  xlen = scale_expansion_zeroelim(dablen, dab, pc[0], det24x);
+  xlen = scale_expansion_zeroelim(xlen, det24x, pc[0], det48x);
+  ylen = scale_expansion_zeroelim(dablen, dab, pc[1], det24y);
+  ylen = scale_expansion_zeroelim(ylen, det24y, pc[1], det48y);
+  clen = fast_expansion_sum_zeroelim(xlen, det48x, ylen, det48y, cdet);
+
+  xlen = scale_expansion_zeroelim(abclen, abc, pd[0], det24x);
+  xlen = scale_expansion_zeroelim(xlen, det24x, -pd[0], det48x);
+  ylen = scale_expansion_zeroelim(abclen, abc, pd[1], det24y);
+  ylen = scale_expansion_zeroelim(ylen, det24y, -pd[1], det48y);
+  dlen = fast_expansion_sum_zeroelim(xlen, det48x, ylen, det48y, ddet);
+
+  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
+  cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet);
+  deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, deter);
+
+  return deter[deterlen - 1];
+}
+
+REAL incircleslow(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
+{
+  INEXACT REAL adx, bdx, cdx, ady, bdy, cdy;
+  REAL adxtail, bdxtail, cdxtail;
+  REAL adytail, bdytail, cdytail;
+  REAL negate, negatetail;
+  INEXACT REAL axby7, bxcy7, axcy7, bxay7, cxby7, cxay7;
+  REAL axby[8], bxcy[8], axcy[8], bxay[8], cxby[8], cxay[8];
+  REAL temp16[16];
+  int temp16len;
+  REAL detx[32], detxx[64], detxt[32], detxxt[64], detxtxt[64];
+  int xlen, xxlen, xtlen, xxtlen, xtxtlen;
+  REAL x1[128], x2[192];
+  int x1len, x2len;
+  REAL dety[32], detyy[64], detyt[32], detyyt[64], detytyt[64];
+  int ylen, yylen, ytlen, yytlen, ytytlen;
+  REAL y1[128], y2[192];
+  int y1len, y2len;
+  REAL adet[384], bdet[384], cdet[384], abdet[768], deter[1152];
+  int alen, blen, clen, ablen, deterlen;
+  int i;
+
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+  INEXACT REAL c;
+  INEXACT REAL abig;
+  REAL a0hi, a0lo, a1hi, a1lo, bhi, blo;
+  REAL err1, err2, err3;
+  INEXACT REAL _i, _j, _k, _l, _m, _n;
+  REAL _0, _1, _2;
+
+  Two_Diff(pa[0], pd[0], adx, adxtail);
+  Two_Diff(pa[1], pd[1], ady, adytail);
+  Two_Diff(pb[0], pd[0], bdx, bdxtail);
+  Two_Diff(pb[1], pd[1], bdy, bdytail);
+  Two_Diff(pc[0], pd[0], cdx, cdxtail);
+  Two_Diff(pc[1], pd[1], cdy, cdytail);
+
+  Two_Two_Product(adx, adxtail, bdy, bdytail,
+                  axby7, axby[6], axby[5], axby[4],
+                  axby[3], axby[2], axby[1], axby[0]);
+  axby[7] = axby7;
+  negate = -ady;
+  negatetail = -adytail;
+  Two_Two_Product(bdx, bdxtail, negate, negatetail,
+                  bxay7, bxay[6], bxay[5], bxay[4],
+                  bxay[3], bxay[2], bxay[1], bxay[0]);
+  bxay[7] = bxay7;
+  Two_Two_Product(bdx, bdxtail, cdy, cdytail,
+                  bxcy7, bxcy[6], bxcy[5], bxcy[4],
+                  bxcy[3], bxcy[2], bxcy[1], bxcy[0]);
+  bxcy[7] = bxcy7;
+  negate = -bdy;
+  negatetail = -bdytail;
+  Two_Two_Product(cdx, cdxtail, negate, negatetail,
+                  cxby7, cxby[6], cxby[5], cxby[4],
+                  cxby[3], cxby[2], cxby[1], cxby[0]);
+  cxby[7] = cxby7;
+  Two_Two_Product(cdx, cdxtail, ady, adytail,
+                  cxay7, cxay[6], cxay[5], cxay[4],
+                  cxay[3], cxay[2], cxay[1], cxay[0]);
+  cxay[7] = cxay7;
+  negate = -cdy;
+  negatetail = -cdytail;
+  Two_Two_Product(adx, adxtail, negate, negatetail,
+                  axcy7, axcy[6], axcy[5], axcy[4],
+                  axcy[3], axcy[2], axcy[1], axcy[0]);
+  axcy[7] = axcy7;
+
+
+  temp16len = fast_expansion_sum_zeroelim(8, bxcy, 8, cxby, temp16);
+
+  xlen = scale_expansion_zeroelim(temp16len, temp16, adx, detx);
+  xxlen = scale_expansion_zeroelim(xlen, detx, adx, detxx);
+  xtlen = scale_expansion_zeroelim(temp16len, temp16, adxtail, detxt);
+  xxtlen = scale_expansion_zeroelim(xtlen, detxt, adx, detxxt);
+  for (i = 0; i < xxtlen; i++) {
+    detxxt[i] *= 2.0;
+  }
+  xtxtlen = scale_expansion_zeroelim(xtlen, detxt, adxtail, detxtxt);
+  x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1);
+  x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2);
+
+  ylen = scale_expansion_zeroelim(temp16len, temp16, ady, dety);
+  yylen = scale_expansion_zeroelim(ylen, dety, ady, detyy);
+  ytlen = scale_expansion_zeroelim(temp16len, temp16, adytail, detyt);
+  yytlen = scale_expansion_zeroelim(ytlen, detyt, ady, detyyt);
+  for (i = 0; i < yytlen; i++) {
+    detyyt[i] *= 2.0;
+  }
+  ytytlen = scale_expansion_zeroelim(ytlen, detyt, adytail, detytyt);
+  y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1);
+  y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2);
+
+  alen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, adet);
+
+
+  temp16len = fast_expansion_sum_zeroelim(8, cxay, 8, axcy, temp16);
+
+  xlen = scale_expansion_zeroelim(temp16len, temp16, bdx, detx);
+  xxlen = scale_expansion_zeroelim(xlen, detx, bdx, detxx);
+  xtlen = scale_expansion_zeroelim(temp16len, temp16, bdxtail, detxt);
+  xxtlen = scale_expansion_zeroelim(xtlen, detxt, bdx, detxxt);
+  for (i = 0; i < xxtlen; i++) {
+    detxxt[i] *= 2.0;
+  }
+  xtxtlen = scale_expansion_zeroelim(xtlen, detxt, bdxtail, detxtxt);
+  x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1);
+  x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2);
+
+  ylen = scale_expansion_zeroelim(temp16len, temp16, bdy, dety);
+  yylen = scale_expansion_zeroelim(ylen, dety, bdy, detyy);
+  ytlen = scale_expansion_zeroelim(temp16len, temp16, bdytail, detyt);
+  yytlen = scale_expansion_zeroelim(ytlen, detyt, bdy, detyyt);
+  for (i = 0; i < yytlen; i++) {
+    detyyt[i] *= 2.0;
+  }
+  ytytlen = scale_expansion_zeroelim(ytlen, detyt, bdytail, detytyt);
+  y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1);
+  y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2);
+
+  blen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, bdet);
+
+
+  temp16len = fast_expansion_sum_zeroelim(8, axby, 8, bxay, temp16);
+
+  xlen = scale_expansion_zeroelim(temp16len, temp16, cdx, detx);
+  xxlen = scale_expansion_zeroelim(xlen, detx, cdx, detxx);
+  xtlen = scale_expansion_zeroelim(temp16len, temp16, cdxtail, detxt);
+  xxtlen = scale_expansion_zeroelim(xtlen, detxt, cdx, detxxt);
+  for (i = 0; i < xxtlen; i++) {
+    detxxt[i] *= 2.0;
+  }
+  xtxtlen = scale_expansion_zeroelim(xtlen, detxt, cdxtail, detxtxt);
+  x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1);
+  x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2);
+
+  ylen = scale_expansion_zeroelim(temp16len, temp16, cdy, dety);
+  yylen = scale_expansion_zeroelim(ylen, dety, cdy, detyy);
+  ytlen = scale_expansion_zeroelim(temp16len, temp16, cdytail, detyt);
+  yytlen = scale_expansion_zeroelim(ytlen, detyt, cdy, detyyt);
+  for (i = 0; i < yytlen; i++) {
+    detyyt[i] *= 2.0;
+  }
+  ytytlen = scale_expansion_zeroelim(ytlen, detyt, cdytail, detytyt);
+  y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1);
+  y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2);
+
+  clen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, cdet);
+
+  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
+  deterlen = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, deter);
+
+  return deter[deterlen - 1];
+}
+
+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);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  inspherefast()   Approximate 3D insphere test.  Nonrobust.               */
+/*  insphereexact()   Exact 3D insphere test.  Robust.                       */
+/*  insphereslow()   Another exact 3D insphere test.  Robust.                */
+/*  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.    */
+/*                                                                           */
+/*  Only the first and last routine should be used; the middle two are for   */
+/*  timings.                                                                 */
+/*                                                                           */
+/*  The last three 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 inspherefast(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 alift, blift, clift, dlift;
+  REAL ab, bc, cd, da, ac, bd;
+  REAL abc, bcd, cda, dab;
+
+  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];
+
+  ab = aex * bey - bex * aey;
+  bc = bex * cey - cex * bey;
+  cd = cex * dey - dex * cey;
+  da = dex * aey - aex * dey;
+
+  ac = aex * cey - cex * aey;
+  bd = bex * dey - dex * bey;
+
+  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;
+
+  return (dlift * abc - clift * dab) + (blift * cda - alift * bcd);
+}
+
+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 insphereslow(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe)
+{
+  INEXACT REAL aex, bex, cex, dex, aey, bey, cey, dey, aez, bez, cez, dez;
+  REAL aextail, bextail, cextail, dextail;
+  REAL aeytail, beytail, ceytail, deytail;
+  REAL aeztail, beztail, ceztail, deztail;
+  REAL negate, negatetail;
+  INEXACT REAL axby7, bxcy7, cxdy7, dxay7, axcy7, bxdy7;
+  INEXACT REAL bxay7, cxby7, dxcy7, axdy7, cxay7, dxby7;
+  REAL axby[8], bxcy[8], cxdy[8], dxay[8], axcy[8], bxdy[8];
+  REAL bxay[8], cxby[8], dxcy[8], axdy[8], cxay[8], dxby[8];
+  REAL ab[16], bc[16], cd[16], da[16], ac[16], bd[16];
+  int ablen, bclen, cdlen, dalen, aclen, bdlen;
+  REAL temp32a[32], temp32b[32], temp64a[64], temp64b[64], temp64c[64];
+  int temp32alen, temp32blen, temp64alen, temp64blen, temp64clen;
+  REAL temp128[128], temp192[192];
+  int temp128len, temp192len;
+  REAL detx[384], detxx[768], detxt[384], detxxt[768], detxtxt[768];
+  int xlen, xxlen, xtlen, xxtlen, xtxtlen;
+  REAL x1[1536], x2[2304];
+  int x1len, x2len;
+  REAL dety[384], detyy[768], detyt[384], detyyt[768], detytyt[768];
+  int ylen, yylen, ytlen, yytlen, ytytlen;
+  REAL y1[1536], y2[2304];
+  int y1len, y2len;
+  REAL detz[384], detzz[768], detzt[384], detzzt[768], detztzt[768];
+  int zlen, zzlen, ztlen, zztlen, ztztlen;
+  REAL z1[1536], z2[2304];
+  int z1len, z2len;
+  REAL detxy[4608];
+  int xylen;
+  REAL adet[6912], bdet[6912], cdet[6912], ddet[6912];
+  int alen, blen, clen, dlen;
+  REAL abdet[13824], cddet[13824], deter[27648];
+  int deterlen;
+  int i;
+
+  INEXACT REAL bvirt;
+  REAL avirt, bround, around;
+  INEXACT REAL c;
+  INEXACT REAL abig;
+  REAL a0hi, a0lo, a1hi, a1lo, bhi, blo;
+  REAL err1, err2, err3;
+  INEXACT REAL _i, _j, _k, _l, _m, _n;
+  REAL _0, _1, _2;
+
+  Two_Diff(pa[0], pe[0], aex, aextail);
+  Two_Diff(pa[1], pe[1], aey, aeytail);
+  Two_Diff(pa[2], pe[2], aez, aeztail);
+  Two_Diff(pb[0], pe[0], bex, bextail);
+  Two_Diff(pb[1], pe[1], bey, beytail);
+  Two_Diff(pb[2], pe[2], bez, beztail);
+  Two_Diff(pc[0], pe[0], cex, cextail);
+  Two_Diff(pc[1], pe[1], cey, ceytail);
+  Two_Diff(pc[2], pe[2], cez, ceztail);
+  Two_Diff(pd[0], pe[0], dex, dextail);
+  Two_Diff(pd[1], pe[1], dey, deytail);
+  Two_Diff(pd[2], pe[2], dez, deztail);
+
+  Two_Two_Product(aex, aextail, bey, beytail,
+                  axby7, axby[6], axby[5], axby[4],
+                  axby[3], axby[2], axby[1], axby[0]);
+  axby[7] = axby7;
+  negate = -aey;
+  negatetail = -aeytail;
+  Two_Two_Product(bex, bextail, negate, negatetail,
+                  bxay7, bxay[6], bxay[5], bxay[4],
+                  bxay[3], bxay[2], bxay[1], bxay[0]);
+  bxay[7] = bxay7;
+  ablen = fast_expansion_sum_zeroelim(8, axby, 8, bxay, ab);
+  Two_Two_Product(bex, bextail, cey, ceytail,
+                  bxcy7, bxcy[6], bxcy[5], bxcy[4],
+                  bxcy[3], bxcy[2], bxcy[1], bxcy[0]);
+  bxcy[7] = bxcy7;
+  negate = -bey;
+  negatetail = -beytail;
+  Two_Two_Product(cex, cextail, negate, negatetail,
+                  cxby7, cxby[6], cxby[5], cxby[4],
+                  cxby[3], cxby[2], cxby[1], cxby[0]);
+  cxby[7] = cxby7;
+  bclen = fast_expansion_sum_zeroelim(8, bxcy, 8, cxby, bc);
+  Two_Two_Product(cex, cextail, dey, deytail,
+                  cxdy7, cxdy[6], cxdy[5], cxdy[4],
+                  cxdy[3], cxdy[2], cxdy[1], cxdy[0]);
+  cxdy[7] = cxdy7;
+  negate = -cey;
+  negatetail = -ceytail;
+  Two_Two_Product(dex, dextail, negate, negatetail,
+                  dxcy7, dxcy[6], dxcy[5], dxcy[4],
+                  dxcy[3], dxcy[2], dxcy[1], dxcy[0]);
+  dxcy[7] = dxcy7;
+  cdlen = fast_expansion_sum_zeroelim(8, cxdy, 8, dxcy, cd);
+  Two_Two_Product(dex, dextail, aey, aeytail,
+                  dxay7, dxay[6], dxay[5], dxay[4],
+                  dxay[3], dxay[2], dxay[1], dxay[0]);
+  dxay[7] = dxay7;
+  negate = -dey;
+  negatetail = -deytail;
+  Two_Two_Product(aex, aextail, negate, negatetail,
+                  axdy7, axdy[6], axdy[5], axdy[4],
+                  axdy[3], axdy[2], axdy[1], axdy[0]);
+  axdy[7] = axdy7;
+  dalen = fast_expansion_sum_zeroelim(8, dxay, 8, axdy, da);
+  Two_Two_Product(aex, aextail, cey, ceytail,
+                  axcy7, axcy[6], axcy[5], axcy[4],
+                  axcy[3], axcy[2], axcy[1], axcy[0]);
+  axcy[7] = axcy7;
+  negate = -aey;
+  negatetail = -aeytail;
+  Two_Two_Product(cex, cextail, negate, negatetail,
+                  cxay7, cxay[6], cxay[5], cxay[4],
+                  cxay[3], cxay[2], cxay[1], cxay[0]);
+  cxay[7] = cxay7;
+  aclen = fast_expansion_sum_zeroelim(8, axcy, 8, cxay, ac);
+  Two_Two_Product(bex, bextail, dey, deytail,
+                  bxdy7, bxdy[6], bxdy[5], bxdy[4],
+                  bxdy[3], bxdy[2], bxdy[1], bxdy[0]);
+  bxdy[7] = bxdy7;
+  negate = -bey;
+  negatetail = -beytail;
+  Two_Two_Product(dex, dextail, negate, negatetail,
+                  dxby7, dxby[6], dxby[5], dxby[4],
+                  dxby[3], dxby[2], dxby[1], dxby[0]);
+  dxby[7] = dxby7;
+  bdlen = fast_expansion_sum_zeroelim(8, bxdy, 8, dxby, bd);
+
+  temp32alen = scale_expansion_zeroelim(cdlen, cd, -bez, temp32a);
+  temp32blen = scale_expansion_zeroelim(cdlen, cd, -beztail, temp32b);
+  temp64alen = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                           temp32blen, temp32b, temp64a);
+  temp32alen = scale_expansion_zeroelim(bdlen, bd, cez, temp32a);
+  temp32blen = scale_expansion_zeroelim(bdlen, bd, ceztail, temp32b);
+  temp64blen = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                           temp32blen, temp32b, temp64b);
+  temp32alen = scale_expansion_zeroelim(bclen, bc, -dez, temp32a);
+  temp32blen = scale_expansion_zeroelim(bclen, bc, -deztail, temp32b);
+  temp64clen = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                           temp32blen, temp32b, temp64c);
+  temp128len = fast_expansion_sum_zeroelim(temp64alen, temp64a,
+                                           temp64blen, temp64b, temp128);
+  temp192len = fast_expansion_sum_zeroelim(temp64clen, temp64c,
+                                           temp128len, temp128, temp192);
+  xlen = scale_expansion_zeroelim(temp192len, temp192, aex, detx);
+  xxlen = scale_expansion_zeroelim(xlen, detx, aex, detxx);
+  xtlen = scale_expansion_zeroelim(temp192len, temp192, aextail, detxt);
+  xxtlen = scale_expansion_zeroelim(xtlen, detxt, aex, detxxt);
+  for (i = 0; i < xxtlen; i++) {
+    detxxt[i] *= 2.0;
+  }
+  xtxtlen = scale_expansion_zeroelim(xtlen, detxt, aextail, detxtxt);
+  x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1);
+  x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2);
+  ylen = scale_expansion_zeroelim(temp192len, temp192, aey, dety);
+  yylen = scale_expansion_zeroelim(ylen, dety, aey, detyy);
+  ytlen = scale_expansion_zeroelim(temp192len, temp192, aeytail, detyt);
+  yytlen = scale_expansion_zeroelim(ytlen, detyt, aey, detyyt);
+  for (i = 0; i < yytlen; i++) {
+    detyyt[i] *= 2.0;
+  }
+  ytytlen = scale_expansion_zeroelim(ytlen, detyt, aeytail, detytyt);
+  y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1);
+  y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2);
+  zlen = scale_expansion_zeroelim(temp192len, temp192, aez, detz);
+  zzlen = scale_expansion_zeroelim(zlen, detz, aez, detzz);
+  ztlen = scale_expansion_zeroelim(temp192len, temp192, aeztail, detzt);
+  zztlen = scale_expansion_zeroelim(ztlen, detzt, aez, detzzt);
+  for (i = 0; i < zztlen; i++) {
+    detzzt[i] *= 2.0;
+  }
+  ztztlen = scale_expansion_zeroelim(ztlen, detzt, aeztail, detztzt);
+  z1len = fast_expansion_sum_zeroelim(zzlen, detzz, zztlen, detzzt, z1);
+  z2len = fast_expansion_sum_zeroelim(z1len, z1, ztztlen, detztzt, z2);
+  xylen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, detxy);
+  alen = fast_expansion_sum_zeroelim(z2len, z2, xylen, detxy, adet);
+
+  temp32alen = scale_expansion_zeroelim(dalen, da, cez, temp32a);
+  temp32blen = scale_expansion_zeroelim(dalen, da, ceztail, temp32b);
+  temp64alen = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                           temp32blen, temp32b, temp64a);
+  temp32alen = scale_expansion_zeroelim(aclen, ac, dez, temp32a);
+  temp32blen = scale_expansion_zeroelim(aclen, ac, deztail, temp32b);
+  temp64blen = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                           temp32blen, temp32b, temp64b);
+  temp32alen = scale_expansion_zeroelim(cdlen, cd, aez, temp32a);
+  temp32blen = scale_expansion_zeroelim(cdlen, cd, aeztail, temp32b);
+  temp64clen = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                           temp32blen, temp32b, temp64c);
+  temp128len = fast_expansion_sum_zeroelim(temp64alen, temp64a,
+                                           temp64blen, temp64b, temp128);
+  temp192len = fast_expansion_sum_zeroelim(temp64clen, temp64c,
+                                           temp128len, temp128, temp192);
+  xlen = scale_expansion_zeroelim(temp192len, temp192, bex, detx);
+  xxlen = scale_expansion_zeroelim(xlen, detx, bex, detxx);
+  xtlen = scale_expansion_zeroelim(temp192len, temp192, bextail, detxt);
+  xxtlen = scale_expansion_zeroelim(xtlen, detxt, bex, detxxt);
+  for (i = 0; i < xxtlen; i++) {
+    detxxt[i] *= 2.0;
+  }
+  xtxtlen = scale_expansion_zeroelim(xtlen, detxt, bextail, detxtxt);
+  x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1);
+  x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2);
+  ylen = scale_expansion_zeroelim(temp192len, temp192, bey, dety);
+  yylen = scale_expansion_zeroelim(ylen, dety, bey, detyy);
+  ytlen = scale_expansion_zeroelim(temp192len, temp192, beytail, detyt);
+  yytlen = scale_expansion_zeroelim(ytlen, detyt, bey, detyyt);
+  for (i = 0; i < yytlen; i++) {
+    detyyt[i] *= 2.0;
+  }
+  ytytlen = scale_expansion_zeroelim(ytlen, detyt, beytail, detytyt);
+  y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1);
+  y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2);
+  zlen = scale_expansion_zeroelim(temp192len, temp192, bez, detz);
+  zzlen = scale_expansion_zeroelim(zlen, detz, bez, detzz);
+  ztlen = scale_expansion_zeroelim(temp192len, temp192, beztail, detzt);
+  zztlen = scale_expansion_zeroelim(ztlen, detzt, bez, detzzt);
+  for (i = 0; i < zztlen; i++) {
+    detzzt[i] *= 2.0;
+  }
+  ztztlen = scale_expansion_zeroelim(ztlen, detzt, beztail, detztzt);
+  z1len = fast_expansion_sum_zeroelim(zzlen, detzz, zztlen, detzzt, z1);
+  z2len = fast_expansion_sum_zeroelim(z1len, z1, ztztlen, detztzt, z2);
+  xylen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, detxy);
+  blen = fast_expansion_sum_zeroelim(z2len, z2, xylen, detxy, bdet);
+
+  temp32alen = scale_expansion_zeroelim(ablen, ab, -dez, temp32a);
+  temp32blen = scale_expansion_zeroelim(ablen, ab, -deztail, temp32b);
+  temp64alen = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                           temp32blen, temp32b, temp64a);
+  temp32alen = scale_expansion_zeroelim(bdlen, bd, -aez, temp32a);
+  temp32blen = scale_expansion_zeroelim(bdlen, bd, -aeztail, temp32b);
+  temp64blen = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                           temp32blen, temp32b, temp64b);
+  temp32alen = scale_expansion_zeroelim(dalen, da, -bez, temp32a);
+  temp32blen = scale_expansion_zeroelim(dalen, da, -beztail, temp32b);
+  temp64clen = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                           temp32blen, temp32b, temp64c);
+  temp128len = fast_expansion_sum_zeroelim(temp64alen, temp64a,
+                                           temp64blen, temp64b, temp128);
+  temp192len = fast_expansion_sum_zeroelim(temp64clen, temp64c,
+                                           temp128len, temp128, temp192);
+  xlen = scale_expansion_zeroelim(temp192len, temp192, cex, detx);
+  xxlen = scale_expansion_zeroelim(xlen, detx, cex, detxx);
+  xtlen = scale_expansion_zeroelim(temp192len, temp192, cextail, detxt);
+  xxtlen = scale_expansion_zeroelim(xtlen, detxt, cex, detxxt);
+  for (i = 0; i < xxtlen; i++) {
+    detxxt[i] *= 2.0;
+  }
+  xtxtlen = scale_expansion_zeroelim(xtlen, detxt, cextail, detxtxt);
+  x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1);
+  x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2);
+  ylen = scale_expansion_zeroelim(temp192len, temp192, cey, dety);
+  yylen = scale_expansion_zeroelim(ylen, dety, cey, detyy);
+  ytlen = scale_expansion_zeroelim(temp192len, temp192, ceytail, detyt);
+  yytlen = scale_expansion_zeroelim(ytlen, detyt, cey, detyyt);
+  for (i = 0; i < yytlen; i++) {
+    detyyt[i] *= 2.0;
+  }
+  ytytlen = scale_expansion_zeroelim(ytlen, detyt, ceytail, detytyt);
+  y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1);
+  y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2);
+  zlen = scale_expansion_zeroelim(temp192len, temp192, cez, detz);
+  zzlen = scale_expansion_zeroelim(zlen, detz, cez, detzz);
+  ztlen = scale_expansion_zeroelim(temp192len, temp192, ceztail, detzt);
+  zztlen = scale_expansion_zeroelim(ztlen, detzt, cez, detzzt);
+  for (i = 0; i < zztlen; i++) {
+    detzzt[i] *= 2.0;
+  }
+  ztztlen = scale_expansion_zeroelim(ztlen, detzt, ceztail, detztzt);
+  z1len = fast_expansion_sum_zeroelim(zzlen, detzz, zztlen, detzzt, z1);
+  z2len = fast_expansion_sum_zeroelim(z1len, z1, ztztlen, detztzt, z2);
+  xylen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, detxy);
+  clen = fast_expansion_sum_zeroelim(z2len, z2, xylen, detxy, cdet);
+
+  temp32alen = scale_expansion_zeroelim(bclen, bc, aez, temp32a);
+  temp32blen = scale_expansion_zeroelim(bclen, bc, aeztail, temp32b);
+  temp64alen = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                           temp32blen, temp32b, temp64a);
+  temp32alen = scale_expansion_zeroelim(aclen, ac, -bez, temp32a);
+  temp32blen = scale_expansion_zeroelim(aclen, ac, -beztail, temp32b);
+  temp64blen = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                           temp32blen, temp32b, temp64b);
+  temp32alen = scale_expansion_zeroelim(ablen, ab, cez, temp32a);
+  temp32blen = scale_expansion_zeroelim(ablen, ab, ceztail, temp32b);
+  temp64clen = fast_expansion_sum_zeroelim(temp32alen, temp32a,
+                                           temp32blen, temp32b, temp64c);
+  temp128len = fast_expansion_sum_zeroelim(temp64alen, temp64a,
+                                           temp64blen, temp64b, temp128);
+  temp192len = fast_expansion_sum_zeroelim(temp64clen, temp64c,
+                                           temp128len, temp128, temp192);
+  xlen = scale_expansion_zeroelim(temp192len, temp192, dex, detx);
+  xxlen = scale_expansion_zeroelim(xlen, detx, dex, detxx);
+  xtlen = scale_expansion_zeroelim(temp192len, temp192, dextail, detxt);
+  xxtlen = scale_expansion_zeroelim(xtlen, detxt, dex, detxxt);
+  for (i = 0; i < xxtlen; i++) {
+    detxxt[i] *= 2.0;
+  }
+  xtxtlen = scale_expansion_zeroelim(xtlen, detxt, dextail, detxtxt);
+  x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1);
+  x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2);
+  ylen = scale_expansion_zeroelim(temp192len, temp192, dey, dety);
+  yylen = scale_expansion_zeroelim(ylen, dety, dey, detyy);
+  ytlen = scale_expansion_zeroelim(temp192len, temp192, deytail, detyt);
+  yytlen = scale_expansion_zeroelim(ytlen, detyt, dey, detyyt);
+  for (i = 0; i < yytlen; i++) {
+    detyyt[i] *= 2.0;
+  }
+  ytytlen = scale_expansion_zeroelim(ytlen, detyt, deytail, detytyt);
+  y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1);
+  y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2);
+  zlen = scale_expansion_zeroelim(temp192len, temp192, dez, detz);
+  zzlen = scale_expansion_zeroelim(zlen, detz, dez, detzz);
+  ztlen = scale_expansion_zeroelim(temp192len, temp192, deztail, detzt);
+  zztlen = scale_expansion_zeroelim(ztlen, detzt, dez, detzzt);
+  for (i = 0; i < zztlen; i++) {
+    detzzt[i] *= 2.0;
+  }
+  ztztlen = scale_expansion_zeroelim(ztlen, detzt, deztail, detztzt);
+  z1len = fast_expansion_sum_zeroelim(zzlen, detzz, zztlen, detzzt, z1);
+  z2len = fast_expansion_sum_zeroelim(z1len, z1, ztztlen, detztzt, z2);
+  xylen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, detxy);
+  dlen = fast_expansion_sum_zeroelim(z2len, z2, xylen, detxy, ddet);
+
+  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
+  cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet);
+  deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, 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/contrib/TetgenNew/refine.cxx b/contrib/TetgenNew/refine.cxx
new file mode 100644
index 0000000000..6a13e9771d
--- /dev/null
+++ b/contrib/TetgenNew/refine.cxx
@@ -0,0 +1,249 @@
+#ifndef refineCXX
+#define refineCXX
+
+#include "tetgen.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkedge4encroach()    Check a subsegment to see if it is encroached.    //
+//                                                                           //
+// If 'testpt' != NULL, only test if the segment is encroached by this point.//
+// Otherwise, test all apexes of faces containing this segment.              //
+//                                                                           //
+// If 'enqflag' > 0, add the segment into list (badsegpool) if it is encroa- //
+// ched.                                                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::checkedge4encroach(face& seg, point testpt, int enqflag)
+{
+  badface *encseg;
+  triface neightet, spintet;
+  point pa, pb, pc, encpt;
+  REAL midpt[3], r, d, diff;
+  int encroached;
+  int i;
+
+  seg.shver = 0;
+  pa = sorg(seg);
+  pb = sdest(seg);
+
+  for (i = 0; i < 3; i++) {
+    midpt[i] = 0.5 * (pa[i] + pb[i]);
+  }
+  r = DIST(midpt, pa);
+
+  encroached = 0;
+  encpt = NULL;
+
+  if (testpt == NULL) {
+    // Check all apexes of faces containing [pa, pb].
+    stpivot(seg, neightet); // sstpivot(seg, neightet);
+    spintet = neightet;
+    while (1) {
+      pc = apex(spintet);
+      if (pc != dummypoint) {
+        d = DIST(midpt, pc);
+        diff = fabs(r - d);
+        if ((diff / r) < b->epsilon) {
+          // testpt is on the diametric ball of [pa, pb].
+          encroached = 0;
+        } else {
+          encroached = (d < r ? 1 : 0);
+        }
+        if (encroached) {
+          encpt = pc; // pc is encroached [pa. pb].
+          break;
+        }
+      }
+      fnextself(spintet);
+      if (spintet.tet == neightet.tet) break;
+    }
+  } else {
+    d = DIST(midpt, testpt);
+    diff = fabs(r - d);
+    if ((diff / r) < b->epsilon) {
+      // testpt is on the diametric ball of [pa, pb].
+      encroached = 0;
+    } else {
+      encroached = (d < r ? 1 : 0);
+      if (encroached) {
+        encpt = testpt;
+      }
+    }
+  }
+
+  if (encroached && enqflag) {
+    if (b->verbose > 1) {
+      printf("    Queuing encroaching segment (%d, %d) ref (%d).\n", 
+        pointmark(pa), pointmark(pb), pointmark(encpt));
+    }
+    encseg = (badface *) badsegpool->alloc();
+    encseg->ss = seg;
+    encseg->forg = pa;
+    encseg->fdest = pb;
+    encseg->foppo = encpt; // The encroaching point.
+    smarktest(seg); // Flag it to avoid multiple testing.
+  }
+
+  return encroached > 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// repairencsegs()    Repair all queued encroached subsegments.              //
+//                                                                           //
+// Encroached segments are repaired by inserting a vertex inside them.  Each //
+// newly inserted vertex may encroach other segments, or makeing them non-   //
+// Delaunay, these segments are also repaired.                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::repairencsegs()
+{
+  badface *encloop;
+  triface searchtet;
+  face splitsh;
+  point newpt, refpt;
+  point pa, pb;
+
+  while ((badsegpool->items > 0) && (b->steinerleft != 0)) {
+
+    badsegpool->traversalinit();
+    encloop = badfacetraverse(badsegpool);
+    while ((encloop != NULL) && (b->steinerleft != 0)) {
+      // assert(smarktested(encloop->ss));
+      sunmarktest(encloop->ss);
+
+      // Check if it is still the same segment when it is tested.
+      pa = sorg(encloop->ss);
+      pb = sdest(encloop->ss);
+      if ((encloop->forg == pa) && (encloop->fdest == pb)) {
+
+        refpt = encloop->foppo;
+        if ((refpt == NULL) || getpointtype(refpt) == DEADVERTEX) {
+          // Check if this segment can be split.
+          assert(0); // Not handled yet.
+        }
+        // Create a new point in the segment.
+        makepoint(&newpt);
+        // getsegmentsplitpoint2(&(encloop->ss), refpt, newpt);
+        getsegmentsplitpoint3(&(encloop->ss), refpt, newpt);
+        setpointtype(newpt, STEINERVERTEX);
+
+        // Decrease the number of allocated Steiner points (-S option).
+        if (b->steinerleft != -1) {
+          b->steinerleft--;
+        }
+
+        // Get an adjacent tet for point location.
+        stpivot(encloop->ss, searchtet);
+
+        // Split the segment by newpt. Two new subsegments and new subfaces
+        //   are queued in subsegstack and subfacstack for recovery.
+        spivot(encloop->ss, splitsh);
+        sinsertvertex(newpt, &splitsh, &(encloop->ss), true, false);
+
+        // Insert newpt into the DT. Since the mesh may be a CDT, always
+        //   set visflag be true. Some existing egments and subfaces may be
+        //   non-Delaunay due to this new vertex, they will be removed from
+        //   the mesh, and are queued in subsegstack and subfacstack for
+        //   recovery.
+        // Newly encroached segments, subfaces, and badly-shaped tets are
+        //   queued in badsegpool, badsubpool, and badtetpool, resp.
+        insertvertex(newpt, &searchtet, true, true, false, false);
+
+        // Recover missing subsegments.
+        assert(subsegstack->objects > 0);
+        delaunizesegments();
+        // Recover missing subfaces.
+        assert(subfacstack->objects > 0);
+        constrainedfacets();
+      }
+
+      // Deallocate the badface.
+      badfacedealloc(badsegpool, encloop);
+      // Get the next badface.
+      encloop = badfacetraverse(badsegpool);
+    } // while (encloop != NULL)
+
+  } // while (badsegpool->items > 0)
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// enforcequality()    Create quality conforming Delaunay mesh.              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::enforcequality()
+{
+  face shloop;
+  REAL bakeps;
+  long bakptcount;
+
+  if (!b->quiet) {
+    printf("Conforming Delaunay meshing.\n");
+  }
+
+  bakeps = b->epsilon;  // Bakup the epsilon.
+  b->epsilon = 0;
+
+  // Initialize the pool for storing encroched segments.
+  badsegpool = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
+
+  // Initialize arrays.
+  tg_crosstets = new arraypool(sizeof(triface), 10);
+  tg_topnewtets = new arraypool(sizeof(triface), 10);
+  tg_botnewtets = new arraypool(sizeof(triface), 10);
+  tg_topfaces = new arraypool(sizeof(triface), 10);
+  tg_botfaces = new arraypool(sizeof(triface), 10);
+  tg_midfaces = new arraypool(sizeof(triface), 10);
+  tg_toppoints = new arraypool(sizeof(point), 8);
+  tg_botpoints = new arraypool(sizeof(point), 8);
+  tg_facpoints = new arraypool(sizeof(point), 8);
+  tg_facfaces = new arraypool(sizeof(face), 10);
+  tg_topshells = new arraypool(sizeof(face), 10);
+  tg_botshells = new arraypool(sizeof(face), 10);
+
+  // Find all encroached segments.
+  subsegpool->traversalinit();
+  shloop.sh = shellfacetraverse(subsegpool);
+  while (shloop.sh != NULL) {
+    checkedge4encroach(shloop, NULL, 1);
+    shloop.sh = shellfacetraverse(subsegpool);
+  }
+
+  if (b->verbose && (badsegpool->items > 0)) {
+    printf("  Splitting encroached segments.\n");
+  }
+  bakptcount = pointpool->items;
+
+  // Fix encroached segments.
+  repairencsegs();
+  // At this point, no segments should be encroached.
+
+  if (b->verbose && ((pointpool->items - bakptcount) > 0)) {
+    printf("  %ld Steiner points.\n", pointpool->items - bakptcount);
+  }
+
+  // Delete arrays.
+  delete tg_crosstets;
+  delete tg_topnewtets;
+  delete tg_botnewtets;
+  delete tg_topfaces;
+  delete tg_botfaces;
+  delete tg_midfaces;
+  delete tg_toppoints;
+  delete tg_botpoints;
+  delete tg_facpoints;
+  delete tg_facfaces;
+  delete tg_topshells;
+  delete tg_botshells;
+
+  delete badsegpool;
+
+  b->epsilon = bakeps;  // Restore the epsilon.
+}
+
+#endif // #ifndef refineCXX
diff --git a/contrib/TetgenNew/surface.cxx b/contrib/TetgenNew/surface.cxx
new file mode 100644
index 0000000000..e9a72b232d
--- /dev/null
+++ b/contrib/TetgenNew/surface.cxx
@@ -0,0 +1,1795 @@
+#ifndef surfaceCXX
+#define surfaceCXX
+
+#include "tetgen.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// calculateabovepoint()    Calculate a point above a facet in 'dummypoint'. //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::calculateabovepoint(arraypool *facpoints, point *ppa,
+  point *ppb, point *ppc)
+{
+  point *ppt, pa, pb, pc;
+  REAL v1[3], v2[3], n[3];
+  REAL lab, len, A, area;
+  REAL x, y, z;
+  int i;
+
+  ppt = (point *) fastlookup(facpoints, 0);
+  pa = *ppt; // a is the first point.
+
+  // Get a point b s.t. the length of [a, b] is maximal.
+  lab = 0;
+  for (i = 1; i < facpoints->objects; i++) {
+    ppt = (point *) fastlookup(facpoints, i);
+    x = (*ppt)[0] - pa[0];
+    y = (*ppt)[1] - pa[1];
+    z = (*ppt)[2] - pa[2];
+    len = x * x + y * y + z * z;
+    if (len > lab) {
+      lab = len;
+      pb = *ppt;
+    }
+  }
+  lab = sqrt(lab);
+  if (lab == 0) {
+    if (!b->quiet) {
+      printf("Warning:  All points of a facet are coincident with %d.\n",
+        pointmark(pa));
+    }
+    return false;
+  }
+
+  // Get a point c s.t. the area of [a, b, c] is maximal.
+  v1[0] = pb[0] - pa[0];
+  v1[1] = pb[1] - pa[1];
+  v1[2] = pb[2] - pa[2];
+  A = 0;
+  for (i = 1; i < facpoints->objects; i++) {
+    ppt = (point *) fastlookup(facpoints, i);
+    v2[0] = (*ppt)[0] - pa[0];
+    v2[1] = (*ppt)[1] - pa[1];
+    v2[2] = (*ppt)[2] - pa[2];
+    CROSS(v1, v2, n);
+    area = DOT(n, n);
+    if (area > A) {
+      A = area;
+      pc = *ppt;
+    }
+  }
+  if (A == 0) {
+    // All points are collinear. No above point.
+    if (!b->quiet) {
+      printf("Warning:  All points of a facet are collinaer with [%d, %d].\n",
+        pointmark(pa), pointmark(pb));
+    }
+    return false;
+  }
+
+  // Calculate an above point of this facet.
+  facenormal(pa, pb, pc, n, 1);
+  len = sqrt(DOT(n, n));
+  n[0] /= len;
+  n[1] /= len;
+  n[2] /= len;
+  lab /= 2.0;
+  dummypoint[0] = 0.5 * (pa[0] + pb[0]) + lab * n[0];
+  dummypoint[1] = 0.5 * (pa[1] + pb[1]) + lab * n[1];
+  dummypoint[2] = 0.5 * (pa[2] + pb[2]) + lab * n[2];
+
+  if (ppa != NULL) {
+    // Return the three points.
+    *ppa = pa;
+    *ppb = pb;
+    *ppc = pc;
+  }
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// slocate()    Locate a point in a surface triangulation.                   //
+//                                                                           //
+// Search the point (p) from the input 'searchsh' (it should not be NULL).   //
+//                                                                           //
+// It is assumed that 'dummypoint' lies above the facet of the triangulation,//
+// hence a CCW test (2D orientation) is equal to a below-plane (3D) test.    //
+//                                                                           //
+// The returned value inducates the following cases:                         //
+//   - ONVERTEX, p is the origin of 'searchsh'.                              //
+//   - ONEDGE, p lies on the edge of 'searchsh'.                             //
+//   - ONFACE, p lies in the interior of 'searchsh'.                         //
+//   - OUTSIDE, p lies outside of the triangulation, p is on the left-hand   //
+//     side of the edge 'searchsh'(s), i.e., org(s), dest(s), p are CW.      //
+//                                                                           //
+// If 'cflag' is not TRUE, the triangulation may not be convex.  Stop search //
+// when a segment is met and return OUTSIDE.                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::location tetgenmesh::slocate(point searchpt, face* searchsh, 
+  bool cflag)
+{
+  face neighsh;
+  face checkseg;
+  point pa, pb, pc, pd;
+  REAL ori, ori_bc, ori_ca;
+  REAL dist_bc, dist_ca;
+  int i;
+
+  enum {MOVE_BC, MOVE_CA} nextmove;
+
+  shellface sptr;
+
+  // Adjust the face orientation s.t. 'dummypt' lies above to it.
+  pa = sorg(*searchsh);
+  pb = sdest(*searchsh);
+  pc = sapex(*searchsh);
+  ori = orient3d(pa, pb, pc, dummypoint);
+  assert(ori != 0); // SELF_CHECK
+  if (ori > 0) {
+    sesymself(*searchsh); // Reverse the face orientation.
+  }
+
+  // Find an edge of the face s.t. p lies on its right-hand side (CCW).
+  for (i = 0; i < 3; i++) {
+    pa = sorg(*searchsh);
+    pb = sdest(*searchsh);
+    ori = orient3d(pa, pb, dummypoint, searchpt);
+    if (ori > 0) break;
+    senextself(*searchsh);
+  }
+  assert(i < 3); // SELF_CHECK
+
+  while (1) {
+
+    pc = sapex(*searchsh);
+
+    if (pc == searchpt) {
+      senext2self(*searchsh);
+      return ONVERTEX;
+    }
+
+    ori_bc = orient3d(pb, pc, dummypoint, searchpt);
+    ori_ca = orient3d(pc, pa, dummypoint, searchpt);
+
+    if (ori_bc < 0) {
+      if (ori_ca < 0) { // (--)
+        // Any of the edges is a viable move.
+        senext(*searchsh, neighsh); // At edge [b, c].
+        spivotself(neighsh);
+        if (neighsh.sh != NULL) {
+          pd = sapex(neighsh);
+          dist_bc = NORM2(searchpt[0] - pd[0], searchpt[1] - pd[1],
+            searchpt[2] - pd[2]);
+        } else {
+          dist_bc = NORM2(xmax - xmin, ymax - ymin, zmax - zmin);
+        }
+        senext2(*searchsh, neighsh); // At edge [c, a].
+        spivotself(neighsh);
+        if (neighsh.sh != NULL) {
+          pd = sapex(neighsh);
+          dist_ca = NORM2(searchpt[0] - pd[0], searchpt[1] - pd[1],
+            searchpt[2] - pd[2]);
+        } else {
+          dist_ca = dist_bc;
+        }
+        if (dist_ca < dist_bc) {
+          nextmove = MOVE_CA;
+        } else {
+          nextmove = MOVE_BC;
+        }
+      } else { // (-#)
+        // Edge [b, c] is viable.
+        nextmove = MOVE_BC;
+      }
+    } else {
+      if (ori_ca < 0) { // (#-)
+        // Edge [c, a] is viable.
+        nextmove = MOVE_CA;
+      } else {
+        if (ori_bc > 0) {
+          if (ori_ca > 0) { // (++)
+            return ONFACE;  // Inside [a, b, c].
+          } else { // (+0)
+            senext2self(*searchsh); // On edge [c, a].
+            return ONEDGE;
+          }
+        } else { // ori_bc == 0
+          if (ori_ca > 0) { // (0+)
+            senextself(*searchsh); // On edge [b, c].
+            return ONEDGE;
+          } else { // (00)
+            // On vertex c. Should be checked in above.
+            assert(0); // SELF_CHECK
+          }
+        }
+      }
+    }
+
+    // Move to the next face.
+    if (nextmove == MOVE_BC) {
+      senextself(*searchsh);
+    } else {
+      senext2self(*searchsh);
+    }
+    if (!cflag) {
+      // NON-convex case. Chekc if we will cross a boundary.
+      sspivot(*searchsh, checkseg);
+      if (checkseg.sh != NULL) {
+        return OUTSIDE; // Do not cross a boundary edge.
+      }
+    }
+    spivot(*searchsh, neighsh);
+    if (neighsh.sh == NULL) {
+      return OUTSIDE; // A hull edge.
+    }
+    // Adjust the edge orientation.
+    if (sorg(neighsh) != sdest(*searchsh)) {
+      sesymself(neighsh);
+    }
+    assert(sorg(neighsh) == sdest(*searchsh)); // SELF_CHECK
+
+    // Update the newly discovered face and its endpoints.
+    *searchsh = neighsh;
+    pa = sorg(*searchsh);
+    pb = sdest(*searchsh);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// sinsertvertex()    Insert a vertex into a triangulation of a facet.       //
+//                                                                           //
+// The new point (p) will be located. Searching from 'splitsh'. If 'splitseg'//
+// is not NULL, p is on a segment, no search is needed.                      //
+//                                                                           //
+// If 'cflag' is not TRUE, the triangulation may be not convex. Don't insert //
+// p if it is found in outside.                                              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::location tetgenmesh::sinsertvertex(point insertpt, 
+  face *splitsh, face *splitseg, bool bwflag, bool cflag)
+{
+  face *abfaces, *parysh, *pssub;
+  face neighsh, newsh, casout, casin;
+  face aseg, bseg, aoutseg, boutseg;
+  face checkseg;
+  triface neightet, spintet;
+  point pa, pb, pc;
+  enum location loc;
+  REAL sign, ori, area;
+  int n, s, i, j;
+
+  tetrahedron ptr;
+  shellface sptr;
+
+  if (splitseg != NULL) {
+    spivot(*splitseg, *splitsh);
+    loc = ONEDGE;
+  } else {
+    assert(splitsh->sh != NULL); // SELF_CHECK
+    loc = slocate(insertpt, splitsh, false);
+  }
+
+  // Return if p lies on a vertex.
+  if (loc == ONVERTEX) return loc;
+
+  if (loc == OUTSIDE) {
+    // Return if 'cflag' is not set.
+    if (!cflag) return loc;
+  }
+
+  if (loc == ONEDGE) {
+    if (splitseg == NULL) {
+      // Do not split a segment.
+      sspivot(*splitsh, checkseg);
+      if (checkseg.sh != NULL) return loc; // return ONSUBSEG;
+      // Check if this edge is on the hull.
+      spivot(*splitsh, neighsh);
+      if (neighsh.sh == NULL) {
+        // A convex hull edge. The new point is on the hull.
+        loc = OUTSIDE;
+      }
+    }
+  }
+
+  if (b->verbose > 1) {
+    pa = sorg(*splitsh);
+    pb = sdest(*splitsh);
+    pc = sapex(*splitsh);
+    printf("    Insert point %d (%d, %d, %d) loc %d\n", pointmark(insertpt),
+      pointmark(pa), pointmark(pb), pointmark(pc), (int) loc);
+  }
+
+  // Does 'insertpt' lie on a segment?
+  if (splitseg != NULL) {
+    splitseg->shver = 0;
+    pa = sorg(*splitseg);
+    // Count the number of faces at segment [a, b].
+    n = 0;
+    neighsh = *splitsh;
+    do {
+      spivotself(neighsh);
+      n++;
+    } while ((neighsh.sh != NULL) && (neighsh.sh != splitsh->sh));
+    // n is at least 1.
+    abfaces = new face[n];
+    // Collect faces at seg [a, b].
+    abfaces[0] = *splitsh;
+    if (sorg(abfaces[0]) != pa) sesymself(abfaces[0]);
+    for (i = 1; i < n; i++) {
+      spivot(abfaces[i - 1], abfaces[i]);
+      if (sorg(abfaces[i]) != pa) sesymself(abfaces[i]);
+    }
+  }
+
+  // Initialize the cavity.
+  if (loc == ONEDGE) {
+    smarktest(*splitsh);
+    caveshlist->newindex((void **) &parysh);
+    *parysh = *splitsh;
+    if (splitseg != NULL) {
+      for (i = 1; i < n; i++) {
+        smarktest(abfaces[i]);
+        caveshlist->newindex((void **) &parysh);
+        *parysh = abfaces[i];
+      }
+    } else {
+      spivot(*splitsh, neighsh);
+      if (neighsh.sh != NULL) {
+        smarktest(neighsh);
+        caveshlist->newindex((void **) &parysh);
+        *parysh = neighsh;
+      }
+    }
+  } else if (loc == ONFACE) {
+    smarktest(*splitsh);
+    caveshlist->newindex((void **) &parysh);
+    *parysh = *splitsh;
+  } else { // loc == OUTSIDE;
+    // This is only possible when T is convex.
+    assert(cflag); // SELF_CHECK
+    // Assume p is on top of the edge ('splitsh'). Find a right-most edge
+    //   which is visible by p.
+    neighsh = *splitsh;
+    while (1) {
+      senext2self(neighsh);
+      spivot(neighsh, casout);
+      if (casout.sh == NULL) {
+        // A convex hull edge. Is it visible by p.
+        pa = sorg(neighsh);
+        pb = sdest(neighsh);
+        ori = orient3d(pa, pb, dummypoint, insertpt);
+        if (ori < 0) {
+          *splitsh = neighsh; // Update 'splitsh'.
+        } else {
+          break; // 'splitsh' is the right-most visible edge.
+        }
+      } else {
+        if (sorg(casout) != sdest(neighsh)) sesymself(casout);
+        neighsh = casout;
+      }
+    }
+    // Create new triangles for all visible edges of p (from right to left).
+    casin.sh = NULL;  // No adjacent face at right.
+    pa = sorg(*splitsh);
+    pb = sdest(*splitsh);
+    while (1) {
+      // Create a new subface on top of the (visible) edge.
+      makeshellface(subfacepool, &newsh); 
+      setshvertices(newsh, pb, pa, insertpt);
+      setshellmark(newsh, getshellmark(*splitsh));
+      if (checkconstraints) {
+        area = areabound(*splitsh);
+        areabound(newsh) = area;
+      }
+      // Connect the new subface to the bottom subfaces.
+      sbond1(newsh, *splitsh);
+      sbond1(*splitsh, newsh);
+      // Connect the new subface to its right-adjacent subface.
+      if (casin.sh != NULL) {
+        senext(newsh, casout);
+        sbond1(casout, casin);
+        sbond1(casin, casout);
+      }
+      // The left-adjacent subface has not been created yet.
+      senext2(newsh, casin);
+      // Add the new face into list.
+      smarktest(newsh);
+      caveshlist->newindex((void **) &parysh);
+      *parysh = newsh;
+      // Move to the convex hull edge at the left of 'splitsh'.
+      neighsh = *splitsh;
+      while (1) {
+        senextself(neighsh);
+        spivot(neighsh, casout);
+        if (casout.sh == NULL) {
+          *splitsh = neighsh;
+          break;
+        }
+        if (sorg(casout) != sdest(neighsh)) sesymself(casout);
+        neighsh = casout;
+      }
+      // A convex hull edge. Is it visible by p.
+      pa = sorg(*splitsh);
+      pb = sdest(*splitsh);
+      ori = orient3d(pa, pb, dummypoint, insertpt);
+      if (ori >= 0) break;
+    }
+  }
+
+  // Form the Bowyer-Watson cavity.
+  for (i = 0; i < caveshlist->objects; i++) {
+    parysh = (face *) fastlookup(caveshlist, i);
+    for (j = 0; j < 3; j++) {
+      sspivot(*parysh, checkseg);
+      if (checkseg.sh == NULL) {
+        spivot(*parysh, neighsh);
+        if (neighsh.sh != NULL) {
+          if (!smarktested(neighsh)) {
+            if (bwflag) {
+              pa = sorg(neighsh);
+              pb = sdest(neighsh);
+              pc = sapex(neighsh);
+              sign = incircle3d(pa, pb, pc, insertpt);
+              if (sign < 0) {
+                smarktest(neighsh);
+                caveshlist->newindex((void **) &pssub);
+                *pssub = neighsh;
+              }
+            } else {
+              sign = 1; // A boundary edge.
+            }
+          } else {
+            sign = -1; // Not a boundary edge.
+          }
+        } else {
+          if (loc == OUTSIDE) {
+            // It is a boundary edge if it does not contain insertp.
+            if ((sorg(*parysh)==insertpt) || (sdest(*parysh)==insertpt)) {
+              sign = -1; // Not a boundary edge.
+            } else {
+              sign = 1; // A boundary edge.
+            }
+          } else {
+            sign = 1; // A boundary edge.
+          }
+        }
+      } else {
+        sign = 1; // A segment!
+      }
+      if (sign >= 0) {
+        // Add a boundary edge.
+        caveshbdlist->newindex((void **) &pssub);
+        *pssub = *parysh;
+      }
+      senextself(*parysh);
+    }
+  }
+
+  // Creating new subfaces.
+  for (i = 0; i < caveshbdlist->objects; i++) {
+    parysh = (face *) fastlookup(caveshbdlist, i);
+    sspivot(*parysh, checkseg);
+    if ((parysh->shver & 01) != 0) sesymself(*parysh);
+    pa = sorg(*parysh);
+    pb = sdest(*parysh);
+    // Create a new subface.
+    makeshellface(subfacepool, &newsh); 
+    setshvertices(newsh, pa, pb, insertpt);
+    setshellmark(newsh, getshellmark(*parysh));
+    if (checkconstraints) {
+      area = areabound(*parysh);
+      areabound(newsh) = area;
+    }
+    // Connect newsh to outer subfaces.
+    spivot(*parysh, casout);
+    if (casout.sh != NULL) {
+      casin = casout;
+      if (checkseg.sh != NULL) {
+        spivot(casin, neighsh);
+        while (neighsh.sh != parysh->sh) {
+          casin = neighsh;
+          spivot(casin, neighsh);
+        }
+      }
+      sbond1(newsh, casout);
+      sbond1(casin, newsh);
+    }
+    if (checkseg.sh != NULL) {
+      ssbond(newsh, checkseg);
+    }
+    // Connect oldsh <== newsh (for connecting adjacent new subfaces).
+    sbond1(*parysh, newsh);
+  }
+
+  // Set a handle for searching.
+  recentsh = newsh;
+
+  // Connect adjacent new subfaces together.
+  for (i = 0; i < caveshbdlist->objects; i++) {
+    // Get an old subface at edge [a, b].
+    parysh = (face *) fastlookup(caveshbdlist, i);
+    sspivot(*parysh, checkseg);
+    spivot(*parysh, newsh); // The new subface [a, b, p].
+    senextself(newsh); // At edge [b, p].
+    spivot(newsh, neighsh);
+    if (neighsh.sh == NULL) {
+      // Find the adjacent new subface at edge [b, p].
+      pb = sdest(*parysh);
+      neighsh = *parysh;
+      while (1) {
+        senextself(neighsh);
+        spivotself(neighsh);
+        if (neighsh.sh == NULL) break;
+        if (!smarktested(neighsh)) break;
+        if (sdest(neighsh) != pb) sesymself(neighsh);
+      }
+      if (neighsh.sh != NULL) {
+        // Now 'neighsh' is a new subface at edge [b, #].
+        if (sorg(neighsh) != pb) sesymself(neighsh);
+        assert(sorg(neighsh) == pb); // SELF_CHECK
+        assert(sapex(neighsh) == insertpt); // SELF_CHECK
+        senext2self(neighsh); // Go to the open edge [p, b].
+        spivot(neighsh, casout); // SELF_CHECK
+        assert(casout.sh == NULL); // SELF_CHECK
+        sbond2(newsh, neighsh);
+      } else {
+        assert(loc == OUTSIDE); // SELF_CHECK
+      }
+    }
+    spivot(*parysh, newsh); // The new subface [a, b, p].
+    senext2self(newsh); // At edge [p, a].
+    spivot(newsh, neighsh);
+    if (neighsh.sh == NULL) {
+      // Find the adjacent new subface at edge [p, a].
+      pa = sorg(*parysh);
+      neighsh = *parysh;
+      while (1) {
+        senext2self(neighsh);
+        spivotself(neighsh);
+        if (neighsh.sh == NULL) break;
+        if (!smarktested(neighsh)) break;
+        if (sorg(neighsh) != pa) sesymself(neighsh);
+      }
+      if (neighsh.sh != NULL) {
+        // Now 'neighsh' is a new subface at edge [#, a].
+        if (sdest(neighsh) != pa) sesymself(neighsh);
+        assert(sdest(neighsh) == pa); // SELF_CHECK
+        assert(sapex(neighsh) == insertpt); // SELF_CHECK
+        senextself(neighsh); // Go to the open edge [a, p].
+        spivot(neighsh, casout); // SELF_CHECK
+        assert(casout.sh == NULL); // SELF_CHECK
+        sbond2(newsh, neighsh);
+      } else {
+        assert(loc == OUTSIDE); // SELF_CHECK
+      }
+    }
+  }
+
+  if (checksubfaces) {
+    // Add all new subfaces into list.
+    for (i = 0; i < caveshbdlist->objects; i++) {
+      // Get an old subface at edge [a, b].
+      parysh = (face *) fastlookup(caveshbdlist, i);
+      spivot(*parysh, newsh); // The new subface [a, b, p].
+      if (b->verbose > 1) {
+        printf("      Queue a new subface (%d, %d, %d).\n",
+          pointmark(sorg(newsh)), pointmark(sdest(newsh)),
+          pointmark(sapex(newsh)));
+      }
+      subfacstack->newindex((void **) &pssub);
+      *pssub = newsh;
+    }
+  }
+
+  if (splitseg != NULL) {
+    // Split the segment [a, b].
+    aseg = *splitseg;
+    pa = sorg(aseg);
+    pb = sdest(aseg);
+    if (b->verbose > 1) {
+      printf("    Split seg (%d, %d) by %d.\n", pointmark(pa), pointmark(pb), 
+        pointmark(insertpt));
+    }
+    // Detach the adjacent tets from this segment.
+    stpivot(aseg, neightet);
+    if (neightet.tet != NULL) {
+      // It should not be a dead tet.
+      assert(neightet.tet[4] != NULL); // SELF_CHECK
+      assert(((org(neightet) == pa) && (dest(neightet) == pb)) ||
+             ((org(neightet) == pb) && (dest(neightet) == pa))); // SELF_CHECK
+      spintet = neightet;
+      while (1) {
+        tssdissolve(spintet);
+        fnextself(spintet);
+        if (spintet.tet == neightet.tet) break;
+      }
+      // Clean the seg-to-tet pointer.
+      stdissolve(aseg);
+    }
+    // Insert the new point p.
+    makeshellface(subsegpool, &bseg);
+    setshvertices(bseg, insertpt, pb, NULL);
+    setsdest(aseg, insertpt);
+    setshellmark(bseg, getshellmark(aseg));
+    if (checkconstraints) {
+      areabound(bseg) = areabound(aseg);
+    }
+    // Connect [p, b]<->[b, #].
+    senext(aseg, aoutseg);
+    spivotself(aoutseg);
+    if (aoutseg.sh != NULL) {
+      senext(bseg, boutseg);
+      sbond2(boutseg, aoutseg);
+    }
+    // Connect [a, p] <-> [p, b].
+    senext(aseg, aoutseg);
+    senext2(bseg, boutseg);
+    sbond2(aoutseg, boutseg);
+    // Connect subsegs [a, p] and [p, b] to the true new subfaces.
+    for (i = 0; i < n; i++) {
+      spivot(abfaces[i], newsh); // The faked new subface.
+      if (sorg(newsh) != pa) sesymself(newsh);
+      senext2(newsh, neighsh); // The edge [p, a] in newsh
+      spivot(neighsh, casout);
+      ssbond(casout, aseg);
+      senext(newsh, neighsh); // The edge [b, p] in newsh
+      spivot(neighsh, casout);
+      ssbond(casout, bseg);
+    }
+    if (n > 1) {
+      // Create the two face rings at [a, p] and [p, b].
+      for (i = 0; i < n; i++) {
+        spivot(abfaces[i], newsh); // The faked new subface.
+        if (sorg(newsh) != pa) sesymself(newsh);
+        spivot(abfaces[(i + 1) % n], neighsh); // The next faked new subface.
+        if (sorg(neighsh) != pa) sesymself(neighsh);
+        senext2(newsh, casout); // The edge [p, a] in newsh.
+        senext2(neighsh, casin); // The edge [p, a] in neighsh.
+        spivotself(casout);
+        spivotself(casin);
+        sbond1(casout, casin); // Let the i's face point to (i+1)'s face.
+        senext(newsh, casout); // The edge [b, p] in newsh.
+        senext(neighsh, casin); // The edge [b, p] in neighsh.
+        spivotself(casout);
+        spivotself(casin);
+        sbond1(casout, casin);
+      }
+    } else { 
+      // Only one subface contains this segment.
+      // assert(n == 1);
+      spivot(abfaces[0], newsh);  // The faked new subface.
+      if (sorg(newsh) != pa) sesymself(newsh);
+      senext2(newsh, casout); // The edge [p, a] in newsh.
+      spivotself(casout);
+      sdissolve(casout); // Disconnect to faked subface.
+      senext(newsh, casout); // The edge [b, p] in newsh.
+      spivotself(casout);
+      sdissolve(casout); // Disconnect to faked subface.
+    }
+    // Delete the faked new subfaces.
+    for (i = 0; i < n; i++) {
+      spivot(abfaces[i], newsh); // The faked new subface.
+      shellfacedealloc(subfacepool, newsh.sh);
+    }
+    if (checksubsegs) {
+      // Add two subsegs into stack (for recovery).
+      if (!sinfected(aseg)) {
+        s = randomnation(subsegstack->objects + 1);
+        subsegstack->newindex((void **) &parysh);
+        *parysh = * (face *) fastlookup(subsegstack, s);
+        sinfect(aseg); 
+        parysh = (face *) fastlookup(subsegstack, s);
+        *parysh = aseg;
+      }
+      assert(!sinfected(bseg)); // SELF_CHECK
+      s = randomnation(subsegstack->objects + 1);
+      subsegstack->newindex((void **) &parysh);
+      *parysh = * (face *) fastlookup(subsegstack, s);
+      sinfect(bseg);
+      parysh = (face *) fastlookup(subsegstack, s);
+      *parysh = bseg;
+    }
+    delete [] abfaces;
+  }
+
+  // Delete the old subfaces.
+  for (i = 0; i < caveshlist->objects; i++) {
+    parysh = (face *) fastlookup(caveshlist, i);
+    if (checksubfaces) {		 
+      // Disconnect in the neighbor tets.		 
+      stpivot(*parysh, neightet);		 
+      if (neightet.tet != NULL) {		 
+        tsdissolve(neightet);		 
+        symself(neightet);		 
+        tsdissolve(neightet);		 
+      }		 
+    }
+    shellfacedealloc(subfacepool, parysh->sh);
+  }
+
+  // Clean the working lists.
+  caveshlist->restart();
+  caveshbdlist->restart();
+
+  return loc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// sscoutsegment()    Look for a segment in surface triangulation.           //
+//                                                                           //
+// The segment is given by the origin of 'searchsh' and 'endpt'.  Assume the //
+// orientation of 'searchsh' is CCW w.r.t. the above point.                  //
+//                                                                           //
+// If an edge in T is found matching this segment, the segment is "locaked"  //
+// in T at the edge.  Otherwise, flip the first edge in T that the segment   //
+// crosses. Continue the search from the flipped face.                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::intersection tetgenmesh::sscoutsegment(face *searchsh,
+  point endpt)
+{
+  face flipshs[2], neighsh;
+  face newseg, checkseg;
+  point startpt, pa, pb, pc, pd;
+  enum intersection dir;
+  REAL ori_ab, ori_ca;
+  REAL dist_b, dist_c;
+
+  enum {MOVE_AB, MOVE_CA} nextmove;
+
+  shellface sptr;
+
+  // The origin of 'searchsh' is fixed.
+  startpt = sorg(*searchsh); // pa = startpt;
+
+  if (b->verbose > 1) {
+    printf("    Scout segment (%d, %d).\n", pointmark(startpt),
+      pointmark(endpt));
+  }
+
+  // Search an edge in 'searchsh' on the path of this segment.
+  while (1) {
+
+    pb = sdest(*searchsh);
+    if (pb == endpt) {
+      dir = SHAREEDGE; // Found!
+      break;
+    }
+
+    pc = sapex(*searchsh);
+    if (pc == endpt) {
+      senext2self(*searchsh);
+      sesymself(*searchsh);
+      dir = SHAREEDGE; // Found!
+      break;
+    }
+
+    ori_ab = orient3d(startpt, pb, dummypoint, endpt);
+    ori_ca = orient3d(pc, startpt, dummypoint, endpt);
+
+    if (ori_ab < 0) {
+      if (ori_ca < 0) { // (--)
+        // Both sides are viable moves.
+        spivot(*searchsh, neighsh); // At edge [a, b].
+        assert(neighsh.sh != NULL); // SELF_CHECK
+        pd = sapex(neighsh);
+        dist_b = NORM2(endpt[0] - pd[0], endpt[1] - pd[1], endpt[2] - pd[2]);
+        senext2(*searchsh, neighsh); // At edge [c, a].
+        spivotself(neighsh);
+        assert(neighsh.sh != NULL); // SELF_CHECK
+        pd = sapex(neighsh);
+        dist_c = NORM2(endpt[0] - pd[0], endpt[1] - pd[1], endpt[2] - pd[2]);
+        if (dist_c < dist_b) {
+          nextmove = MOVE_CA;
+        } else {
+          nextmove = MOVE_AB;
+        }
+      } else { // (-#)
+        nextmove = MOVE_AB;
+      }
+    } else {
+      if (ori_ca < 0) { // (#-)
+        nextmove = MOVE_CA;
+      } else {
+        if (ori_ab > 0) {
+          if (ori_ca > 0) { // (++)
+            // The segment intersects with edge [b, c].
+            dir = ACROSSEDGE;
+            break;
+          } else { // (+0)
+            // The segment collinear with edge [c, a].
+            senext2self(*searchsh);
+            sesymself(*searchsh);
+            dir = ACROSSVERT;
+            break;
+          }
+        } else {
+          if (ori_ca > 0) { // (0+)
+            // The segment collinear with edge [a, b].
+            dir = ACROSSVERT;
+            break;
+          } else { // (00)
+            // startpt == endpt. Not possible.
+            assert(0); // SELF_CHECK
+          }
+        }
+      }
+    }
+
+    // Move 'searchsh' to the next face, keep the origin unchanged.
+    if (nextmove == MOVE_AB) {
+      spivot(*searchsh, neighsh);
+      if (sorg(neighsh) != pb) sesymself(neighsh);
+      senext(neighsh, *searchsh);      
+    } else {
+      senext2(*searchsh, neighsh);
+      spivotself(neighsh);
+      if (sdest(neighsh) != pc) sesymself(neighsh);
+      *searchsh = neighsh;
+    }
+    assert(sorg(*searchsh) == startpt); // SELF_CHECK
+
+  } // while
+
+  if (dir == SHAREEDGE) {
+    // Insert the segment into the triangulation.
+    makeshellface(subsegpool, &newseg);
+    setshvertices(newseg, startpt, endpt, NULL);
+    ssbond(*searchsh, newseg);
+    spivot(*searchsh, neighsh);
+    if (neighsh.sh != NULL) {
+      ssbond(neighsh, newseg);
+    }
+    return dir;
+  }
+
+  if (dir == ACROSSVERT) {
+    // A point is found collinear with this segment.
+    return dir;
+  }
+
+  if (dir == ACROSSEDGE) {
+    // Edge [b, c] intersects with the segment.
+    senext(*searchsh, flipshs[0]);
+    sspivot(flipshs[0], checkseg);
+    if (checkseg.sh != NULL) {
+      printf("Error:  Invalid PLC.\n");
+      pb = sorg(flipshs[0]);
+      pc = sdest(flipshs[0]);
+      printf("  Two segments (%d, %d) and (%d, %d) intersect.\n",
+        pointmark(startpt), pointmark(endpt), pointmark(pb), pointmark(pc));
+      terminatetetgen(2);
+    }
+    // Flip edge [b, c], queue unflipped edges (for Delaunay checks).
+    spivot(flipshs[0], flipshs[1]);
+    assert(flipshs[1].sh != NULL); // SELF_CHECK
+    if (sorg(flipshs[1]) != sdest(flipshs[0])) sesymself(flipshs[1]);
+    flip22(flipshs, 1);
+    // The flip may create an invered triangle, check it.
+    pa = sapex(flipshs[1]);
+    pb = sapex(flipshs[0]);
+    pc = sorg(flipshs[0]);
+    pd = sdest(flipshs[0]);
+    // Check if pa and pb are on the different sides of [pc, pd]. 
+    // Re-use ori_ab, ori_ca for the tests.
+    ori_ab = orient3d(pc, pd, dummypoint, pb);
+    ori_ca = orient3d(pd, pc, dummypoint, pa);
+    assert(ori_ab * ori_ca != 0); // SELF_CHECK
+    if (ori_ab < 0) {
+      if (b->verbose > 1) {
+        printf("    Queue an inversed triangle (%d, %d, %d) %d\n",
+          pointmark(pc), pointmark(pd), pointmark(pb), pointmark(pa));
+      }
+      futureflip = flipshpush(futureflip, &flipshs[0]);
+    } else if (ori_ca < 0) {
+      if (b->verbose > 1) {
+        printf("    Queue an inversed triangle (%d, %d, %d) %d\n",
+          pointmark(pd), pointmark(pc), pointmark(pa), pointmark(pb));
+      }
+      futureflip = flipshpush(futureflip, &flipshs[1]);
+    }
+    // Set 'searchsh' s.t. its origin is 'startpt'.
+    *searchsh = flipshs[0];
+    assert(sorg(*searchsh) == startpt);
+  }
+
+  return sscoutsegment(searchsh, endpt);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// scarveholes()    Remove triangles not in the facet.                       //
+//                                                                           //
+// This routine re-uses the two global arrays: caveshlist and caveshbdlist.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::scarveholes(int holes, REAL* holelist)
+{
+  face *parysh, searchsh, neighsh;
+  face checkseg;
+  enum location loc;
+  int i, j;
+
+  // Get all triangles. Infect unprotected convex hull triangles. 
+  smarktest(recentsh);
+  caveshlist->newindex((void **) &parysh);
+  *parysh = recentsh;
+  for (i = 0; i < caveshlist->objects; i++) {
+    parysh = (face *) fastlookup(caveshlist, i);
+    searchsh = *parysh;
+    searchsh.shver = 0;
+    for (j = 0; j < 3; j++) {
+      spivot(searchsh, neighsh);
+      // Is this side on the convex hull?
+      if (neighsh.sh != NULL) {
+        if (!smarktested(neighsh)) {
+          smarktest(neighsh);
+          caveshlist->newindex((void **) &parysh);
+          *parysh = neighsh;
+        }
+      } else {
+        // A hull side. Check if it is protected by a segment.
+        sspivot(searchsh, checkseg);
+        if (checkseg.sh == NULL) {
+          // Not protected. Save this face.
+          if (!sinfected(searchsh)) {
+            sinfect(searchsh);
+            caveshbdlist->newindex((void **) &parysh);
+            *parysh = searchsh;
+          }
+        }
+      }
+      senextself(searchsh);
+    }
+  }
+
+  // Infect the triangles in the holes.
+  for (i = 0; i < 3 * holes; i += 3) {
+    searchsh = recentsh;
+    loc = slocate(&(holelist[i]), &searchsh, true);
+    if (loc != OUTSIDE) {
+      sinfect(searchsh);
+      caveshbdlist->newindex((void **) &parysh);
+      *parysh = searchsh;
+    }
+  }
+
+  // Find and infect all exterior triangles.
+  for (i = 0; i < caveshbdlist->objects; i++) {
+    parysh = (face *) fastlookup(caveshbdlist, i);
+    searchsh = *parysh;
+    searchsh.shver = 0;
+    for (j = 0; j < 3; j++) {
+      spivot(searchsh, neighsh);
+      if (neighsh.sh != NULL) {
+        sspivot(searchsh, checkseg);
+        if (checkseg.sh == NULL) {
+          if (!sinfected(neighsh)) {
+            sinfect(neighsh);
+            caveshbdlist->newindex((void **) &parysh);
+            *parysh = neighsh;
+          }
+        } else {
+          sdissolve(neighsh); // Disconnect a protected face.
+        }
+      }
+      senextself(searchsh);
+    }
+  }
+
+  // Delete exterior triangles, unmark interior triangles.
+  for (i = 0; i < caveshlist->objects; i++) {
+    parysh = (face *) fastlookup(caveshlist, i);
+    if (sinfected(*parysh)) {
+      shellfacedealloc(subfacepool, parysh->sh);
+    } else {
+      sunmarktest(*parysh);
+    }
+  }
+
+  caveshlist->restart();
+  caveshbdlist->restart();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// triangulate()    Create a CDT for the facet.                              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist,
+  int holes, REAL* holelist)
+{
+  face searchsh, newsh; 
+  face newseg;
+  point pa, pb, pc, *ppt, *cons;
+  enum location loc;
+  int i;
+
+  if (b->verbose > 1) {
+    printf("    %ld vertices, %ld segments",ptlist->objects,conlist->objects);
+    if (holes > 0) {
+      printf(", %d holes", holes);
+    }
+    printf(", shmark: %d.\n", shmark);
+  }
+
+  if (ptlist->objects < 3l) {
+    return; // No enough points. Do nothing.
+  }
+  if (conlist->objects < 3l) {
+    return; // No enough segments. Do nothing.
+  }
+
+  if (ptlist->objects == 3l) {
+    // The facet has only one triangle.
+    pa = * (point *) fastlookup(ptlist, 0);
+    pb = * (point *) fastlookup(ptlist, 1);
+    pc = * (point *) fastlookup(ptlist, 2);
+    makeshellface(subfacepool, &newsh);
+    setshvertices(newsh, pa, pb, pc);
+    setshellmark(newsh, shmark);
+    // Create three new segments.
+    for (i = 0; i < 3; i++) {
+      makeshellface(subsegpool, &newseg);
+      setshvertices(newseg, sorg(newsh), sdest(newsh), NULL);
+      ssbond(newsh, newseg);
+      senextself(newsh);
+    }
+    if (getpointtype(pa) == VOLVERTEX) {
+      setpointtype(pa, FACETVERTEX);
+    }
+    if (getpointtype(pb) == VOLVERTEX) {
+      setpointtype(pb, FACETVERTEX);
+    }
+    if (getpointtype(pc) == VOLVERTEX) {
+      setpointtype(pc, FACETVERTEX);
+    }
+    return;
+  }
+
+  // Calulcate an above point of this facet.
+  if (!calculateabovepoint(ptlist, &pa, &pb, &pc)) {
+    return; // The point set is degenerate.
+  }
+
+  // Create an initial triangulation.
+  makeshellface(subfacepool, &newsh);
+  setshvertices(newsh, pa, pb, pc);
+  setshellmark(newsh, shmark);
+  recentsh = newsh;
+
+  if (getpointtype(pa) == VOLVERTEX) {
+    setpointtype(pa, FACETVERTEX);
+  }
+  if (getpointtype(pb) == VOLVERTEX) {
+    setpointtype(pb, FACETVERTEX);
+  }
+  if (getpointtype(pc) == VOLVERTEX) {
+    setpointtype(pc, FACETVERTEX);
+  }
+
+  // Incrementally build the triangulation.
+  pinfect(pa);
+  pinfect(pb);
+  pinfect(pc);
+  for (i = 0; i < ptlist->objects; i++) {
+    ppt = (point *) fastlookup(ptlist, i);
+    if (!pinfected(*ppt)) {
+      searchsh = recentsh;
+      loc = sinsertvertex(*ppt, &searchsh, NULL, true, true);
+      if (getpointtype(*ppt) == VOLVERTEX) {
+        setpointtype(*ppt, FACETVERTEX);
+      }
+    } else {
+      puninfect(*ppt); // This point has inserted.
+    }
+  }
+
+  // Insert the segments.
+  for (i = 0; i < conlist->objects; i++) {
+    cons = (point *) fastlookup(conlist, i);
+    searchsh = recentsh;
+    loc = slocate(cons[0], &searchsh, true);
+    assert(loc == ONVERTEX); // SELF_CHECK
+    // Recover the segment. Some edges may be flipped.
+    sscoutsegment(&searchsh, cons[1]);
+    if (futureflip != NULL) {
+      // Recover locally Delaunay edges.
+      lawsonflip();
+    }
+  }
+
+  // Remove exterior and hole triangles.
+  scarveholes(holes, holelist);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// unifysubfaces()    Unify two identical subfaces.                          //
+//                                                                           //
+// Two subfaces, f1 [a, b, c] and f2 [a, b, d], share the same edge [a, b].  //
+// If c = d, then f1 and f2 are identical. In such case, f2 is deleted, all  //
+// connections to f2 are re-directed to f1.  Otherwise, these two subfaces   //
+// intersect, and the mesher is stopped.                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::unifysubfaces(face *f1, face *f2)
+{
+  face casout, casin, neighsh;
+  face sseg, checkseg;
+  point pa, pb, pc, pd;
+  int i;
+
+  assert(f1->sh != f2->sh); // SELF_CHECK
+
+  pa = sorg(*f1);
+  pb = sdest(*f1);
+  pc = sapex(*f1);
+
+  assert(sorg(*f2) == pa); // SELF_CHECK
+  assert(sdest(*f2) == pb); // SELF_CHECK
+  pd = sapex(*f2);
+
+  if (pc != pd) {
+    printf("Error:  Invalid PLC! Two coplanar subfaces intersect.\n");
+    printf("  1st (#%4d): (%d, %d, %d)\n", getshellmark(*f1),
+      pointmark(pa), pointmark(pb), pointmark(pc));
+    printf("  2nd (#%4d): (%d, %d, %d)\n", getshellmark(*f2),
+      pointmark(pa), pointmark(pb), pointmark(pd));
+    terminatetetgen(2);
+  }
+
+  // f1 and f2 are identical, replace f2 by f1.
+  if (!b->quiet) {
+    printf("Warning:  Facet #%d is duplicated with Facet #%d. Removed!\n",
+      getshellmark(*f2), getshellmark(*f1));
+  }
+
+  // Make possible disconnections/reconnections at neighbors of f2.
+  for (i = 0; i < 3; i++) {
+    spivot(*f1, casout);
+    if (casout.sh == NULL) {
+      // f1 has no adjacent subfaces yet.
+      spivot(*f2, casout);
+      if (casout.sh != NULL) {
+        // Re-direct the adjacent connections of f2 to f1.
+        casin = casout;
+        spivot(casin, neighsh);
+        while (neighsh.sh != f2->sh) {
+          casin = neighsh;
+          spivot(casin, neighsh);
+        }
+        // Connect casout <= f1 <= casin.
+        sbond1(*f1, casout);
+        sbond1(casin, *f1);
+      }
+    }
+    sspivot(*f2, sseg); 
+    if (sseg.sh != NULL) {
+      // f2 has a segment. It must be different to f1's.
+      sspivot(*f1, checkseg); // SELF_CHECK
+      if (checkseg.sh != NULL) { // SELF_CHECK
+        assert(checkseg.sh != sseg.sh); // SELF_CHECK
+      }
+      // Disconnect bonds of subfaces to this segment.
+      spivot(*f2, casout);
+      if (casout.sh != NULL) {
+        casin = casout;
+        ssdissolve(casin);
+        spivot(casin, neighsh);
+        while (neighsh.sh != f2->sh) {
+          casin = neighsh;
+          ssdissolve(casin);
+          spivot(casin, neighsh);
+        }
+      }
+      // Delete the segment.
+      shellfacedealloc(subsegpool, sseg.sh);
+    }
+    spivot(*f2, casout);
+    if (casout.sh != NULL) {
+      // Find the subface (casin) pointing to f2.
+      casin = casout;
+      spivot(casin, neighsh);
+      while (neighsh.sh != f2->sh) {
+        casin = neighsh;
+        spivot(casin, neighsh);
+      }
+      // Disconnect f2 <= casin.
+      sdissolve(casin);
+    }
+    senextself(*f1);
+    senextself(*f2);
+  } // i
+
+  // Delete f2.
+  shellfacedealloc(subfacepool, f2->sh);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// unifysegments()    Remove redundant segments and create face links.       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::unifysegments()
+{
+  badface *facelink, *newlinkitem, *f1, *f2;
+  face *facperverlist, sface;
+  face subsegloop, testseg;
+  point torg, tdest;
+  REAL ori1, ori2, ori3;
+  REAL n1[3], n2[3];
+  int *idx2faclist;
+  int segmarker;
+  int idx, k, m;
+
+  if (b->verbose > 1) {
+    printf("  Unifying segments.\n");
+  }
+
+  // Create a mapping from vertices to subfaces.
+  makepoint2submap(subfacepool, idx2faclist, facperverlist);
+
+  segmarker = 1;
+  subsegloop.shver = 0;
+  subsegpool->traversalinit();
+  subsegloop.sh = shellfacetraverse(subsegpool);
+  while (subsegloop.sh != (shellface *) NULL) {
+    torg = sorg(subsegloop);
+    tdest = sdest(subsegloop);
+
+    idx = pointmark(torg) - in->firstnumber;
+    // Loop through the set of subfaces containing 'torg'.  Get all the
+    //   subfaces containing the edge (torg, tdest). Save and order them
+    //   in 'sfacelist', the ordering is defined by the right-hand rule
+    //   with thumb points from torg to tdest.
+    for (k = idx2faclist[idx]; k < idx2faclist[idx + 1]; k++) {
+      sface = facperverlist[k];
+      // The face may be deleted if it is a duplicated face.
+      if (sface.sh[3] == NULL) continue;
+      // Search the edge torg->tdest.
+      assert(sorg(sface) == torg); // SELF_CHECK
+      if (sdest(sface) != tdest) {
+        senext2self(sface);
+        sesymself(sface);
+      }
+      if (sdest(sface) != tdest) continue;
+
+      // Save the face f in facelink.
+      if (flippool->items >= 2) {
+        f1 = facelink;
+        for (m = 0; m < flippool->items - 1; m++) {
+          f2 = f1->nextitem;
+          ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(f2->ss));
+          ori2 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface));
+          if (ori1 > 0) {
+            // apex(f2) is below f1.
+            if (ori2 > 0) {
+              // apex(f) is below f1 (see Fig.1). 
+              ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
+              if (ori3 > 0) {
+                // apex(f) is below f2, insert it.
+                break; 
+              } else if (ori3 < 0) {
+                // apex(f) is above f2, continue.
+              } else { // ori3 == 0; 
+                // f is coplanar and codirection with f2.
+                unifysubfaces(&(f2->ss), &sface);
+                break;
+              }
+            } else if (ori2 < 0) {
+              // apex(f) is above f1 below f2, inset it (see Fig. 2).
+              break;
+            } else { // ori2 == 0;
+              // apex(f) is coplanar with f1 (see Fig. 5).
+              ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
+              if (ori3 > 0) {
+                // apex(f) is below f2, insert it.
+                break; 
+              } else {
+                // f is coplanar and codirection with f1.
+                unifysubfaces(&(f1->ss), &sface);
+                break;
+              }
+            }
+          } else if (ori1 < 0) {
+            // apex(f2) is above f1.
+            if (ori2 > 0) {
+              // apex(f) is below f1, continue (see Fig. 3).
+            } else if (ori2 < 0) {
+              // apex(f) is above f1 (see Fig.4).
+              ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
+              if (ori3 > 0) {
+                // apex(f) is below f2, insert it.
+                break;
+              } else if (ori3 < 0) {
+                // apex(f) is above f2, continue.
+              } else { // ori3 == 0;
+                // f is coplanar and codirection with f2.
+                unifysubfaces(&(f2->ss), &sface);
+                break;
+              }
+            } else { // ori2 == 0;
+              // f is coplanar and with f1 (see Fig. 6).
+              ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
+              if (ori3 > 0) {
+                // f is also codirection with f1.
+                unifysubfaces(&(f1->ss), &sface);
+                break;
+              } else {
+                // f is above f2, continue.
+              }
+            }
+          } else { // ori1 == 0;
+            // apex(f2) is coplanar with f1. By assumption, f1 is not
+            //   coplanar and codirection with f2.
+            if (ori2 > 0) {
+              // apex(f) is below f1, continue (see Fig. 7).
+            } else if (ori2 < 0) {
+              // apex(f) is above f1, insert it (see Fig. 7).
+              break;
+            } else { // ori2 == 0.
+              // apex(f) is coplanar with f1 (see Fig. 8).
+              // f is either codirection with f1 or is codirection with f2. 
+              facenormal(torg, tdest, sapex(f1->ss), n1, 1);
+              facenormal(torg, tdest, sapex(sface), n2, 1);
+              if (DOT(n1, n2) > 0) {
+                unifysubfaces(&(f1->ss), &sface);
+              } else {
+                unifysubfaces(&(f2->ss), &sface);
+              }
+              break;
+            }
+          }
+          // Go to the next item;
+          f1 = f2;
+        } // for (m = 0; ...)
+        if (sface.sh[3] != NULL) {
+          // Insert sface between f1 and f2.
+          newlinkitem = (badface *) flippool->alloc();
+          newlinkitem->ss = sface;
+          newlinkitem->nextitem = f1->nextitem;
+          f1->nextitem = newlinkitem;
+        }
+      } else if (flippool->items == 1) {
+        f1 = facelink;
+        // Make sure that f is not coplanar and codirection with f1.
+        ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface));
+        if (ori1 == 0) {
+          // f is coplanar with f1 (see Fig. 8).
+          facenormal(torg, tdest, sapex(f1->ss), n1, 1);
+          facenormal(torg, tdest, sapex(sface), n2, 1);
+          if (DOT(n1, n2) > 0) {
+            // The two faces are codirectional as well.
+            unifysubfaces(&(f1->ss), &sface);
+          }
+        }
+        // Add this face to link if it is not deleted.
+        if (sface.sh[3] != NULL) {
+          // Add this face into link.
+          newlinkitem = (badface *) flippool->alloc();
+          newlinkitem->ss = sface;
+          newlinkitem->nextitem = NULL;
+          f1->nextitem = newlinkitem;
+        }
+      } else {
+        // The first face.
+        newlinkitem = (badface *) flippool->alloc();
+        newlinkitem->ss = sface;
+        newlinkitem->nextitem = NULL;
+        facelink = newlinkitem;
+      }
+    } // for (k = idx2faclist[idx]; ...)
+
+    if (b->verbose > 1) {
+      printf("    Found %ld segments at (%d  %d).\n", flippool->items,
+             pointmark(torg), pointmark(tdest));
+    }
+
+    // Set the connection between this segment and faces containing it,
+    //   at the same time, remove redundant segments.
+    f1 = facelink;
+    for (k = 0; k < flippool->items; k++) {
+      sspivot(f1->ss, testseg);
+      // If 'testseg' is not 'subsegloop' and is not dead, it is redundant.
+      if ((testseg.sh != subsegloop.sh) && (testseg.sh[3] != NULL)) {
+        shellfacedealloc(subsegpool, testseg.sh);
+      }
+      // Bonds the subface and the segment together.
+      ssbond(f1->ss, subsegloop);
+      f1 = f1->nextitem;
+    }
+
+    // Create the face ring at the segment.
+    if (flippool->items > 1) {
+      f1 = facelink;
+      for (k = 1; k <= flippool->items; k++) {
+        k < flippool->items ? f2 = f1->nextitem : f2 = facelink;
+        if (b->verbose > 2) {
+          printf("    Bond subfaces (%d, %d, %d) and (%d, %d, %d).\n",
+                 pointmark(torg), pointmark(tdest), pointmark(sapex(f1->ss)),
+                 pointmark(torg), pointmark(tdest), pointmark(sapex(f2->ss)));
+        }
+        sbond1(f1->ss, f2->ss);
+        f1 = f2;
+      }
+    }
+
+    // Set the unique segment marker into the unified segment.
+    setshellmark(subsegloop, segmarker);
+    segmarker++;
+    flippool->restart();
+
+    subsegloop.sh = shellfacetraverse(subsegpool);
+  }
+
+  delete [] idx2faclist;
+  delete [] facperverlist;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// mergefacets()    Merge adjacent coplanar facets.                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::mergefacets()
+{
+  arraypool *ptlist;
+  face parentsh, neighsh, neineighsh;
+  face segloop;
+  point eorg, edest, *parypt;
+  REAL ori, ori1, ori2;
+  bool mergeflag, aboveflag;
+  int* segspernodelist;
+  int fidx1, fidx2;
+  int i, j;
+
+  if (b->verbose > 1) {
+    printf("  Merging adjacent coplanar facets.\n");
+  }
+
+  // Initialize 'segspernodelist'.
+  segspernodelist = new int[pointpool->items + 1];
+  for (i = 0; i < pointpool->items + 1; i++) segspernodelist[i] = 0;
+
+  // Allocate a list for calculate an above point.
+  ptlist = new arraypool(sizeof(point *), 4);
+
+  // Loop all segments, counter the number of segments sharing each vertex.
+  subsegpool->traversalinit();
+  segloop.sh = shellfacetraverse(subsegpool);
+  while (segloop.sh != (shellface *) NULL) {
+    // Increment the number of sharing segments for each endpoint.
+    for (i = 0; i < 2; i++) {
+      j = pointmark((point) segloop.sh[3 + i]);
+      segspernodelist[j]++;
+    }
+    segloop.sh = shellfacetraverse(subsegpool);
+  }
+
+  // Loop all segments, merge adjacent coplanar facets.
+  subsegpool->traversalinit();
+  segloop.sh = shellfacetraverse(subsegpool);
+  while (segloop.sh != (shellface *) NULL) {
+    eorg = sorg(segloop);
+    edest = sdest(segloop);
+    spivot(segloop, parentsh);
+    spivot(parentsh, neighsh);
+    if (neighsh.sh != NULL) {
+      spivot(neighsh, neineighsh);
+      if (parentsh.sh == neineighsh.sh) {
+        // Exactly two subfaces at this segment.
+        fidx1 = getshellmark(parentsh) - 1;
+        fidx2 = getshellmark(neighsh) - 1;
+        // Possible to merge them if they are not in the same facet.
+        if (fidx1 != fidx2) {
+          // Test if they are coplanar wrt the tolerance.
+          ori = orient3d(eorg, edest, sapex(parentsh), sapex(neighsh));
+          if ((ori == 0) || iscoplanar(eorg, edest, sapex(parentsh),
+            sapex(neighsh), ori)) {
+            // Found two adjacent coplanar facets.
+            // Only can remove the segment if both apexes are on the 
+            //   different sides of the edge [eorg, edest].
+            ptlist->newindex((void **) &parypt);
+            *parypt = eorg;
+            ptlist->newindex((void **) &parypt);
+            *parypt = edest;
+            ptlist->newindex((void **) &parypt);
+            *parypt = sapex(parentsh);
+            ptlist->newindex((void **) &parypt);
+            *parypt = sapex(neighsh);
+            aboveflag = calculateabovepoint(ptlist, NULL, NULL, NULL);
+            if (aboveflag) {
+              ori1 = orient3d(eorg, edest, dummypoint, sapex(parentsh));
+              ori2 = orient3d(eorg, edest, dummypoint, sapex(neighsh));
+            } else {
+              ori1 = ori2 = 1.0; // Bad data.
+            }
+            if (ori1 * ori2 < 0) {
+              mergeflag = ((in->facetmarkerlist == NULL) || 
+                (in->facetmarkerlist[fidx1] == in->facetmarkerlist[fidx2]));
+              if (mergeflag) {
+                if (b->verbose > 1) {
+                  printf("  Removing segment (%d, %d).\n", pointmark(eorg),
+                         pointmark(edest));
+                }
+                ssdissolve(parentsh);
+                ssdissolve(neighsh);
+                shellfacedealloc(subsegpool, segloop.sh);
+                j = pointmark(eorg);
+                segspernodelist[j]--;
+                if (segspernodelist[j] == 0) {
+                  setpointtype(eorg, FACETVERTEX);
+                }
+                j = pointmark(edest);
+                segspernodelist[j]--;
+                if (segspernodelist[j] == 0) {
+                  setpointtype(edest, FACETVERTEX);
+                }
+                // Add the edge to flip stack.
+                futureflip = flipshpush(futureflip, &parentsh);
+              }
+            }
+            ptlist->restart(); // For the next test.
+          }
+        }
+      }
+    } // if (neighsh.sh != NULL)
+    segloop.sh = shellfacetraverse(subsegpool);
+  }
+
+  if (futureflip != NULL) {
+    // Do Delaunay flip.
+    lawsonflip();
+  }
+
+  delete ptlist;
+  delete [] segspernodelist;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// markacutevertices()    Classify vertices as ACUTEVERTEXs or RIDGEVERTEXs. //
+//                                                                           //
+// Initially, all segment vertices are marked as VOLVERTEX (after calling    //
+// incrementaldelaunay()).                                                   //
+//                                                                           //
+// A segment vertex is ACUTEVERTEX if it two segments incident it form an    //
+// interior angle less than 60 degree, otherwise, it is a RIDGEVERTEX.       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::markacutevertices()
+{
+  point pa, pb, pc;
+  REAL anglimit, ang;
+  bool acuteflag;
+  int acutecount;
+  int idx, i, j;
+
+  face* segperverlist;
+  int* idx2seglist;
+
+  if (b->verbose) {
+    printf("  Marking acute vertices.\n");
+  }
+
+  // Construct a map from points to segments.
+  makepoint2submap(subsegpool, idx2seglist, segperverlist);
+
+  anglimit = PI / 3.0;  // 60 degree.
+  acutecount = 0;
+
+  // Loop over the set of vertices.
+  pointpool->traversalinit();
+  pa = pointtraverse();
+  while (pa != NULL) {
+    idx = pointmark(pa) - in->firstnumber;
+    // Mark it if it is an endpoint of some segments.
+    if (idx2seglist[idx + 1] > idx2seglist[idx]) {
+      acuteflag = false;
+      // Do a brute-force pair-pair check.
+      for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !acuteflag; i++) {
+        pb = sdest(segperverlist[i]);
+        for (j = i + 1; j < idx2seglist[idx + 1] && !acuteflag; j++) {
+          pc = sdest(segperverlist[j]);
+          ang = interiorangle(pa, pb, pc, NULL);
+          acuteflag = ang < anglimit;
+        }
+      }
+      // Now mark the vertex.
+      if (b->verbose > 1) {
+        printf("    Mark %d as %s.\n", pointmark(pa), acuteflag ?
+          "ACUTEVERTEX" : "RIDGEVERTEX");
+      }
+      setpointtype(pa, acuteflag ? ACUTEVERTEX : RIDGEVERTEX);
+      acutecount += (acuteflag ? 1 : 0);
+    }
+    pa = pointtraverse();
+  }
+
+  if (b->verbose) {
+    printf("  %d acute vertices.\n", acutecount);
+  }
+
+  delete [] idx2seglist;
+  delete [] segperverlist;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// meshsurface()    Create a surface mesh of the input PLC.                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::meshsurface()
+{
+  arraypool *ptlist, *conlist;
+  point *idx2verlist;
+  point tstart, tend, *pnewpt, *cons;
+  tetgenio::facet *f;
+  tetgenio::polygon *p;
+  int end1, end2;
+  int shmark, i, j;
+
+  if (!b->quiet) {
+    printf("Creating surface mesh.\n");
+  }
+
+  // Create a map from indices to points.
+  makeindex2pointmap(idx2verlist);
+
+  // Initialize arrays (block size: 2^8 = 256).
+  ptlist = new arraypool(sizeof(point *), 8);
+  conlist = new arraypool(2 * sizeof(point *), 8);
+
+  // Loop the facet list, triangulate each facet.
+  for (shmark = 1; shmark <= in->numberoffacets; shmark++) {
+
+    // Get a facet F.
+    f = &in->facetlist[shmark - 1];
+
+    // Process the duplicated points first, they are marked with type
+    //   DUPLICATEDVERTEX.  If p and q are duplicated, and p'index > q's,
+    //   then p is substituted by q.
+    if (dupverts > 0l) {
+      // Loop all polygons of this facet.
+      for (i = 0; i < f->numberofpolygons; i++) {
+        p = &(f->polygonlist[i]);
+        // Loop other vertices of this polygon.
+        for (j = 0; j < p->numberofvertices; j++) {
+          end1 = p->vertexlist[j];
+          tstart = idx2verlist[end1];
+          if (getpointtype(tstart) == DUPLICATEDVERTEX) {
+            // Reset the index of vertex-j.
+            tend = point2ppt(tstart);
+            end2 = pointmark(tend);
+            p->vertexlist[j] = end2;
+          }
+        }
+      }
+    }
+
+    // Loop polygons of F, get the set of vertices and segments.
+    for (i = 0; i < f->numberofpolygons; i++) {
+      // Get a polygon.
+      p = &(f->polygonlist[i]);
+      // Get the first vertex.
+      end1 = p->vertexlist[0];
+      if ((end1 < in->firstnumber) || 
+          (end1 >= in->firstnumber + in->numberofpoints)) {
+        if (!b->quiet) {
+          printf("Warning:  Invalid the 1st vertex %d of polygon", end1);
+          printf(" %d in facet %d.\n", i + 1, shmark);
+        }
+        continue; // Skip this polygon.
+      }
+      tstart = idx2verlist[end1];
+      // Add tstart to V if it haven't been added yet.
+      if (!pinfected(tstart)) {
+        pinfect(tstart);
+        ptlist->newindex((void **) &pnewpt);
+        *pnewpt = tstart;
+      }
+      // Loop other vertices of this polygon.
+      for (j = 1; j <= p->numberofvertices; j++) {
+        // get a vertex.
+        if (j < p->numberofvertices) {
+          end2 = p->vertexlist[j];
+        } else {
+          end2 = p->vertexlist[0];  // Form a loop from last to first.
+        }
+        if ((end2 < in->firstnumber) ||
+            (end2 >= in->firstnumber + in->numberofpoints)) {
+          if (!b->quiet) {
+            printf("Warning:  Invalid vertex %d in polygon %d", end2, i + 1);
+            printf(" in facet %d.\n", shmark);
+          }
+        } else {
+          if (end1 != end2) {
+            // 'end1' and 'end2' form a segment.
+            tend = idx2verlist[end2];
+            // Add tstart to V if it haven't been added yet.
+            if (!pinfected(tend)) {
+              pinfect(tend);
+              ptlist->newindex((void **) &pnewpt);
+              *pnewpt = tend;
+            }
+            // Save the segment in S (conlist).
+            conlist->newindex((void **) &cons);
+            cons[0] = tstart;
+            cons[1] = tend;
+            // Set the start for next continuous segment.
+            end1 = end2;
+            tstart = tend;
+          } else {
+            // Two identical vertices mean an isolated vertex of F.
+            if (p->numberofvertices > 2) {
+              // This may be an error in the input, anyway, we can continue
+              //   by simply skipping this segment.
+              if (!b->quiet) {
+                printf("Warning:  Polygon %d has two identical verts", i + 1);
+                printf(" in facet %d.\n", shmark);
+              }
+            } 
+            // Ignore this vertex.
+          }
+        }
+        // Is the polygon degenerate (a segment or a vertex)?
+        if (p->numberofvertices == 2) break;
+      }
+    }
+    // Unmark vertices.
+    for (i = 0; i < ptlist->objects; i++) {
+      pnewpt = (point *) fastlookup(ptlist, i);
+      puninfect(*pnewpt);
+    }
+
+    // Triangulate F into a CDT.
+    triangulate(shmark, ptlist, conlist, f->numberofholes, f->holelist);
+
+    // Clear working lists.
+    ptlist->restart();
+    conlist->restart();
+  }
+
+  delete ptlist;
+  delete conlist;
+  delete [] idx2verlist;
+
+  // Remove redundant segments and build the face links.
+  unifysegments();
+
+  if (b->object == tetgenbehavior::STL) {
+    // Remove redundant vertices (for .stl input mesh).
+    jettisonnodes();
+  }
+
+  if (!b->nomerge && !b->nobisect) {
+    // Merge adjacent coplanar facets.
+    mergefacets();
+  }
+
+  // Mark acutes vertices.
+  markacutevertices();
+
+  // The total number of iunput segments.
+  insegments = subsegpool->items;
+}
+
+#endif // #ifndef surfaceCXX
\ No newline at end of file
diff --git a/contrib/TetgenNew/tetgen.h b/contrib/TetgenNew/tetgen.h
new file mode 100644
index 0000000000..b7e971f039
--- /dev/null
+++ b/contrib/TetgenNew/tetgen.h
@@ -0,0 +1,1922 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// TetGen                                                                    //
+//                                                                           //
+// A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator         //
+//                                                                           //
+// Develop version                                                           //
+// Start: August 9, 2008                                                     //
+//                                                                           //
+// Copyright (C) 2002--2008                                                  //
+// Hang Si                                                                   //
+// Research Group: Numerical Mathematics and Scientific Computing            //
+// Weierstrass Institute for Applied Analysis and Stochastics                //
+// Mohrenstr. 39, 10117 Berlin, Germany                                      //
+// si@wias-berlin.de                                                         //
+//                                                                           //
+// TetGen is freely available through the website: http://tetgen.berlios.de. //
+//   It may be copied, modified, and redistributed for non-commercial use.   //
+//   Please consult the file LICENSE for the detailed copyright notices.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef tetgenH
+#define tetgenH
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetgen.h                                                                  //
+//                                                                           //
+// Header file of the TetGen library. Also is the user-level header file.    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// Header files for using the C/C++ standard library.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include <assert.h>
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// TetGen Library                                                            //
+//                                                                           //
+// The library consists of three classes: tetgenio, tetgenbehavior, and      //
+// tetgenmesh. Tetgenio provides interfaces for passing data into and out of //
+// the library; tetgenbehavior keeps the runtime options and thus controls   //
+// the behaviors of TetGen; tetgenmesh implements mesh data strcutures and   //
+// algorithms for generating meshes.                                         //
+//                                                                           //
+// There are few global functions. tetrahedralize() is provided for calling  //
+// TetGen from another program. Two functions: orient3d() and insphere() are //
+// incorporated from a public C code provided by Shewchuk.  They performing  //
+// exact geometrical tests.                                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// To compile TetGen as a library instead of an executable program, define
+//   the TETLIBRARY symbol.
+
+// #define TETLIBRARY
+
+// Uncomment the following line to disable assert macros. These macros are
+//   inserted in places where I hope to catch bugs.
+
+// #define NDEBUG
+
+// To insert lots of self-checks for internal errors, define the SELF_CHECK
+//   symbol.  This will slow down the program significantly. 
+
+// #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.
+
+// #define SINGLE
+
+#ifdef SINGLE
+  #define REAL float
+#else
+  #define REAL double
+#endif 	// not defined SINGLE
+
+// Maximum number of characters in a file name (including the null).
+
+enum {FILENAMESIZE = 1024};
+
+// Maximum numbers of chars in a line read from a file (incl. the null).
+
+enum {INPUTLINESIZE = 1024};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetgenio    Passing data into and out of the library.                     //
+//                                                                           //
+// This class contains a collection of arrays which stores points, facets,   //
+// tetrahedra, and so forth. TetGen will read and write these arrays accord- //
+// ing to the options specified in a tetgenbehavior object. The arrays are   //
+// corresponding to the fields defined in TetGen's input/output file formats.//
+// If you want to use the library of TetGen, It is necessary to understand   //
+// TetGen's input/output file formats (see user's manual).                   //
+//                                                                           //
+// Once an object of tetgenio is declared,  no array is created. One has to  //
+// allocate enough memory for them, e.g., use the "new" operator in C++. On  //
+// deletion of the object, the memory occupied by these arrays needs to be   //
+// freed.  Routine deinitialize() will be automatically called. It will de-  //
+// allocate the memory for an array if it is not a NULL. However, it assumes //
+// that the memory is allocated by the C++ "new" operator. If you use malloc //
+// (), you should free() them and set the pointers to NULLs before reaching  //
+// deinitialize().                                                           //
+//                                                                           //
+// In all cases, the first item in an array is stored starting at index [0]. //
+// However, that item is item number `firstnumber' which may be '0' or '1'.  //
+// Be sure to set the 'firstnumber' be '1' if your indices pointing into the //
+// pointlist is starting from '1'. Default, it is '0'.                       //
+//                                                                           //
+// Tetgenio also contains routines for reading and writing TetGen's files as //
+// well.  Both the library of TetGen and TetView use these routines to parse //
+// input files, i.e., .node, .poly, .smesh, .ele, .face, and .edge files.    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+class tetgenio {
+
+  public:
+
+    // The polygon structure.  A "polygon" is a planar polygon which may be
+    //   non-convex but contains no holes. 
+    // 'vertexlist' is a list of vertices (indices) of the polygon odered in
+    //   either counterclockwise or clockwise way. 
+    
+    typedef struct {
+      int *vertexlist;
+      int numberofvertices;
+    } polygon;
+
+    static void init(polygon* p) {
+      p->vertexlist = (int *) NULL;
+      p->numberofvertices = 0;
+    }
+
+    // The facet structure.  A "facet" is a facet. It may be non-convex and
+    //   contains arbitrary number of holes. Hence it consistes of a list of
+    //   polygons and a list holes.
+
+    typedef struct {
+      polygon *polygonlist;
+      int numberofpolygons;
+      REAL *holelist;
+      int numberofholes;
+    } facet;
+
+    static void init(facet* f) {
+      f->polygonlist = (polygon *) NULL;
+      f->numberofpolygons = 0;
+      f->holelist = (REAL *) NULL;
+      f->numberofholes = 0;
+    }
+
+    // A 'voroedge' is an edge of the Voronoi diagram. It corresponds to a
+    //   Delaunay face.  Each voroedge is either a line segment connecting
+    //   two Voronoi vertices or a ray starting from a Voronoi vertex to an
+    //   "infinite vertex".  'v1' and 'v2' are two indices pointing to the
+    //   list of Voronoi vertices. 'v1' must be non-negative, while 'v2' may
+    //   be -1 if it is a ray, in this case, the unit normal of this ray is
+    //   given in 'vnormal'. 
+    
+    typedef struct {
+      int v1, v2;
+      REAL vnormal[3];
+    } voroedge;
+
+    // A 'vorofacet' is an facet of the Voronoi diagram. It corresponds to a
+    //   Delaunay edge.  Each Voronoi facet is a convex polygon formed by a
+    //   list of Voronoi edges, it may not be closed.  'c1' and 'c2' are two
+    //   indices pointing into the list of Voronoi cells, i.e., the two cells
+    //   share this facet.  'elist' is an array of indices pointing into the
+    //   list of Voronoi edges, 'elist[0]' saves the number of Voronoi edges
+    //   (including rays) of this facet.
+    
+    typedef struct {
+      int c1, c2;
+      int *elist;
+    } vorofacet;
+
+    // The periodic boundary condition group data structure.  A "pbcgroup"
+    //   contains the definition of a pbc and the list of pbc point pairs.
+    //   'fmark1' and 'fmark2' are the facetmarkers of the two pbc facets f1
+    //   and f2, respectively. 'transmat' is the transformation matrix which
+    //   maps a point in f1 into f2.  An array of pbc point pairs are saved
+    //   in 'pointpairlist'. The first point pair is at indices [0] and [1],
+    //   followed by remaining pairs. Two integers per pair.
+    
+    typedef struct {
+      int fmark1, fmark2;
+      REAL transmat[4][4];
+      int numberofpointpairs;
+      int *pointpairlist;
+    } pbcgroup;
+
+  public:
+
+    // Items are numbered starting from 'firstnumber' (0 or 1), default is 0.
+    int firstnumber; 
+    // Dimension of the mesh (2 or 3), default is 3.
+    int mesh_dim;
+    // Does the lines in .node file contain index or not, default is TRUE.
+    bool useindex;
+
+    // 'pointlist':  The array of point coordinates.  The first point's x
+    //   coordinate is at index [0] and its y coordinate at index [1], its
+    //   z coordinate is at index [2], followed by the coordinates of the
+    //   remaining points.  Each point occupies three REALs. 
+    // 'pointattributelist':  An array of point attributes.  Each point's
+    //   attributes occupy 'numberofpointattributes' REALs.
+    // 'pointmtrlist': An array of metric tensors at points. Each point's
+    //   tensor occupies 'numberofpointmtr' REALs.
+    // 'pointmarkerlist':  An array of point markers; one int per point.
+    
+    REAL *pointlist;
+    REAL *pointattributelist;
+    REAL *pointmtrlist;
+    int *pointmarkerlist;
+    int numberofpoints;
+    int numberofpointattributes;
+    int numberofpointmtrs;
+ 
+    // 'tetrahedronlist':  The array of tetrahedra.  The first tet's first
+    //   node is at index [0], followed by its other nodes, optionally
+    //   followed by quadratc nodes of the tet.  Each tet occupies
+    //   'numberofcorners' (4 or 6) ints.
+    // 'tetrahedronattributelist':  The array of tet attributes.  Each tet
+    //   has `numberoftetrahedronattributes' REALs.
+    // 'tetrahedronvolumelist':  The array of constraints, i.e. tetrahedron's
+    //   maximum volume; one REAL per element. Input only.
+    // 'neighborlist':  The array of element neighbors; 'numberofcorners'
+    //   ints per element. Output only.
+    
+    int *tetrahedronlist;
+    REAL *tetrahedronattributelist;
+    REAL *tetrahedronvolumelist;
+    int *neighborlist;
+    int numberoftetrahedra;
+    int numberofcorners;
+    int numberoftetrahedronattributes;
+
+    // `facetlist':  The array of facets.  Each entry is a structure of facet.
+    // `facetmarkerlist':  An array of facet markers; one int per facet.
+    
+    facet *facetlist;
+    int *facetmarkerlist;
+    int numberoffacets;
+
+    // `holelist':  The array of volume holes.  The first hole's x, y and z
+    //   coordinates  are at indices [0], [1] and [2], followed by the
+    //   remaining holes. Three REALs per hole. 
+    
+    REAL *holelist;
+    int numberofholes;
+
+    // `regionlist': The array of regional attributes and volume constraints.
+    //   The first constraint's x, y and z coordinates are at indices [0],
+    //   [1] and [2], followed by the regional attribute at index [3], foll-
+    //   owed by the maximum volume at index [4]. Five REALs per constraint. 
+    // Note that each regional attribute is used only if you select the `A'
+    //   switch, and each volume constraint is used only if you select the
+    //   `a' switch (with no number following).
+    
+    REAL *regionlist;
+    int numberofregions;
+
+    // `facetconstraintlist': The array of facet maximal area constraints.
+    //   Two REALs per constraint. The first one is the facet marker (cast
+    //   it to int), the second is its maximum area bound.
+    // Note the 'facetconstraintlist' is used only for the 'q' switch. 
+    
+    REAL *facetconstraintlist;
+    int numberoffacetconstraints;
+
+    // `segmentconstraintlist': The array of segment max. length constraints.
+    //   Three REALs per constraint. The first two are the indices (pointing
+    //   into 'pointlist') of the endpoints of the segment, the third is its
+    //   maximum length bound.
+    // Note the 'segmentconstraintlist' is used only for the 'q' switch.
+     
+    REAL *segmentconstraintlist;
+    int numberofsegmentconstraints;
+
+    // 'pbcgrouplist':  The array of periodic boundary condition groups.
+    
+    pbcgroup *pbcgrouplist;
+    int numberofpbcgroups;
+
+    // `trifacelist':  The array of triangluar face list.  The first face's
+    //   endpoints are at indices [0], [1] and [2], followed by the
+    //   remaining faces.  Three ints per face.
+    // `adjtetlist':  The array of adjacent tets. Each face has at most two
+    //   adjacent tets, the first face's adjacent tets are at [0], [1]. Two
+    //   ints per face. A '-1' indicates outside (no adj. tet).  This list
+    //   is output when '-nn' switch is used.
+    // `trifacemarkerlist':  The array of face markers; one int per face.
+    
+    int *trifacelist;
+    int *adjtetlist;
+    int *trifacemarkerlist;
+    int numberoftrifaces;
+
+    // `edgelist':  The array of edges (or segments).  The first edge's 
+    //   endpoints are at indices [0] and [1], followed by the remaining 
+    //   edges.  Two ints per edge.
+    // `edgemarkerlist':  The array of edge markers; one int per edge.
+    
+    int *edgelist;
+    int *edgemarkerlist;
+    int numberofedges;
+
+    // 'vpointlist':  The array of Voronoi vertex coordinates (like pointlist).
+    // 'vedgelist':  The array of Voronoi edges.  Each entry is a 'voroedge'.
+    // 'vfacetlist':  The array of Voronoi facets. Each entry is a 'vorofacet'.
+    // 'vcelllist':  The array of Voronoi cells.  Each entry is an array of
+    //   indices pointing into 'vfacetlist'. The 0th entry is used to store
+    //   the length of this array.
+    
+    REAL *vpointlist;
+    voroedge *vedgelist;
+    vorofacet *vfacetlist;
+    int **vcelllist;
+    int numberofvpoints;
+    int numberofvedges;
+    int numberofvfacets;
+    int numberofvcells;
+
+  public:
+
+    // Initialize routine.
+    void initialize();
+    void deinitialize();
+
+    // Input & output routines.
+    bool load_node_call(FILE* infile, int markers, const char* nodefilename);
+    bool load_node(const char* filename);
+    bool load_pbc(const char* filename);
+    bool load_var(const char* filename);
+    bool load_mtr(const char* filename);
+    bool load_poly(const char* filename);
+    bool load_off(const char* filename);
+    bool load_ply(const char* filename);
+    bool load_stl(const char* filename);
+    bool load_medit(const char* filename);
+    bool load_vtk(const char* filename);
+    bool load_plc(const char* filename, int object);
+    bool load_tetmesh(const char* filename);
+    bool load_voronoi(const char* filename);
+    void save_nodes(const char* filename);
+    void save_elements(const char* filename);
+    void save_faces(const char* filename);
+    void save_edges(const char* filename);
+    void save_neighbors(const char* filename);
+    void save_poly(const char* filename);
+
+    // Read line and parse string functions.
+    char *readline(char* string, FILE* infile, int *linenumber);
+    char *findnextfield(char* string);
+    char *readnumberline(char* string, FILE* infile, const char* infilename);
+    char *findnextnumber(char* string);
+
+    // Constructor and destructor.
+    tetgenio() {initialize();}
+    ~tetgenio() {deinitialize();}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetgenbehavior    Parsing command line switches and file names.           //
+//                                                                           //
+// It includes a list of variables corresponding to the commandline switches //
+// for control the behavior of TetGen.  These varibales are all initialized  //
+// to their default values.                                                  //
+//                                                                           //
+// Use function parse_commandline() to set the vaules of the variables.  It  //
+// accepts the standard parameters (e.g., 'argc' and 'argv') that pass to C  //
+// & C++ main() function. Alternatively a string which contains the command  //
+// line options can be used as its parameter.  Please refer to the User's    //
+// manula for the availble options of TetGen.                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+class tetgenbehavior {    // Begin of class tetgenbehavior
+
+  public:
+
+  // Labels defining the input objects supported by TetGen. They are 
+  //   identified from the file extension of the inputs.
+  //   - NODES, a list of nodes (.node); 
+  //   - POLY, a piecewise linear complex (.poly or .smesh); 
+  //   - OFF, a polyhedron (.off, Geomview's file format); 
+  //   - PLY, a polyhedron (.ply, file format from gatech);
+  //   - STL, a surface mesh (.stl, stereolithography format);
+  //   - MEDIT, a surface mesh (.mesh, Medit's file format); 
+  //   - MESH, a tetrahedral mesh (.ele).
+  //   If no extension is available, the imposed commandline switch
+  //   (-p or -r) implies the type of the object. 
+
+  enum objecttype {NONE, NODES, POLY, OFF, PLY, STL, MEDIT, VTK, MESH};
+
+  // Variables of command line switches. Each variable corresponds to a
+  //   switch. Most of them are initialized to 0.
+
+  int plc;                                                           // -p
+  int quality;                                                       // -q
+  int refine;                                                        // -r
+  int coarse;                                                        // -R
+  int metric;                                                        // -m
+  int varvolume;                                    // -a without a number
+  int fixedvolume;                                     // -a with a number
+  int bowyerwatson;                                                  // -b
+  int convexity;                                                     // -c
+  int insertaddpoints;                                               // -i
+  int regionattrib;                                                  // -A
+  int conformdel;                                                    // -D
+  int diagnose;                                                      // -d
+  int zeroindex;                                                     // -z
+  int order;                                                         // -o
+  int facesout;                                                      // -f
+  int edgesout;                                                      // -e
+  int neighout;                                                      // -n
+  int voroout;                                                       // -v
+  int meditview;                                                     // -g
+  int gidview;                                                       // -G
+  int geomview;                                                      // -O
+  int nobound;                                                       // -B
+  int nonodewritten;                                                 // -N
+  int noelewritten;                                                  // -E
+  int nofacewritten;                                                 // -F
+  int noiterationnum;                                                // -I
+  int nomerge;                                                       // -M
+  int nobisect;                                                      // -Y
+  int nojettison;                                                    // -J
+  int docheck;                                                       // -C
+  int quiet;                                                         // -Q
+  int verbose;                                                       // -V
+  int useshelles;                                 // -p, -r, -q, -d, or -R
+  long steinerleft;                                    // -S with a number
+  REAL minratio;                                        // number after -q
+  REAL goodratio;                     // number calculated from 'minratio' 
+  REAL minangle;                                    // minimum angle bound
+  REAL goodangle;                            // cosine squared of minangle
+  REAL maxvolume;                                       // number after -a
+  REAL mindihedral;                                    // number after -qq
+  REAL maxdihedral;                                   // number after -qqq
+  REAL epsilon;                                         // number after -T
+  enum objecttype object;                       // determined by -p, or -r
+
+  // Variables used to save command line switches and in/out file names.
+  char commandline[1024];
+  char infilename[1024];
+  char outfilename[1024];
+  char addinfilename[1024];
+  char bgmeshfilename[1024];
+
+  void versioninfo();
+  void syntax();
+  void usage();
+
+  // Command line parse routine.
+  bool parse_commandline(int argc, char **argv);
+  bool parse_commandline(char *switches) {
+    return parse_commandline(0, &switches);
+  }
+  
+  tetgenbehavior();
+  ~tetgenbehavior() {}  
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Geometric predicates                                                      //
+//                                                                           //
+// Return one of the values +1, 0, and -1 on basic geometric questions such  //
+// as the orientation of point sets, in-circle, and in-sphere tests.  They   //
+// are basic units for implmenting geometric algorithms.  TetGen uses two 3D //
+// geometric predicates: the orientation and in-sphere tests.                //
+//                                                                           //
+// Orientation test:  let a, b, c be a sequence of 3 non-collinear points in //
+// R^3.  They defines a unique hypeplane H.  Let H+ and H- be the two spaces //
+// separated by H, which are defined as follows (using the left-hand rule):  //
+// make a fist using your left hand in such a way that your fingers follow   //
+// the order of a, b and c, then your thumb is pointing to H+.  Given any    //
+// point d in R^3, the orientation test returns +1 if d lies in H+, -1 if d  //
+// lies in H-, or 0 if d lies on H.                                          //
+//                                                                           //
+// In-sphere test:  let a, b, c, d be 4 non-coplanar points in R^3.  They    //
+// defines a unique circumsphere S.  Given any point e in R^3, the in-sphere //
+// test returns +1 if e lies inside S, or -1 if e lies outside S, or 0 if e  //
+// lies on S.                                                                //
+//                                                                           //
+// The correctness of geometric predicates is crucial for the control flow   //
+// and hence for the correctness and robustness of an implementation of a    //
+// geometric algorithm.  The following routines use arbitrary precision      //
+// floating-point arithmetic. They are fast and robust. It is provided by J. //
+// Schewchuk in public domain (http://www.cs.cmu.edu/~quake/robust.html).    //
+// The source code are found in a separate file "predicates.cxx".            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL exactinit();
+REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd);
+REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe);
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Class tetgenmesh                                                          //
+//                                                                           //
+// An object of tetgenmesh can be used to store a triangular or tetrahedral  //
+// mesh and its settings. TetGen's functions operates on one mesh each time. //
+// This type allows reusing of the same function for different meshes.       //
+//                                                                           //
+// The mesh data structure (tetrahedron-based and triangle-edge data struct- //
+// ures) are declared. There are other accessary data type defined as well,  //
+// for efficient memory management and link list operations, etc.            //
+//                                                                           //
+// All algorithms TetGen used are implemented in this data type as member    //
+// functions. References of these algorithms can be found in user's manual.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+class tetgenmesh {  // Begin of class tetgenmesh
+///////////////////////////////////////////////////////////////////////////////
+
+public:
+  
+// For efficiency, a variety of data structures are allocated in bulk.
+//   The following constants determine how many of each structure is
+//   allocated at once.
+
+enum {VERPERBLOCK = 4092, SUBPERBLOCK = 4092, ELEPERBLOCK = 8188};
+    
+// Labels that signify whether a record consists primarily of pointers
+//   or of floating-point words. Used for data alignment in memorypool.
+
+enum wordtype {POINTER, FLOATINGPOINT};
+
+// Labels that signify the type of a vertex. 
+
+enum verttype {UNUSEDVERTEX, DUPLICATEDVERTEX, VOLVERTEX, RIDGEVERTEX, 
+  ACUTEVERTEX, FACETVERTEX, STEINERVERTEX, DEADVERTEX};
+
+// Labels that signify the result of point location.
+
+enum location {INTET, ONFACE, ONEDGE, ONVERTEX, OUTSIDE, ENCSEGMENT, ENCFACE};
+
+// Labels that signify the result of intersection tests.
+
+enum intersection {DISJOINT, INTERSECT, SHAREVERT, SHAREEDGE, SHAREFACE,
+  TOUCHEDGE, TOUCHFACE, ACROSSVERT, ACROSSEDGE, ACROSSFACE, ACROSSTET,
+  TRIEDGEINT, EDGETRIINT, COLLISIONFACE, ACROSSSUBSEG, ACROSSSUBFACE};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh data structures                                                      //
+//                                                                           //
+// There are four types of mesh elements: tetrahedra, subfaces, subsegments, //
+// and points,  where subfaces and subsegments are triangles and edges which //
+// appear on boundaries.  The elements of all the four types consist of a    //
+// tetrahedral mesh of a 3D domain.  TetGen uses three data types:  'tetra-  //
+// hedron', 'shellface', and 'point'. A 'tetrahedron' is a tetrahedron;  a   //
+// 'shellface' represents either a subface or a subsegment;  and a 'point'   //
+// is a point.  These three data types, linked by pointers comprise a mesh.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// The tetrahedron data structure.  
+typedef REAL **tetrahedron;
+
+// The shellface data structure. 
+typedef REAL **shellface;
+
+// The point data structure.  
+typedef REAL *point;
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh handles                                                              //
+//                                                                           //
+// Two special data types, 'triface' and 'face' are defined for maintaining  //
+// and updating meshes. They are like pointers (or handles), which allow you //
+// to hold one particular part of the mesh, i.e., a tetrahedron, a triangle, //
+// an edge and a vertex.  However, these data types do not themselves store  //
+// any part of the mesh. The mesh is made of the data types defined above.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// A 'triface' holds a tetrahedron 'tet'. In particular, it holds one
+//   edge of a face of the tetrahedron.  Since each tetrahedron has 4
+//   faces and each face has 6 directed edges, hence there are total
+//   24 different edges in 'tet'. Each edge of 'tet' is represented by
+//   a pair (loc, ver), where 'loc' (range from 0 to 3) indicates a face
+//   of 'tet', and 'ver' (range from 0 to 5) indicates a directed edge
+//   edge of that face.
+
+class triface {
+
+  public:
+
+  tetrahedron* tet;
+  int loc, ver;
+
+  // Constructors;
+  triface() : tet(0), loc(0), ver(0) {}
+  // Operators;
+  triface& operator=(const triface& t) {
+    tet = t.tet; loc = t.loc; ver = t.ver;
+    return *this;
+  }
+  bool operator==(triface& t) {
+    return tet == t.tet && loc == t.loc && ver == t.ver;
+  }
+  bool operator!=(triface& t) {
+    return tet != t.tet || loc != t.loc || ver != t.ver;
+  }
+};
+
+// A 'face' holds a shellface 'sh'. In particular, it holds one directed
+//   edge of the shellface. There are 6 directed edges in a triangle.
+//   'shver' (range from 0 to 5) indicates a directed edge in 'sh'.
+
+class face {
+
+  public:
+
+  shellface *sh;
+  int shver;
+
+  // Constructors;
+  face() : sh(0), shver(0) {}
+  // Operators;
+  face& operator=(const face& s) {
+    sh = s.sh; shver = s.shver;
+    return *this;
+  }
+  bool operator==(face& s) {return (sh == s.sh) && (shver == s.shver);}
+  bool operator!=(face& s) {return (sh != s.sh) || (shver != s.shver);}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Arraypool    A dynamic array                                              //
+//                                                                           //
+// Each arraypool contains an array of pointers to a number of blocks.  Each //
+// block contains the same fixed number of objects.  Each index of the array //
+// addesses a particular object in the pool.  The most significant bits add- //
+// ress the index of the block containing the object. The less significant   //
+// bits address this object within the block.                                //
+//                                                                           //
+// 'objectbytes' is the size of one object in blocks; 'log2objectsperblock'  //
+// is the base-2 logarithm of 'objectsperblock'; 'objects' counts the number //
+// of allocated objects; 'totalmemory' is the totoal memorypool in bytes.    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+class arraypool {
+
+  public:
+
+  int objectbytes;
+  int objectsperblock;
+  int log2objectsperblock; 
+  int toparraylen;
+  char **toparray;
+  unsigned long objects;
+  unsigned long totalmemory;
+
+  void restart();
+  void poolinit(int sizeofobject, int log2objperblk);
+  char* getblock(int objectindex);
+  void* lookup(int objectindex);
+  int newindex(void **newptr);
+
+  arraypool(int sizeofobject, int log2objperblk);
+  ~arraypool();
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Memorypool    A dynamic pool of memory                                    //
+//                                                                           //
+// A type used to allocate memory written by J. Shewchuk.                    //
+//                                                                           //
+// 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.                                                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+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;
+
+  void poolinit(int, int, enum wordtype, int);
+  void restart();
+  void *alloc();
+  void dealloc(void*);
+  void traversalinit();
+  void *traverse();
+
+  memorypool() {}
+  memorypool(int, int, enum wordtype, int);
+  ~memorypool();
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// The badface structure                                                     //
+//                                                                           //
+// A multiple usages structure. Despite of its name, a 'badface' can be used //
+// to represent the following objects:                                       //
+//   - a face of a tetrahedron which is (possibly) non-Delaunay;             //
+//   - an encroached subsegment or subface;                                  //
+//   - a bad-quality tetrahedron, i.e, has too large radius-edge ratio;      //
+//   - a sliver, i.e., has good radius-edge ratio but nearly zero volume;    //
+//   - a degenerate tetrahedron (see routine checkdegetet()).                //
+//   - a recently flipped face (saved for undoing the flip later).           //
+//                                                                           //
+// It has the following fields:  'tt' holds a tetrahedron; 'ss' holds a sub- //
+// segment or subface; 'cent' is the circumcent of 'tt' or 'ss', 'key' is a  //
+// special value depending on the use, it can be either the square of the    //
+// radius-edge ratio of 'tt' or the flipped type of 'tt';  'forg', 'fdest',  //
+// 'fapex', and 'foppo' are vertices saved for checking the object in 'tt'   //
+// or 'ss' is still the same when it was stored; 'noppo' is the fifth vertex //
+// of a degenerate point set.  'previtem' and 'nextitem' implement a double  //
+// link for managing many basfaces.                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+struct badface {
+  triface tt; 
+  face ss; 
+  REAL key;
+  REAL cent[3];
+  point forg, fdest, fapex, foppo, noppo;
+  struct badface *previtem, *nextitem; 
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Fast Lookup Tables                                                        //
+//                                                                           //
+// The mesh data structures additionally store geometric informations which  //
+// help for fast queries.                                                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// For enext() primitive, uses 'ver' as the key.
+static int ve[6], ve2[6];
+
+// For sorg(), sdest, spaex(), use 'shver' as the key.
+static int vo[6], vd[6], va[6];
+
+// For bond(), t1 and t2 are two symmetric faces sharing the same edges, it
+//   takes t1's and t2's edge versions as the first and second keys, returns
+//   t2's edge corresponds to t1's 0th edge.
+// Note: the returned edge version is in {0, 2, 4}. The same follows.
+static int verver2zero[6][6];
+
+// For bond(), t1's edge corresponds to t2's 0th edge, it takes t1's edge
+//   version as the key, returns t2's edge corresponds to t1's 0th edge.
+static int ver2zero[6];
+
+// For fnext(), symedge(), t1 and t2 share the same face, and t2's edge
+//   corresponds to t1's 0th edge, it takes t1's and t2's edge versions as
+//   the first and second keys, return t2's edge corresponds to t1's edge. 
+static int zero2ver[6][6];
+
+// For org(), dest() and apex() primitives, use ('loc', 'ver') as the key.
+static int locver2org[4][6];
+static int locver2dest[4][6];
+static int locver2apex[4][6];
+
+// For oppo() primitives, uses 'loc' as the key.
+static int loc2oppo[4];
+
+// For fnext() primitives, uses ('loc' * 8 + 'ver') as the key. Returns
+//   an array containing a new ('loc', 'ver'). 
+// Note: Only valid for 'ver' equals one of {0, 2, 4}.
+static int locver2nextf[32];
+
+// Twos maps between ('loc', 'ver') and the edge number (from 0 to 5).
+static int locver2edge[4][6];
+static int edge2locver[6][2];
+
+// The map from a given face ('loc') to the other three faces in the tet.
+//   and the map from a given face's edge ('loc', 'ver') to other two
+//   faces in the tet opposite to this edge. (used in speeding the Bowyer-
+//   Watson cavity construction).
+static int locpivot[4][3];
+static int locverpivot[4][6][2];
+
+static int mi1mo3[3];
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh manipulation primitives                                              //
+//                                                                           //
+// Mesh navigation and updating are accomplished through a set of mesh       //
+// manipulation primitives which operate on trifaces and faces.  They are    //
+// introduced below.                                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Primitives for tetrahedron                                                //
+//                                                                           //
+// Each tetrahedron contains four pointers to its adjacent tetrahedra, with  //
+// their face indices (loc in [0, 3]) and edge versions (ver in [0, 5]).  To //
+// save memory, all informations of an adjacent tetrahedron are compressed   //
+// in a single pointer. To make this possible, all tetrahedra are aligned to //
+// 16-byte boundaries, so that the last four bits of each pointer are zeros. //
+// Each face indice (loc) is compressed into the last two bits,  each edge   //
+// version (ver) is compressed into the second last two bits of the pointer, //
+// respectively. encode() and decode() functions implement this feature.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// encode() -- to compress a triface 't' into a single pointer. 
+//   't.ver' is in [0, 5], first we map it to [0, 2], this is equal to
+//   divide it by 2 (>> 1), next we shift it to the second last two bits
+//   of the pointer, this is equal to multiply it by 4 (<< 2). 
+// Note: Do not combine the bit options for (t).ver.
+
+#define encode(t) (tetrahedron) ((unsigned long) (t).tet | \
+  ((unsigned long) (((t).ver >> 1) << 2)) | (unsigned long) (t).loc)
+
+// decode() -- to decompose a pointer 'ptr' into a triface 't'. 
+//   For obtaining t.ver, we first extract it (& 12l), then shift it to
+//   the right by 2 bits (>> 2), then multiply it by 2 (<< 1), hence 
+//   t.ver is in {0,2,4}. Combining the last two operations, we only
+//   need to divide it by 2 (>> 1).
+
+#define decode(ptr, t) \
+  (t).loc = (int) ((unsigned long) (ptr) & (unsigned long) 3l);\
+  (t).ver = (int) (((unsigned long) (ptr) & (unsigned long) 12l) >> 1);\
+  (t).tet = (tetrahedron *) ((unsigned long) (ptr) & ~(unsigned long) 15l)
+    
+// sym() -- given triface 't1', get a triface 't2', where 't1' and 't2'
+//   are the same face in two adjacent tetrahedra. But they may not be 
+//   the same edge. (Refer to bond() function.)
+    
+#define sym(t1, t2) decode((t1).tet[(t1).loc], (t2))
+    
+#define symself(t) \
+  ptr = (t).tet[(t).loc];\
+  decode(ptr, (t))
+  
+// symedge() -- given triface 't1', get a triface 't2', where 't1' and 't2'
+//   are the same face and the same edge in two adjacent tetrahedra.
+// Require "tetrahedron ptr;" and "int tver".
+
+#define symedge(t1, t2) \
+  decode((t1).tet[(t1).loc], (t2));\
+  (t2).ver = zero2ver[(t1).ver][(t2).ver]
+
+#define symedgeself(t) \
+  ptr = (t).tet[(t).loc];\
+  tver = (t).ver;\
+  decode(ptr, (t));\
+  (t).ver = zero2ver[tver][(t).ver];
+
+// org(), dest(), apex(), oppo() -- return the origin, destination, apex,
+//   and opposite vertices of the triface.
+    
+#define org(t) (point) (t).tet[locver2org[(t).loc][(t).ver] + 4]
+
+#define dest(t) (point) (t).tet[locver2dest[(t).loc][(t).ver] + 4]
+
+#define apex(t) (point) (t).tet[locver2apex[(t).loc][(t).ver] + 4]
+
+#define oppo(t) (point) (t).tet[loc2oppo[(t).loc] + 4]
+
+#define setorg(t, p) \
+  (t).tet[locver2org[(t).loc][(t).ver] + 4] = (tetrahedron) (p)
+
+#define setdest(t, p) \
+  (t).tet[locver2dest[(t).loc][(t).ver] + 4] = (tetrahedron) (p)
+
+#define setapex(t, p) \
+  (t).tet[locver2apex[(t).loc][(t).ver] + 4] = (tetrahedron) (p)
+
+#define setoppo(t, p) (t).tet[loc2oppo[(t).loc] + 4] = (tetrahedron) (p)
+
+#define setvertices(t, p1, p2, p3, p4) \
+  setorg(t, p1); \
+  setdest(t, p2); \
+  setapex(t, p3); \
+  setoppo(t, p4)
+
+// esym(), enext(), enext2() -- primitives for moving edges in face.
+//   The face remains the same.
+
+#define esym(t1, t2) \
+  (t2).tet = (t1).tet; (t2).loc = (t1).loc;\
+  (t2).ver = (t1).ver + (((t1).ver & 01) ? -1 : 1)
+
+#define esymself(t) (t).ver += (((t).ver & 01) ? -1 : 1)
+
+#define enext(t1, t2) \
+  (t2).tet = (t1).tet; (t2).loc = (t1).loc;\
+  (t2).ver = ve[(t1).ver]
+
+#define enextself(t) (t).ver = ve[(t).ver]
+
+#define enext2(t1, t2) \
+  (t2).tet = (t1).tet; (t2).loc = (t1).loc;\
+  (t2).ver = ve2[(t1).ver]
+
+#define enext2self(t) (t).ver = ve2[(t).ver]
+
+// enextfnext(), enext2fnext() -- primitives for moving faces in tet.
+//   the tetrahedron remains the same. 
+// Note: The input edge version is in {0, 2, 4}.
+
+#define enext0fnext(t1, t2) \
+  iptr = &(locver2nextf[(t1).loc * 8 + (t1).ver]);\
+  (t2).tet = (t1).tet;\
+  (t2).loc = iptr[0];\
+  (t2).ver = iptr[1]
+
+#define enext0fnextself(t) \
+  iptr = &(locver2nextf[(t).loc * 8 + (t).ver]);\
+  (t).loc = iptr[0];\
+  (t).ver = iptr[1]
+
+#define enextfnext(t1, t2) \
+  iptr = &(locver2nextf[(t1).loc * 8 + ve[(t1).ver]]);\
+  (t2).tet = (t1).tet;\
+  (t2).loc = iptr[0];\
+  (t2).ver = iptr[1]
+
+#define enextfnextself(t) \
+  iptr = &(locver2nextf[(t).loc * 8 + ve[(t).ver]]);\
+  (t).loc = iptr[0];\
+  (t).ver = iptr[1]
+
+#define enext2fnext(t1, t2) \
+  iptr = &(locver2nextf[(t1).loc * 8 + ve2[(t1).ver]]);\
+  (t2).tet = (t1).tet;\
+  (t2).loc = iptr[0];\
+  (t2).ver = iptr[1]
+
+#define enext2fnextself(t) \
+  iptr = &(locver2nextf[(t).loc * 8 + ve2[(t).ver]]);\
+  (t).loc = iptr[0];\
+  (t).ver = iptr[1]
+
+// fnext() -- given an edge (i, j) of a face (i, j, k1) = t1, find the
+//   next face t2 in the face ring of (i, j), i.e. a face (i, j, k2),
+//   where (i, j, k1) and (i, j, k2) belong to two tetrahedra.
+    
+void fnext(triface& t1, triface& t2) {
+  int *iptr;
+  if (t1.ver & 01) {
+    // Get the adjacent tet.
+    decode(t1.tet[t1.loc], t2);
+    // Adjust the edge (see Fig. fnext-base).
+    t2.ver = zero2ver[t1.ver][t2.ver];
+    // Go to the next face in t2.
+    iptr = &(locver2nextf[t2.loc * 8 + t2.ver]);
+    t2.loc = iptr[0];
+    t2.ver = iptr[1];
+  } else {
+    // Go to the next face in t1.
+    iptr = &(locver2nextf[t1.loc * 8 + t1.ver]);
+    // Get the adjacent tet.
+    decode(t1.tet[iptr[0]], t2);
+    // Adjust the edge (see Fig. fnext-base).
+    t2.ver = zero2ver[iptr[1]][t2.ver];
+  }
+}
+
+void fnextself(triface& t) {
+  tetrahedron ptr;
+  int *iptr, tver;
+  if (t.ver & 01) {
+    ptr = t.tet[t.loc];
+    tver = t.ver;
+    decode(ptr, t);
+    t.ver = zero2ver[tver][t.ver];
+    iptr = &(locver2nextf[t.loc * 8 + t.ver]);
+    t.loc = iptr[0];
+    t.ver = iptr[1]; 
+  } else {
+    iptr = &(locver2nextf[t.loc * 8 + t.ver]);
+    ptr = t.tet[iptr[0]];
+    decode(ptr, t);
+    t.ver = zero2ver[iptr[1]][t.ver];
+  }
+}
+
+// bond() -- to setup the connections between 't1.loc' <==> 't2.loc'.
+//   From t1 <-- t2, we bond the edge in 't2' corresponding to the 0-th
+//   edge in 't1', and vice versa for t1 --> t2.
+// NOTE: We assume that t1 and t2 refer to the same edge on input.  
+
+void bond(triface& t1, triface& t2) {
+  // We will modify edge vers, backup them.
+  int t1ver = t1.ver, t2ver = t2.ver;
+  // Find t2's edge corresponds to the t1's 0th edge.
+  t2.ver = verver2zero[t1.ver][t2.ver];
+  // t1 <-- t2
+  t1.tet[t1.loc] = encode(t2);
+  // Find t1's edge corresponds to t2's 0th edge.
+  t1.ver = ver2zero[t2.ver];
+  // t1 --> t2
+  t2.tet[t2.loc] = encode(t1);
+  // Restore the original vers.
+  t1.ver = t1ver; t2.ver = t2ver;
+}
+
+// elemmarker() -- to read or set element's marker.
+
+#define elemmarker(ptr) ((int *) (ptr))[elemmarkerindex]
+
+// elemattribute() -- to check or set element attributes.
+
+#define elemattribute(ptr, num) (((REAL *) (ptr))[elemattribindex + num])
+
+#define setelemattribute(ptr, num, value) \
+  ((REAL *) (ptr))[elemattribindex + num] = value
+
+// volumebound() -- to check or set element's maximum volume bound.
+
+#define volumebound(ptr) (((REAL *) (ptr))[volumeboundindex])
+
+#define setvolumebound(ptr, value) \
+  ((REAL *) (ptr))[volumeboundindex] = value
+
+// infect(), infected(), uninfect() -- primitives to flag or unflag a
+//   tetrahedron. The last bit of the element marker is flagged (1)
+//   or unflagged (0).
+
+#define infect(t) elemmarker((t).tet) |= 1
+
+#define uninfect(t) elemmarker((t).tet) &= ~1
+
+#define infected(t) ((elemmarker((t).tet) & 1) != 0)
+
+// marktest(), marktested(), unmarktest() -- primitives to flag or unflag a
+//   tetrahedron.  The last second bit of the element marker is marked (1)
+//   or unmarked (0).
+// One needs them in forming Bowyer-Watson cavity, to mark a tetrahedron if
+//   it has been checked (for Delaunay case) so later check can be avoided.
+
+#define marktest(t) elemmarker((t).tet) |= 2
+
+#define unmarktest(t) elemmarker((t).tet) &= ~2
+    
+#define marktested(t) ((elemmarker((t).tet) & 2) != 0)
+
+// markface(), unmarkface(), facemarked() -- primitives to flag or unflag a
+//   face of a tetrahedron.  From the last 3rd to 6th bits are used for
+//   face markers, e.g., the last third bit corresponds to loc = 0. 
+// One use of the face marker is in flip algorithm. Each queued face (check
+//   for locally Delaunay) is marked.
+
+#define markface(t) elemmarker((t).tet) |= (4<<(t).loc)
+
+#define unmarkface(t) elemmarker((t).tet) &= ~(4<<(t).loc)
+
+#define facemarked(t) ((elemmarker((t).tet) & (4<<(t).loc)) != 0)
+
+// markedge(), unmarkedge(), edgemarked() -- primitives to flag or unflag an
+//   edge of a tetrahedron.  From the last 7th to 12th bits are used for
+//   edge markers, e.g., the last 7th bit corresponds to the 0th edge, etc. 
+// Remark: The last 7th bit is marked by 2^6 = 64.
+
+#define markedge(t) elemmarker((t).tet) |= (64<<locver2edge[(t).loc][(t).ver])
+
+#define unmarkedge(t) \
+  elemmarker((t).tet) &= ~(64<<locver2edge[(t).loc][(t).ver])
+
+#define edgemarked(t) \
+  ((elemmarker((t).tet) & (64<<locver2edge[(t).loc][(t).ver])) != 0)
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Primitives for shellfaces                                                 //
+//                                                                           //
+// Each shellface contains three pointers to its adjacent shellfaces, with   //
+// their edge versions (shver in [0, 5]).  To save memory, all informations  //
+// of an adjacent shellface are compressed in a single pointer. To make this //
+// possible, all shellface are aligned to 8-byte boundaries.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// sencode(), sdecode -- to compress/uncompress a face/pointer. 
+//   The pointer 's.sh' is assumed to be 8-byte aligned.
+
+#define sencode(s) \
+  (shellface) ((unsigned long) (s).sh | (unsigned long) (s).shver)
+
+#define sdecode(sptr, s) \
+  (s).shver = (int) ((unsigned long) (sptr) & (unsigned long) 7l);\
+  (s).sh = (shellface *) ((unsigned long) (sptr) & ~ (unsigned long) 7l)
+
+// sorg(), sdest(), sapex() -- return the origin, destination, apex,
+//   of the subface.
+    
+#define sorg(s) (point) (s).sh[vo[(s).shver] + 3]
+
+#define sdest(s) (point) (s).sh[vd[(s).shver] + 3]
+
+#define sapex(s) (point) (s).sh[va[(s).shver] + 3]
+
+#define setsdest(s, p) (s).sh[vd[(s).shver] + 3] = (shellface) (p)
+
+#define setsapex(s, p) (s).sh[va[(s).shver] + 3] = (shellface) (p)
+
+#define setshvertices(s, p1, p2, p3) \
+  (s).sh[vo[(s).shver] + 3] = (shellface) (p1); \
+  (s).sh[vd[(s).shver] + 3] = (shellface) (p2); \
+  (s).sh[va[(s).shver] + 3] = (shellface) (p3)
+
+// sesym() - change the origin and destination of the face edge.
+
+#define sesym(s1, s2) \
+  (s2).sh = (s1).sh;\
+  (s2).shver = (s1).shver + (((s1).shver & 01) ? -1 : 1);
+
+#define sesymself(s) \
+  (s).shver += (((s).shver & 01) ? -1 : 1);
+
+// senext(), senext2() -- go to the next (or the previous) face edge.
+
+#define senext(s1, s2) \
+  (s2).sh = (s1).sh;\
+  (s2).shver = ve[(s1).shver]
+  
+#define senextself(s) \
+  (s).shver = ve[(s).shver]
+
+#define senext2(s1, s2) \
+  (s2).sh = (s1).sh;\
+  (s2).shver = ve2[(s1).shver]
+  
+#define senext2self(s) \
+  (s).shver = ve2[(s).shver]
+
+// The general rule to connect two subfaces s1 and s2 is:  Let s1's edge
+//   be a->b, which is in s1's 0th edge ring, then the edge b->a of s2 is
+//   bonded to s1.  The same rule for connecting a subface and a subseg.
+
+// sbond1() -- s1 and s2 share an edge, connect s1 <-- s2, i.e., s1 knows
+//   its neighbor is s2. sbond2() connects s1 <==> s2.
+
+#define sbond1(s1, s2) (s1).sh[(s1).shver >> 1] = sencode(s2);
+
+#define sbond2(s1, s2) \
+  (s1).sh[(s1).shver >> 1] = sencode(s2);\
+  (s2).sh[(s2).shver >> 1] = sencode(s1)
+
+// sdisolve() -- dissolve a subface-subface connection (at one side).
+
+#define sdissolve(s) (s).sh[(s).shver >> 1] = NULL;
+
+// ssbond() -- connect a subface (s) and a subsegment (seg) together.
+// NOTE: we allow that 'seg.sh' should not be NULL.
+
+#define ssbond(s, seg) \
+  (s).sh[((s).shver >> 1) + 6] = sencode(seg);\
+  if ((seg).sh != NULL) (seg).sh[0] = sencode(s)
+
+// ssdisolve() -- dissolve a subface-subsegment connection (at subface side).
+
+#define ssdissolve(s) (s).sh[((s).shver >> 1) + 6] = NULL;
+
+// spivot() -- find the next face in the face ring.
+
+#define spivot(s1, s2) sdecode((s1).sh[(s1).shver >> 1], s2)
+
+#define spivotself(s) \
+  sptr = (s).sh[(s).shver >> 1];\
+  sdecode(sptr, s)
+
+// sspivot() -- find the abutting subsegment (seg) at the face (s).
+
+#define sspivot(s, seg) sdecode((s).sh[((s).shver >> 1) + 6], seg)
+
+// shellmark() -- set or read the shell mark.
+
+// #define shellmark(s) ((int *) ((s).sh))[shmarkindex]
+
+// The last two bits of the int ((int *) ((s).sh))[shmarkindex] are used
+//   by sinfect() and smarktest().
+
+int getshellmark(face& s) {
+  return (((int *) ((s).sh))[shmarkindex]) >> 2;
+}
+
+void setshellmark(face& s, int mark) {
+  ((int *) ((s).sh))[shmarkindex] = (mark << 2) + 
+    ((((int *) ((s).sh))[shmarkindex]) & 3);
+}
+
+// areabound() -- set of read the maximal area bound.
+
+#define areabound(s) ((REAL *) ((s).sh))[areaboundindex]
+
+// sinfect(), sinfected(), suninfect() -- primitives to flag or unflag a
+//   subface. The last bit of ((int *) ((s).sh))[shmarkindex] is flaged.
+
+#define sinfect(s) \
+  ((int *) ((s).sh))[shmarkindex] = (((int *) ((s).sh))[shmarkindex] | 1)
+
+#define suninfect(s) \
+  ((int *) ((s).sh))[shmarkindex] = (((int *) ((s).sh))[shmarkindex] & ~1)
+
+#define sinfected(s) ((((int *) ((s).sh))[shmarkindex] & 1) != 0)
+
+// smarktest(), smarktested(), sunmarktest() -- primitives to flag or unflag
+//   a subface. The last 2nd bit of ((int *) ((s).sh))[shmarkindex] is flaged.
+
+#define smarktest(s) \
+  ((int *) ((s).sh))[shmarkindex] = (((int *) ((s).sh))[shmarkindex] | 2)
+
+#define sunmarktest(s) \
+  ((int *) ((s).sh))[shmarkindex] = (((int *) ((s).sh))[shmarkindex] & ~2)
+
+#define smarktested(s) ((((int *) ((s).sh))[shmarkindex] & 2) != 0)
+
+// farsorg(), farsdest() -- s is a subsegment, return the origin or
+//   destination of the segment containing s.
+// Note: here we assume that two subsegment (a->p) and (p->b) bonded
+//   at p as: (p->nil->a) and (nil->p->b), in flipn2nf().
+
+point farsorg(face& s) {
+  face travesh, neighsh;
+  shellface sptr;
+  travesh = s;
+  while (1) {
+    senext2(travesh, neighsh);
+    spivotself(neighsh); 
+    if (neighsh.sh == NULL) break;
+    if (sorg(neighsh) != sorg(travesh)) sesymself(neighsh);
+    assert(sorg(neighsh) == sorg(travesh)); // SELF_CHECK
+    senext2(neighsh, travesh); 
+  }
+  return sorg(travesh);
+}
+
+point farsdest(face& s) {
+  face travesh, neighsh;
+  shellface sptr;
+  travesh = s;
+  while (1) {
+    senext(travesh, neighsh);
+    spivotself(neighsh); 
+    if (neighsh.sh == NULL) break;
+    if (sdest(neighsh) != sdest(travesh)) sesymself(neighsh);
+    assert(sdest(neighsh) == sdest(travesh)); // SELF_CHECK
+    senext(neighsh, travesh); 
+  }
+  return sdest(travesh);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Interactions between tetrahedra and subfaces and subsegments.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// tspivot(), stpivot -- given a tet's face t (or a subface s), find the
+//   abutting subface (or tet).
+
+void tspivot(triface& t, face& s) {
+  if ((t).tet[9] != NULL) {
+    sdecode(((shellface *) (t).tet[9])[(t).loc], s);
+  } else {
+    (s).sh = NULL;
+  }
+}
+
+#define stpivot(s, t) decode((tetrahedron) (s).sh[9], t)
+
+// tsbond() -- connect a tet and subface.
+
+void tsbond(triface& t, face& s) {
+  if ((t).tet[9] == NULL) {
+    // Allocate space for this tet.
+    (t).tet[9] = (tetrahedron) tet2subpool->alloc();
+    // NULL all fields in this space.
+    for (int i = 0; i < 4; i++) {
+      ((shellface *) (t).tet[9])[i] = NULL;
+    }
+  }
+  // Bond t <==> s.
+  ((shellface *) (t).tet[9])[(t).loc] = sencode(s);
+  (s).sh[9] = (shellface) encode(t);
+}
+
+// tsdissolve() -- dissolve a tet-subface bond at the tet side.
+
+void tsdissolve(triface& t) {
+  if ((t).tet[9] != NULL) {
+    ((shellface *) (t).tet[9])[(t).loc] = NULL;
+  }
+}
+
+// stdissolve() -- dissolbe a tet-subface bond at the subface side.
+
+#define stdissolve(s) (s).sh[9] = NULL;
+
+// tsspivot() -- given a tet's edge t, return a subsegment s at this edge.
+//   t and s is bonded through tssbond1(). if s.sh == NULL, the edge is
+//   not a subsegment.
+
+void tsspivot(triface& t, face& s) {
+  if ((t).tet[8] != NULL) {
+    sdecode(((shellface *) (t).tet[8])[locver2edge[(t).loc][(t).ver]], s);
+  } else {
+    (s).sh = NULL;
+  }
+}
+
+// tssbond1() -- bond a tet edge and a segment (only at tet's edge).
+
+void tssbond1(triface& t, face& s) {
+  if ((t).tet[8] == NULL) {
+    // Allocate space for this tet.
+    (t).tet[8] = (tetrahedron) tet2segpool->alloc();
+    // NULL all fields in this space.
+    for (int i = 0; i < 6; i++) {
+      ((shellface *) (t).tet[8])[i] = NULL;
+    }
+  }
+  // Bond the segment.
+  ((shellface *) (t).tet[8])[locver2edge[(t).loc][(t).ver]] = sencode((s));
+}
+
+// sstbond() -- bond a tet edge to a segment (only at the segment side).
+
+#define sstbond(s, t) (s).sh[9] = (shellface) encode(t)
+
+// tssdissolve() -- dissolve a tet-seg bond at the tet edge side.
+
+void tssdissolve(triface& t) {
+  if ((t).tet[8] != NULL) {
+    ((shellface *) (t).tet[8])[locver2edge[(t).loc][(t).ver]] = NULL;
+  }
+}
+
+// sstdissolve() -- dissolve a tet-seg bond at the segment side.
+//   Use stdissolve().
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Primitives for points                                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#define pointmark(pt) ((int *) (pt))[pointmarkindex]
+    
+#define point2tet(pt) ((tetrahedron *) (pt))[point2tetindex]
+
+// Given a point 'pa', return a tet 'searchtet' whose origin is pa.
+
+void point2tetorg(point pa, triface& searchtet)
+{
+  int i;
+
+  // Search a tet whose origin is pa.
+  decode(point2tet(pa), searchtet);
+  assert(searchtet.tet != NULL); // SELF_CHECK
+  for (i = 4; i < 8; i++) {
+    if ((point) searchtet.tet[i] == pa) {
+      // Found. Set pa as its origin.
+      switch (i) {
+        case 4: searchtet.loc = 0; searchtet.ver = 0; break;
+        case 5: searchtet.loc = 0; searchtet.ver = 2; break;
+        case 6: searchtet.loc = 0; searchtet.ver = 4; break;
+        case 7: searchtet.loc = 1; searchtet.ver = 2; break;
+      }
+      break;
+    }
+  }
+  assert(i < 8); // SELF_CHECK
+}
+    
+#define point2ppt(pt) ((point *) (pt))[point2tetindex + 1]
+
+// #define pointtype(pt) ((enum verttype *) (pt))[pointmarkindex + 1]
+
+enum verttype getpointtype(point pt) {
+  return (enum verttype) (((int *) (pt))[pointmarkindex + 1] >> 1);
+}
+
+void setpointtype(point pt, enum verttype type) {
+  ((int *) (pt))[pointmarkindex + 1] = 
+    ((int) type << 1) + (((int *) (pt))[pointmarkindex + 1] & 1);
+}
+
+// pinfect(), puninfect(), pinfected() -- primitives to flag or unflag
+//   a point. The last bit of the integer '[pointindex+1]' is flaged.
+
+#define pinfect(pt) \
+  ((int *) (pt))[pointmarkindex + 1] = ((int *) (pt))[pointmarkindex + 1] | 1
+
+#define puninfect(pt) \
+  ((int *) (pt))[pointmarkindex + 1] = ((int *) (pt))[pointmarkindex + 1] & ~1
+
+#define pinfected(pt) ((((int *) (pt))[pointmarkindex + 1] & 1) != 0)
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Primitives for arraypools.                                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// fastlookup() -- A fast, unsafe operation. Return the pointer to the object
+//   with a given index.  Note: The object's block must have been allocated,
+//   i.e., by the function newindex().
+
+#define fastlookup(pool, index) \
+  (void *) ((pool)->toparray[(index) >> (pool)->log2objectsperblock] + \
+            ((index) & ((pool)->objectsperblock - 1)) * (pool)->objectbytes)
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Class Variables.                                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// Pointer to the input data (a PLC or a mesh).
+tetgenio *in;
+
+// Pointer to the options (and filenames).
+tetgenbehavior *b;
+
+// Pools of tetrahedra, shellfaces, points, etc.
+memorypool *tetrahedronpool;
+memorypool *subsegpool, *subfacepool;
+memorypool *tet2segpool, *tet2subpool;
+memorypool *pointpool;
+memorypool *flippool;
+memorypool *badsegpool, *badsubpool, *badtetpool;
+
+// A dummy point at infinity (see [Guibas & Stolfi 85]).  All the hull
+//   tetrahedra having this point as a vertex.
+point dummypoint;
+
+// Statck and queue (use flippool) for flips.
+badface *futureflip;
+
+// Arrays used by Bowyer-Watson algorithm.
+arraypool *cavetetlist, *cavebdrylist, *caveoldtetlist;
+arraypool *caveshlist, *caveshbdlist;
+
+// Stacks used by the boundary recovery algorithm.
+arraypool *subsegstack, *subfacstack;
+
+// Arrays used for facet recovery.
+arraypool *tg_crosstets, *tg_topnewtets, *tg_botnewtets;
+arraypool *tg_topfaces, *tg_botfaces, *tg_midfaces;
+arraypool *tg_topshells, *tg_botshells, *tg_facfaces;
+arraypool *tg_toppoints, *tg_botpoints, *tg_facpoints;
+
+// Variables for accessing data fields (initialized in initializepools()).
+int point2tetindex, pointmarkindex;
+int elemmarkerindex;
+int elemattribindex, volumeboundindex, highorderindex;
+int shmarkindex, areaboundindex;
+
+// The number of hull tetrahedra (= the number of outer boundary faces).
+long hullsize;
+
+// Current random number seed, number of random samples (for point location).
+unsigned long randomseed, samples;
+
+// Pointers to a recently visited tetrahedron and subface.
+triface recenttet;
+face recentsh;
+
+// Two handles used in facet recovery (formcavity and fillcavity).
+triface firsttopface, firstbotface;
+
+// The size of bounding boxes.
+REAL xmax, xmin, ymax, ymin, zmax, zmin;
+
+// The number of duplicated vertices, mesh edges, and input segments.
+long dupverts, meshedges, meshsubedges, insegments;
+
+// Flags to check imposed constraints, subfaces, subsegs.
+int checkconstraints, checksubfaces, checksubsegs, checkpbcs;
+
+// Algorithm statistical counters.
+long ptloc_count, ptloc_max_count;
+long orient3dcount;
+long inspherecount, insphere_sos_count;
+long maxbowatcavsize, totalbowatcavsize, totaldeadtets;
+long flip14count, flip26count, flipn2ncount;
+long flip23count, flip32count, flipnmcount;
+long flip13count, flip22count, flipn2nfcount;
+REAL tloctime, tfliptime, tinserttime;
+long triedgcount, triedgcopcount, trivercopcount;
+long across_face_count, across_edge_count, across_max_count;
+long r1count, r2count, r3count;
+long maxcavsize, maxregionsize;
+long cavitycount, ndelaunayedgecount, cavityexpcount;
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Functions for using memorypools.                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void initializepools();
+void tetrahedrondealloc(tetrahedron*);
+tetrahedron *tetrahedrontraverse();
+tetrahedron *alltetrahedrontraverse();
+void shellfacedealloc(memorypool*, shellface*);
+shellface *shellfacetraverse(memorypool*);
+void badfacedealloc(memorypool*, badface*);
+badface *badfacetraverse(memorypool*);
+void pointdealloc(point);
+point pointtraverse();
+void maketetrahedron(triface*);
+void makeshellface(memorypool*, face*);
+void makepoint(point*);
+void makeindex2pointmap(point*&);
+void makepoint2submap(memorypool*, int*&, face*&);
+void makepoint2tetmap();
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Linear algebra operators.                                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#define NORM2(x, y, z) ((x) * (x) + (y) * (y) + (z) * (z))
+
+#define DIST(p1, p2) \
+  sqrt(NORM2((p2)[0] - (p1)[0], (p2)[1] - (p1)[1], (p2)[2] - (p1)[2]))
+
+#define DOT(v1, v2) \
+  ((v1)[0] * (v2)[0] + (v1)[1] * (v2)[1] + (v1)[2] * (v2)[2])
+
+#define CROSS(v1, v2, n) \
+  (n)[0] =   (v1)[1] * (v2)[2] - (v2)[1] * (v1)[2];\
+  (n)[1] = -((v1)[0] * (v2)[2] - (v2)[0] * (v1)[2]);\
+  (n)[2] =   (v1)[0] * (v2)[1] - (v2)[0] * (v1)[1]
+
+#define SETVECTOR3(V, a0, a1, a2) (V)[0] = (a0); (V)[1] = (a1); (V)[2] = (a2)
+
+#define SWAP2(a0, a1, tmp) (tmp) = (a0); (a0) = (a1); (a1) = (tmp)
+
+bool lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N);
+void lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N);
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Geometric predicates, advanced tests, intersections.                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+static REAL PI;
+
+REAL interiorangle(point o, point p1, point p2, REAL* n);
+void facenormal(point, point, point, REAL *n, int pivot);
+void circumsphere(point, point, point, point, REAL* cent, REAL* radius);
+
+REAL insphere_sos(point pa, point pb, point pc, point pd, point pe);
+REAL incircle3d(point pa, point pb, point pc, point pd);
+bool iscoplanar(point k, point l, point m, point n, REAL ori);
+
+int tri_edge_2d(point,point,point,point,point,point,int,int*,int*);
+int tri_edge_test(point,point,point,point,point,point,int,int*,int*);
+int tri_tri_2d(point,point,point,point,point,point,point,int,int*,int*);
+int tri_tri_test(point,point,point,point,point,point,point,int,int*,int*);
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh transformation operations.                                           //
+//                                                                           //
+// Mesh transformation operations translate an old set of tetrahedra into a  //
+// new set of tetrahedra in the same region of the tetrahedralization. Such  //
+// operations include face/edge flips, vertex insertion/deletions.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+badface* flipshpush(badface* flipstack, face* flipedge);
+void flip13(point newpt, face* splitface, int flipflag);
+void flipn2nf(point newpt, face* splitedges, int flipflag);
+void flip22(face* flipfaces, int flipflag);
+void lawsonflip();
+
+badface* flippush(badface* flipstack, triface* flipface, point pushpt);
+void flip14(point newpt, triface* splittet, int flipflag);
+void flip26(point newpt, triface* splitface, int flipflag);
+void flipn2n(point newpt, triface* splitedge, int flipflag);
+void flip23(triface* fliptets, int hullflag, int flipflag);
+void flip32(triface* fliptets, int hullflag, int flipflag);
+//bool flipnm(int n, triface* fliptets, int flipflag);
+void lawsonflip3d(int flipflag);
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Jump-and-Walk point location algorithm.                                   //
+//                                                                           //
+// The following functions implemented the randomized jump-and-walk point    //
+// location algorithm of Muecke, Saias, and Zhu [MueckeSaiasZhu96].          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+unsigned long randomnation(unsigned long choices);
+void randomsample(point searchpt, triface* searchtet);
+enum location locate(point searchpt, triface* searchtet);
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Incremental Delaunay tetrahedralization algorithms.                       //
+//                                                                           //
+// Bowyer and Watson's incrmental insertion algorithm [Bowyer81, Watson81],  //
+// and Edelsbrunner and Shah's incrmental flip algorithm [Edelsbrunner96].   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void initialDT(point pa, point pb, point pc, point pd);
+enum location insertvertex(point, triface*, bool, bool, bool, bool);
+void flipinsertvertex(point, triface*, int);
+void incrementaldelaunay();
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Surface mesh routines.                                                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool calculateabovepoint(arraypool*, point*, point*, point*);
+enum location slocate(point, face*, bool);
+enum location sinsertvertex(point, face*, face*, bool, bool);
+enum intersection sscoutsegment(face* searchsh, point endpt);
+void scarveholes(int, REAL*);
+void triangulate(int, arraypool*, arraypool*, int, REAL*);
+
+void unifysubfaces(face*, face*);
+void unifysegments();
+void mergefacets();
+void markacutevertices();
+void meshsurface();
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Boundary recovery functions.                                              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum intersection finddirection(triface* searchtet, point endpt);
+enum intersection scoutsegment(face* sseg, triface* searchtet, point* refpt);
+void getsegmentsplitpoint(face* sseg, point refpt, REAL* vt);
+void getsegmentsplitpoint2(face* sseg, point refpt, REAL* vt);
+void getsegmentsplitpoint3(face* sseg, point refpt, REAL* vt);
+void delaunizesegments();
+
+enum intersection scoutsubface(face* ssub, triface* searchtet);
+enum intersection scoutcrosstet(face* ssub, triface* searchtet, arraypool*);
+void recoversubfacebyflips(face* pssub, triface* crossface, arraypool*);
+void formcavity(face*, arraypool*, arraypool*, arraypool*, arraypool*, 
+                arraypool*, arraypool*);
+bool delaunizecavity(arraypool*, arraypool*, arraypool*, arraypool*,
+                     arraypool*, arraypool*);
+bool fillcavity(arraypool*, arraypool*, arraypool*, arraypool*);
+void carvecavity(arraypool*, arraypool*, arraypool*);
+void restorecavity(arraypool*, arraypool*, arraypool*);
+void splitsubedge(point, face*, arraypool*, arraypool*);
+void constrainedfacets();
+
+enum intersection scoutsegment2(face*, triface*, arraypool*);
+bool tetrasegcavity(face*, arraypool*, arraypool*, arraypool*, arraypool*,
+                    arraypool*, arraypool*, arraypool*, arraypool*);
+bool recoversegments(arraypool*, arraypool*, arraypool*, arraypool*, 
+                     arraypool*, arraypool*);
+void constrainedsegments();
+
+void formskeleton();
+void carveholes();
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh refinement functions.                                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool checkedge4encroach(face& seg, point testpt, int enqflag);
+void repairencsegs();
+
+void enforcequality();
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh input & output functions.                                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void transfernodes();
+void reconstructmesh();
+void jettisonnodes();
+void highorder();
+void numberedges();
+void numbersubedges();
+void outnodes(tetgenio* out);
+void outelements(tetgenio* out);
+void outfaces(tetgenio* out);
+void outhullfaces(tetgenio* out);
+void outsubfaces(tetgenio* out);
+void outedges(tetgenio* out);
+void outsubsegments(tetgenio* out);
+void outneighbors(tetgenio* out);
+void outvoronoi(tetgenio* out);
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh statistic functions.                                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int checkmesh();
+int checkshells(int);
+int checkdelaunay(int);
+int checksegments();
+int checkconforming();
+void algorithmstatistics();
+void qualitystatistics();
+void statistics();
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Class Constructor and Destructor.                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void initialize()
+{
+  in = (tetgenio *) NULL;
+  b = (tetgenbehavior *) NULL;
+  tetrahedronpool = (memorypool *) NULL;
+  subfacepool = subsegpool = (memorypool *) NULL;
+  tet2segpool = tet2subpool = (memorypool *) NULL;
+  pointpool = (memorypool *) NULL;
+  flippool = (memorypool *) NULL;
+  badsegpool = badsubpool = badtetpool = (memorypool *) NULL;
+  dummypoint = (point) NULL;
+  futureflip = (badface *) NULL;
+  cavetetlist = cavebdrylist = caveoldtetlist = (arraypool *) NULL;
+  caveshlist = caveshbdlist = (arraypool *) NULL;
+  subsegstack = subfacstack = (arraypool *) NULL;
+  arraypool *tg_crosstets, *tg_topnewtets, *tg_botnewtets;
+  tg_topfaces = tg_botfaces = tg_midfaces = NULL;
+  tg_topshells = tg_botshells = tg_facfaces = NULL;
+  tg_toppoints = tg_botpoints = tg_facpoints = NULL;
+  point2tetindex = pointmarkindex = 0;
+  elemmarkerindex = 0;
+  elemattribindex = volumeboundindex = highorderindex = 0;
+  hullsize = 0l;
+  randomseed = samples = 1l;
+  recenttet.tet = (tetrahedron *) NULL;
+  recenttet.loc = recenttet.ver = 0;
+  xmax = xmin = ymax = ymin = zmax = zmin = 0.0;
+  dupverts = meshedges = meshsubedges = insegments = 0l;
+  checkconstraints = checksubfaces = checksubsegs = checkpbcs = 0;
+  ptloc_count = ptloc_max_count = 0l;
+  orient3dcount = 0l;
+  inspherecount = insphere_sos_count = 0l;
+  maxbowatcavsize = totalbowatcavsize = totaldeadtets = 0l;
+  flip14count = flip26count = flipn2ncount = 0l;
+  flip23count = flip32count = flipnmcount = 0l;
+  flip13count = flip22count = flipn2nfcount = 0l;
+  tloctime = tfliptime = tinserttime = 0.0;
+  triedgcount = triedgcopcount = trivercopcount = 0l;
+  across_face_count = across_edge_count = across_max_count = 0l;
+  r1count = r2count = r3count = 0l;
+  maxcavsize = maxregionsize = 0l;
+  cavitycount = ndelaunayedgecount = cavityexpcount = 0l;
+}
+
+void deinitialize()
+{
+  in = (tetgenio *) NULL;
+  b = (tetgenbehavior *) NULL;
+  if (pointpool != (memorypool *) NULL) {
+    delete pointpool;
+    delete [] dummypoint;
+  }
+  if (tetrahedronpool != (memorypool *) NULL) {
+    delete tetrahedronpool;
+    delete cavetetlist;
+    delete cavebdrylist;
+    delete caveoldtetlist;
+    delete flippool;
+  }
+  if (subfacepool != (memorypool *) NULL) {
+    delete subfacepool;
+    delete subsegpool;
+    delete tet2segpool;
+    delete tet2subpool;
+    delete subsegstack;
+    delete subfacstack;
+    delete caveshlist;
+    delete caveshbdlist;
+  }
+  futureflip = (badface *) NULL;
+}
+
+tetgenmesh() 
+{
+  initialize();
+}
+
+~tetgenmesh() 
+{
+  deinitialize();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Debug functions.                                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void ptet(triface* t);
+void psh(face* s);
+void pteti(int i, int j, int k, int l);
+void pface(int i, int j, int k);
+bool pedge(int i, int j);
+void psubface(int i, int j, int k);
+int psubseg(int i, int j);
+int pmark(point p);
+void pvert(point p);
+int pverti(int i);
+REAL test_orient3d(int i, int j, int k, int l);
+REAL test_insphere(int i, int j, int k, int l, int m);
+int test_tritri(int a, int b, int c, int p,  int q, int r);
+void print_cavebdrylist();
+void print_flipstack();
+void print_tetarray(arraypool* tetarray, bool nohulltet);
+void print_facearray(arraypool* facearray);
+void print_subfacearray(arraypool* subfacearray);
+void dump_cavity(arraypool *topfaces, arraypool *botfaces);
+void dump_facetof(face* pssub, char* filename);
+void dump_cavitynewtets();
+
+///////////////////////////////////////////////////////////////////////////////
+};  // End of class tetgenmesh;
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// terminatetetgen()    Terminate TetGen with a given exit code.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void terminatetetgen(int x);
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetrahedralize()    Interface for using TetGen's library to generate      //
+//                     Delaunay tetrahedralizations, constrained Delaunay    //
+//                     tetrahedralizations, quality tetrahedral meshes.      //
+//                                                                           //
+// 'in' is an object of 'tetgenio' which contains a PLC you want to tetrahed-//
+// ralize or a previously generated tetrahedral mesh you want to refine.  It //
+// must not be a NULL. 'out' is another object of 'tetgenio' for storing the //
+// generated tetrahedral mesh. It can be a NULL. If so, the output will be   //
+// saved to file(s). If 'bgmin' != NULL, it contains a background mesh which //
+// defines a mesh size distruction function.                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, 
+                    tetgenio *addin = NULL, tetgenio *bgmin = NULL);
+
+void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
+                    tetgenio *addin = NULL, tetgenio *bgmin = NULL);
+
+#endif // #ifndef tetgenH
-- 
GitLab