diff --git a/TEST.py b/TEST.py
new file mode 100644
index 0000000000000000000000000000000000000000..c92540f616a57ab709e5a27f9bb953f178de468b
--- /dev/null
+++ b/TEST.py
@@ -0,0 +1,33 @@
+#from fem_2d import Constraint2D, Force2D, Node2D, Element2D, Structure
+from meshpy import triangle
+import numpy as np
+import matplotlib.pyplot as plt
+import time
+
+
+def get_facets(start, end):
+    return [(i, i+1) for i in range(start, end)] + [(end, start)]
+
+def refine_grid(vertices, area):
+    max_area = 0.3  ########################################################################
+    return bool(area>max_area)
+
+points = [(0,0),
+          (1,0),
+          (1.5, 0.5),
+          (1,1),
+          (0,1)]
+
+facets = get_facets(0, len(points)-1)
+
+grid_info = triangle.MeshInfo()
+grid_info.set_points(points)
+grid_info.set_facets(facets)
+time.sleep(2) 
+mesh = triangle.build(grid_info, refinement_func=refine_grid, min_angle=30)
+mesh_points = np.array(mesh.points)
+mesh_elements = np.array(mesh.elements)
+
+plt.triplot(mesh_points[:, 0], mesh_points[:, 1], mesh_elements)
+plt.gca().set_aspect('equal')
+plt.show()
diff --git a/TEST_2.py b/TEST_2.py
new file mode 100644
index 0000000000000000000000000000000000000000..cbe7d1638c1ff423688c4408a726971eef1fadf6
--- /dev/null
+++ b/TEST_2.py
@@ -0,0 +1,30 @@
+import numpy as np
+from fem_2d import Structure2DPlaneStress, Force2D
+
+mesh_elements = np.array([[1, 3, 5],
+                          [4, 0, 5],
+                          [1, 2, 3],
+                          [5, 3, 4],
+                          [0, 1, 5]], dtype='int32')
+
+mesh_points = np.array([[0. , 0. ],
+                        [1. , 0. ],
+                        [1.5, 0.5],
+                        [1. , 1. ],
+                        [0. , 1. ],
+                        [0.5, 0.5]], dtype='float64')
+
+STR = Structure2DPlaneStress(mesh_elements, mesh_points,
+                              elastic_modulus = 10e6,
+                              poisson_ratio = 0.3,
+                              thickness = 0.1)
+
+
+STRUCT = list()
+STRUCT.append(STR)
+NODES = STR.nodes
+ELEMENTS = STR.elements
+
+
+STR.nodes[2].force_2d = Force2D([1,1])
+STR.solve()
diff --git a/fem_2d.py b/fem_2d.py
new file mode 100644
index 0000000000000000000000000000000000000000..40981dbc12aad1e7ba1ea248f4485971bbbd2f0f
--- /dev/null
+++ b/fem_2d.py
@@ -0,0 +1,429 @@
+"""
+This is the module that will contain all required classes for the calculations
+and visualization of the linear model on 2d.
+
+Author: Ernesto Oquelis.
+
+Written on:     15.Sep.18
+Last edited on: 23.Sep.18
+"""
+
+
+import numpy as np
+
+
+class Constraint2D:
+    """
+    Class constraint in 2D. Value True for is constraint, False for is free.
+    """
+    def __init__(self, constraint_array):
+        self.value = np.array(constraint_array, dtype='bool')
+
+    def print_details(self):
+        """
+        Prints the details of the constraint object.
+        """
+        values_to_print = list()
+        for val_bool in self.value:
+            if val_bool:
+                values_to_print.append('Fixed')
+            else:
+                values_to_print.append('Free')
+        txt_1 = 'Constraint on components: '
+        print('\n')
+        print('{:<35}[{:>10}, {:>10}]'.format(txt_1, 'u1', 'u2'))
+        print('{:<35}[{:>10}, {:>10}]'.format('', values_to_print[0],
+                                              values_to_print[1]))
+
+
+class Force2D:
+    """
+    Class force in 2D. Values stored as float64.
+    """
+    def __init__(self, force_array):
+        self.value = np.array(force_array, dtype='float64')
+
+    def print_details(self):
+        """
+        Prints the details of the force object.
+        """
+        txt_1 = 'Force on components: '
+        print('\n')
+        print('{:<35}[{:>10}, {:>10}]'.format(txt_1, 'r1', 'r2'))
+        print('{:<35}[{:>10.6E}, {:>10.6E}]'.format('', self.value[0],
+                                                    self.value[1]))
+
+class Node2D:
+    """
+    Class node in 2D. Values stored as float64.
+    """
+    def __init__(self, position_array):
+        self.position = np.array(position_array, dtype='float64')
+        self.displacement = np.zeros((2,))
+        self.constraint_2d = None
+        self.force_2d = None
+
+    def print_details(self):
+        """
+        Prints details of the node object.
+        """
+        pos = self.position
+        dis = self.displacement
+
+        txt_1 = 'Node position on components: '
+        txt_2 = 'Node displacement on components: '
+        print('\n')
+        print('{:<35}[{:>10}, {:>10}]'.format(txt_1, 'x1', 'x2'))
+        print('{:<35}[{:>10.6E}, {:>10.6E}]'.format('', pos[0], pos[1]))
+        print('{:<35}[{:>10}, {:>10}]'.format(txt_2, 'x1', 'x2'))
+        print('{:<35}[{:>10.6E}, {:>10.6E}]'.format('', dis[0], dis[1]))
+
+
+class Element2D:
+    """
+    Class element in 2D.
+    """
+    def __init__(self, node_1, node_2, node_3):
+        self.node_1 = node_1
+        self.node_2 = node_2
+        self.node_3 = node_3
+        self.node_ids = None
+
+        const_a = np.linalg.norm(self.node_1.position - self.node_2.position)
+        const_b = np.linalg.norm(self.node_2.position - self.node_3.position)
+        const_c = np.linalg.norm(self.node_3.position - self.node_1.position)
+        const_s = (const_a + const_b + const_c) / 2
+        self.area = np.sqrt(const_s * (const_s - const_a) *
+                            (const_s - const_b) *
+                            (const_s - const_c))
+
+    def get_k_mat(self, thickness, c_mat):
+        """
+        Computes the local stiffness matrix of the element.
+        """
+        b_11 = self.node_2.position[1] - self.node_3.position[1]
+        b_12 = self.node_3.position[0] - self.node_2.position[0]
+        b_21 = self.node_3.position[1] - self.node_1.position[1]
+        b_22 = self.node_1.position[0] - self.node_3.position[0]
+        b_31 = self.node_1.position[1] - self.node_2.position[1]
+        b_32 = self.node_2.position[0] - self.node_1.position[0]
+
+        b_mat = np.array([[b_11, 0.0, b_21, 0.0, b_31, 0.0],
+                          [0.0, b_12, 0.0, b_22, 0.0, b_32],
+                          [b_21, b_11, b_22, b_21, b_32, b_31]])
+
+        return self.area * thickness * np.dot(np.dot(b_mat.T, c_mat), b_mat)
+
+    def print_details(self):
+        """
+        Pritns details of the element object.
+        """
+        print('\nDetails of node 1:')
+        self.node_1().print_node()
+        print('Details of node 2:')
+        self.node_2().print_node()
+        print('Details of node 3:')
+        self.node_3().print_node()
+
+
+class Structure2DPlaneStress:
+    """
+    Class structure.
+    """
+    def __init__(self, mesh_elements, mesh_points, elastic_modulus,
+                 poisson_ratio, thickness):
+        self.nodes = list()
+        self.elements = list()
+
+        nodes_array = mesh_points
+        self.num_nodes = nodes_array.shape[0]
+        self.num_eq = 2 * self.num_nodes
+        for node_id in range(self.num_nodes):
+            self.nodes.append(Node2D(nodes_array[node_id, :]))
+
+        elements_array = mesh_elements
+        self.num_elements = mesh_elements.shape[0]
+        for element_id in range(self.num_elements):
+            element_nodes = elements_array[element_id, :]
+            self.elements.append(Element2D(self.nodes[element_nodes[0]],
+                                           self.nodes[element_nodes[1]],
+                                           self.nodes[element_nodes[2]]))
+            self.elements[-1].node_ids = element_nodes
+
+        self.thickness = thickness
+        self.structure_displacement = None
+        self.c_mat = (elastic_modulus / (1 - poisson_ratio ** 2) *
+                      np.array([[1, poisson_ratio, 0],
+                                [poisson_ratio, 1, 0],
+                                [0, 0, (1-poisson_ratio)/2]]))
+
+    def solve(self):
+        """
+        Solves linear system of equations.
+        """
+        # Defines empty k matrix and r vector
+        k_global = np.zeros((self.num_eq, self.num_eq))
+        r_global = np.zeros((self.num_eq, 1))
+
+        # Assembles load vector
+        for node_id in range(self.num_nodes):
+            if self.nodes[node_id].force_2d is not None:
+                r_global[node_id * 2] = self.nodes[node_id].force_2d.value[0]
+                r_global[node_id * 2 + 1] = self.nodes[node_id].force_2d.value[1]
+
+        # Assembles stiffness matrix
+        for element_id in range(self.num_elements):
+            node_ids = self.elements[element_id].node_ids
+            k_e = self.elements[element_id].get_k_mat(self.thickness,
+                                                      self.c_mat)
+            for (i, j) in ((0, 0), (0, 1), (1, 0), (1, 1)):
+                k_global[node_ids[i], node_ids[j]] = (k_global[node_ids[i],
+                                                               node_ids[j]] +
+                                                      k_e[i, j])
+
+
+
+
+
+
+'''
+    def solve(self):
+        """
+        Solves linear system of equations.
+        """
+        self.number_equations = self.enumerate_dofs()
+        k_global = np.zeros((self.number_equations, self.number_equations))
+        r_global = np.zeros((self.number_equations, 1))
+        k_global = self.assemble_stiffness_matrix(k_global)
+        r_global = self.assemble_load_vector(r_global)
+        self.structure_displacement = np.linalg.solve(k_global, r_global)
+
+    def select_displacements(self):
+        """
+        Sets displacements on the nodes according to solution of linear system.
+        """
+        for node_id in range(self.get_number_nodes()):
+            dof = np.array(self.get_node(node_id).get_dof_numbers()).reshape(3,)
+            displacement = np.zeros((3,))
+            for i in range(3):
+                if dof[i] != -1:
+                    displacement[i] = self.structure_displacement[int(dof[i])]
+            self.get_node(node_id).set_displacement(displacement)
+
+    def print_details(self):
+        """
+        Prints details of the structure object.
+        """
+        print('\nDetails of structure:\n')
+        print('{:<25}{:>5}'.format('Structures elements: ',
+                                   self.get_number_elements()))
+        print('{:<25}{:>5}'.format('Structures nodes: ',
+                                   self.get_number_nodes()))
+        print('\nNodes in structure:')
+        print('{:<10}{:>15}{:>15}{:>15}'.format('idx', 'x1', 'x2', 'x3'))
+        for node_id in range(self.get_number_nodes()):
+            position = self.get_node(node_id).get_position()
+            print('{:<10}{:>15.6E}{:>15.6E}{:>15.6E}'.format(node_id,
+                                                             position[0],
+                                                             position[1],
+                                                             position[2]))
+        print('\nConstraints in structure:')
+        print('{:<10}{:>15}{:>15}{:>15}'.format('idx', 'u1', 'u2', 'u3'))
+        for node_id in range(self.get_number_nodes()):
+            constraint = self.get_node(node_id).get_constraint()
+            if constraint is not None:
+                values = constraint.get_values()
+                print('{:<10}{:>15}{:>15}{:>15}'.format(node_id, values[0],
+                                                        values[1], values[2]))
+        print('\nForces in structure:')
+        print('{:<10}{:>15}{:>15}{:>15}'.format('idx', 'r1', 'r2', 'r3'))
+        for node_id in range(self.get_number_nodes()):
+            force = self.get_node(node_id).get_force()
+            if force is not None:
+                values = force.get_value()
+
+                print('{:<10}{:>15.6E}{:>15.6E}{:>15.6E}'.format(node_id,
+                                                                 values[0],
+                                                                 values[1],
+                                                                 values[2]))
+        print('\nElements in structure:')
+        print('{:<10}{:>15}{:>15}{:>15}'.format('idx', 'Emod', 'Area', 'Length'))
+        for element in range(self.get_number_elements()):
+            e_mod = self.get_element(element).get_elastic_modulus()
+            area = self.get_element(element).get_area()
+            length = self.get_element(element).get_length()
+            print('{:<10}{:>15.6E}{:>15.6E}{:>15.6E}'.format(element, e_mod,
+                                                             area, length))
+
+    def print_results(self):
+        """
+        Prints result details.
+        """
+        print('\nStructure calculation results:')
+        print('\nDisplacements:')
+        print('{:<10}{:>15}{:>15}{:>15}'.format('idx', 'u1', 'u2', 'u3'))
+        for node_id in range(self.get_number_nodes()):
+            displacement = self.get_node(node_id).get_displacement()
+            print('{:<10}{:>15.6E}{:>15.6E}{:>15.6E}'.format(node_id,
+                                                             displacement[0],
+                                                             displacement[1],
+                                                             displacement[2]))
+        print('\nElement forces:')
+        print('{:<10}{:>15}'.format('idx', 'force'))
+        for element in range(self.get_number_elements()):
+            force = self.get_element(element).compute_force()
+            print('{:<10}{:>15.6E}'.format(element, force))
+
+
+class Visualizer:
+    """
+    Class visualizer.
+    """
+    def __init__(self, struct, viewer):
+        self.struct = struct
+        self.viewer = viewer
+        self.num_nodes = self.struct.get_number_nodes()
+        self.num_elements = self.struct.get_number_elements()
+        self.symbol_scale = None
+        self.displacement_scale = 5000
+        self.constraint_height = 1.5
+        self.arrow_height = 1.5
+        self.arrow_radius = 0.1
+        self.normal_forces_scale = 5e-5
+        self.elements_color = 'antiquewhite'
+        self.constraints_color = 'brown'
+        self.forces_color = 'yellow'
+        self.displaced_elements_color = 'magenta'
+        self.displaced_forces = self.forces_color
+
+    def draw_elements(self):
+        """
+        Draws elements on its original locations.
+        """
+        cylinder_set = CylinderSet()
+        for element in range(self.num_elements):
+            radius = (self.struct.get_element(element).get_area()/math.pi) ** 0.5
+            node_1 = self.struct.get_element(element).get_node_1().get_position()
+            node_2 = self.struct.get_element(element).get_node_2().get_position()
+            cylinder_set.add_cylinder(node_1, node_2, radius)
+        cylinder_set.color = self.elements_color
+        self.viewer.add_object(cylinder_set)
+
+    def draw_constraints(self):
+        """
+        Draws constraints on its original locations.
+        """
+        for node_id in range(self.num_nodes):
+            node = self.struct.get_node(node_id)
+            node_constraint = self.struct.get_node(node_id).get_constraint()
+            if node_constraint != None:
+                for component in range(3):
+                    if not node_constraint.is_free(component):
+                        if component == 0:
+                            con = Cone()
+                            con.height = self.constraint_height
+                            con.direction = [1, 0, 0]
+                            con.center = node.position - [self.constraint_height, 0, 0]
+                            con.color = self.constraints_color
+                            self.viewer.add_object(con)
+                        if component == 1:
+                            con = Cone()
+                            con.height = self.constraint_height
+                            con.direction = [0, 1, 0]
+                            con.center = node.position - [0, self.constraint_height, 0]
+                            con.color = self.constraints_color
+                            self.viewer.add_object(con)
+                        if component == 2:
+                            con = Cone()
+                            con.height = self.constraint_height
+                            con.direction = [0, 0, 1]
+                            con.center = node.position - [0, 0, self.constraint_height]
+                            con.color = self.constraints_color
+                            self.viewer.add_object(con)
+
+    def draw_element_forces(self):
+        """
+        Draws element forces on its original locations.
+        """
+        for node_id in range(self.num_nodes):
+            force = self.struct.get_node(node_id).get_force()
+            if force != None:
+                force = force.get_value()
+                if force.any() != None:
+                    position = self.struct.get_node(node_id).get_position()
+                    direction = np.array(force/np.linalg.norm(force) * -self.arrow_height)
+                    arr = Arrow()
+                    arr.point1 = position + direction
+                    arr.point2 = position
+                    arr.radius = self.arrow_radius
+                    arr.color = self.forces_color
+                    self.viewer.add_object(arr)
+
+    def draw_displaced_elements(self):
+        """
+        Draws elements on its displaced locations.
+        """
+        cylinder_set = CylinderSet()
+        for element in range(self.num_elements):
+            node_1 = self.struct.get_element(element).get_node_1()
+            node_2 = self.struct.get_element(element).get_node_2()
+            radius = (self.struct.get_element(element).get_area()/math.pi) ** 0.5
+            n1_new = node_1.get_position() + node_1.get_displacement() * self.displacement_scale
+            n2_new = node_2.get_position() + node_2.get_displacement() * self.displacement_scale
+            cylinder_set.add_cylinder(n1_new, n2_new, radius)
+        cylinder_set.color = self.displaced_elements_color
+        self.viewer.add_object(cylinder_set)
+
+    def draw_displaced_forces(self):
+        """
+        Draws element forces on its displaced locations.
+        """
+        for node_id in range(self.num_nodes):
+            force = self.struct.get_node(node_id).get_force()
+            if force != None:
+                force = force.get_value()
+                if force.any() != None:
+                    node = self.struct.get_node(node_id)
+                    position = node.get_position()
+                    displacement = node.get_displacement() * self.displacement_scale
+                    direction = np.array(force/np.linalg.norm(force))
+                    direction = direction * -self.arrow_height
+                    arr = Arrow()
+                    arr.point1 = position + direction + displacement
+                    arr.point2 = position + displacement
+                    arr.radius = self.arrow_radius
+                    arr.color = self.displaced_forces
+                    self.viewer.add_object(arr)
+
+    def draw_normal_forces(self):
+        """
+        Draws planes showing graphically magnitudes of calculated normal forces.
+        """
+        vector = np.array([0, 0, -1])
+        for element in range(self.struct.get_number_elements()):
+            node_1 = self.struct.get_element(element).get_node_1()
+            node_2 = self.struct.get_element(element).get_node_2()
+            n1_new = (node_1.get_position() +
+                      node_1.get_displacement() * self.displacement_scale)
+            n2_new = (node_2.get_position() +
+                      node_2.get_displacement() * self.displacement_scale)
+            #p = np.cross(n2_new-n1_new, p)
+            #p = p / np.linalg.norm(p)
+            force = self.struct.get_element(element).compute_force()
+            normal_vector = force * self.normal_forces_scale
+            force_position_1 = n1_new + vector * normal_vector
+            force_position_2 = n2_new + vector * normal_vector
+            poly_set = PolygonSet()
+            poly_set.insert_vertex(n1_new[0], n1_new[1], n1_new[2], 0)
+            poly_set.insert_vertex(force_position_1[0], force_position_1[1],
+                                   force_position_1[2], 1)
+            poly_set.insert_vertex(force_position_2[0], force_position_2[1],
+                                   force_position_2[2], 2)
+            poly_set.insert_vertex(n2_new[0], n2_new[1], n2_new[2], 3)
+            poly_set.polygon_complete()
+            if normal_vector >= 0:
+                poly_set.color = 'blue'
+            else:
+                poly_set.color = 'red'
+            self.viewer.add_object(poly_set)
+'''
\ No newline at end of file
diff --git a/meshpy/.eggs/README.txt b/meshpy/.eggs/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5d01668824f45c3a6683e12d1b9048bb1d273041
--- /dev/null
+++ b/meshpy/.eggs/README.txt
@@ -0,0 +1,6 @@
+This directory contains eggs that were downloaded by setuptools to build, test, and run plug-ins.
+
+This directory caches those eggs to prevent repeated downloads.
+
+However, it is safe to delete this directory.
+
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/DESCRIPTION.rst b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/DESCRIPTION.rst
new file mode 100644
index 0000000000000000000000000000000000000000..13a5db327f9f15f177ca1b2d47782ba7144d93fd
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/DESCRIPTION.rst
@@ -0,0 +1,24 @@
+pybind11 is a lightweight header-only library that
+exposes C++ types in Python and vice versa, mainly to create Python bindings of
+existing C++ code. Its goals and syntax are similar to the excellent
+Boost.Python by David Abrahams: to minimize boilerplate code in traditional
+extension modules by inferring type information using compile-time
+introspection.
+
+The main issue with Boost.Python-and the reason for creating such a similar
+project-is Boost. Boost is an enormously large and complex suite of utility
+libraries that works with almost every C++ compiler in existence. This
+compatibility has its cost: arcane template tricks and workarounds are
+necessary to support the oldest and buggiest of compiler specimens. Now that
+C++11-compatible compilers are widely available, this heavy machinery has
+become an excessively large and unnecessary dependency.
+
+Think of this library as a tiny self-contained version of Boost.Python with
+everything stripped away that isn't relevant for binding generation. Without
+comments, the core header files only require ~4K lines of code and depend on
+Python (2.7 or 3.x, or PyPy2.7 >= 5.7) and the C++ standard library. This
+compact implementation was possible thanks to some of the new C++11 language
+features (specifically: tuples, lambda functions and variadic templates). Since
+its creation, this library has grown beyond Boost.Python in many ways, leading
+to dramatically simpler binding code in many common situations.
+
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/PKG-INFO b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/PKG-INFO
new file mode 100644
index 0000000000000000000000000000000000000000..59d6bdb22cb1010f11012eabd1f677decf139db2
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/PKG-INFO
@@ -0,0 +1,49 @@
+Metadata-Version: 2.0
+Name: pybind11
+Version: 2.2.4
+Summary: Seamless operability between C++11 and Python
+Home-page: https://github.com/pybind/pybind11
+Author: Wenzel Jakob
+Author-email: wenzel.jakob@epfl.ch
+License: BSD
+Download-URL: https://github.com/pybind/pybind11/tarball/v2.2.4
+Keywords: C++11,Python bindings
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Utilities
+Classifier: Programming Language :: C++
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.2
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: License :: OSI Approved :: BSD License
+
+pybind11 is a lightweight header-only library that
+exposes C++ types in Python and vice versa, mainly to create Python bindings of
+existing C++ code. Its goals and syntax are similar to the excellent
+Boost.Python by David Abrahams: to minimize boilerplate code in traditional
+extension modules by inferring type information using compile-time
+introspection.
+
+The main issue with Boost.Python-and the reason for creating such a similar
+project-is Boost. Boost is an enormously large and complex suite of utility
+libraries that works with almost every C++ compiler in existence. This
+compatibility has its cost: arcane template tricks and workarounds are
+necessary to support the oldest and buggiest of compiler specimens. Now that
+C++11-compatible compilers are widely available, this heavy machinery has
+become an excessively large and unnecessary dependency.
+
+Think of this library as a tiny self-contained version of Boost.Python with
+everything stripped away that isn't relevant for binding generation. Without
+comments, the core header files only require ~4K lines of code and depend on
+Python (2.7 or 3.x, or PyPy2.7 >= 5.7) and the C++ standard library. This
+compact implementation was possible thanks to some of the new C++11 language
+features (specifically: tuples, lambda functions and variadic templates). Since
+its creation, this library has grown beyond Boost.Python in many ways, leading
+to dramatically simpler binding code in many common situations.
+
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/RECORD b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/RECORD
new file mode 100644
index 0000000000000000000000000000000000000000..505ba3e1ba9424640478ea78c4656bcc0e23f3cd
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/RECORD
@@ -0,0 +1,33 @@
+pybind11/__init__.py,sha256=uRzaXjt6dY5zQRy0oKvBTwfj6NwEpQe4QuVUqOWSp3Y,879
+pybind11/__main__.py,sha256=0UffzZ5NWHggU75g-342Kc3j0E5_gTtQzvKl935gUDw,871
+pybind11/_version.py,sha256=tAa6skcBWj1D_lZYhqe0axzypmtA3BU_YQiM9kFn_AI,72
+pybind11-2.2.4.data/headers/attr.h,sha256=ze9m4F2nNwHRenL3SRNJJD0QrU3Wgn7Wth1k2TQfVws,18946
+pybind11-2.2.4.data/headers/buffer_info.h,sha256=ZzzextvuEJAQrO17Yy2gG0GljcvvnZ90hwI42aRJK8g,4326
+pybind11-2.2.4.data/headers/cast.h,sha256=n6UUnYRct9LL8Jz--TIRAQzuZZsXkUd8ys0Rkb3MmGQ,86330
+pybind11-2.2.4.data/headers/chrono.h,sha256=LbTevQzFguNzy_M61ZdcTxhtIiLhsLouflyNq6kH84c,6616
+pybind11-2.2.4.data/headers/common.h,sha256=ATg9Bt1pwF8qnNuI086fprM4CUTdrZdk_g2HXE1Sf6A,120
+pybind11-2.2.4.data/headers/complex.h,sha256=KVEwAElsuiR1VOiLLnCkTr1uCNgO-TdFg1fQDlHipH8,1969
+pybind11-2.2.4.data/headers/eigen.h,sha256=iU7LtEsl34t71mvZhezoZ_dXHOG4vi-HCkUVv-r6snk,28937
+pybind11-2.2.4.data/headers/embed.h,sha256=zNet-2LKba2Cx3tynYXYl-W8rVhbaxk3DVbI9dPP3AM,7417
+pybind11-2.2.4.data/headers/eval.h,sha256=_aw_DVHM1tO6uaPThOvfa7GMKWqPanFknrvxUZQxCIo,3865
+pybind11-2.2.4.data/headers/functional.h,sha256=9vuv8BoNu6FTLSrj-yChxPM7aWKoSfxQBbp4DQx_uaU,2954
+pybind11-2.2.4.data/headers/iostream.h,sha256=AJBaTgsjM5m50FHymzPqNcLpZB4fLJaUmI6m0xAhd78,5393
+pybind11-2.2.4.data/headers/numpy.h,sha256=QavR2HnWwXf-k62hazc3pmdhzH1LE9WqQf6_8j52Nlg,65752
+pybind11-2.2.4.data/headers/operators.h,sha256=xk1NdnJCEL_BvfQDCQWvB_S0uDbtEUOD5Gjxio2Fo20,8749
+pybind11-2.2.4.data/headers/options.h,sha256=rnv5QBoRNBqUv59A20XOODS8tV0wGHtMFCbsp6CJbnk,2031
+pybind11-2.2.4.data/headers/pybind11.h,sha256=KVf1gYLndaiDVRJDfGFJlarsACEtqMzudrd-aHRYXTI,88892
+pybind11-2.2.4.data/headers/pytypes.h,sha256=esKdJS0Ur0nun4-5exZjT4icv8yIFoBUrmZbRJKfXxY,51318
+pybind11-2.2.4.data/headers/stl.h,sha256=t3WTfYCDw-7bQtwdF70pVA_x8cKfbehMdsE9r-p_n2k,13612
+pybind11-2.2.4.data/headers/stl_bind.h,sha256=zyLLfeF54ukoLmUkoVIAIQFfcKswNEcPUDKkpcedZXM,21607
+pybind11-2.2.4.data/headers/detail/class.h,sha256=NG_NhZlfKSEvrIzxVqB8PFzdhxR_jyuNVgvqwVtbJIM,24896
+pybind11-2.2.4.data/headers/detail/common.h,sha256=r-amQVQT0WmaLAZDebSgRALZx1ZFonpK5om2OzkR23E,37460
+pybind11-2.2.4.data/headers/detail/descr.h,sha256=rWhzhfBwy_pQtNNfPACTtiVn_gQxfBECHlu9_EC4KFg,7720
+pybind11-2.2.4.data/headers/detail/init.h,sha256=0hnFYqzGLOj6fKSE0Q1kOUwXtK9gEofVi45y2LLj_C4,16345
+pybind11-2.2.4.data/headers/detail/internals.h,sha256=tJEkfqaLwh7EldgyVcQPG1Rs6HLHy2pk-IQ6YPFDXWg,13474
+pybind11-2.2.4.data/headers/detail/typeid.h,sha256=ssb4m9GwBtiVgXZU8ZY07xbuK036p6U6hXLddH8WN6c,1429
+pybind11-2.2.4.dist-info/DESCRIPTION.rst,sha256=iToWQUG8E8OATsRcdodz5Sg01PicRsle5qIRELqCK8c,1466
+pybind11-2.2.4.dist-info/METADATA,sha256=gCxDiBuOtZakhvM2o3QT2Sq4cEcJusNHyQsjl3IIcKk,2446
+pybind11-2.2.4.dist-info/RECORD,,
+pybind11-2.2.4.dist-info/WHEEL,sha256=kdsN-5OJAZIiHN-iO4Rhl82KyS0bDWf4uBwMbkNafr8,110
+pybind11-2.2.4.dist-info/metadata.json,sha256=FgUgoGjK_oWreAtjB93znj2gDm89aB-oMUrV-KS0ALA,1086
+pybind11-2.2.4.dist-info/top_level.txt,sha256=d1mqwSpUlmlZhXDQ9Y57eNlXc3dVDM1toKmfC1kJbvU,9
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/WHEEL b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/WHEEL
new file mode 100644
index 0000000000000000000000000000000000000000..7332a419cda6903b61439f3bac93492b0747e6e7
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/WHEEL
@@ -0,0 +1,6 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.30.0)
+Root-Is-Purelib: true
+Tag: py2-none-any
+Tag: py3-none-any
+
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/metadata.json b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/metadata.json
new file mode 100644
index 0000000000000000000000000000000000000000..c1abbad64240dd85726fbc9c25acbba1e8f29390
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/metadata.json
@@ -0,0 +1 @@
+{"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Utilities", "Programming Language :: C++", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "License :: OSI Approved :: BSD License"], "download_url": "https://github.com/pybind/pybind11/tarball/v2.2.4", "extensions": {"python.details": {"contacts": [{"email": "wenzel.jakob@epfl.ch", "name": "Wenzel Jakob", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/pybind/pybind11"}}}, "generator": "bdist_wheel (0.30.0)", "keywords": ["C", "11", "Python", "bindings"], "license": "BSD", "metadata_version": "2.0", "name": "pybind11", "summary": "Seamless operability between C++11 and Python", "version": "2.2.4"}
\ No newline at end of file
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/top_level.txt b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/top_level.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e47c59fd7ced4c11e813c3ef82d919443a5f1d33
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/EGG-INFO/top_level.txt
@@ -0,0 +1 @@
+pybind11
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/attr.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/attr.h
new file mode 100644
index 0000000000000000000000000000000000000000..dce875a6b996036e833a451997d21c81af11c9ed
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/attr.h
@@ -0,0 +1,489 @@
+/*
+    pybind11/attr.h: Infrastructure for processing custom
+    type and function attributes
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "cast.h"
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+
+/// \addtogroup annotations
+/// @{
+
+/// Annotation for methods
+struct is_method { handle class_; is_method(const handle &c) : class_(c) { } };
+
+/// Annotation for operators
+struct is_operator { };
+
+/// Annotation for parent scope
+struct scope { handle value; scope(const handle &s) : value(s) { } };
+
+/// Annotation for documentation
+struct doc { const char *value; doc(const char *value) : value(value) { } };
+
+/// Annotation for function names
+struct name { const char *value; name(const char *value) : value(value) { } };
+
+/// Annotation indicating that a function is an overload associated with a given "sibling"
+struct sibling { handle value; sibling(const handle &value) : value(value.ptr()) { } };
+
+/// Annotation indicating that a class derives from another given type
+template <typename T> struct base {
+    PYBIND11_DEPRECATED("base<T>() was deprecated in favor of specifying 'T' as a template argument to class_")
+    base() { }
+};
+
+/// Keep patient alive while nurse lives
+template <size_t Nurse, size_t Patient> struct keep_alive { };
+
+/// Annotation indicating that a class is involved in a multiple inheritance relationship
+struct multiple_inheritance { };
+
+/// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class
+struct dynamic_attr { };
+
+/// Annotation which enables the buffer protocol for a type
+struct buffer_protocol { };
+
+/// Annotation which requests that a special metaclass is created for a type
+struct metaclass {
+    handle value;
+
+    PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.")
+    metaclass() {}
+
+    /// Override pybind11's default metaclass
+    explicit metaclass(handle value) : value(value) { }
+};
+
+/// Annotation that marks a class as local to the module:
+struct module_local { const bool value; constexpr module_local(bool v = true) : value(v) { } };
+
+/// Annotation to mark enums as an arithmetic type
+struct arithmetic { };
+
+/** \rst
+    A call policy which places one or more guard variables (``Ts...``) around the function call.
+
+    For example, this definition:
+
+    .. code-block:: cpp
+
+        m.def("foo", foo, py::call_guard<T>());
+
+    is equivalent to the following pseudocode:
+
+    .. code-block:: cpp
+
+        m.def("foo", [](args...) {
+            T scope_guard;
+            return foo(args...); // forwarded arguments
+        });
+ \endrst */
+template <typename... Ts> struct call_guard;
+
+template <> struct call_guard<> { using type = detail::void_type; };
+
+template <typename T>
+struct call_guard<T> {
+    static_assert(std::is_default_constructible<T>::value,
+                  "The guard type must be default constructible");
+
+    using type = T;
+};
+
+template <typename T, typename... Ts>
+struct call_guard<T, Ts...> {
+    struct type {
+        T guard{}; // Compose multiple guard types with left-to-right default-constructor order
+        typename call_guard<Ts...>::type next{};
+    };
+};
+
+/// @} annotations
+
+NAMESPACE_BEGIN(detail)
+/* Forward declarations */
+enum op_id : int;
+enum op_type : int;
+struct undefined_t;
+template <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t> struct op_;
+inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret);
+
+/// Internal data structure which holds metadata about a keyword argument
+struct argument_record {
+    const char *name;  ///< Argument name
+    const char *descr; ///< Human-readable version of the argument value
+    handle value;      ///< Associated Python object
+    bool convert : 1;  ///< True if the argument is allowed to convert when loading
+    bool none : 1;     ///< True if None is allowed when loading
+
+    argument_record(const char *name, const char *descr, handle value, bool convert, bool none)
+        : name(name), descr(descr), value(value), convert(convert), none(none) { }
+};
+
+/// Internal data structure which holds metadata about a bound function (signature, overloads, etc.)
+struct function_record {
+    function_record()
+        : is_constructor(false), is_new_style_constructor(false), is_stateless(false),
+          is_operator(false), has_args(false), has_kwargs(false), is_method(false) { }
+
+    /// Function name
+    char *name = nullptr; /* why no C++ strings? They generate heavier code.. */
+
+    // User-specified documentation string
+    char *doc = nullptr;
+
+    /// Human-readable version of the function signature
+    char *signature = nullptr;
+
+    /// List of registered keyword arguments
+    std::vector<argument_record> args;
+
+    /// Pointer to lambda function which converts arguments and performs the actual call
+    handle (*impl) (function_call &) = nullptr;
+
+    /// Storage for the wrapped function pointer and captured data, if any
+    void *data[3] = { };
+
+    /// Pointer to custom destructor for 'data' (if needed)
+    void (*free_data) (function_record *ptr) = nullptr;
+
+    /// Return value policy associated with this function
+    return_value_policy policy = return_value_policy::automatic;
+
+    /// True if name == '__init__'
+    bool is_constructor : 1;
+
+    /// True if this is a new-style `__init__` defined in `detail/init.h`
+    bool is_new_style_constructor : 1;
+
+    /// True if this is a stateless function pointer
+    bool is_stateless : 1;
+
+    /// True if this is an operator (__add__), etc.
+    bool is_operator : 1;
+
+    /// True if the function has a '*args' argument
+    bool has_args : 1;
+
+    /// True if the function has a '**kwargs' argument
+    bool has_kwargs : 1;
+
+    /// True if this is a method
+    bool is_method : 1;
+
+    /// Number of arguments (including py::args and/or py::kwargs, if present)
+    std::uint16_t nargs;
+
+    /// Python method object
+    PyMethodDef *def = nullptr;
+
+    /// Python handle to the parent scope (a class or a module)
+    handle scope;
+
+    /// Python handle to the sibling function representing an overload chain
+    handle sibling;
+
+    /// Pointer to next overload
+    function_record *next = nullptr;
+};
+
+/// Special data structure which (temporarily) holds metadata about a bound class
+struct type_record {
+    PYBIND11_NOINLINE type_record()
+        : multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false), module_local(false) { }
+
+    /// Handle to the parent scope
+    handle scope;
+
+    /// Name of the class
+    const char *name = nullptr;
+
+    // Pointer to RTTI type_info data structure
+    const std::type_info *type = nullptr;
+
+    /// How large is the underlying C++ type?
+    size_t type_size = 0;
+
+    /// How large is the type's holder?
+    size_t holder_size = 0;
+
+    /// The global operator new can be overridden with a class-specific variant
+    void *(*operator_new)(size_t) = ::operator new;
+
+    /// Function pointer to class_<..>::init_instance
+    void (*init_instance)(instance *, const void *) = nullptr;
+
+    /// Function pointer to class_<..>::dealloc
+    void (*dealloc)(detail::value_and_holder &) = nullptr;
+
+    /// List of base classes of the newly created type
+    list bases;
+
+    /// Optional docstring
+    const char *doc = nullptr;
+
+    /// Custom metaclass (optional)
+    handle metaclass;
+
+    /// Multiple inheritance marker
+    bool multiple_inheritance : 1;
+
+    /// Does the class manage a __dict__?
+    bool dynamic_attr : 1;
+
+    /// Does the class implement the buffer protocol?
+    bool buffer_protocol : 1;
+
+    /// Is the default (unique_ptr) holder type used?
+    bool default_holder : 1;
+
+    /// Is the class definition local to the module shared object?
+    bool module_local : 1;
+
+    PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *)) {
+        auto base_info = detail::get_type_info(base, false);
+        if (!base_info) {
+            std::string tname(base.name());
+            detail::clean_type_id(tname);
+            pybind11_fail("generic_type: type \"" + std::string(name) +
+                          "\" referenced unknown base type \"" + tname + "\"");
+        }
+
+        if (default_holder != base_info->default_holder) {
+            std::string tname(base.name());
+            detail::clean_type_id(tname);
+            pybind11_fail("generic_type: type \"" + std::string(name) + "\" " +
+                    (default_holder ? "does not have" : "has") +
+                    " a non-default holder type while its base \"" + tname + "\" " +
+                    (base_info->default_holder ? "does not" : "does"));
+        }
+
+        bases.append((PyObject *) base_info->type);
+
+        if (base_info->type->tp_dictoffset != 0)
+            dynamic_attr = true;
+
+        if (caster)
+            base_info->implicit_casts.emplace_back(type, caster);
+    }
+};
+
+inline function_call::function_call(function_record &f, handle p) :
+        func(f), parent(p) {
+    args.reserve(f.nargs);
+    args_convert.reserve(f.nargs);
+}
+
+/// Tag for a new-style `__init__` defined in `detail/init.h`
+struct is_new_style_constructor { };
+
+/**
+ * Partial template specializations to process custom attributes provided to
+ * cpp_function_ and class_. These are either used to initialize the respective
+ * fields in the type_record and function_record data structures or executed at
+ * runtime to deal with custom call policies (e.g. keep_alive).
+ */
+template <typename T, typename SFINAE = void> struct process_attribute;
+
+template <typename T> struct process_attribute_default {
+    /// Default implementation: do nothing
+    static void init(const T &, function_record *) { }
+    static void init(const T &, type_record *) { }
+    static void precall(function_call &) { }
+    static void postcall(function_call &, handle) { }
+};
+
+/// Process an attribute specifying the function's name
+template <> struct process_attribute<name> : process_attribute_default<name> {
+    static void init(const name &n, function_record *r) { r->name = const_cast<char *>(n.value); }
+};
+
+/// Process an attribute specifying the function's docstring
+template <> struct process_attribute<doc> : process_attribute_default<doc> {
+    static void init(const doc &n, function_record *r) { r->doc = const_cast<char *>(n.value); }
+};
+
+/// Process an attribute specifying the function's docstring (provided as a C-style string)
+template <> struct process_attribute<const char *> : process_attribute_default<const char *> {
+    static void init(const char *d, function_record *r) { r->doc = const_cast<char *>(d); }
+    static void init(const char *d, type_record *r) { r->doc = const_cast<char *>(d); }
+};
+template <> struct process_attribute<char *> : process_attribute<const char *> { };
+
+/// Process an attribute indicating the function's return value policy
+template <> struct process_attribute<return_value_policy> : process_attribute_default<return_value_policy> {
+    static void init(const return_value_policy &p, function_record *r) { r->policy = p; }
+};
+
+/// Process an attribute which indicates that this is an overloaded function associated with a given sibling
+template <> struct process_attribute<sibling> : process_attribute_default<sibling> {
+    static void init(const sibling &s, function_record *r) { r->sibling = s.value; }
+};
+
+/// Process an attribute which indicates that this function is a method
+template <> struct process_attribute<is_method> : process_attribute_default<is_method> {
+    static void init(const is_method &s, function_record *r) { r->is_method = true; r->scope = s.class_; }
+};
+
+/// Process an attribute which indicates the parent scope of a method
+template <> struct process_attribute<scope> : process_attribute_default<scope> {
+    static void init(const scope &s, function_record *r) { r->scope = s.value; }
+};
+
+/// Process an attribute which indicates that this function is an operator
+template <> struct process_attribute<is_operator> : process_attribute_default<is_operator> {
+    static void init(const is_operator &, function_record *r) { r->is_operator = true; }
+};
+
+template <> struct process_attribute<is_new_style_constructor> : process_attribute_default<is_new_style_constructor> {
+    static void init(const is_new_style_constructor &, function_record *r) { r->is_new_style_constructor = true; }
+};
+
+/// Process a keyword argument attribute (*without* a default value)
+template <> struct process_attribute<arg> : process_attribute_default<arg> {
+    static void init(const arg &a, function_record *r) {
+        if (r->is_method && r->args.empty())
+            r->args.emplace_back("self", nullptr, handle(), true /*convert*/, false /*none not allowed*/);
+        r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none);
+    }
+};
+
+/// Process a keyword argument attribute (*with* a default value)
+template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
+    static void init(const arg_v &a, function_record *r) {
+        if (r->is_method && r->args.empty())
+            r->args.emplace_back("self", nullptr /*descr*/, handle() /*parent*/, true /*convert*/, false /*none not allowed*/);
+
+        if (!a.value) {
+#if !defined(NDEBUG)
+            std::string descr("'");
+            if (a.name) descr += std::string(a.name) + ": ";
+            descr += a.type + "'";
+            if (r->is_method) {
+                if (r->name)
+                    descr += " in method '" + (std::string) str(r->scope) + "." + (std::string) r->name + "'";
+                else
+                    descr += " in method of '" + (std::string) str(r->scope) + "'";
+            } else if (r->name) {
+                descr += " in function '" + (std::string) r->name + "'";
+            }
+            pybind11_fail("arg(): could not convert default argument "
+                          + descr + " into a Python object (type not registered yet?)");
+#else
+            pybind11_fail("arg(): could not convert default argument "
+                          "into a Python object (type not registered yet?). "
+                          "Compile in debug mode for more information.");
+#endif
+        }
+        r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none);
+    }
+};
+
+/// Process a parent class attribute.  Single inheritance only (class_ itself already guarantees that)
+template <typename T>
+struct process_attribute<T, enable_if_t<is_pyobject<T>::value>> : process_attribute_default<handle> {
+    static void init(const handle &h, type_record *r) { r->bases.append(h); }
+};
+
+/// Process a parent class attribute (deprecated, does not support multiple inheritance)
+template <typename T>
+struct process_attribute<base<T>> : process_attribute_default<base<T>> {
+    static void init(const base<T> &, type_record *r) { r->add_base(typeid(T), nullptr); }
+};
+
+/// Process a multiple inheritance attribute
+template <>
+struct process_attribute<multiple_inheritance> : process_attribute_default<multiple_inheritance> {
+    static void init(const multiple_inheritance &, type_record *r) { r->multiple_inheritance = true; }
+};
+
+template <>
+struct process_attribute<dynamic_attr> : process_attribute_default<dynamic_attr> {
+    static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; }
+};
+
+template <>
+struct process_attribute<buffer_protocol> : process_attribute_default<buffer_protocol> {
+    static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; }
+};
+
+template <>
+struct process_attribute<metaclass> : process_attribute_default<metaclass> {
+    static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; }
+};
+
+template <>
+struct process_attribute<module_local> : process_attribute_default<module_local> {
+    static void init(const module_local &l, type_record *r) { r->module_local = l.value; }
+};
+
+/// Process an 'arithmetic' attribute for enums (does nothing here)
+template <>
+struct process_attribute<arithmetic> : process_attribute_default<arithmetic> {};
+
+template <typename... Ts>
+struct process_attribute<call_guard<Ts...>> : process_attribute_default<call_guard<Ts...>> { };
+
+/**
+ * Process a keep_alive call policy -- invokes keep_alive_impl during the
+ * pre-call handler if both Nurse, Patient != 0 and use the post-call handler
+ * otherwise
+ */
+template <size_t Nurse, size_t Patient> struct process_attribute<keep_alive<Nurse, Patient>> : public process_attribute_default<keep_alive<Nurse, Patient>> {
+    template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
+    static void precall(function_call &call) { keep_alive_impl(Nurse, Patient, call, handle()); }
+    template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
+    static void postcall(function_call &, handle) { }
+    template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
+    static void precall(function_call &) { }
+    template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
+    static void postcall(function_call &call, handle ret) { keep_alive_impl(Nurse, Patient, call, ret); }
+};
+
+/// Recursively iterate over variadic template arguments
+template <typename... Args> struct process_attributes {
+    static void init(const Args&... args, function_record *r) {
+        int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... };
+        ignore_unused(unused);
+    }
+    static void init(const Args&... args, type_record *r) {
+        int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... };
+        ignore_unused(unused);
+    }
+    static void precall(function_call &call) {
+        int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::precall(call), 0) ... };
+        ignore_unused(unused);
+    }
+    static void postcall(function_call &call, handle fn_ret) {
+        int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::postcall(call, fn_ret), 0) ... };
+        ignore_unused(unused);
+    }
+};
+
+template <typename T>
+using is_call_guard = is_instantiation<call_guard, T>;
+
+/// Extract the ``type`` from the first `call_guard` in `Extras...` (or `void_type` if none found)
+template <typename... Extra>
+using extract_guard_t = typename exactly_one_t<is_call_guard, call_guard<>, Extra...>::type;
+
+/// Check the number of named arguments at compile time
+template <typename... Extra,
+          size_t named = constexpr_sum(std::is_base_of<arg, Extra>::value...),
+          size_t self  = constexpr_sum(std::is_same<is_method, Extra>::value...)>
+constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) {
+    return named == 0 || (self + named + has_args + has_kwargs) == nargs;
+}
+
+NAMESPACE_END(detail)
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/buffer_info.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/buffer_info.h
new file mode 100644
index 0000000000000000000000000000000000000000..9f072fa738793cd4720504b71037df58e2a93179
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/buffer_info.h
@@ -0,0 +1,108 @@
+/*
+    pybind11/buffer_info.h: Python buffer object interface
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "detail/common.h"
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+
+/// Information record describing a Python buffer object
+struct buffer_info {
+    void *ptr = nullptr;          // Pointer to the underlying storage
+    ssize_t itemsize = 0;         // Size of individual items in bytes
+    ssize_t size = 0;             // Total number of entries
+    std::string format;           // For homogeneous buffers, this should be set to format_descriptor<T>::format()
+    ssize_t ndim = 0;             // Number of dimensions
+    std::vector<ssize_t> shape;   // Shape of the tensor (1 entry per dimension)
+    std::vector<ssize_t> strides; // Number of entries between adjacent entries (for each per dimension)
+
+    buffer_info() { }
+
+    buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim,
+                detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in)
+    : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim),
+      shape(std::move(shape_in)), strides(std::move(strides_in)) {
+        if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size())
+            pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length");
+        for (size_t i = 0; i < (size_t) ndim; ++i)
+            size *= shape[i];
+    }
+
+    template <typename T>
+    buffer_info(T *ptr, detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in)
+    : buffer_info(private_ctr_tag(), ptr, sizeof(T), format_descriptor<T>::format(), static_cast<ssize_t>(shape_in->size()), std::move(shape_in), std::move(strides_in)) { }
+
+    buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size)
+    : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}) { }
+
+    template <typename T>
+    buffer_info(T *ptr, ssize_t size)
+    : buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size) { }
+
+    explicit buffer_info(Py_buffer *view, bool ownview = true)
+    : buffer_info(view->buf, view->itemsize, view->format, view->ndim,
+            {view->shape, view->shape + view->ndim}, {view->strides, view->strides + view->ndim}) {
+        this->view = view;
+        this->ownview = ownview;
+    }
+
+    buffer_info(const buffer_info &) = delete;
+    buffer_info& operator=(const buffer_info &) = delete;
+
+    buffer_info(buffer_info &&other) {
+        (*this) = std::move(other);
+    }
+
+    buffer_info& operator=(buffer_info &&rhs) {
+        ptr = rhs.ptr;
+        itemsize = rhs.itemsize;
+        size = rhs.size;
+        format = std::move(rhs.format);
+        ndim = rhs.ndim;
+        shape = std::move(rhs.shape);
+        strides = std::move(rhs.strides);
+        std::swap(view, rhs.view);
+        std::swap(ownview, rhs.ownview);
+        return *this;
+    }
+
+    ~buffer_info() {
+        if (view && ownview) { PyBuffer_Release(view); delete view; }
+    }
+
+private:
+    struct private_ctr_tag { };
+
+    buffer_info(private_ctr_tag, void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim,
+                detail::any_container<ssize_t> &&shape_in, detail::any_container<ssize_t> &&strides_in)
+    : buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in)) { }
+
+    Py_buffer *view = nullptr;
+    bool ownview = false;
+};
+
+NAMESPACE_BEGIN(detail)
+
+template <typename T, typename SFINAE = void> struct compare_buffer_info {
+    static bool compare(const buffer_info& b) {
+        return b.format == format_descriptor<T>::format() && b.itemsize == (ssize_t) sizeof(T);
+    }
+};
+
+template <typename T> struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> {
+    static bool compare(const buffer_info& b) {
+        return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor<T>::value ||
+            ((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned<T>::value ? "L" : "l")) ||
+            ((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned<T>::value ? "N" : "n")));
+    }
+};
+
+NAMESPACE_END(detail)
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/cast.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/cast.h
new file mode 100644
index 0000000000000000000000000000000000000000..21454508351bef93901f4af9137408ab89aa2f99
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/cast.h
@@ -0,0 +1,2067 @@
+/*
+    pybind11/cast.h: Partial template specializations to cast between
+    C++ and Python types
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "pytypes.h"
+#include "detail/typeid.h"
+#include "detail/descr.h"
+#include "detail/internals.h"
+#include <array>
+#include <limits>
+#include <tuple>
+
+#if defined(PYBIND11_CPP17)
+#  if defined(__has_include)
+#    if __has_include(<string_view>)
+#      define PYBIND11_HAS_STRING_VIEW
+#    endif
+#  elif defined(_MSC_VER)
+#    define PYBIND11_HAS_STRING_VIEW
+#  endif
+#endif
+#ifdef PYBIND11_HAS_STRING_VIEW
+#include <string_view>
+#endif
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+NAMESPACE_BEGIN(detail)
+
+/// A life support system for temporary objects created by `type_caster::load()`.
+/// Adding a patient will keep it alive up until the enclosing function returns.
+class loader_life_support {
+public:
+    /// A new patient frame is created when a function is entered
+    loader_life_support() {
+        get_internals().loader_patient_stack.push_back(nullptr);
+    }
+
+    /// ... and destroyed after it returns
+    ~loader_life_support() {
+        auto &stack = get_internals().loader_patient_stack;
+        if (stack.empty())
+            pybind11_fail("loader_life_support: internal error");
+
+        auto ptr = stack.back();
+        stack.pop_back();
+        Py_CLEAR(ptr);
+
+        // A heuristic to reduce the stack's capacity (e.g. after long recursive calls)
+        if (stack.capacity() > 16 && stack.size() != 0 && stack.capacity() / stack.size() > 2)
+            stack.shrink_to_fit();
+    }
+
+    /// This can only be used inside a pybind11-bound function, either by `argument_loader`
+    /// at argument preparation time or by `py::cast()` at execution time.
+    PYBIND11_NOINLINE static void add_patient(handle h) {
+        auto &stack = get_internals().loader_patient_stack;
+        if (stack.empty())
+            throw cast_error("When called outside a bound function, py::cast() cannot "
+                             "do Python -> C++ conversions which require the creation "
+                             "of temporary values");
+
+        auto &list_ptr = stack.back();
+        if (list_ptr == nullptr) {
+            list_ptr = PyList_New(1);
+            if (!list_ptr)
+                pybind11_fail("loader_life_support: error allocating list");
+            PyList_SET_ITEM(list_ptr, 0, h.inc_ref().ptr());
+        } else {
+            auto result = PyList_Append(list_ptr, h.ptr());
+            if (result == -1)
+                pybind11_fail("loader_life_support: error adding patient");
+        }
+    }
+};
+
+// Gets the cache entry for the given type, creating it if necessary.  The return value is the pair
+// returned by emplace, i.e. an iterator for the entry and a bool set to `true` if the entry was
+// just created.
+inline std::pair<decltype(internals::registered_types_py)::iterator, bool> all_type_info_get_cache(PyTypeObject *type);
+
+// Populates a just-created cache entry.
+PYBIND11_NOINLINE inline void all_type_info_populate(PyTypeObject *t, std::vector<type_info *> &bases) {
+    std::vector<PyTypeObject *> check;
+    for (handle parent : reinterpret_borrow<tuple>(t->tp_bases))
+        check.push_back((PyTypeObject *) parent.ptr());
+
+    auto const &type_dict = get_internals().registered_types_py;
+    for (size_t i = 0; i < check.size(); i++) {
+        auto type = check[i];
+        // Ignore Python2 old-style class super type:
+        if (!PyType_Check((PyObject *) type)) continue;
+
+        // Check `type` in the current set of registered python types:
+        auto it = type_dict.find(type);
+        if (it != type_dict.end()) {
+            // We found a cache entry for it, so it's either pybind-registered or has pre-computed
+            // pybind bases, but we have to make sure we haven't already seen the type(s) before: we
+            // want to follow Python/virtual C++ rules that there should only be one instance of a
+            // common base.
+            for (auto *tinfo : it->second) {
+                // NB: Could use a second set here, rather than doing a linear search, but since
+                // having a large number of immediate pybind11-registered types seems fairly
+                // unlikely, that probably isn't worthwhile.
+                bool found = false;
+                for (auto *known : bases) {
+                    if (known == tinfo) { found = true; break; }
+                }
+                if (!found) bases.push_back(tinfo);
+            }
+        }
+        else if (type->tp_bases) {
+            // It's some python type, so keep follow its bases classes to look for one or more
+            // registered types
+            if (i + 1 == check.size()) {
+                // When we're at the end, we can pop off the current element to avoid growing
+                // `check` when adding just one base (which is typical--i.e. when there is no
+                // multiple inheritance)
+                check.pop_back();
+                i--;
+            }
+            for (handle parent : reinterpret_borrow<tuple>(type->tp_bases))
+                check.push_back((PyTypeObject *) parent.ptr());
+        }
+    }
+}
+
+/**
+ * Extracts vector of type_info pointers of pybind-registered roots of the given Python type.  Will
+ * be just 1 pybind type for the Python type of a pybind-registered class, or for any Python-side
+ * derived class that uses single inheritance.  Will contain as many types as required for a Python
+ * class that uses multiple inheritance to inherit (directly or indirectly) from multiple
+ * pybind-registered classes.  Will be empty if neither the type nor any base classes are
+ * pybind-registered.
+ *
+ * The value is cached for the lifetime of the Python type.
+ */
+inline const std::vector<detail::type_info *> &all_type_info(PyTypeObject *type) {
+    auto ins = all_type_info_get_cache(type);
+    if (ins.second)
+        // New cache entry: populate it
+        all_type_info_populate(type, ins.first->second);
+
+    return ins.first->second;
+}
+
+/**
+ * Gets a single pybind11 type info for a python type.  Returns nullptr if neither the type nor any
+ * ancestors are pybind11-registered.  Throws an exception if there are multiple bases--use
+ * `all_type_info` instead if you want to support multiple bases.
+ */
+PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) {
+    auto &bases = all_type_info(type);
+    if (bases.size() == 0)
+        return nullptr;
+    if (bases.size() > 1)
+        pybind11_fail("pybind11::detail::get_type_info: type has multiple pybind11-registered bases");
+    return bases.front();
+}
+
+inline detail::type_info *get_local_type_info(const std::type_index &tp) {
+    auto &locals = registered_local_types_cpp();
+    auto it = locals.find(tp);
+    if (it != locals.end())
+        return it->second;
+    return nullptr;
+}
+
+inline detail::type_info *get_global_type_info(const std::type_index &tp) {
+    auto &types = get_internals().registered_types_cpp;
+    auto it = types.find(tp);
+    if (it != types.end())
+        return it->second;
+    return nullptr;
+}
+
+/// Return the type info for a given C++ type; on lookup failure can either throw or return nullptr.
+PYBIND11_NOINLINE inline detail::type_info *get_type_info(const std::type_index &tp,
+                                                          bool throw_if_missing = false) {
+    if (auto ltype = get_local_type_info(tp))
+        return ltype;
+    if (auto gtype = get_global_type_info(tp))
+        return gtype;
+
+    if (throw_if_missing) {
+        std::string tname = tp.name();
+        detail::clean_type_id(tname);
+        pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + tname + "\"");
+    }
+    return nullptr;
+}
+
+PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp, bool throw_if_missing) {
+    detail::type_info *type_info = get_type_info(tp, throw_if_missing);
+    return handle(type_info ? ((PyObject *) type_info->type) : nullptr);
+}
+
+struct value_and_holder {
+    instance *inst;
+    size_t index;
+    const detail::type_info *type;
+    void **vh;
+
+    // Main constructor for a found value/holder:
+    value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index) :
+        inst{i}, index{index}, type{type},
+        vh{inst->simple_layout ? inst->simple_value_holder : &inst->nonsimple.values_and_holders[vpos]}
+    {}
+
+    // Default constructor (used to signal a value-and-holder not found by get_value_and_holder())
+    value_and_holder() : inst{nullptr} {}
+
+    // Used for past-the-end iterator
+    value_and_holder(size_t index) : index{index} {}
+
+    template <typename V = void> V *&value_ptr() const {
+        return reinterpret_cast<V *&>(vh[0]);
+    }
+    // True if this `value_and_holder` has a non-null value pointer
+    explicit operator bool() const { return value_ptr(); }
+
+    template <typename H> H &holder() const {
+        return reinterpret_cast<H &>(vh[1]);
+    }
+    bool holder_constructed() const {
+        return inst->simple_layout
+            ? inst->simple_holder_constructed
+            : inst->nonsimple.status[index] & instance::status_holder_constructed;
+    }
+    void set_holder_constructed(bool v = true) {
+        if (inst->simple_layout)
+            inst->simple_holder_constructed = v;
+        else if (v)
+            inst->nonsimple.status[index] |= instance::status_holder_constructed;
+        else
+            inst->nonsimple.status[index] &= (uint8_t) ~instance::status_holder_constructed;
+    }
+    bool instance_registered() const {
+        return inst->simple_layout
+            ? inst->simple_instance_registered
+            : inst->nonsimple.status[index] & instance::status_instance_registered;
+    }
+    void set_instance_registered(bool v = true) {
+        if (inst->simple_layout)
+            inst->simple_instance_registered = v;
+        else if (v)
+            inst->nonsimple.status[index] |= instance::status_instance_registered;
+        else
+            inst->nonsimple.status[index] &= (uint8_t) ~instance::status_instance_registered;
+    }
+};
+
+// Container for accessing and iterating over an instance's values/holders
+struct values_and_holders {
+private:
+    instance *inst;
+    using type_vec = std::vector<detail::type_info *>;
+    const type_vec &tinfo;
+
+public:
+    values_and_holders(instance *inst) : inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {}
+
+    struct iterator {
+    private:
+        instance *inst;
+        const type_vec *types;
+        value_and_holder curr;
+        friend struct values_and_holders;
+        iterator(instance *inst, const type_vec *tinfo)
+            : inst{inst}, types{tinfo},
+            curr(inst /* instance */,
+                 types->empty() ? nullptr : (*types)[0] /* type info */,
+                 0, /* vpos: (non-simple types only): the first vptr comes first */
+                 0 /* index */)
+        {}
+        // Past-the-end iterator:
+        iterator(size_t end) : curr(end) {}
+    public:
+        bool operator==(const iterator &other) { return curr.index == other.curr.index; }
+        bool operator!=(const iterator &other) { return curr.index != other.curr.index; }
+        iterator &operator++() {
+            if (!inst->simple_layout)
+                curr.vh += 1 + (*types)[curr.index]->holder_size_in_ptrs;
+            ++curr.index;
+            curr.type = curr.index < types->size() ? (*types)[curr.index] : nullptr;
+            return *this;
+        }
+        value_and_holder &operator*() { return curr; }
+        value_and_holder *operator->() { return &curr; }
+    };
+
+    iterator begin() { return iterator(inst, &tinfo); }
+    iterator end() { return iterator(tinfo.size()); }
+
+    iterator find(const type_info *find_type) {
+        auto it = begin(), endit = end();
+        while (it != endit && it->type != find_type) ++it;
+        return it;
+    }
+
+    size_t size() { return tinfo.size(); }
+};
+
+/**
+ * Extracts C++ value and holder pointer references from an instance (which may contain multiple
+ * values/holders for python-side multiple inheritance) that match the given type.  Throws an error
+ * if the given type (or ValueType, if omitted) is not a pybind11 base of the given instance.  If
+ * `find_type` is omitted (or explicitly specified as nullptr) the first value/holder are returned,
+ * regardless of type (and the resulting .type will be nullptr).
+ *
+ * The returned object should be short-lived: in particular, it must not outlive the called-upon
+ * instance.
+ */
+PYBIND11_NOINLINE inline value_and_holder instance::get_value_and_holder(const type_info *find_type /*= nullptr default in common.h*/, bool throw_if_missing /*= true in common.h*/) {
+    // Optimize common case:
+    if (!find_type || Py_TYPE(this) == find_type->type)
+        return value_and_holder(this, find_type, 0, 0);
+
+    detail::values_and_holders vhs(this);
+    auto it = vhs.find(find_type);
+    if (it != vhs.end())
+        return *it;
+
+    if (!throw_if_missing)
+        return value_and_holder();
+
+#if defined(NDEBUG)
+    pybind11_fail("pybind11::detail::instance::get_value_and_holder: "
+            "type is not a pybind11 base of the given instance "
+            "(compile in debug mode for type details)");
+#else
+    pybind11_fail("pybind11::detail::instance::get_value_and_holder: `" +
+            std::string(find_type->type->tp_name) + "' is not a pybind11 base of the given `" +
+            std::string(Py_TYPE(this)->tp_name) + "' instance");
+#endif
+}
+
+PYBIND11_NOINLINE inline void instance::allocate_layout() {
+    auto &tinfo = all_type_info(Py_TYPE(this));
+
+    const size_t n_types = tinfo.size();
+
+    if (n_types == 0)
+        pybind11_fail("instance allocation failed: new instance has no pybind11-registered base types");
+
+    simple_layout =
+        n_types == 1 && tinfo.front()->holder_size_in_ptrs <= instance_simple_holder_in_ptrs();
+
+    // Simple path: no python-side multiple inheritance, and a small-enough holder
+    if (simple_layout) {
+        simple_value_holder[0] = nullptr;
+        simple_holder_constructed = false;
+        simple_instance_registered = false;
+    }
+    else { // multiple base types or a too-large holder
+        // Allocate space to hold: [v1*][h1][v2*][h2]...[bb...] where [vN*] is a value pointer,
+        // [hN] is the (uninitialized) holder instance for value N, and [bb...] is a set of bool
+        // values that tracks whether each associated holder has been initialized.  Each [block] is
+        // padded, if necessary, to an integer multiple of sizeof(void *).
+        size_t space = 0;
+        for (auto t : tinfo) {
+            space += 1; // value pointer
+            space += t->holder_size_in_ptrs; // holder instance
+        }
+        size_t flags_at = space;
+        space += size_in_ptrs(n_types); // status bytes (holder_constructed and instance_registered)
+
+        // Allocate space for flags, values, and holders, and initialize it to 0 (flags and values,
+        // in particular, need to be 0).  Use Python's memory allocation functions: in Python 3.6
+        // they default to using pymalloc, which is designed to be efficient for small allocations
+        // like the one we're doing here; in earlier versions (and for larger allocations) they are
+        // just wrappers around malloc.
+#if PY_VERSION_HEX >= 0x03050000
+        nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *));
+        if (!nonsimple.values_and_holders) throw std::bad_alloc();
+#else
+        nonsimple.values_and_holders = (void **) PyMem_New(void *, space);
+        if (!nonsimple.values_and_holders) throw std::bad_alloc();
+        std::memset(nonsimple.values_and_holders, 0, space * sizeof(void *));
+#endif
+        nonsimple.status = reinterpret_cast<uint8_t *>(&nonsimple.values_and_holders[flags_at]);
+    }
+    owned = true;
+}
+
+PYBIND11_NOINLINE inline void instance::deallocate_layout() {
+    if (!simple_layout)
+        PyMem_Free(nonsimple.values_and_holders);
+}
+
+PYBIND11_NOINLINE inline bool isinstance_generic(handle obj, const std::type_info &tp) {
+    handle type = detail::get_type_handle(tp, false);
+    if (!type)
+        return false;
+    return isinstance(obj, type);
+}
+
+PYBIND11_NOINLINE inline std::string error_string() {
+    if (!PyErr_Occurred()) {
+        PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred");
+        return "Unknown internal error occurred";
+    }
+
+    error_scope scope; // Preserve error state
+
+    std::string errorString;
+    if (scope.type) {
+        errorString += handle(scope.type).attr("__name__").cast<std::string>();
+        errorString += ": ";
+    }
+    if (scope.value)
+        errorString += (std::string) str(scope.value);
+
+    PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace);
+
+#if PY_MAJOR_VERSION >= 3
+    if (scope.trace != nullptr)
+        PyException_SetTraceback(scope.value, scope.trace);
+#endif
+
+#if !defined(PYPY_VERSION)
+    if (scope.trace) {
+        PyTracebackObject *trace = (PyTracebackObject *) scope.trace;
+
+        /* Get the deepest trace possible */
+        while (trace->tb_next)
+            trace = trace->tb_next;
+
+        PyFrameObject *frame = trace->tb_frame;
+        errorString += "\n\nAt:\n";
+        while (frame) {
+            int lineno = PyFrame_GetLineNumber(frame);
+            errorString +=
+                "  " + handle(frame->f_code->co_filename).cast<std::string>() +
+                "(" + std::to_string(lineno) + "): " +
+                handle(frame->f_code->co_name).cast<std::string>() + "\n";
+            frame = frame->f_back;
+        }
+    }
+#endif
+
+    return errorString;
+}
+
+PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr, const detail::type_info *type ) {
+    auto &instances = get_internals().registered_instances;
+    auto range = instances.equal_range(ptr);
+    for (auto it = range.first; it != range.second; ++it) {
+        for (auto vh : values_and_holders(it->second)) {
+            if (vh.type == type)
+                return handle((PyObject *) it->second);
+        }
+    }
+    return handle();
+}
+
+inline PyThreadState *get_thread_state_unchecked() {
+#if defined(PYPY_VERSION)
+    return PyThreadState_GET();
+#elif PY_VERSION_HEX < 0x03000000
+    return _PyThreadState_Current;
+#elif PY_VERSION_HEX < 0x03050000
+    return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current);
+#elif PY_VERSION_HEX < 0x03050200
+    return (PyThreadState*) _PyThreadState_Current.value;
+#else
+    return _PyThreadState_UncheckedGet();
+#endif
+}
+
+// Forward declarations
+inline void keep_alive_impl(handle nurse, handle patient);
+inline PyObject *make_new_instance(PyTypeObject *type);
+
+class type_caster_generic {
+public:
+    PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info)
+        : typeinfo(get_type_info(type_info)), cpptype(&type_info) { }
+
+    type_caster_generic(const type_info *typeinfo)
+        : typeinfo(typeinfo), cpptype(typeinfo ? typeinfo->cpptype : nullptr) { }
+
+    bool load(handle src, bool convert) {
+        return load_impl<type_caster_generic>(src, convert);
+    }
+
+    PYBIND11_NOINLINE static handle cast(const void *_src, return_value_policy policy, handle parent,
+                                         const detail::type_info *tinfo,
+                                         void *(*copy_constructor)(const void *),
+                                         void *(*move_constructor)(const void *),
+                                         const void *existing_holder = nullptr) {
+        if (!tinfo) // no type info: error will be set already
+            return handle();
+
+        void *src = const_cast<void *>(_src);
+        if (src == nullptr)
+            return none().release();
+
+        auto it_instances = get_internals().registered_instances.equal_range(src);
+        for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) {
+            for (auto instance_type : detail::all_type_info(Py_TYPE(it_i->second))) {
+                if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype))
+                    return handle((PyObject *) it_i->second).inc_ref();
+            }
+        }
+
+        auto inst = reinterpret_steal<object>(make_new_instance(tinfo->type));
+        auto wrapper = reinterpret_cast<instance *>(inst.ptr());
+        wrapper->owned = false;
+        void *&valueptr = values_and_holders(wrapper).begin()->value_ptr();
+
+        switch (policy) {
+            case return_value_policy::automatic:
+            case return_value_policy::take_ownership:
+                valueptr = src;
+                wrapper->owned = true;
+                break;
+
+            case return_value_policy::automatic_reference:
+            case return_value_policy::reference:
+                valueptr = src;
+                wrapper->owned = false;
+                break;
+
+            case return_value_policy::copy:
+                if (copy_constructor)
+                    valueptr = copy_constructor(src);
+                else
+                    throw cast_error("return_value_policy = copy, but the "
+                                     "object is non-copyable!");
+                wrapper->owned = true;
+                break;
+
+            case return_value_policy::move:
+                if (move_constructor)
+                    valueptr = move_constructor(src);
+                else if (copy_constructor)
+                    valueptr = copy_constructor(src);
+                else
+                    throw cast_error("return_value_policy = move, but the "
+                                     "object is neither movable nor copyable!");
+                wrapper->owned = true;
+                break;
+
+            case return_value_policy::reference_internal:
+                valueptr = src;
+                wrapper->owned = false;
+                keep_alive_impl(inst, parent);
+                break;
+
+            default:
+                throw cast_error("unhandled return_value_policy: should not happen!");
+        }
+
+        tinfo->init_instance(wrapper, existing_holder);
+
+        return inst.release();
+    }
+
+    // Base methods for generic caster; there are overridden in copyable_holder_caster
+    void load_value(value_and_holder &&v_h) {
+        auto *&vptr = v_h.value_ptr();
+        // Lazy allocation for unallocated values:
+        if (vptr == nullptr) {
+            auto *type = v_h.type ? v_h.type : typeinfo;
+            vptr = type->operator_new(type->type_size);
+        }
+        value = vptr;
+    }
+    bool try_implicit_casts(handle src, bool convert) {
+        for (auto &cast : typeinfo->implicit_casts) {
+            type_caster_generic sub_caster(*cast.first);
+            if (sub_caster.load(src, convert)) {
+                value = cast.second(sub_caster.value);
+                return true;
+            }
+        }
+        return false;
+    }
+    bool try_direct_conversions(handle src) {
+        for (auto &converter : *typeinfo->direct_conversions) {
+            if (converter(src.ptr(), value))
+                return true;
+        }
+        return false;
+    }
+    void check_holder_compat() {}
+
+    PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) {
+        auto caster = type_caster_generic(ti);
+        if (caster.load(src, false))
+            return caster.value;
+        return nullptr;
+    }
+
+    /// Try to load with foreign typeinfo, if available. Used when there is no
+    /// native typeinfo, or when the native one wasn't able to produce a value.
+    PYBIND11_NOINLINE bool try_load_foreign_module_local(handle src) {
+        constexpr auto *local_key = PYBIND11_MODULE_LOCAL_ID;
+        const auto pytype = src.get_type();
+        if (!hasattr(pytype, local_key))
+            return false;
+
+        type_info *foreign_typeinfo = reinterpret_borrow<capsule>(getattr(pytype, local_key));
+        // Only consider this foreign loader if actually foreign and is a loader of the correct cpp type
+        if (foreign_typeinfo->module_local_load == &local_load
+            || (cpptype && !same_type(*cpptype, *foreign_typeinfo->cpptype)))
+            return false;
+
+        if (auto result = foreign_typeinfo->module_local_load(src.ptr(), foreign_typeinfo)) {
+            value = result;
+            return true;
+        }
+        return false;
+    }
+
+    // Implementation of `load`; this takes the type of `this` so that it can dispatch the relevant
+    // bits of code between here and copyable_holder_caster where the two classes need different
+    // logic (without having to resort to virtual inheritance).
+    template <typename ThisT>
+    PYBIND11_NOINLINE bool load_impl(handle src, bool convert) {
+        if (!src) return false;
+        if (!typeinfo) return try_load_foreign_module_local(src);
+        if (src.is_none()) {
+            // Defer accepting None to other overloads (if we aren't in convert mode):
+            if (!convert) return false;
+            value = nullptr;
+            return true;
+        }
+
+        auto &this_ = static_cast<ThisT &>(*this);
+        this_.check_holder_compat();
+
+        PyTypeObject *srctype = Py_TYPE(src.ptr());
+
+        // Case 1: If src is an exact type match for the target type then we can reinterpret_cast
+        // the instance's value pointer to the target type:
+        if (srctype == typeinfo->type) {
+            this_.load_value(reinterpret_cast<instance *>(src.ptr())->get_value_and_holder());
+            return true;
+        }
+        // Case 2: We have a derived class
+        else if (PyType_IsSubtype(srctype, typeinfo->type)) {
+            auto &bases = all_type_info(srctype);
+            bool no_cpp_mi = typeinfo->simple_type;
+
+            // Case 2a: the python type is a Python-inherited derived class that inherits from just
+            // one simple (no MI) pybind11 class, or is an exact match, so the C++ instance is of
+            // the right type and we can use reinterpret_cast.
+            // (This is essentially the same as case 2b, but because not using multiple inheritance
+            // is extremely common, we handle it specially to avoid the loop iterator and type
+            // pointer lookup overhead)
+            if (bases.size() == 1 && (no_cpp_mi || bases.front()->type == typeinfo->type)) {
+                this_.load_value(reinterpret_cast<instance *>(src.ptr())->get_value_and_holder());
+                return true;
+            }
+            // Case 2b: the python type inherits from multiple C++ bases.  Check the bases to see if
+            // we can find an exact match (or, for a simple C++ type, an inherited match); if so, we
+            // can safely reinterpret_cast to the relevant pointer.
+            else if (bases.size() > 1) {
+                for (auto base : bases) {
+                    if (no_cpp_mi ? PyType_IsSubtype(base->type, typeinfo->type) : base->type == typeinfo->type) {
+                        this_.load_value(reinterpret_cast<instance *>(src.ptr())->get_value_and_holder(base));
+                        return true;
+                    }
+                }
+            }
+
+            // Case 2c: C++ multiple inheritance is involved and we couldn't find an exact type match
+            // in the registered bases, above, so try implicit casting (needed for proper C++ casting
+            // when MI is involved).
+            if (this_.try_implicit_casts(src, convert))
+                return true;
+        }
+
+        // Perform an implicit conversion
+        if (convert) {
+            for (auto &converter : typeinfo->implicit_conversions) {
+                auto temp = reinterpret_steal<object>(converter(src.ptr(), typeinfo->type));
+                if (load_impl<ThisT>(temp, false)) {
+                    loader_life_support::add_patient(temp);
+                    return true;
+                }
+            }
+            if (this_.try_direct_conversions(src))
+                return true;
+        }
+
+        // Failed to match local typeinfo. Try again with global.
+        if (typeinfo->module_local) {
+            if (auto gtype = get_global_type_info(*typeinfo->cpptype)) {
+                typeinfo = gtype;
+                return load(src, false);
+            }
+        }
+
+        // Global typeinfo has precedence over foreign module_local
+        return try_load_foreign_module_local(src);
+    }
+
+
+    // Called to do type lookup and wrap the pointer and type in a pair when a dynamic_cast
+    // isn't needed or can't be used.  If the type is unknown, sets the error and returns a pair
+    // with .second = nullptr.  (p.first = nullptr is not an error: it becomes None).
+    PYBIND11_NOINLINE static std::pair<const void *, const type_info *> src_and_type(
+            const void *src, const std::type_info &cast_type, const std::type_info *rtti_type = nullptr) {
+        if (auto *tpi = get_type_info(cast_type))
+            return {src, const_cast<const type_info *>(tpi)};
+
+        // Not found, set error:
+        std::string tname = rtti_type ? rtti_type->name() : cast_type.name();
+        detail::clean_type_id(tname);
+        std::string msg = "Unregistered type : " + tname;
+        PyErr_SetString(PyExc_TypeError, msg.c_str());
+        return {nullptr, nullptr};
+    }
+
+    const type_info *typeinfo = nullptr;
+    const std::type_info *cpptype = nullptr;
+    void *value = nullptr;
+};
+
+/**
+ * Determine suitable casting operator for pointer-or-lvalue-casting type casters.  The type caster
+ * needs to provide `operator T*()` and `operator T&()` operators.
+ *
+ * If the type supports moving the value away via an `operator T&&() &&` method, it should use
+ * `movable_cast_op_type` instead.
+ */
+template <typename T>
+using cast_op_type =
+    conditional_t<std::is_pointer<remove_reference_t<T>>::value,
+        typename std::add_pointer<intrinsic_t<T>>::type,
+        typename std::add_lvalue_reference<intrinsic_t<T>>::type>;
+
+/**
+ * Determine suitable casting operator for a type caster with a movable value.  Such a type caster
+ * needs to provide `operator T*()`, `operator T&()`, and `operator T&&() &&`.  The latter will be
+ * called in appropriate contexts where the value can be moved rather than copied.
+ *
+ * These operator are automatically provided when using the PYBIND11_TYPE_CASTER macro.
+ */
+template <typename T>
+using movable_cast_op_type =
+    conditional_t<std::is_pointer<typename std::remove_reference<T>::type>::value,
+        typename std::add_pointer<intrinsic_t<T>>::type,
+    conditional_t<std::is_rvalue_reference<T>::value,
+        typename std::add_rvalue_reference<intrinsic_t<T>>::type,
+        typename std::add_lvalue_reference<intrinsic_t<T>>::type>>;
+
+// std::is_copy_constructible isn't quite enough: it lets std::vector<T> (and similar) through when
+// T is non-copyable, but code containing such a copy constructor fails to actually compile.
+template <typename T, typename SFINAE = void> struct is_copy_constructible : std::is_copy_constructible<T> {};
+
+// Specialization for types that appear to be copy constructible but also look like stl containers
+// (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if
+// so, copy constructability depends on whether the value_type is copy constructible.
+template <typename Container> struct is_copy_constructible<Container, enable_if_t<all_of<
+        std::is_copy_constructible<Container>,
+        std::is_same<typename Container::value_type &, typename Container::reference>
+    >::value>> : is_copy_constructible<typename Container::value_type> {};
+
+#if !defined(PYBIND11_CPP17)
+// Likewise for std::pair before C++17 (which mandates that the copy constructor not exist when the
+// two types aren't themselves copy constructible).
+template <typename T1, typename T2> struct is_copy_constructible<std::pair<T1, T2>>
+    : all_of<is_copy_constructible<T1>, is_copy_constructible<T2>> {};
+#endif
+
+/// Generic type caster for objects stored on the heap
+template <typename type> class type_caster_base : public type_caster_generic {
+    using itype = intrinsic_t<type>;
+public:
+    static PYBIND11_DESCR name() { return type_descr(_<type>()); }
+
+    type_caster_base() : type_caster_base(typeid(type)) { }
+    explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { }
+
+    static handle cast(const itype &src, return_value_policy policy, handle parent) {
+        if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference)
+            policy = return_value_policy::copy;
+        return cast(&src, policy, parent);
+    }
+
+    static handle cast(itype &&src, return_value_policy, handle parent) {
+        return cast(&src, return_value_policy::move, parent);
+    }
+
+    // Returns a (pointer, type_info) pair taking care of necessary RTTI type lookup for a
+    // polymorphic type.  If the instance isn't derived, returns the non-RTTI base version.
+    template <typename T = itype, enable_if_t<std::is_polymorphic<T>::value, int> = 0>
+    static std::pair<const void *, const type_info *> src_and_type(const itype *src) {
+        const void *vsrc = src;
+        auto &cast_type = typeid(itype);
+        const std::type_info *instance_type = nullptr;
+        if (vsrc) {
+            instance_type = &typeid(*src);
+            if (!same_type(cast_type, *instance_type)) {
+                // This is a base pointer to a derived type; if it is a pybind11-registered type, we
+                // can get the correct derived pointer (which may be != base pointer) by a
+                // dynamic_cast to most derived type:
+                if (auto *tpi = get_type_info(*instance_type))
+                    return {dynamic_cast<const void *>(src), const_cast<const type_info *>(tpi)};
+            }
+        }
+        // Otherwise we have either a nullptr, an `itype` pointer, or an unknown derived pointer, so
+        // don't do a cast
+        return type_caster_generic::src_and_type(vsrc, cast_type, instance_type);
+    }
+
+    // Non-polymorphic type, so no dynamic casting; just call the generic version directly
+    template <typename T = itype, enable_if_t<!std::is_polymorphic<T>::value, int> = 0>
+    static std::pair<const void *, const type_info *> src_and_type(const itype *src) {
+        return type_caster_generic::src_and_type(src, typeid(itype));
+    }
+
+    static handle cast(const itype *src, return_value_policy policy, handle parent) {
+        auto st = src_and_type(src);
+        return type_caster_generic::cast(
+            st.first, policy, parent, st.second,
+            make_copy_constructor(src), make_move_constructor(src));
+    }
+
+    static handle cast_holder(const itype *src, const void *holder) {
+        auto st = src_and_type(src);
+        return type_caster_generic::cast(
+            st.first, return_value_policy::take_ownership, {}, st.second,
+            nullptr, nullptr, holder);
+    }
+
+    template <typename T> using cast_op_type = cast_op_type<T>;
+
+    operator itype*() { return (type *) value; }
+    operator itype&() { if (!value) throw reference_cast_error(); return *((itype *) value); }
+
+protected:
+    using Constructor = void *(*)(const void *);
+
+    /* Only enabled when the types are {copy,move}-constructible *and* when the type
+       does not have a private operator new implementation. */
+    template <typename T, typename = enable_if_t<is_copy_constructible<T>::value>>
+    static auto make_copy_constructor(const T *x) -> decltype(new T(*x), Constructor{}) {
+        return [](const void *arg) -> void * {
+            return new T(*reinterpret_cast<const T *>(arg));
+        };
+    }
+
+    template <typename T, typename = enable_if_t<std::is_move_constructible<T>::value>>
+    static auto make_move_constructor(const T *x) -> decltype(new T(std::move(*const_cast<T *>(x))), Constructor{}) {
+        return [](const void *arg) -> void * {
+            return new T(std::move(*const_cast<T *>(reinterpret_cast<const T *>(arg))));
+        };
+    }
+
+    static Constructor make_copy_constructor(...) { return nullptr; }
+    static Constructor make_move_constructor(...) { return nullptr; }
+};
+
+template <typename type, typename SFINAE = void> class type_caster : public type_caster_base<type> { };
+template <typename type> using make_caster = type_caster<intrinsic_t<type>>;
+
+// Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T
+template <typename T> typename make_caster<T>::template cast_op_type<T> cast_op(make_caster<T> &caster) {
+    return caster.operator typename make_caster<T>::template cast_op_type<T>();
+}
+template <typename T> typename make_caster<T>::template cast_op_type<typename std::add_rvalue_reference<T>::type>
+cast_op(make_caster<T> &&caster) {
+    return std::move(caster).operator
+        typename make_caster<T>::template cast_op_type<typename std::add_rvalue_reference<T>::type>();
+}
+
+template <typename type> class type_caster<std::reference_wrapper<type>> {
+private:
+    using caster_t = make_caster<type>;
+    caster_t subcaster;
+    using subcaster_cast_op_type = typename caster_t::template cast_op_type<type>;
+    static_assert(std::is_same<typename std::remove_const<type>::type &, subcaster_cast_op_type>::value,
+            "std::reference_wrapper<T> caster requires T to have a caster with an `T &` operator");
+public:
+    bool load(handle src, bool convert) { return subcaster.load(src, convert); }
+    static PYBIND11_DESCR name() { return caster_t::name(); }
+    static handle cast(const std::reference_wrapper<type> &src, return_value_policy policy, handle parent) {
+        // It is definitely wrong to take ownership of this pointer, so mask that rvp
+        if (policy == return_value_policy::take_ownership || policy == return_value_policy::automatic)
+            policy = return_value_policy::automatic_reference;
+        return caster_t::cast(&src.get(), policy, parent);
+    }
+    template <typename T> using cast_op_type = std::reference_wrapper<type>;
+    operator std::reference_wrapper<type>() { return subcaster.operator subcaster_cast_op_type&(); }
+};
+
+#define PYBIND11_TYPE_CASTER(type, py_name) \
+    protected: \
+        type value; \
+    public: \
+        static PYBIND11_DESCR name() { return type_descr(py_name); } \
+        template <typename T_, enable_if_t<std::is_same<type, remove_cv_t<T_>>::value, int> = 0> \
+        static handle cast(T_ *src, return_value_policy policy, handle parent) { \
+            if (!src) return none().release(); \
+            if (policy == return_value_policy::take_ownership) { \
+                auto h = cast(std::move(*src), policy, parent); delete src; return h; \
+            } else { \
+                return cast(*src, policy, parent); \
+            } \
+        } \
+        operator type*() { return &value; } \
+        operator type&() { return value; } \
+        operator type&&() && { return std::move(value); } \
+        template <typename T_> using cast_op_type = pybind11::detail::movable_cast_op_type<T_>
+
+
+template <typename CharT> using is_std_char_type = any_of<
+    std::is_same<CharT, char>, /* std::string */
+    std::is_same<CharT, char16_t>, /* std::u16string */
+    std::is_same<CharT, char32_t>, /* std::u32string */
+    std::is_same<CharT, wchar_t> /* std::wstring */
+>;
+
+template <typename T>
+struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_type<T>::value>> {
+    using _py_type_0 = conditional_t<sizeof(T) <= sizeof(long), long, long long>;
+    using _py_type_1 = conditional_t<std::is_signed<T>::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>;
+    using py_type = conditional_t<std::is_floating_point<T>::value, double, _py_type_1>;
+public:
+
+    bool load(handle src, bool convert) {
+        py_type py_value;
+
+        if (!src)
+            return false;
+
+        if (std::is_floating_point<T>::value) {
+            if (convert || PyFloat_Check(src.ptr()))
+                py_value = (py_type) PyFloat_AsDouble(src.ptr());
+            else
+                return false;
+        } else if (PyFloat_Check(src.ptr())) {
+            return false;
+        } else if (std::is_unsigned<py_type>::value) {
+            py_value = as_unsigned<py_type>(src.ptr());
+        } else { // signed integer:
+            py_value = sizeof(T) <= sizeof(long)
+                ? (py_type) PyLong_AsLong(src.ptr())
+                : (py_type) PYBIND11_LONG_AS_LONGLONG(src.ptr());
+        }
+
+        bool py_err = py_value == (py_type) -1 && PyErr_Occurred();
+        if (py_err || (std::is_integral<T>::value && sizeof(py_type) != sizeof(T) &&
+                       (py_value < (py_type) std::numeric_limits<T>::min() ||
+                        py_value > (py_type) std::numeric_limits<T>::max()))) {
+            bool type_error = py_err && PyErr_ExceptionMatches(
+#if PY_VERSION_HEX < 0x03000000 && !defined(PYPY_VERSION)
+                PyExc_SystemError
+#else
+                PyExc_TypeError
+#endif
+            );
+            PyErr_Clear();
+            if (type_error && convert && PyNumber_Check(src.ptr())) {
+                auto tmp = reinterpret_steal<object>(std::is_floating_point<T>::value
+                                                     ? PyNumber_Float(src.ptr())
+                                                     : PyNumber_Long(src.ptr()));
+                PyErr_Clear();
+                return load(tmp, false);
+            }
+            return false;
+        }
+
+        value = (T) py_value;
+        return true;
+    }
+
+    static handle cast(T src, return_value_policy /* policy */, handle /* parent */) {
+        if (std::is_floating_point<T>::value) {
+            return PyFloat_FromDouble((double) src);
+        } else if (sizeof(T) <= sizeof(long)) {
+            if (std::is_signed<T>::value)
+                return PyLong_FromLong((long) src);
+            else
+                return PyLong_FromUnsignedLong((unsigned long) src);
+        } else {
+            if (std::is_signed<T>::value)
+                return PyLong_FromLongLong((long long) src);
+            else
+                return PyLong_FromUnsignedLongLong((unsigned long long) src);
+        }
+    }
+
+    PYBIND11_TYPE_CASTER(T, _<std::is_integral<T>::value>("int", "float"));
+};
+
+template<typename T> struct void_caster {
+public:
+    bool load(handle src, bool) {
+        if (src && src.is_none())
+            return true;
+        return false;
+    }
+    static handle cast(T, return_value_policy /* policy */, handle /* parent */) {
+        return none().inc_ref();
+    }
+    PYBIND11_TYPE_CASTER(T, _("None"));
+};
+
+template <> class type_caster<void_type> : public void_caster<void_type> {};
+
+template <> class type_caster<void> : public type_caster<void_type> {
+public:
+    using type_caster<void_type>::cast;
+
+    bool load(handle h, bool) {
+        if (!h) {
+            return false;
+        } else if (h.is_none()) {
+            value = nullptr;
+            return true;
+        }
+
+        /* Check if this is a capsule */
+        if (isinstance<capsule>(h)) {
+            value = reinterpret_borrow<capsule>(h);
+            return true;
+        }
+
+        /* Check if this is a C++ type */
+        auto &bases = all_type_info((PyTypeObject *) h.get_type().ptr());
+        if (bases.size() == 1) { // Only allowing loading from a single-value type
+            value = values_and_holders(reinterpret_cast<instance *>(h.ptr())).begin()->value_ptr();
+            return true;
+        }
+
+        /* Fail */
+        return false;
+    }
+
+    static handle cast(const void *ptr, return_value_policy /* policy */, handle /* parent */) {
+        if (ptr)
+            return capsule(ptr).release();
+        else
+            return none().inc_ref();
+    }
+
+    template <typename T> using cast_op_type = void*&;
+    operator void *&() { return value; }
+    static PYBIND11_DESCR name() { return type_descr(_("capsule")); }
+private:
+    void *value = nullptr;
+};
+
+template <> class type_caster<std::nullptr_t> : public void_caster<std::nullptr_t> { };
+
+template <> class type_caster<bool> {
+public:
+    bool load(handle src, bool convert) {
+        if (!src) return false;
+        else if (src.ptr() == Py_True) { value = true; return true; }
+        else if (src.ptr() == Py_False) { value = false; return true; }
+        else if (convert || !strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name)) {
+            // (allow non-implicit conversion for numpy booleans)
+
+            Py_ssize_t res = -1;
+            if (src.is_none()) {
+                res = 0;  // None is implicitly converted to False
+            }
+            #if defined(PYPY_VERSION)
+            // On PyPy, check that "__bool__" (or "__nonzero__" on Python 2.7) attr exists
+            else if (hasattr(src, PYBIND11_BOOL_ATTR)) {
+                res = PyObject_IsTrue(src.ptr());
+            }
+            #else
+            // Alternate approach for CPython: this does the same as the above, but optimized
+            // using the CPython API so as to avoid an unneeded attribute lookup.
+            else if (auto tp_as_number = src.ptr()->ob_type->tp_as_number) {
+                if (PYBIND11_NB_BOOL(tp_as_number)) {
+                    res = (*PYBIND11_NB_BOOL(tp_as_number))(src.ptr());
+                }
+            }
+            #endif
+            if (res == 0 || res == 1) {
+                value = (bool) res;
+                return true;
+            }
+        }
+        return false;
+    }
+    static handle cast(bool src, return_value_policy /* policy */, handle /* parent */) {
+        return handle(src ? Py_True : Py_False).inc_ref();
+    }
+    PYBIND11_TYPE_CASTER(bool, _("bool"));
+};
+
+// Helper class for UTF-{8,16,32} C++ stl strings:
+template <typename StringType, bool IsView = false> struct string_caster {
+    using CharT = typename StringType::value_type;
+
+    // Simplify life by being able to assume standard char sizes (the standard only guarantees
+    // minimums, but Python requires exact sizes)
+    static_assert(!std::is_same<CharT, char>::value || sizeof(CharT) == 1, "Unsupported char size != 1");
+    static_assert(!std::is_same<CharT, char16_t>::value || sizeof(CharT) == 2, "Unsupported char16_t size != 2");
+    static_assert(!std::is_same<CharT, char32_t>::value || sizeof(CharT) == 4, "Unsupported char32_t size != 4");
+    // wchar_t can be either 16 bits (Windows) or 32 (everywhere else)
+    static_assert(!std::is_same<CharT, wchar_t>::value || sizeof(CharT) == 2 || sizeof(CharT) == 4,
+            "Unsupported wchar_t size != 2/4");
+    static constexpr size_t UTF_N = 8 * sizeof(CharT);
+
+    bool load(handle src, bool) {
+#if PY_MAJOR_VERSION < 3
+        object temp;
+#endif
+        handle load_src = src;
+        if (!src) {
+            return false;
+        } else if (!PyUnicode_Check(load_src.ptr())) {
+#if PY_MAJOR_VERSION >= 3
+            return load_bytes(load_src);
+#else
+            if (sizeof(CharT) == 1) {
+                return load_bytes(load_src);
+            }
+
+            // The below is a guaranteed failure in Python 3 when PyUnicode_Check returns false
+            if (!PYBIND11_BYTES_CHECK(load_src.ptr()))
+                return false;
+
+            temp = reinterpret_steal<object>(PyUnicode_FromObject(load_src.ptr()));
+            if (!temp) { PyErr_Clear(); return false; }
+            load_src = temp;
+#endif
+        }
+
+        object utfNbytes = reinterpret_steal<object>(PyUnicode_AsEncodedString(
+            load_src.ptr(), UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr));
+        if (!utfNbytes) { PyErr_Clear(); return false; }
+
+        const CharT *buffer = reinterpret_cast<const CharT *>(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr()));
+        size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT);
+        if (UTF_N > 8) { buffer++; length--; } // Skip BOM for UTF-16/32
+        value = StringType(buffer, length);
+
+        // If we're loading a string_view we need to keep the encoded Python object alive:
+        if (IsView)
+            loader_life_support::add_patient(utfNbytes);
+
+        return true;
+    }
+
+    static handle cast(const StringType &src, return_value_policy /* policy */, handle /* parent */) {
+        const char *buffer = reinterpret_cast<const char *>(src.data());
+        ssize_t nbytes = ssize_t(src.size() * sizeof(CharT));
+        handle s = decode_utfN(buffer, nbytes);
+        if (!s) throw error_already_set();
+        return s;
+    }
+
+    PYBIND11_TYPE_CASTER(StringType, _(PYBIND11_STRING_NAME));
+
+private:
+    static handle decode_utfN(const char *buffer, ssize_t nbytes) {
+#if !defined(PYPY_VERSION)
+        return
+            UTF_N == 8  ? PyUnicode_DecodeUTF8(buffer, nbytes, nullptr) :
+            UTF_N == 16 ? PyUnicode_DecodeUTF16(buffer, nbytes, nullptr, nullptr) :
+                          PyUnicode_DecodeUTF32(buffer, nbytes, nullptr, nullptr);
+#else
+        // PyPy seems to have multiple problems related to PyUnicode_UTF*: the UTF8 version
+        // sometimes segfaults for unknown reasons, while the UTF16 and 32 versions require a
+        // non-const char * arguments, which is also a nuisance, so bypass the whole thing by just
+        // passing the encoding as a string value, which works properly:
+        return PyUnicode_Decode(buffer, nbytes, UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr);
+#endif
+    }
+
+    // When loading into a std::string or char*, accept a bytes object as-is (i.e.
+    // without any encoding/decoding attempt).  For other C++ char sizes this is a no-op.
+    // which supports loading a unicode from a str, doesn't take this path.
+    template <typename C = CharT>
+    bool load_bytes(enable_if_t<sizeof(C) == 1, handle> src) {
+        if (PYBIND11_BYTES_CHECK(src.ptr())) {
+            // We were passed a Python 3 raw bytes; accept it into a std::string or char*
+            // without any encoding attempt.
+            const char *bytes = PYBIND11_BYTES_AS_STRING(src.ptr());
+            if (bytes) {
+                value = StringType(bytes, (size_t) PYBIND11_BYTES_SIZE(src.ptr()));
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    template <typename C = CharT>
+    bool load_bytes(enable_if_t<sizeof(C) != 1, handle>) { return false; }
+};
+
+template <typename CharT, class Traits, class Allocator>
+struct type_caster<std::basic_string<CharT, Traits, Allocator>, enable_if_t<is_std_char_type<CharT>::value>>
+    : string_caster<std::basic_string<CharT, Traits, Allocator>> {};
+
+#ifdef PYBIND11_HAS_STRING_VIEW
+template <typename CharT, class Traits>
+struct type_caster<std::basic_string_view<CharT, Traits>, enable_if_t<is_std_char_type<CharT>::value>>
+    : string_caster<std::basic_string_view<CharT, Traits>, true> {};
+#endif
+
+// Type caster for C-style strings.  We basically use a std::string type caster, but also add the
+// ability to use None as a nullptr char* (which the string caster doesn't allow).
+template <typename CharT> struct type_caster<CharT, enable_if_t<is_std_char_type<CharT>::value>> {
+    using StringType = std::basic_string<CharT>;
+    using StringCaster = type_caster<StringType>;
+    StringCaster str_caster;
+    bool none = false;
+    CharT one_char = 0;
+public:
+    bool load(handle src, bool convert) {
+        if (!src) return false;
+        if (src.is_none()) {
+            // Defer accepting None to other overloads (if we aren't in convert mode):
+            if (!convert) return false;
+            none = true;
+            return true;
+        }
+        return str_caster.load(src, convert);
+    }
+
+    static handle cast(const CharT *src, return_value_policy policy, handle parent) {
+        if (src == nullptr) return pybind11::none().inc_ref();
+        return StringCaster::cast(StringType(src), policy, parent);
+    }
+
+    static handle cast(CharT src, return_value_policy policy, handle parent) {
+        if (std::is_same<char, CharT>::value) {
+            handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr);
+            if (!s) throw error_already_set();
+            return s;
+        }
+        return StringCaster::cast(StringType(1, src), policy, parent);
+    }
+
+    operator CharT*() { return none ? nullptr : const_cast<CharT *>(static_cast<StringType &>(str_caster).c_str()); }
+    operator CharT&() {
+        if (none)
+            throw value_error("Cannot convert None to a character");
+
+        auto &value = static_cast<StringType &>(str_caster);
+        size_t str_len = value.size();
+        if (str_len == 0)
+            throw value_error("Cannot convert empty string to a character");
+
+        // If we're in UTF-8 mode, we have two possible failures: one for a unicode character that
+        // is too high, and one for multiple unicode characters (caught later), so we need to figure
+        // out how long the first encoded character is in bytes to distinguish between these two
+        // errors.  We also allow want to allow unicode characters U+0080 through U+00FF, as those
+        // can fit into a single char value.
+        if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) {
+            unsigned char v0 = static_cast<unsigned char>(value[0]);
+            size_t char0_bytes = !(v0 & 0x80) ? 1 : // low bits only: 0-127
+                (v0 & 0xE0) == 0xC0 ? 2 : // 0b110xxxxx - start of 2-byte sequence
+                (v0 & 0xF0) == 0xE0 ? 3 : // 0b1110xxxx - start of 3-byte sequence
+                4; // 0b11110xxx - start of 4-byte sequence
+
+            if (char0_bytes == str_len) {
+                // If we have a 128-255 value, we can decode it into a single char:
+                if (char0_bytes == 2 && (v0 & 0xFC) == 0xC0) { // 0x110000xx 0x10xxxxxx
+                    one_char = static_cast<CharT>(((v0 & 3) << 6) + (static_cast<unsigned char>(value[1]) & 0x3F));
+                    return one_char;
+                }
+                // Otherwise we have a single character, but it's > U+00FF
+                throw value_error("Character code point not in range(0x100)");
+            }
+        }
+
+        // UTF-16 is much easier: we can only have a surrogate pair for values above U+FFFF, thus a
+        // surrogate pair with total length 2 instantly indicates a range error (but not a "your
+        // string was too long" error).
+        else if (StringCaster::UTF_N == 16 && str_len == 2) {
+            one_char = static_cast<CharT>(value[0]);
+            if (one_char >= 0xD800 && one_char < 0xE000)
+                throw value_error("Character code point not in range(0x10000)");
+        }
+
+        if (str_len != 1)
+            throw value_error("Expected a character, but multi-character string found");
+
+        one_char = value[0];
+        return one_char;
+    }
+
+    static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); }
+    template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>;
+};
+
+// Base implementation for std::tuple and std::pair
+template <template<typename...> class Tuple, typename... Ts> class tuple_caster {
+    using type = Tuple<Ts...>;
+    static constexpr auto size = sizeof...(Ts);
+    using indices = make_index_sequence<size>;
+public:
+
+    bool load(handle src, bool convert) {
+        if (!isinstance<sequence>(src))
+            return false;
+        const auto seq = reinterpret_borrow<sequence>(src);
+        if (seq.size() != size)
+            return false;
+        return load_impl(seq, convert, indices{});
+    }
+
+    template <typename T>
+    static handle cast(T &&src, return_value_policy policy, handle parent) {
+        return cast_impl(std::forward<T>(src), policy, parent, indices{});
+    }
+
+    static PYBIND11_DESCR name() {
+        return type_descr(_("Tuple[") + detail::concat(make_caster<Ts>::name()...) + _("]"));
+    }
+
+    template <typename T> using cast_op_type = type;
+
+    operator type() & { return implicit_cast(indices{}); }
+    operator type() && { return std::move(*this).implicit_cast(indices{}); }
+
+protected:
+    template <size_t... Is>
+    type implicit_cast(index_sequence<Is...>) & { return type(cast_op<Ts>(std::get<Is>(subcasters))...); }
+    template <size_t... Is>
+    type implicit_cast(index_sequence<Is...>) && { return type(cast_op<Ts>(std::move(std::get<Is>(subcasters)))...); }
+
+    static constexpr bool load_impl(const sequence &, bool, index_sequence<>) { return true; }
+
+    template <size_t... Is>
+    bool load_impl(const sequence &seq, bool convert, index_sequence<Is...>) {
+        for (bool r : {std::get<Is>(subcasters).load(seq[Is], convert)...})
+            if (!r)
+                return false;
+        return true;
+    }
+
+    /* Implementation: Convert a C++ tuple into a Python tuple */
+    template <typename T, size_t... Is>
+    static handle cast_impl(T &&src, return_value_policy policy, handle parent, index_sequence<Is...>) {
+        std::array<object, size> entries{{
+            reinterpret_steal<object>(make_caster<Ts>::cast(std::get<Is>(std::forward<T>(src)), policy, parent))...
+        }};
+        for (const auto &entry: entries)
+            if (!entry)
+                return handle();
+        tuple result(size);
+        int counter = 0;
+        for (auto & entry: entries)
+            PyTuple_SET_ITEM(result.ptr(), counter++, entry.release().ptr());
+        return result.release();
+    }
+
+    Tuple<make_caster<Ts>...> subcasters;
+};
+
+template <typename T1, typename T2> class type_caster<std::pair<T1, T2>>
+    : public tuple_caster<std::pair, T1, T2> {};
+
+template <typename... Ts> class type_caster<std::tuple<Ts...>>
+    : public tuple_caster<std::tuple, Ts...> {};
+
+/// Helper class which abstracts away certain actions. Users can provide specializations for
+/// custom holders, but it's only necessary if the type has a non-standard interface.
+template <typename T>
+struct holder_helper {
+    static auto get(const T &p) -> decltype(p.get()) { return p.get(); }
+};
+
+/// Type caster for holder types like std::shared_ptr, etc.
+template <typename type, typename holder_type>
+struct copyable_holder_caster : public type_caster_base<type> {
+public:
+    using base = type_caster_base<type>;
+    static_assert(std::is_base_of<base, type_caster<type>>::value,
+            "Holder classes are only supported for custom types");
+    using base::base;
+    using base::cast;
+    using base::typeinfo;
+    using base::value;
+
+    bool load(handle src, bool convert) {
+        return base::template load_impl<copyable_holder_caster<type, holder_type>>(src, convert);
+    }
+
+    explicit operator type*() { return this->value; }
+    explicit operator type&() { return *(this->value); }
+    explicit operator holder_type*() { return std::addressof(holder); }
+
+    // Workaround for Intel compiler bug
+    // see pybind11 issue 94
+    #if defined(__ICC) || defined(__INTEL_COMPILER)
+    operator holder_type&() { return holder; }
+    #else
+    explicit operator holder_type&() { return holder; }
+    #endif
+
+    static handle cast(const holder_type &src, return_value_policy, handle) {
+        const auto *ptr = holder_helper<holder_type>::get(src);
+        return type_caster_base<type>::cast_holder(ptr, &src);
+    }
+
+protected:
+    friend class type_caster_generic;
+    void check_holder_compat() {
+        if (typeinfo->default_holder)
+            throw cast_error("Unable to load a custom holder type from a default-holder instance");
+    }
+
+    bool load_value(value_and_holder &&v_h) {
+        if (v_h.holder_constructed()) {
+            value = v_h.value_ptr();
+            holder = v_h.template holder<holder_type>();
+            return true;
+        } else {
+            throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) "
+#if defined(NDEBUG)
+                             "(compile in debug mode for type information)");
+#else
+                             "of type '" + type_id<holder_type>() + "''");
+#endif
+        }
+    }
+
+    template <typename T = holder_type, detail::enable_if_t<!std::is_constructible<T, const T &, type*>::value, int> = 0>
+    bool try_implicit_casts(handle, bool) { return false; }
+
+    template <typename T = holder_type, detail::enable_if_t<std::is_constructible<T, const T &, type*>::value, int> = 0>
+    bool try_implicit_casts(handle src, bool convert) {
+        for (auto &cast : typeinfo->implicit_casts) {
+            copyable_holder_caster sub_caster(*cast.first);
+            if (sub_caster.load(src, convert)) {
+                value = cast.second(sub_caster.value);
+                holder = holder_type(sub_caster.holder, (type *) value);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    static bool try_direct_conversions(handle) { return false; }
+
+
+    holder_type holder;
+};
+
+/// Specialize for the common std::shared_ptr, so users don't need to
+template <typename T>
+class type_caster<std::shared_ptr<T>> : public copyable_holder_caster<T, std::shared_ptr<T>> { };
+
+template <typename type, typename holder_type>
+struct move_only_holder_caster {
+    static_assert(std::is_base_of<type_caster_base<type>, type_caster<type>>::value,
+            "Holder classes are only supported for custom types");
+
+    static handle cast(holder_type &&src, return_value_policy, handle) {
+        auto *ptr = holder_helper<holder_type>::get(src);
+        return type_caster_base<type>::cast_holder(ptr, std::addressof(src));
+    }
+    static PYBIND11_DESCR name() { return type_caster_base<type>::name(); }
+};
+
+template <typename type, typename deleter>
+class type_caster<std::unique_ptr<type, deleter>>
+    : public move_only_holder_caster<type, std::unique_ptr<type, deleter>> { };
+
+template <typename type, typename holder_type>
+using type_caster_holder = conditional_t<is_copy_constructible<holder_type>::value,
+                                         copyable_holder_caster<type, holder_type>,
+                                         move_only_holder_caster<type, holder_type>>;
+
+template <typename T, bool Value = false> struct always_construct_holder { static constexpr bool value = Value; };
+
+/// Create a specialization for custom holder types (silently ignores std::shared_ptr)
+#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type, ...) \
+    namespace pybind11 { namespace detail { \
+    template <typename type> \
+    struct always_construct_holder<holder_type> : always_construct_holder<void, ##__VA_ARGS__>  { }; \
+    template <typename type> \
+    class type_caster<holder_type, enable_if_t<!is_shared_ptr<holder_type>::value>> \
+        : public type_caster_holder<type, holder_type> { }; \
+    }}
+
+// PYBIND11_DECLARE_HOLDER_TYPE holder types:
+template <typename base, typename holder> struct is_holder_type :
+    std::is_base_of<detail::type_caster_holder<base, holder>, detail::type_caster<holder>> {};
+// Specialization for always-supported unique_ptr holders:
+template <typename base, typename deleter> struct is_holder_type<base, std::unique_ptr<base, deleter>> :
+    std::true_type {};
+
+template <typename T> struct handle_type_name { static PYBIND11_DESCR name() { return _<T>(); } };
+template <> struct handle_type_name<bytes> { static PYBIND11_DESCR name() { return _(PYBIND11_BYTES_NAME); } };
+template <> struct handle_type_name<args> { static PYBIND11_DESCR name() { return _("*args"); } };
+template <> struct handle_type_name<kwargs> { static PYBIND11_DESCR name() { return _("**kwargs"); } };
+
+template <typename type>
+struct pyobject_caster {
+    template <typename T = type, enable_if_t<std::is_same<T, handle>::value, int> = 0>
+    bool load(handle src, bool /* convert */) { value = src; return static_cast<bool>(value); }
+
+    template <typename T = type, enable_if_t<std::is_base_of<object, T>::value, int> = 0>
+    bool load(handle src, bool /* convert */) {
+        if (!isinstance<type>(src))
+            return false;
+        value = reinterpret_borrow<type>(src);
+        return true;
+    }
+
+    static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {
+        return src.inc_ref();
+    }
+    PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name());
+};
+
+template <typename T>
+class type_caster<T, enable_if_t<is_pyobject<T>::value>> : public pyobject_caster<T> { };
+
+// Our conditions for enabling moving are quite restrictive:
+// At compile time:
+// - T needs to be a non-const, non-pointer, non-reference type
+// - type_caster<T>::operator T&() must exist
+// - the type must be move constructible (obviously)
+// At run-time:
+// - if the type is non-copy-constructible, the object must be the sole owner of the type (i.e. it
+//   must have ref_count() == 1)h
+// If any of the above are not satisfied, we fall back to copying.
+template <typename T> using move_is_plain_type = satisfies_none_of<T,
+    std::is_void, std::is_pointer, std::is_reference, std::is_const
+>;
+template <typename T, typename SFINAE = void> struct move_always : std::false_type {};
+template <typename T> struct move_always<T, enable_if_t<all_of<
+    move_is_plain_type<T>,
+    negation<is_copy_constructible<T>>,
+    std::is_move_constructible<T>,
+    std::is_same<decltype(std::declval<make_caster<T>>().operator T&()), T&>
+>::value>> : std::true_type {};
+template <typename T, typename SFINAE = void> struct move_if_unreferenced : std::false_type {};
+template <typename T> struct move_if_unreferenced<T, enable_if_t<all_of<
+    move_is_plain_type<T>,
+    negation<move_always<T>>,
+    std::is_move_constructible<T>,
+    std::is_same<decltype(std::declval<make_caster<T>>().operator T&()), T&>
+>::value>> : std::true_type {};
+template <typename T> using move_never = none_of<move_always<T>, move_if_unreferenced<T>>;
+
+// Detect whether returning a `type` from a cast on type's type_caster is going to result in a
+// reference or pointer to a local variable of the type_caster.  Basically, only
+// non-reference/pointer `type`s and reference/pointers from a type_caster_generic are safe;
+// everything else returns a reference/pointer to a local variable.
+template <typename type> using cast_is_temporary_value_reference = bool_constant<
+    (std::is_reference<type>::value || std::is_pointer<type>::value) &&
+    !std::is_base_of<type_caster_generic, make_caster<type>>::value
+>;
+
+// When a value returned from a C++ function is being cast back to Python, we almost always want to
+// force `policy = move`, regardless of the return value policy the function/method was declared
+// with.
+template <typename Return, typename SFINAE = void> struct return_value_policy_override {
+    static return_value_policy policy(return_value_policy p) { return p; }
+};
+
+template <typename Return> struct return_value_policy_override<Return,
+        detail::enable_if_t<std::is_base_of<type_caster_generic, make_caster<Return>>::value, void>> {
+    static return_value_policy policy(return_value_policy p) {
+        return !std::is_lvalue_reference<Return>::value && !std::is_pointer<Return>::value
+            ? return_value_policy::move : p;
+    }
+};
+
+// Basic python -> C++ casting; throws if casting fails
+template <typename T, typename SFINAE> type_caster<T, SFINAE> &load_type(type_caster<T, SFINAE> &conv, const handle &handle) {
+    if (!conv.load(handle, true)) {
+#if defined(NDEBUG)
+        throw cast_error("Unable to cast Python instance to C++ type (compile in debug mode for details)");
+#else
+        throw cast_error("Unable to cast Python instance of type " +
+            (std::string) str(handle.get_type()) + " to C++ type '" + type_id<T>() + "'");
+#endif
+    }
+    return conv;
+}
+// Wrapper around the above that also constructs and returns a type_caster
+template <typename T> make_caster<T> load_type(const handle &handle) {
+    make_caster<T> conv;
+    load_type(conv, handle);
+    return conv;
+}
+
+NAMESPACE_END(detail)
+
+// pytype -> C++ type
+template <typename T, detail::enable_if_t<!detail::is_pyobject<T>::value, int> = 0>
+T cast(const handle &handle) {
+    using namespace detail;
+    static_assert(!cast_is_temporary_value_reference<T>::value,
+            "Unable to cast type to reference: value is local to type caster");
+    return cast_op<T>(load_type<T>(handle));
+}
+
+// pytype -> pytype (calls converting constructor)
+template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0>
+T cast(const handle &handle) { return T(reinterpret_borrow<object>(handle)); }
+
+// C++ type -> py::object
+template <typename T, detail::enable_if_t<!detail::is_pyobject<T>::value, int> = 0>
+object cast(const T &value, return_value_policy policy = return_value_policy::automatic_reference,
+            handle parent = handle()) {
+    if (policy == return_value_policy::automatic)
+        policy = std::is_pointer<T>::value ? return_value_policy::take_ownership : return_value_policy::copy;
+    else if (policy == return_value_policy::automatic_reference)
+        policy = std::is_pointer<T>::value ? return_value_policy::reference : return_value_policy::copy;
+    return reinterpret_steal<object>(detail::make_caster<T>::cast(value, policy, parent));
+}
+
+template <typename T> T handle::cast() const { return pybind11::cast<T>(*this); }
+template <> inline void handle::cast() const { return; }
+
+template <typename T>
+detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) {
+    if (obj.ref_count() > 1)
+#if defined(NDEBUG)
+        throw cast_error("Unable to cast Python instance to C++ rvalue: instance has multiple references"
+            " (compile in debug mode for details)");
+#else
+        throw cast_error("Unable to move from Python " + (std::string) str(obj.get_type()) +
+                " instance to C++ " + type_id<T>() + " instance: instance has multiple references");
+#endif
+
+    // Move into a temporary and return that, because the reference may be a local value of `conv`
+    T ret = std::move(detail::load_type<T>(obj).operator T&());
+    return ret;
+}
+
+// Calling cast() on an rvalue calls pybind::cast with the object rvalue, which does:
+// - If we have to move (because T has no copy constructor), do it.  This will fail if the moved
+//   object has multiple references, but trying to copy will fail to compile.
+// - If both movable and copyable, check ref count: if 1, move; otherwise copy
+// - Otherwise (not movable), copy.
+template <typename T> detail::enable_if_t<detail::move_always<T>::value, T> cast(object &&object) {
+    return move<T>(std::move(object));
+}
+template <typename T> detail::enable_if_t<detail::move_if_unreferenced<T>::value, T> cast(object &&object) {
+    if (object.ref_count() > 1)
+        return cast<T>(object);
+    else
+        return move<T>(std::move(object));
+}
+template <typename T> detail::enable_if_t<detail::move_never<T>::value, T> cast(object &&object) {
+    return cast<T>(object);
+}
+
+template <typename T> T object::cast() const & { return pybind11::cast<T>(*this); }
+template <typename T> T object::cast() && { return pybind11::cast<T>(std::move(*this)); }
+template <> inline void object::cast() const & { return; }
+template <> inline void object::cast() && { return; }
+
+NAMESPACE_BEGIN(detail)
+
+// Declared in pytypes.h:
+template <typename T, enable_if_t<!is_pyobject<T>::value, int>>
+object object_or_cast(T &&o) { return pybind11::cast(std::forward<T>(o)); }
+
+struct overload_unused {}; // Placeholder type for the unneeded (and dead code) static variable in the OVERLOAD_INT macro
+template <typename ret_type> using overload_caster_t = conditional_t<
+    cast_is_temporary_value_reference<ret_type>::value, make_caster<ret_type>, overload_unused>;
+
+// Trampoline use: for reference/pointer types to value-converted values, we do a value cast, then
+// store the result in the given variable.  For other types, this is a no-op.
+template <typename T> enable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&o, make_caster<T> &caster) {
+    return cast_op<T>(load_type(caster, o));
+}
+template <typename T> enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&, overload_unused &) {
+    pybind11_fail("Internal error: cast_ref fallback invoked"); }
+
+// Trampoline use: Having a pybind11::cast with an invalid reference type is going to static_assert, even
+// though if it's in dead code, so we provide a "trampoline" to pybind11::cast that only does anything in
+// cases where pybind11::cast is valid.
+template <typename T> enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&o) {
+    return pybind11::cast<T>(std::move(o)); }
+template <typename T> enable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&) {
+    pybind11_fail("Internal error: cast_safe fallback invoked"); }
+template <> inline void cast_safe<void>(object &&) {}
+
+NAMESPACE_END(detail)
+
+template <return_value_policy policy = return_value_policy::automatic_reference>
+tuple make_tuple() { return tuple(0); }
+
+template <return_value_policy policy = return_value_policy::automatic_reference,
+          typename... Args> tuple make_tuple(Args&&... args_) {
+    constexpr size_t size = sizeof...(Args);
+    std::array<object, size> args {
+        { reinterpret_steal<object>(detail::make_caster<Args>::cast(
+            std::forward<Args>(args_), policy, nullptr))... }
+    };
+    for (size_t i = 0; i < args.size(); i++) {
+        if (!args[i]) {
+#if defined(NDEBUG)
+            throw cast_error("make_tuple(): unable to convert arguments to Python object (compile in debug mode for details)");
+#else
+            std::array<std::string, size> argtypes { {type_id<Args>()...} };
+            throw cast_error("make_tuple(): unable to convert argument of type '" +
+                argtypes[i] + "' to Python object");
+#endif
+        }
+    }
+    tuple result(size);
+    int counter = 0;
+    for (auto &arg_value : args)
+        PyTuple_SET_ITEM(result.ptr(), counter++, arg_value.release().ptr());
+    return result;
+}
+
+/// \ingroup annotations
+/// Annotation for arguments
+struct arg {
+    /// Constructs an argument with the name of the argument; if null or omitted, this is a positional argument.
+    constexpr explicit arg(const char *name = nullptr) : name(name), flag_noconvert(false), flag_none(true) { }
+    /// Assign a value to this argument
+    template <typename T> arg_v operator=(T &&value) const;
+    /// Indicate that the type should not be converted in the type caster
+    arg &noconvert(bool flag = true) { flag_noconvert = flag; return *this; }
+    /// Indicates that the argument should/shouldn't allow None (e.g. for nullable pointer args)
+    arg &none(bool flag = true) { flag_none = flag; return *this; }
+
+    const char *name; ///< If non-null, this is a named kwargs argument
+    bool flag_noconvert : 1; ///< If set, do not allow conversion (requires a supporting type caster!)
+    bool flag_none : 1; ///< If set (the default), allow None to be passed to this argument
+};
+
+/// \ingroup annotations
+/// Annotation for arguments with values
+struct arg_v : arg {
+private:
+    template <typename T>
+    arg_v(arg &&base, T &&x, const char *descr = nullptr)
+        : arg(base),
+          value(reinterpret_steal<object>(
+              detail::make_caster<T>::cast(x, return_value_policy::automatic, {})
+          )),
+          descr(descr)
+#if !defined(NDEBUG)
+        , type(type_id<T>())
+#endif
+    { }
+
+public:
+    /// Direct construction with name, default, and description
+    template <typename T>
+    arg_v(const char *name, T &&x, const char *descr = nullptr)
+        : arg_v(arg(name), std::forward<T>(x), descr) { }
+
+    /// Called internally when invoking `py::arg("a") = value`
+    template <typename T>
+    arg_v(const arg &base, T &&x, const char *descr = nullptr)
+        : arg_v(arg(base), std::forward<T>(x), descr) { }
+
+    /// Same as `arg::noconvert()`, but returns *this as arg_v&, not arg&
+    arg_v &noconvert(bool flag = true) { arg::noconvert(flag); return *this; }
+
+    /// Same as `arg::nonone()`, but returns *this as arg_v&, not arg&
+    arg_v &none(bool flag = true) { arg::none(flag); return *this; }
+
+    /// The default value
+    object value;
+    /// The (optional) description of the default value
+    const char *descr;
+#if !defined(NDEBUG)
+    /// The C++ type name of the default value (only available when compiled in debug mode)
+    std::string type;
+#endif
+};
+
+template <typename T>
+arg_v arg::operator=(T &&value) const { return {std::move(*this), std::forward<T>(value)}; }
+
+/// Alias for backward compatibility -- to be removed in version 2.0
+template <typename /*unused*/> using arg_t = arg_v;
+
+inline namespace literals {
+/** \rst
+    String literal version of `arg`
+ \endrst */
+constexpr arg operator"" _a(const char *name, size_t) { return arg(name); }
+}
+
+NAMESPACE_BEGIN(detail)
+
+// forward declaration (definition in attr.h)
+struct function_record;
+
+/// Internal data associated with a single function call
+struct function_call {
+    function_call(function_record &f, handle p); // Implementation in attr.h
+
+    /// The function data:
+    const function_record &func;
+
+    /// Arguments passed to the function:
+    std::vector<handle> args;
+
+    /// The `convert` value the arguments should be loaded with
+    std::vector<bool> args_convert;
+
+    /// Extra references for the optional `py::args` and/or `py::kwargs` arguments (which, if
+    /// present, are also in `args` but without a reference).
+    object args_ref, kwargs_ref;
+
+    /// The parent, if any
+    handle parent;
+
+    /// If this is a call to an initializer, this argument contains `self`
+    handle init_self;
+};
+
+
+/// Helper class which loads arguments for C++ functions called from Python
+template <typename... Args>
+class argument_loader {
+    using indices = make_index_sequence<sizeof...(Args)>;
+
+    template <typename Arg> using argument_is_args   = std::is_same<intrinsic_t<Arg>, args>;
+    template <typename Arg> using argument_is_kwargs = std::is_same<intrinsic_t<Arg>, kwargs>;
+    // Get args/kwargs argument positions relative to the end of the argument list:
+    static constexpr auto args_pos = constexpr_first<argument_is_args, Args...>() - (int) sizeof...(Args),
+                        kwargs_pos = constexpr_first<argument_is_kwargs, Args...>() - (int) sizeof...(Args);
+
+    static constexpr bool args_kwargs_are_last = kwargs_pos >= - 1 && args_pos >= kwargs_pos - 1;
+
+    static_assert(args_kwargs_are_last, "py::args/py::kwargs are only permitted as the last argument(s) of a function");
+
+public:
+    static constexpr bool has_kwargs = kwargs_pos < 0;
+    static constexpr bool has_args = args_pos < 0;
+
+    static PYBIND11_DESCR arg_names() { return detail::concat(make_caster<Args>::name()...); }
+
+    bool load_args(function_call &call) {
+        return load_impl_sequence(call, indices{});
+    }
+
+    template <typename Return, typename Guard, typename Func>
+    enable_if_t<!std::is_void<Return>::value, Return> call(Func &&f) && {
+        return std::move(*this).template call_impl<Return>(std::forward<Func>(f), indices{}, Guard{});
+    }
+
+    template <typename Return, typename Guard, typename Func>
+    enable_if_t<std::is_void<Return>::value, void_type> call(Func &&f) && {
+        std::move(*this).template call_impl<Return>(std::forward<Func>(f), indices{}, Guard{});
+        return void_type();
+    }
+
+private:
+
+    static bool load_impl_sequence(function_call &, index_sequence<>) { return true; }
+
+    template <size_t... Is>
+    bool load_impl_sequence(function_call &call, index_sequence<Is...>) {
+        for (bool r : {std::get<Is>(argcasters).load(call.args[Is], call.args_convert[Is])...})
+            if (!r)
+                return false;
+        return true;
+    }
+
+    template <typename Return, typename Func, size_t... Is, typename Guard>
+    Return call_impl(Func &&f, index_sequence<Is...>, Guard &&) {
+        return std::forward<Func>(f)(cast_op<Args>(std::move(std::get<Is>(argcasters)))...);
+    }
+
+    std::tuple<make_caster<Args>...> argcasters;
+};
+
+/// Helper class which collects only positional arguments for a Python function call.
+/// A fancier version below can collect any argument, but this one is optimal for simple calls.
+template <return_value_policy policy>
+class simple_collector {
+public:
+    template <typename... Ts>
+    explicit simple_collector(Ts &&...values)
+        : m_args(pybind11::make_tuple<policy>(std::forward<Ts>(values)...)) { }
+
+    const tuple &args() const & { return m_args; }
+    dict kwargs() const { return {}; }
+
+    tuple args() && { return std::move(m_args); }
+
+    /// Call a Python function and pass the collected arguments
+    object call(PyObject *ptr) const {
+        PyObject *result = PyObject_CallObject(ptr, m_args.ptr());
+        if (!result)
+            throw error_already_set();
+        return reinterpret_steal<object>(result);
+    }
+
+private:
+    tuple m_args;
+};
+
+/// Helper class which collects positional, keyword, * and ** arguments for a Python function call
+template <return_value_policy policy>
+class unpacking_collector {
+public:
+    template <typename... Ts>
+    explicit unpacking_collector(Ts &&...values) {
+        // Tuples aren't (easily) resizable so a list is needed for collection,
+        // but the actual function call strictly requires a tuple.
+        auto args_list = list();
+        int _[] = { 0, (process(args_list, std::forward<Ts>(values)), 0)... };
+        ignore_unused(_);
+
+        m_args = std::move(args_list);
+    }
+
+    const tuple &args() const & { return m_args; }
+    const dict &kwargs() const & { return m_kwargs; }
+
+    tuple args() && { return std::move(m_args); }
+    dict kwargs() && { return std::move(m_kwargs); }
+
+    /// Call a Python function and pass the collected arguments
+    object call(PyObject *ptr) const {
+        PyObject *result = PyObject_Call(ptr, m_args.ptr(), m_kwargs.ptr());
+        if (!result)
+            throw error_already_set();
+        return reinterpret_steal<object>(result);
+    }
+
+private:
+    template <typename T>
+    void process(list &args_list, T &&x) {
+        auto o = reinterpret_steal<object>(detail::make_caster<T>::cast(std::forward<T>(x), policy, {}));
+        if (!o) {
+#if defined(NDEBUG)
+            argument_cast_error();
+#else
+            argument_cast_error(std::to_string(args_list.size()), type_id<T>());
+#endif
+        }
+        args_list.append(o);
+    }
+
+    void process(list &args_list, detail::args_proxy ap) {
+        for (const auto &a : ap)
+            args_list.append(a);
+    }
+
+    void process(list &/*args_list*/, arg_v a) {
+        if (!a.name)
+#if defined(NDEBUG)
+            nameless_argument_error();
+#else
+            nameless_argument_error(a.type);
+#endif
+
+        if (m_kwargs.contains(a.name)) {
+#if defined(NDEBUG)
+            multiple_values_error();
+#else
+            multiple_values_error(a.name);
+#endif
+        }
+        if (!a.value) {
+#if defined(NDEBUG)
+            argument_cast_error();
+#else
+            argument_cast_error(a.name, a.type);
+#endif
+        }
+        m_kwargs[a.name] = a.value;
+    }
+
+    void process(list &/*args_list*/, detail::kwargs_proxy kp) {
+        if (!kp)
+            return;
+        for (const auto &k : reinterpret_borrow<dict>(kp)) {
+            if (m_kwargs.contains(k.first)) {
+#if defined(NDEBUG)
+                multiple_values_error();
+#else
+                multiple_values_error(str(k.first));
+#endif
+            }
+            m_kwargs[k.first] = k.second;
+        }
+    }
+
+    [[noreturn]] static void nameless_argument_error() {
+        throw type_error("Got kwargs without a name; only named arguments "
+                         "may be passed via py::arg() to a python function call. "
+                         "(compile in debug mode for details)");
+    }
+    [[noreturn]] static void nameless_argument_error(std::string type) {
+        throw type_error("Got kwargs without a name of type '" + type + "'; only named "
+                         "arguments may be passed via py::arg() to a python function call. ");
+    }
+    [[noreturn]] static void multiple_values_error() {
+        throw type_error("Got multiple values for keyword argument "
+                         "(compile in debug mode for details)");
+    }
+
+    [[noreturn]] static void multiple_values_error(std::string name) {
+        throw type_error("Got multiple values for keyword argument '" + name + "'");
+    }
+
+    [[noreturn]] static void argument_cast_error() {
+        throw cast_error("Unable to convert call argument to Python object "
+                         "(compile in debug mode for details)");
+    }
+
+    [[noreturn]] static void argument_cast_error(std::string name, std::string type) {
+        throw cast_error("Unable to convert call argument '" + name
+                         + "' of type '" + type + "' to Python object");
+    }
+
+private:
+    tuple m_args;
+    dict m_kwargs;
+};
+
+/// Collect only positional arguments for a Python function call
+template <return_value_policy policy, typename... Args,
+          typename = enable_if_t<all_of<is_positional<Args>...>::value>>
+simple_collector<policy> collect_arguments(Args &&...args) {
+    return simple_collector<policy>(std::forward<Args>(args)...);
+}
+
+/// Collect all arguments, including keywords and unpacking (only instantiated when needed)
+template <return_value_policy policy, typename... Args,
+          typename = enable_if_t<!all_of<is_positional<Args>...>::value>>
+unpacking_collector<policy> collect_arguments(Args &&...args) {
+    // Following argument order rules for generalized unpacking according to PEP 448
+    static_assert(
+        constexpr_last<is_positional, Args...>() < constexpr_first<is_keyword_or_ds, Args...>()
+        && constexpr_last<is_s_unpacking, Args...>() < constexpr_first<is_ds_unpacking, Args...>(),
+        "Invalid function call: positional args must precede keywords and ** unpacking; "
+        "* unpacking must precede ** unpacking"
+    );
+    return unpacking_collector<policy>(std::forward<Args>(args)...);
+}
+
+template <typename Derived>
+template <return_value_policy policy, typename... Args>
+object object_api<Derived>::operator()(Args &&...args) const {
+    return detail::collect_arguments<policy>(std::forward<Args>(args)...).call(derived().ptr());
+}
+
+template <typename Derived>
+template <return_value_policy policy, typename... Args>
+object object_api<Derived>::call(Args &&...args) const {
+    return operator()<policy>(std::forward<Args>(args)...);
+}
+
+NAMESPACE_END(detail)
+
+#define PYBIND11_MAKE_OPAQUE(Type) \
+    namespace pybind11 { namespace detail { \
+        template<> class type_caster<Type> : public type_caster_base<Type> { }; \
+    }}
+
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/chrono.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/chrono.h
new file mode 100644
index 0000000000000000000000000000000000000000..95ada76e0f0091e6ff6527a89212702111cfa7f2
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/chrono.h
@@ -0,0 +1,162 @@
+/*
+    pybind11/chrono.h: Transparent conversion between std::chrono and python's datetime
+
+    Copyright (c) 2016 Trent Houliston <trent@houliston.me> and
+                       Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "pybind11.h"
+#include <cmath>
+#include <ctime>
+#include <chrono>
+#include <datetime.h>
+
+// Backport the PyDateTime_DELTA functions from Python3.3 if required
+#ifndef PyDateTime_DELTA_GET_DAYS
+#define PyDateTime_DELTA_GET_DAYS(o)         (((PyDateTime_Delta*)o)->days)
+#endif
+#ifndef PyDateTime_DELTA_GET_SECONDS
+#define PyDateTime_DELTA_GET_SECONDS(o)      (((PyDateTime_Delta*)o)->seconds)
+#endif
+#ifndef PyDateTime_DELTA_GET_MICROSECONDS
+#define PyDateTime_DELTA_GET_MICROSECONDS(o) (((PyDateTime_Delta*)o)->microseconds)
+#endif
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+NAMESPACE_BEGIN(detail)
+
+template <typename type> class duration_caster {
+public:
+    typedef typename type::rep rep;
+    typedef typename type::period period;
+
+    typedef std::chrono::duration<uint_fast32_t, std::ratio<86400>> days;
+
+    bool load(handle src, bool) {
+        using namespace std::chrono;
+
+        // Lazy initialise the PyDateTime import
+        if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
+
+        if (!src) return false;
+        // If invoked with datetime.delta object
+        if (PyDelta_Check(src.ptr())) {
+            value = type(duration_cast<duration<rep, period>>(
+                  days(PyDateTime_DELTA_GET_DAYS(src.ptr()))
+                + seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr()))
+                + microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr()))));
+            return true;
+        }
+        // If invoked with a float we assume it is seconds and convert
+        else if (PyFloat_Check(src.ptr())) {
+            value = type(duration_cast<duration<rep, period>>(duration<double>(PyFloat_AsDouble(src.ptr()))));
+            return true;
+        }
+        else return false;
+    }
+
+    // If this is a duration just return it back
+    static const std::chrono::duration<rep, period>& get_duration(const std::chrono::duration<rep, period> &src) {
+        return src;
+    }
+
+    // If this is a time_point get the time_since_epoch
+    template <typename Clock> static std::chrono::duration<rep, period> get_duration(const std::chrono::time_point<Clock, std::chrono::duration<rep, period>> &src) {
+        return src.time_since_epoch();
+    }
+
+    static handle cast(const type &src, return_value_policy /* policy */, handle /* parent */) {
+        using namespace std::chrono;
+
+        // Use overloaded function to get our duration from our source
+        // Works out if it is a duration or time_point and get the duration
+        auto d = get_duration(src);
+
+        // Lazy initialise the PyDateTime import
+        if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
+
+        // Declare these special duration types so the conversions happen with the correct primitive types (int)
+        using dd_t = duration<int, std::ratio<86400>>;
+        using ss_t = duration<int, std::ratio<1>>;
+        using us_t = duration<int, std::micro>;
+
+        auto dd = duration_cast<dd_t>(d);
+        auto subd = d - dd;
+        auto ss = duration_cast<ss_t>(subd);
+        auto us = duration_cast<us_t>(subd - ss);
+        return PyDelta_FromDSU(dd.count(), ss.count(), us.count());
+    }
+
+    PYBIND11_TYPE_CASTER(type, _("datetime.timedelta"));
+};
+
+// This is for casting times on the system clock into datetime.datetime instances
+template <typename Duration> class type_caster<std::chrono::time_point<std::chrono::system_clock, Duration>> {
+public:
+    typedef std::chrono::time_point<std::chrono::system_clock, Duration> type;
+    bool load(handle src, bool) {
+        using namespace std::chrono;
+
+        // Lazy initialise the PyDateTime import
+        if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
+
+        if (!src) return false;
+        if (PyDateTime_Check(src.ptr())) {
+            std::tm cal;
+            cal.tm_sec   = PyDateTime_DATE_GET_SECOND(src.ptr());
+            cal.tm_min   = PyDateTime_DATE_GET_MINUTE(src.ptr());
+            cal.tm_hour  = PyDateTime_DATE_GET_HOUR(src.ptr());
+            cal.tm_mday  = PyDateTime_GET_DAY(src.ptr());
+            cal.tm_mon   = PyDateTime_GET_MONTH(src.ptr()) - 1;
+            cal.tm_year  = PyDateTime_GET_YEAR(src.ptr()) - 1900;
+            cal.tm_isdst = -1;
+
+            value = system_clock::from_time_t(std::mktime(&cal)) + microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr()));
+            return true;
+        }
+        else return false;
+    }
+
+    static handle cast(const std::chrono::time_point<std::chrono::system_clock, Duration> &src, return_value_policy /* policy */, handle /* parent */) {
+        using namespace std::chrono;
+
+        // Lazy initialise the PyDateTime import
+        if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
+
+        std::time_t tt = system_clock::to_time_t(src);
+        // this function uses static memory so it's best to copy it out asap just in case
+        // otherwise other code that is using localtime may break this (not just python code)
+        std::tm localtime = *std::localtime(&tt);
+
+        // Declare these special duration types so the conversions happen with the correct primitive types (int)
+        using us_t = duration<int, std::micro>;
+
+        return PyDateTime_FromDateAndTime(localtime.tm_year + 1900,
+                                          localtime.tm_mon + 1,
+                                          localtime.tm_mday,
+                                          localtime.tm_hour,
+                                          localtime.tm_min,
+                                          localtime.tm_sec,
+                                          (duration_cast<us_t>(src.time_since_epoch() % seconds(1))).count());
+    }
+    PYBIND11_TYPE_CASTER(type, _("datetime.datetime"));
+};
+
+// Other clocks that are not the system clock are not measured as datetime.datetime objects
+// since they are not measured on calendar time. So instead we just make them timedeltas
+// Or if they have passed us a time as a float we convert that
+template <typename Clock, typename Duration> class type_caster<std::chrono::time_point<Clock, Duration>>
+: public duration_caster<std::chrono::time_point<Clock, Duration>> {
+};
+
+template <typename Rep, typename Period> class type_caster<std::chrono::duration<Rep, Period>>
+: public duration_caster<std::chrono::duration<Rep, Period>> {
+};
+
+NAMESPACE_END(detail)
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/common.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/common.h
new file mode 100644
index 0000000000000000000000000000000000000000..6c8a4f1e88e493ee08d24e668639c8d495fd49b1
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/common.h
@@ -0,0 +1,2 @@
+#include "detail/common.h"
+#warning "Including 'common.h' is deprecated. It will be removed in v3.0. Use 'pybind11.h'."
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/complex.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/complex.h
new file mode 100644
index 0000000000000000000000000000000000000000..5dac27cc4ef801f7af23c5faa6bcd1713a1cdc92
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/complex.h
@@ -0,0 +1,61 @@
+/*
+    pybind11/complex.h: Complex number support
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "pybind11.h"
+#include <complex>
+
+/// glibc defines I as a macro which breaks things, e.g., boost template names
+#ifdef I
+#  undef I
+#endif
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+
+template <typename T> struct format_descriptor<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
+    static constexpr const char c = format_descriptor<T>::c;
+    static constexpr const char value[3] = { 'Z', c, '\0' };
+    static std::string format() { return std::string(value); }
+};
+
+template <typename T> constexpr const char format_descriptor<
+    std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>>::value[3];
+
+NAMESPACE_BEGIN(detail)
+
+template <typename T> struct is_fmt_numeric<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
+    static constexpr bool value = true;
+    static constexpr int index = is_fmt_numeric<T>::index + 3;
+};
+
+template <typename T> class type_caster<std::complex<T>> {
+public:
+    bool load(handle src, bool convert) {
+        if (!src)
+            return false;
+        if (!convert && !PyComplex_Check(src.ptr()))
+            return false;
+        Py_complex result = PyComplex_AsCComplex(src.ptr());
+        if (result.real == -1.0 && PyErr_Occurred()) {
+            PyErr_Clear();
+            return false;
+        }
+        value = std::complex<T>((T) result.real, (T) result.imag);
+        return true;
+    }
+
+    static handle cast(const std::complex<T> &src, return_value_policy /* policy */, handle /* parent */) {
+        return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
+    }
+
+    PYBIND11_TYPE_CASTER(std::complex<T>, _("complex"));
+};
+NAMESPACE_END(detail)
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/class.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/class.h
new file mode 100644
index 0000000000000000000000000000000000000000..ff06370fa06c5e95e45b57b825ad683f2f4386f0
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/class.h
@@ -0,0 +1,626 @@
+/*
+    pybind11/detail/class.h: Python C API implementation details for py::class_
+
+    Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "../attr.h"
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+NAMESPACE_BEGIN(detail)
+
+#if PY_VERSION_HEX >= 0x03030000
+#  define PYBIND11_BUILTIN_QUALNAME
+#  define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj)
+#else
+// In pre-3.3 Python, we still set __qualname__ so that we can produce reliable function type
+// signatures; in 3.3+ this macro expands to nothing:
+#  define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) setattr((PyObject *) obj, "__qualname__", nameobj)
+#endif
+
+inline PyTypeObject *type_incref(PyTypeObject *type) {
+    Py_INCREF(type);
+    return type;
+}
+
+#if !defined(PYPY_VERSION)
+
+/// `pybind11_static_property.__get__()`: Always pass the class instead of the instance.
+extern "C" inline PyObject *pybind11_static_get(PyObject *self, PyObject * /*ob*/, PyObject *cls) {
+    return PyProperty_Type.tp_descr_get(self, cls, cls);
+}
+
+/// `pybind11_static_property.__set__()`: Just like the above `__get__()`.
+extern "C" inline int pybind11_static_set(PyObject *self, PyObject *obj, PyObject *value) {
+    PyObject *cls = PyType_Check(obj) ? obj : (PyObject *) Py_TYPE(obj);
+    return PyProperty_Type.tp_descr_set(self, cls, value);
+}
+
+/** A `static_property` is the same as a `property` but the `__get__()` and `__set__()`
+    methods are modified to always use the object type instead of a concrete instance.
+    Return value: New reference. */
+inline PyTypeObject *make_static_property_type() {
+    constexpr auto *name = "pybind11_static_property";
+    auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
+
+    /* Danger zone: from now (and until PyType_Ready), make sure to
+       issue no Python C API calls which could potentially invoke the
+       garbage collector (the GC will call type_traverse(), which will in
+       turn find the newly constructed type in an invalid state) */
+    auto heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);
+    if (!heap_type)
+        pybind11_fail("make_static_property_type(): error allocating type!");
+
+    heap_type->ht_name = name_obj.inc_ref().ptr();
+#ifdef PYBIND11_BUILTIN_QUALNAME
+    heap_type->ht_qualname = name_obj.inc_ref().ptr();
+#endif
+
+    auto type = &heap_type->ht_type;
+    type->tp_name = name;
+    type->tp_base = type_incref(&PyProperty_Type);
+    type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
+    type->tp_descr_get = pybind11_static_get;
+    type->tp_descr_set = pybind11_static_set;
+
+    if (PyType_Ready(type) < 0)
+        pybind11_fail("make_static_property_type(): failure in PyType_Ready()!");
+
+    setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
+    PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
+
+    return type;
+}
+
+#else // PYPY
+
+/** PyPy has some issues with the above C API, so we evaluate Python code instead.
+    This function will only be called once so performance isn't really a concern.
+    Return value: New reference. */
+inline PyTypeObject *make_static_property_type() {
+    auto d = dict();
+    PyObject *result = PyRun_String(R"(\
+        class pybind11_static_property(property):
+            def __get__(self, obj, cls):
+                return property.__get__(self, cls, cls)
+
+            def __set__(self, obj, value):
+                cls = obj if isinstance(obj, type) else type(obj)
+                property.__set__(self, cls, value)
+        )", Py_file_input, d.ptr(), d.ptr()
+    );
+    if (result == nullptr)
+        throw error_already_set();
+    Py_DECREF(result);
+    return (PyTypeObject *) d["pybind11_static_property"].cast<object>().release().ptr();
+}
+
+#endif // PYPY
+
+/** Types with static properties need to handle `Type.static_prop = x` in a specific way.
+    By default, Python replaces the `static_property` itself, but for wrapped C++ types
+    we need to call `static_property.__set__()` in order to propagate the new value to
+    the underlying C++ data structure. */
+extern "C" inline int pybind11_meta_setattro(PyObject* obj, PyObject* name, PyObject* value) {
+    // Use `_PyType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw
+    // descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`).
+    PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name);
+
+    // The following assignment combinations are possible:
+    //   1. `Type.static_prop = value`             --> descr_set: `Type.static_prop.__set__(value)`
+    //   2. `Type.static_prop = other_static_prop` --> setattro:  replace existing `static_prop`
+    //   3. `Type.regular_attribute = value`       --> setattro:  regular attribute assignment
+    const auto static_prop = (PyObject *) get_internals().static_property_type;
+    const auto call_descr_set = descr && PyObject_IsInstance(descr, static_prop)
+                                && !PyObject_IsInstance(value, static_prop);
+    if (call_descr_set) {
+        // Call `static_property.__set__()` instead of replacing the `static_property`.
+#if !defined(PYPY_VERSION)
+        return Py_TYPE(descr)->tp_descr_set(descr, obj, value);
+#else
+        if (PyObject *result = PyObject_CallMethod(descr, "__set__", "OO", obj, value)) {
+            Py_DECREF(result);
+            return 0;
+        } else {
+            return -1;
+        }
+#endif
+    } else {
+        // Replace existing attribute.
+        return PyType_Type.tp_setattro(obj, name, value);
+    }
+}
+
+#if PY_MAJOR_VERSION >= 3
+/**
+ * Python 3's PyInstanceMethod_Type hides itself via its tp_descr_get, which prevents aliasing
+ * methods via cls.attr("m2") = cls.attr("m1"): instead the tp_descr_get returns a plain function,
+ * when called on a class, or a PyMethod, when called on an instance.  Override that behaviour here
+ * to do a special case bypass for PyInstanceMethod_Types.
+ */
+extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name) {
+    PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name);
+    if (descr && PyInstanceMethod_Check(descr)) {
+        Py_INCREF(descr);
+        return descr;
+    }
+    else {
+        return PyType_Type.tp_getattro(obj, name);
+    }
+}
+#endif
+
+/** This metaclass is assigned by default to all pybind11 types and is required in order
+    for static properties to function correctly. Users may override this using `py::metaclass`.
+    Return value: New reference. */
+inline PyTypeObject* make_default_metaclass() {
+    constexpr auto *name = "pybind11_type";
+    auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
+
+    /* Danger zone: from now (and until PyType_Ready), make sure to
+       issue no Python C API calls which could potentially invoke the
+       garbage collector (the GC will call type_traverse(), which will in
+       turn find the newly constructed type in an invalid state) */
+    auto heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);
+    if (!heap_type)
+        pybind11_fail("make_default_metaclass(): error allocating metaclass!");
+
+    heap_type->ht_name = name_obj.inc_ref().ptr();
+#ifdef PYBIND11_BUILTIN_QUALNAME
+    heap_type->ht_qualname = name_obj.inc_ref().ptr();
+#endif
+
+    auto type = &heap_type->ht_type;
+    type->tp_name = name;
+    type->tp_base = type_incref(&PyType_Type);
+    type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
+
+    type->tp_setattro = pybind11_meta_setattro;
+#if PY_MAJOR_VERSION >= 3
+    type->tp_getattro = pybind11_meta_getattro;
+#endif
+
+    if (PyType_Ready(type) < 0)
+        pybind11_fail("make_default_metaclass(): failure in PyType_Ready()!");
+
+    setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
+    PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
+
+    return type;
+}
+
+/// For multiple inheritance types we need to recursively register/deregister base pointers for any
+/// base classes with pointers that are difference from the instance value pointer so that we can
+/// correctly recognize an offset base class pointer. This calls a function with any offset base ptrs.
+inline void traverse_offset_bases(void *valueptr, const detail::type_info *tinfo, instance *self,
+        bool (*f)(void * /*parentptr*/, instance * /*self*/)) {
+    for (handle h : reinterpret_borrow<tuple>(tinfo->type->tp_bases)) {
+        if (auto parent_tinfo = get_type_info((PyTypeObject *) h.ptr())) {
+            for (auto &c : parent_tinfo->implicit_casts) {
+                if (c.first == tinfo->cpptype) {
+                    auto *parentptr = c.second(valueptr);
+                    if (parentptr != valueptr)
+                        f(parentptr, self);
+                    traverse_offset_bases(parentptr, parent_tinfo, self, f);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+inline bool register_instance_impl(void *ptr, instance *self) {
+    get_internals().registered_instances.emplace(ptr, self);
+    return true; // unused, but gives the same signature as the deregister func
+}
+inline bool deregister_instance_impl(void *ptr, instance *self) {
+    auto &registered_instances = get_internals().registered_instances;
+    auto range = registered_instances.equal_range(ptr);
+    for (auto it = range.first; it != range.second; ++it) {
+        if (Py_TYPE(self) == Py_TYPE(it->second)) {
+            registered_instances.erase(it);
+            return true;
+        }
+    }
+    return false;
+}
+
+inline void register_instance(instance *self, void *valptr, const type_info *tinfo) {
+    register_instance_impl(valptr, self);
+    if (!tinfo->simple_ancestors)
+        traverse_offset_bases(valptr, tinfo, self, register_instance_impl);
+}
+
+inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo) {
+    bool ret = deregister_instance_impl(valptr, self);
+    if (!tinfo->simple_ancestors)
+        traverse_offset_bases(valptr, tinfo, self, deregister_instance_impl);
+    return ret;
+}
+
+/// Instance creation function for all pybind11 types. It allocates the internal instance layout for
+/// holding C++ objects and holders.  Allocation is done lazily (the first time the instance is cast
+/// to a reference or pointer), and initialization is done by an `__init__` function.
+inline PyObject *make_new_instance(PyTypeObject *type) {
+#if defined(PYPY_VERSION)
+    // PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first inherited
+    // object is a a plain Python type (i.e. not derived from an extension type).  Fix it.
+    ssize_t instance_size = static_cast<ssize_t>(sizeof(instance));
+    if (type->tp_basicsize < instance_size) {
+        type->tp_basicsize = instance_size;
+    }
+#endif
+    PyObject *self = type->tp_alloc(type, 0);
+    auto inst = reinterpret_cast<instance *>(self);
+    // Allocate the value/holder internals:
+    inst->allocate_layout();
+
+    inst->owned = true;
+
+    return self;
+}
+
+/// Instance creation function for all pybind11 types. It only allocates space for the
+/// C++ object, but doesn't call the constructor -- an `__init__` function must do that.
+extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *) {
+    return make_new_instance(type);
+}
+
+/// An `__init__` function constructs the C++ object. Users should provide at least one
+/// of these using `py::init` or directly with `.def(__init__, ...)`. Otherwise, the
+/// following default function will be used which simply throws an exception.
+extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject *) {
+    PyTypeObject *type = Py_TYPE(self);
+    std::string msg;
+#if defined(PYPY_VERSION)
+    msg += handle((PyObject *) type).attr("__module__").cast<std::string>() + ".";
+#endif
+    msg += type->tp_name;
+    msg += ": No constructor defined!";
+    PyErr_SetString(PyExc_TypeError, msg.c_str());
+    return -1;
+}
+
+inline void add_patient(PyObject *nurse, PyObject *patient) {
+    auto &internals = get_internals();
+    auto instance = reinterpret_cast<detail::instance *>(nurse);
+    auto &current_patients = internals.patients[nurse];
+    instance->has_patients = true;
+    for (auto &p : current_patients)
+        if (p == patient)
+            return;
+    Py_INCREF(patient);
+    current_patients.push_back(patient);
+}
+
+inline void clear_patients(PyObject *self) {
+    auto instance = reinterpret_cast<detail::instance *>(self);
+    auto &internals = get_internals();
+    auto pos = internals.patients.find(self);
+    assert(pos != internals.patients.end());
+    // Clearing the patients can cause more Python code to run, which
+    // can invalidate the iterator. Extract the vector of patients
+    // from the unordered_map first.
+    auto patients = std::move(pos->second);
+    internals.patients.erase(pos);
+    instance->has_patients = false;
+    for (PyObject *&patient : patients)
+        Py_CLEAR(patient);
+}
+
+/// Clears all internal data from the instance and removes it from registered instances in
+/// preparation for deallocation.
+inline void clear_instance(PyObject *self) {
+    auto instance = reinterpret_cast<detail::instance *>(self);
+
+    // Deallocate any values/holders, if present:
+    for (auto &v_h : values_and_holders(instance)) {
+        if (v_h) {
+
+            // We have to deregister before we call dealloc because, for virtual MI types, we still
+            // need to be able to get the parent pointers.
+            if (v_h.instance_registered() && !deregister_instance(instance, v_h.value_ptr(), v_h.type))
+                pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!");
+
+            if (instance->owned || v_h.holder_constructed())
+                v_h.type->dealloc(v_h);
+        }
+    }
+    // Deallocate the value/holder layout internals:
+    instance->deallocate_layout();
+
+    if (instance->weakrefs)
+        PyObject_ClearWeakRefs(self);
+
+    PyObject **dict_ptr = _PyObject_GetDictPtr(self);
+    if (dict_ptr)
+        Py_CLEAR(*dict_ptr);
+
+    if (instance->has_patients)
+        clear_patients(self);
+}
+
+/// Instance destructor function for all pybind11 types. It calls `type_info.dealloc`
+/// to destroy the C++ object itself, while the rest is Python bookkeeping.
+extern "C" inline void pybind11_object_dealloc(PyObject *self) {
+    clear_instance(self);
+
+    auto type = Py_TYPE(self);
+    type->tp_free(self);
+
+    // `type->tp_dealloc != pybind11_object_dealloc` means that we're being called
+    // as part of a derived type's dealloc, in which case we're not allowed to decref
+    // the type here. For cross-module compatibility, we shouldn't compare directly
+    // with `pybind11_object_dealloc`, but with the common one stashed in internals.
+    auto pybind11_object_type = (PyTypeObject *) get_internals().instance_base;
+    if (type->tp_dealloc == pybind11_object_type->tp_dealloc)
+        Py_DECREF(type);
+}
+
+/** Create the type which can be used as a common base for all classes.  This is
+    needed in order to satisfy Python's requirements for multiple inheritance.
+    Return value: New reference. */
+inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
+    constexpr auto *name = "pybind11_object";
+    auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
+
+    /* Danger zone: from now (and until PyType_Ready), make sure to
+       issue no Python C API calls which could potentially invoke the
+       garbage collector (the GC will call type_traverse(), which will in
+       turn find the newly constructed type in an invalid state) */
+    auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
+    if (!heap_type)
+        pybind11_fail("make_object_base_type(): error allocating type!");
+
+    heap_type->ht_name = name_obj.inc_ref().ptr();
+#ifdef PYBIND11_BUILTIN_QUALNAME
+    heap_type->ht_qualname = name_obj.inc_ref().ptr();
+#endif
+
+    auto type = &heap_type->ht_type;
+    type->tp_name = name;
+    type->tp_base = type_incref(&PyBaseObject_Type);
+    type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
+    type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
+
+    type->tp_new = pybind11_object_new;
+    type->tp_init = pybind11_object_init;
+    type->tp_dealloc = pybind11_object_dealloc;
+
+    /* Support weak references (needed for the keep_alive feature) */
+    type->tp_weaklistoffset = offsetof(instance, weakrefs);
+
+    if (PyType_Ready(type) < 0)
+        pybind11_fail("PyType_Ready failed in make_object_base_type():" + error_string());
+
+    setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
+    PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
+
+    assert(!PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
+    return (PyObject *) heap_type;
+}
+
+/// dynamic_attr: Support for `d = instance.__dict__`.
+extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) {
+    PyObject *&dict = *_PyObject_GetDictPtr(self);
+    if (!dict)
+        dict = PyDict_New();
+    Py_XINCREF(dict);
+    return dict;
+}
+
+/// dynamic_attr: Support for `instance.__dict__ = dict()`.
+extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void *) {
+    if (!PyDict_Check(new_dict)) {
+        PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'",
+                     Py_TYPE(new_dict)->tp_name);
+        return -1;
+    }
+    PyObject *&dict = *_PyObject_GetDictPtr(self);
+    Py_INCREF(new_dict);
+    Py_CLEAR(dict);
+    dict = new_dict;
+    return 0;
+}
+
+/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`.
+extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {
+    PyObject *&dict = *_PyObject_GetDictPtr(self);
+    Py_VISIT(dict);
+    return 0;
+}
+
+/// dynamic_attr: Allow the GC to clear the dictionary.
+extern "C" inline int pybind11_clear(PyObject *self) {
+    PyObject *&dict = *_PyObject_GetDictPtr(self);
+    Py_CLEAR(dict);
+    return 0;
+}
+
+/// Give instances of this type a `__dict__` and opt into garbage collection.
+inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
+    auto type = &heap_type->ht_type;
+#if defined(PYPY_VERSION)
+    pybind11_fail(std::string(type->tp_name) + ": dynamic attributes are "
+                                               "currently not supported in "
+                                               "conjunction with PyPy!");
+#endif
+    type->tp_flags |= Py_TPFLAGS_HAVE_GC;
+    type->tp_dictoffset = type->tp_basicsize; // place dict at the end
+    type->tp_basicsize += (ssize_t)sizeof(PyObject *); // and allocate enough space for it
+    type->tp_traverse = pybind11_traverse;
+    type->tp_clear = pybind11_clear;
+
+    static PyGetSetDef getset[] = {
+        {const_cast<char*>("__dict__"), pybind11_get_dict, pybind11_set_dict, nullptr, nullptr},
+        {nullptr, nullptr, nullptr, nullptr, nullptr}
+    };
+    type->tp_getset = getset;
+}
+
+/// buffer_protocol: Fill in the view as specified by flags.
+extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int flags) {
+    // Look for a `get_buffer` implementation in this type's info or any bases (following MRO).
+    type_info *tinfo = nullptr;
+    for (auto type : reinterpret_borrow<tuple>(Py_TYPE(obj)->tp_mro)) {
+        tinfo = get_type_info((PyTypeObject *) type.ptr());
+        if (tinfo && tinfo->get_buffer)
+            break;
+    }
+    if (view == nullptr || obj == nullptr || !tinfo || !tinfo->get_buffer) {
+        if (view)
+            view->obj = nullptr;
+        PyErr_SetString(PyExc_BufferError, "pybind11_getbuffer(): Internal error");
+        return -1;
+    }
+    std::memset(view, 0, sizeof(Py_buffer));
+    buffer_info *info = tinfo->get_buffer(obj, tinfo->get_buffer_data);
+    view->obj = obj;
+    view->ndim = 1;
+    view->internal = info;
+    view->buf = info->ptr;
+    view->itemsize = info->itemsize;
+    view->len = view->itemsize;
+    for (auto s : info->shape)
+        view->len *= s;
+    if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
+        view->format = const_cast<char *>(info->format.c_str());
+    if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
+        view->ndim = (int) info->ndim;
+        view->strides = &info->strides[0];
+        view->shape = &info->shape[0];
+    }
+    Py_INCREF(view->obj);
+    return 0;
+}
+
+/// buffer_protocol: Release the resources of the buffer.
+extern "C" inline void pybind11_releasebuffer(PyObject *, Py_buffer *view) {
+    delete (buffer_info *) view->internal;
+}
+
+/// Give this type a buffer interface.
+inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) {
+    heap_type->ht_type.tp_as_buffer = &heap_type->as_buffer;
+#if PY_MAJOR_VERSION < 3
+    heap_type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
+#endif
+
+    heap_type->as_buffer.bf_getbuffer = pybind11_getbuffer;
+    heap_type->as_buffer.bf_releasebuffer = pybind11_releasebuffer;
+}
+
+/** Create a brand new Python type according to the `type_record` specification.
+    Return value: New reference. */
+inline PyObject* make_new_python_type(const type_record &rec) {
+    auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec.name));
+
+    auto qualname = name;
+    if (rec.scope && !PyModule_Check(rec.scope.ptr()) && hasattr(rec.scope, "__qualname__")) {
+#if PY_MAJOR_VERSION >= 3
+        qualname = reinterpret_steal<object>(
+            PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name.ptr()));
+#else
+        qualname = str(rec.scope.attr("__qualname__").cast<std::string>() + "." + rec.name);
+#endif
+    }
+
+    object module;
+    if (rec.scope) {
+        if (hasattr(rec.scope, "__module__"))
+            module = rec.scope.attr("__module__");
+        else if (hasattr(rec.scope, "__name__"))
+            module = rec.scope.attr("__name__");
+    }
+
+    auto full_name = c_str(
+#if !defined(PYPY_VERSION)
+        module ? str(module).cast<std::string>() + "." + rec.name :
+#endif
+        rec.name);
+
+    char *tp_doc = nullptr;
+    if (rec.doc && options::show_user_defined_docstrings()) {
+        /* Allocate memory for docstring (using PyObject_MALLOC, since
+           Python will free this later on) */
+        size_t size = strlen(rec.doc) + 1;
+        tp_doc = (char *) PyObject_MALLOC(size);
+        memcpy((void *) tp_doc, rec.doc, size);
+    }
+
+    auto &internals = get_internals();
+    auto bases = tuple(rec.bases);
+    auto base = (bases.size() == 0) ? internals.instance_base
+                                    : bases[0].ptr();
+
+    /* Danger zone: from now (and until PyType_Ready), make sure to
+       issue no Python C API calls which could potentially invoke the
+       garbage collector (the GC will call type_traverse(), which will in
+       turn find the newly constructed type in an invalid state) */
+    auto metaclass = rec.metaclass.ptr() ? (PyTypeObject *) rec.metaclass.ptr()
+                                         : internals.default_metaclass;
+
+    auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
+    if (!heap_type)
+        pybind11_fail(std::string(rec.name) + ": Unable to create type object!");
+
+    heap_type->ht_name = name.release().ptr();
+#ifdef PYBIND11_BUILTIN_QUALNAME
+    heap_type->ht_qualname = qualname.inc_ref().ptr();
+#endif
+
+    auto type = &heap_type->ht_type;
+    type->tp_name = full_name;
+    type->tp_doc = tp_doc;
+    type->tp_base = type_incref((PyTypeObject *)base);
+    type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
+    if (bases.size() > 0)
+        type->tp_bases = bases.release().ptr();
+
+    /* Don't inherit base __init__ */
+    type->tp_init = pybind11_object_init;
+
+    /* Supported protocols */
+    type->tp_as_number = &heap_type->as_number;
+    type->tp_as_sequence = &heap_type->as_sequence;
+    type->tp_as_mapping = &heap_type->as_mapping;
+
+    /* Flags */
+    type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
+#if PY_MAJOR_VERSION < 3
+    type->tp_flags |= Py_TPFLAGS_CHECKTYPES;
+#endif
+
+    if (rec.dynamic_attr)
+        enable_dynamic_attributes(heap_type);
+
+    if (rec.buffer_protocol)
+        enable_buffer_protocol(heap_type);
+
+    if (PyType_Ready(type) < 0)
+        pybind11_fail(std::string(rec.name) + ": PyType_Ready failed (" + error_string() + ")!");
+
+    assert(rec.dynamic_attr ? PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC)
+                            : !PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
+
+    /* Register type with the parent scope */
+    if (rec.scope)
+        setattr(rec.scope, rec.name, (PyObject *) type);
+    else
+        Py_INCREF(type); // Keep it alive forever (reference leak)
+
+    if (module) // Needed by pydoc
+        setattr((PyObject *) type, "__module__", module);
+
+    PYBIND11_SET_OLDPY_QUALNAME(type, qualname);
+
+    return (PyObject *) type;
+}
+
+NAMESPACE_END(detail)
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/common.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/common.h
new file mode 100644
index 0000000000000000000000000000000000000000..892de0f8fdcbf7ef2a1c132d78f0eab773d0802c
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/common.h
@@ -0,0 +1,803 @@
+/*
+    pybind11/detail/common.h -- Basic macros
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#if !defined(NAMESPACE_BEGIN)
+#  define NAMESPACE_BEGIN(name) namespace name {
+#endif
+#if !defined(NAMESPACE_END)
+#  define NAMESPACE_END(name) }
+#endif
+
+// Robust support for some features and loading modules compiled against different pybind versions
+// requires forcing hidden visibility on pybind code, so we enforce this by setting the attribute on
+// the main `pybind11` namespace.
+#if !defined(PYBIND11_NAMESPACE)
+#  ifdef __GNUG__
+#    define PYBIND11_NAMESPACE pybind11 __attribute__((visibility("hidden")))
+#  else
+#    define PYBIND11_NAMESPACE pybind11
+#  endif
+#endif
+
+#if !(defined(_MSC_VER) && __cplusplus == 199711L) && !defined(__INTEL_COMPILER)
+#  if __cplusplus >= 201402L
+#    define PYBIND11_CPP14
+#    if __cplusplus >= 201703L
+#      define PYBIND11_CPP17
+#    endif
+#  endif
+#elif defined(_MSC_VER) && __cplusplus == 199711L
+// MSVC sets _MSVC_LANG rather than __cplusplus (supposedly until the standard is fully implemented)
+// Unless you use the /Zc:__cplusplus flag on Visual Studio 2017 15.7 Preview 3 or newer
+#  if _MSVC_LANG >= 201402L
+#    define PYBIND11_CPP14
+#    if _MSVC_LANG > 201402L && _MSC_VER >= 1910
+#      define PYBIND11_CPP17
+#    endif
+#  endif
+#endif
+
+// Compiler version assertions
+#if defined(__INTEL_COMPILER)
+#  if __INTEL_COMPILER < 1700
+#    error pybind11 requires Intel C++ compiler v17 or newer
+#  endif
+#elif defined(__clang__) && !defined(__apple_build_version__)
+#  if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 3)
+#    error pybind11 requires clang 3.3 or newer
+#  endif
+#elif defined(__clang__)
+// Apple changes clang version macros to its Xcode version; the first Xcode release based on
+// (upstream) clang 3.3 was Xcode 5:
+#  if __clang_major__ < 5
+#    error pybind11 requires Xcode/clang 5.0 or newer
+#  endif
+#elif defined(__GNUG__)
+#  if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)
+#    error pybind11 requires gcc 4.8 or newer
+#  endif
+#elif defined(_MSC_VER)
+// Pybind hits various compiler bugs in 2015u2 and earlier, and also makes use of some stl features
+// (e.g. std::negation) added in 2015u3:
+#  if _MSC_FULL_VER < 190024210
+#    error pybind11 requires MSVC 2015 update 3 or newer
+#  endif
+#endif
+
+#if !defined(PYBIND11_EXPORT)
+#  if defined(WIN32) || defined(_WIN32)
+#    define PYBIND11_EXPORT __declspec(dllexport)
+#  else
+#    define PYBIND11_EXPORT __attribute__ ((visibility("default")))
+#  endif
+#endif
+
+#if defined(_MSC_VER)
+#  define PYBIND11_NOINLINE __declspec(noinline)
+#else
+#  define PYBIND11_NOINLINE __attribute__ ((noinline))
+#endif
+
+#if defined(PYBIND11_CPP14)
+#  define PYBIND11_DEPRECATED(reason) [[deprecated(reason)]]
+#else
+#  define PYBIND11_DEPRECATED(reason) __attribute__((deprecated(reason)))
+#endif
+
+#define PYBIND11_VERSION_MAJOR 2
+#define PYBIND11_VERSION_MINOR 2
+#define PYBIND11_VERSION_PATCH 4
+
+/// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode
+#if defined(_MSC_VER)
+#  if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 4)
+#    define HAVE_ROUND 1
+#  endif
+#  pragma warning(push)
+#  pragma warning(disable: 4510 4610 4512 4005)
+#  if defined(_DEBUG)
+#    define PYBIND11_DEBUG_MARKER
+#    undef _DEBUG
+#  endif
+#endif
+
+#include <Python.h>
+#include <frameobject.h>
+#include <pythread.h>
+
+#if defined(_WIN32) && (defined(min) || defined(max))
+#  error Macro clash with min and max -- define NOMINMAX when compiling your program on Windows
+#endif
+
+#if defined(isalnum)
+#  undef isalnum
+#  undef isalpha
+#  undef islower
+#  undef isspace
+#  undef isupper
+#  undef tolower
+#  undef toupper
+#endif
+
+#if defined(_MSC_VER)
+#  if defined(PYBIND11_DEBUG_MARKER)
+#    define _DEBUG
+#    undef PYBIND11_DEBUG_MARKER
+#  endif
+#  pragma warning(pop)
+#endif
+
+#include <cstddef>
+#include <cstring>
+#include <forward_list>
+#include <vector>
+#include <string>
+#include <stdexcept>
+#include <unordered_set>
+#include <unordered_map>
+#include <memory>
+#include <typeindex>
+#include <type_traits>
+
+#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions
+#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)
+#define PYBIND11_INSTANCE_METHOD_CHECK PyInstanceMethod_Check
+#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyInstanceMethod_GET_FUNCTION
+#define PYBIND11_BYTES_CHECK PyBytes_Check
+#define PYBIND11_BYTES_FROM_STRING PyBytes_FromString
+#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
+#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize
+#define PYBIND11_BYTES_AS_STRING PyBytes_AsString
+#define PYBIND11_BYTES_SIZE PyBytes_Size
+#define PYBIND11_LONG_CHECK(o) PyLong_Check(o)
+#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)
+#define PYBIND11_BYTES_NAME "bytes"
+#define PYBIND11_STRING_NAME "str"
+#define PYBIND11_SLICE_OBJECT PyObject
+#define PYBIND11_FROM_STRING PyUnicode_FromString
+#define PYBIND11_STR_TYPE ::pybind11::str
+#define PYBIND11_BOOL_ATTR "__bool__"
+#define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool)
+#define PYBIND11_PLUGIN_IMPL(name) \
+    extern "C" PYBIND11_EXPORT PyObject *PyInit_##name()
+
+#else
+#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyMethod_New(ptr, nullptr, class_)
+#define PYBIND11_INSTANCE_METHOD_CHECK PyMethod_Check
+#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyMethod_GET_FUNCTION
+#define PYBIND11_BYTES_CHECK PyString_Check
+#define PYBIND11_BYTES_FROM_STRING PyString_FromString
+#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize
+#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyString_AsStringAndSize
+#define PYBIND11_BYTES_AS_STRING PyString_AsString
+#define PYBIND11_BYTES_SIZE PyString_Size
+#define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o))
+#define PYBIND11_LONG_AS_LONGLONG(o) (PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o))
+#define PYBIND11_BYTES_NAME "str"
+#define PYBIND11_STRING_NAME "unicode"
+#define PYBIND11_SLICE_OBJECT PySliceObject
+#define PYBIND11_FROM_STRING PyString_FromString
+#define PYBIND11_STR_TYPE ::pybind11::bytes
+#define PYBIND11_BOOL_ATTR "__nonzero__"
+#define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_nonzero)
+#define PYBIND11_PLUGIN_IMPL(name) \
+    static PyObject *pybind11_init_wrapper();               \
+    extern "C" PYBIND11_EXPORT void init##name() {          \
+        (void)pybind11_init_wrapper();                      \
+    }                                                       \
+    PyObject *pybind11_init_wrapper()
+#endif
+
+#if PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03050200
+extern "C" {
+    struct _Py_atomic_address { void *value; };
+    PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current;
+}
+#endif
+
+#define PYBIND11_TRY_NEXT_OVERLOAD ((PyObject *) 1) // special failure return code
+#define PYBIND11_STRINGIFY(x) #x
+#define PYBIND11_TOSTRING(x) PYBIND11_STRINGIFY(x)
+#define PYBIND11_CONCAT(first, second) first##second
+
+/** \rst
+    ***Deprecated in favor of PYBIND11_MODULE***
+
+    This macro creates the entry point that will be invoked when the Python interpreter
+    imports a plugin library. Please create a `module` in the function body and return
+    the pointer to its underlying Python object at the end.
+
+    .. code-block:: cpp
+
+        PYBIND11_PLUGIN(example) {
+            pybind11::module m("example", "pybind11 example plugin");
+            /// Set up bindings here
+            return m.ptr();
+        }
+\endrst */
+#define PYBIND11_PLUGIN(name)                                                  \
+    PYBIND11_DEPRECATED("PYBIND11_PLUGIN is deprecated, use PYBIND11_MODULE")  \
+    static PyObject *pybind11_init();                                          \
+    PYBIND11_PLUGIN_IMPL(name) {                                               \
+        int major, minor;                                                      \
+        if (sscanf(Py_GetVersion(), "%i.%i", &major, &minor) != 2) {           \
+            PyErr_SetString(PyExc_ImportError, "Can't parse Python version."); \
+            return nullptr;                                                    \
+        } else if (major != PY_MAJOR_VERSION || minor != PY_MINOR_VERSION) {   \
+            PyErr_Format(PyExc_ImportError,                                    \
+                         "Python version mismatch: module was compiled for "   \
+                         "version %i.%i, while the interpreter is running "    \
+                         "version %i.%i.", PY_MAJOR_VERSION, PY_MINOR_VERSION, \
+                         major, minor);                                        \
+            return nullptr;                                                    \
+        }                                                                      \
+        try {                                                                  \
+            return pybind11_init();                                            \
+        } catch (pybind11::error_already_set &e) {                             \
+            PyErr_SetString(PyExc_ImportError, e.what());                      \
+            return nullptr;                                                    \
+        } catch (const std::exception &e) {                                    \
+            PyErr_SetString(PyExc_ImportError, e.what());                      \
+            return nullptr;                                                    \
+        }                                                                      \
+    }                                                                          \
+    PyObject *pybind11_init()
+
+/** \rst
+    This macro creates the entry point that will be invoked when the Python interpreter
+    imports an extension module. The module name is given as the fist argument and it
+    should not be in quotes. The second macro argument defines a variable of type
+    `py::module` which can be used to initialize the module.
+
+    .. code-block:: cpp
+
+        PYBIND11_MODULE(example, m) {
+            m.doc() = "pybind11 example module";
+
+            // Add bindings here
+            m.def("foo", []() {
+                return "Hello, World!";
+            });
+        }
+\endrst */
+#define PYBIND11_MODULE(name, variable)                                        \
+    static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &);     \
+    PYBIND11_PLUGIN_IMPL(name) {                                               \
+        int major, minor;                                                      \
+        if (sscanf(Py_GetVersion(), "%i.%i", &major, &minor) != 2) {           \
+            PyErr_SetString(PyExc_ImportError, "Can't parse Python version."); \
+            return nullptr;                                                    \
+        } else if (major != PY_MAJOR_VERSION || minor != PY_MINOR_VERSION) {   \
+            PyErr_Format(PyExc_ImportError,                                    \
+                         "Python version mismatch: module was compiled for "   \
+                         "version %i.%i, while the interpreter is running "    \
+                         "version %i.%i.", PY_MAJOR_VERSION, PY_MINOR_VERSION, \
+                         major, minor);                                        \
+            return nullptr;                                                    \
+        }                                                                      \
+        auto m = pybind11::module(PYBIND11_TOSTRING(name));                    \
+        try {                                                                  \
+            PYBIND11_CONCAT(pybind11_init_, name)(m);                          \
+            return m.ptr();                                                    \
+        } catch (pybind11::error_already_set &e) {                             \
+            PyErr_SetString(PyExc_ImportError, e.what());                      \
+            return nullptr;                                                    \
+        } catch (const std::exception &e) {                                    \
+            PyErr_SetString(PyExc_ImportError, e.what());                      \
+            return nullptr;                                                    \
+        }                                                                      \
+    }                                                                          \
+    void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &variable)
+
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+
+using ssize_t = Py_ssize_t;
+using size_t  = std::size_t;
+
+/// Approach used to cast a previously unknown C++ instance into a Python object
+enum class return_value_policy : uint8_t {
+    /** This is the default return value policy, which falls back to the policy
+        return_value_policy::take_ownership when the return value is a pointer.
+        Otherwise, it uses return_value::move or return_value::copy for rvalue
+        and lvalue references, respectively. See below for a description of what
+        all of these different policies do. */
+    automatic = 0,
+
+    /** As above, but use policy return_value_policy::reference when the return
+        value is a pointer. This is the default conversion policy for function
+        arguments when calling Python functions manually from C++ code (i.e. via
+        handle::operator()). You probably won't need to use this. */
+    automatic_reference,
+
+    /** Reference an existing object (i.e. do not create a new copy) and take
+        ownership. Python will call the destructor and delete operator when the
+        object’s reference count reaches zero. Undefined behavior ensues when
+        the C++ side does the same.. */
+    take_ownership,
+
+    /** Create a new copy of the returned object, which will be owned by
+        Python. This policy is comparably safe because the lifetimes of the two
+        instances are decoupled. */
+    copy,
+
+    /** Use std::move to move the return value contents into a new instance
+        that will be owned by Python. This policy is comparably safe because the
+        lifetimes of the two instances (move source and destination) are
+        decoupled. */
+    move,
+
+    /** Reference an existing object, but do not take ownership. The C++ side
+        is responsible for managing the object’s lifetime and deallocating it
+        when it is no longer used. Warning: undefined behavior will ensue when
+        the C++ side deletes an object that is still referenced and used by
+        Python. */
+    reference,
+
+    /** This policy only applies to methods and properties. It references the
+        object without taking ownership similar to the above
+        return_value_policy::reference policy. In contrast to that policy, the
+        function or property’s implicit this argument (called the parent) is
+        considered to be the the owner of the return value (the child).
+        pybind11 then couples the lifetime of the parent to the child via a
+        reference relationship that ensures that the parent cannot be garbage
+        collected while Python is still using the child. More advanced
+        variations of this scheme are also possible using combinations of
+        return_value_policy::reference and the keep_alive call policy */
+    reference_internal
+};
+
+NAMESPACE_BEGIN(detail)
+
+inline static constexpr int log2(size_t n, int k = 0) { return (n <= 1) ? k : log2(n >> 1, k + 1); }
+
+// Returns the size as a multiple of sizeof(void *), rounded up.
+inline static constexpr size_t size_in_ptrs(size_t s) { return 1 + ((s - 1) >> log2(sizeof(void *))); }
+
+/**
+ * The space to allocate for simple layout instance holders (see below) in multiple of the size of
+ * a pointer (e.g.  2 means 16 bytes on 64-bit architectures).  The default is the minimum required
+ * to holder either a std::unique_ptr or std::shared_ptr (which is almost always
+ * sizeof(std::shared_ptr<T>)).
+ */
+constexpr size_t instance_simple_holder_in_ptrs() {
+    static_assert(sizeof(std::shared_ptr<int>) >= sizeof(std::unique_ptr<int>),
+            "pybind assumes std::shared_ptrs are at least as big as std::unique_ptrs");
+    return size_in_ptrs(sizeof(std::shared_ptr<int>));
+}
+
+// Forward declarations
+struct type_info;
+struct value_and_holder;
+
+struct nonsimple_values_and_holders {
+    void **values_and_holders;
+    uint8_t *status;
+};
+
+/// The 'instance' type which needs to be standard layout (need to be able to use 'offsetof')
+struct instance {
+    PyObject_HEAD
+    /// Storage for pointers and holder; see simple_layout, below, for a description
+    union {
+        void *simple_value_holder[1 + instance_simple_holder_in_ptrs()];
+        nonsimple_values_and_holders nonsimple;
+    };
+    /// Weak references (needed for keep alive):
+    PyObject *weakrefs;
+    /// If true, the pointer is owned which means we're free to manage it with a holder.
+    bool owned : 1;
+    /**
+     * An instance has two possible value/holder layouts.
+     *
+     * Simple layout (when this flag is true), means the `simple_value_holder` is set with a pointer
+     * and the holder object governing that pointer, i.e. [val1*][holder].  This layout is applied
+     * whenever there is no python-side multiple inheritance of bound C++ types *and* the type's
+     * holder will fit in the default space (which is large enough to hold either a std::unique_ptr
+     * or std::shared_ptr).
+     *
+     * Non-simple layout applies when using custom holders that require more space than `shared_ptr`
+     * (which is typically the size of two pointers), or when multiple inheritance is used on the
+     * python side.  Non-simple layout allocates the required amount of memory to have multiple
+     * bound C++ classes as parents.  Under this layout, `nonsimple.values_and_holders` is set to a
+     * pointer to allocated space of the required space to hold a a sequence of value pointers and
+     * holders followed `status`, a set of bit flags (1 byte each), i.e.
+     * [val1*][holder1][val2*][holder2]...[bb...]  where each [block] is rounded up to a multiple of
+     * `sizeof(void *)`.  `nonsimple.holder_constructed` is, for convenience, a pointer to the
+     * beginning of the [bb...] block (but not independently allocated).
+     *
+     * Status bits indicate whether the associated holder is constructed (&
+     * status_holder_constructed) and whether the value pointer is registered (&
+     * status_instance_registered) in `registered_instances`.
+     */
+    bool simple_layout : 1;
+    /// For simple layout, tracks whether the holder has been constructed
+    bool simple_holder_constructed : 1;
+    /// For simple layout, tracks whether the instance is registered in `registered_instances`
+    bool simple_instance_registered : 1;
+    /// If true, get_internals().patients has an entry for this object
+    bool has_patients : 1;
+
+    /// Initializes all of the above type/values/holders data (but not the instance values themselves)
+    void allocate_layout();
+
+    /// Destroys/deallocates all of the above
+    void deallocate_layout();
+
+    /// Returns the value_and_holder wrapper for the given type (or the first, if `find_type`
+    /// omitted).  Returns a default-constructed (with `.inst = nullptr`) object on failure if
+    /// `throw_if_missing` is false.
+    value_and_holder get_value_and_holder(const type_info *find_type = nullptr, bool throw_if_missing = true);
+
+    /// Bit values for the non-simple status flags
+    static constexpr uint8_t status_holder_constructed  = 1;
+    static constexpr uint8_t status_instance_registered = 2;
+};
+
+static_assert(std::is_standard_layout<instance>::value, "Internal error: `pybind11::detail::instance` is not standard layout!");
+
+/// from __cpp_future__ import (convenient aliases from C++14/17)
+#if defined(PYBIND11_CPP14) && (!defined(_MSC_VER) || _MSC_VER >= 1910)
+using std::enable_if_t;
+using std::conditional_t;
+using std::remove_cv_t;
+using std::remove_reference_t;
+#else
+template <bool B, typename T = void> using enable_if_t = typename std::enable_if<B, T>::type;
+template <bool B, typename T, typename F> using conditional_t = typename std::conditional<B, T, F>::type;
+template <typename T> using remove_cv_t = typename std::remove_cv<T>::type;
+template <typename T> using remove_reference_t = typename std::remove_reference<T>::type;
+#endif
+
+/// Index sequences
+#if defined(PYBIND11_CPP14)
+using std::index_sequence;
+using std::make_index_sequence;
+#else
+template<size_t ...> struct index_sequence  { };
+template<size_t N, size_t ...S> struct make_index_sequence_impl : make_index_sequence_impl <N - 1, N - 1, S...> { };
+template<size_t ...S> struct make_index_sequence_impl <0, S...> { typedef index_sequence<S...> type; };
+template<size_t N> using make_index_sequence = typename make_index_sequence_impl<N>::type;
+#endif
+
+/// Make an index sequence of the indices of true arguments
+template <typename ISeq, size_t, bool...> struct select_indices_impl { using type = ISeq; };
+template <size_t... IPrev, size_t I, bool B, bool... Bs> struct select_indices_impl<index_sequence<IPrev...>, I, B, Bs...>
+    : select_indices_impl<conditional_t<B, index_sequence<IPrev..., I>, index_sequence<IPrev...>>, I + 1, Bs...> {};
+template <bool... Bs> using select_indices = typename select_indices_impl<index_sequence<>, 0, Bs...>::type;
+
+/// Backports of std::bool_constant and std::negation to accommodate older compilers
+template <bool B> using bool_constant = std::integral_constant<bool, B>;
+template <typename T> struct negation : bool_constant<!T::value> { };
+
+template <typename...> struct void_t_impl { using type = void; };
+template <typename... Ts> using void_t = typename void_t_impl<Ts...>::type;
+
+/// Compile-time all/any/none of that check the boolean value of all template types
+#if defined(__cpp_fold_expressions) && !(defined(_MSC_VER) && (_MSC_VER < 1916))
+template <class... Ts> using all_of = bool_constant<(Ts::value && ...)>;
+template <class... Ts> using any_of = bool_constant<(Ts::value || ...)>;
+#elif !defined(_MSC_VER)
+template <bool...> struct bools {};
+template <class... Ts> using all_of = std::is_same<
+    bools<Ts::value..., true>,
+    bools<true, Ts::value...>>;
+template <class... Ts> using any_of = negation<all_of<negation<Ts>...>>;
+#else
+// MSVC has trouble with the above, but supports std::conjunction, which we can use instead (albeit
+// at a slight loss of compilation efficiency).
+template <class... Ts> using all_of = std::conjunction<Ts...>;
+template <class... Ts> using any_of = std::disjunction<Ts...>;
+#endif
+template <class... Ts> using none_of = negation<any_of<Ts...>>;
+
+template <class T, template<class> class... Predicates> using satisfies_all_of = all_of<Predicates<T>...>;
+template <class T, template<class> class... Predicates> using satisfies_any_of = any_of<Predicates<T>...>;
+template <class T, template<class> class... Predicates> using satisfies_none_of = none_of<Predicates<T>...>;
+
+/// Strip the class from a method type
+template <typename T> struct remove_class { };
+template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...)> { typedef R type(A...); };
+template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...) const> { typedef R type(A...); };
+
+/// Helper template to strip away type modifiers
+template <typename T> struct intrinsic_type                       { typedef T type; };
+template <typename T> struct intrinsic_type<const T>              { typedef typename intrinsic_type<T>::type type; };
+template <typename T> struct intrinsic_type<T*>                   { typedef typename intrinsic_type<T>::type type; };
+template <typename T> struct intrinsic_type<T&>                   { typedef typename intrinsic_type<T>::type type; };
+template <typename T> struct intrinsic_type<T&&>                  { typedef typename intrinsic_type<T>::type type; };
+template <typename T, size_t N> struct intrinsic_type<const T[N]> { typedef typename intrinsic_type<T>::type type; };
+template <typename T, size_t N> struct intrinsic_type<T[N]>       { typedef typename intrinsic_type<T>::type type; };
+template <typename T> using intrinsic_t = typename intrinsic_type<T>::type;
+
+/// Helper type to replace 'void' in some expressions
+struct void_type { };
+
+/// Helper template which holds a list of types
+template <typename...> struct type_list { };
+
+/// Compile-time integer sum
+#ifdef __cpp_fold_expressions
+template <typename... Ts> constexpr size_t constexpr_sum(Ts... ns) { return (0 + ... + size_t{ns}); }
+#else
+constexpr size_t constexpr_sum() { return 0; }
+template <typename T, typename... Ts>
+constexpr size_t constexpr_sum(T n, Ts... ns) { return size_t{n} + constexpr_sum(ns...); }
+#endif
+
+NAMESPACE_BEGIN(constexpr_impl)
+/// Implementation details for constexpr functions
+constexpr int first(int i) { return i; }
+template <typename T, typename... Ts>
+constexpr int first(int i, T v, Ts... vs) { return v ? i : first(i + 1, vs...); }
+
+constexpr int last(int /*i*/, int result) { return result; }
+template <typename T, typename... Ts>
+constexpr int last(int i, int result, T v, Ts... vs) { return last(i + 1, v ? i : result, vs...); }
+NAMESPACE_END(constexpr_impl)
+
+/// Return the index of the first type in Ts which satisfies Predicate<T>.  Returns sizeof...(Ts) if
+/// none match.
+template <template<typename> class Predicate, typename... Ts>
+constexpr int constexpr_first() { return constexpr_impl::first(0, Predicate<Ts>::value...); }
+
+/// Return the index of the last type in Ts which satisfies Predicate<T>, or -1 if none match.
+template <template<typename> class Predicate, typename... Ts>
+constexpr int constexpr_last() { return constexpr_impl::last(0, -1, Predicate<Ts>::value...); }
+
+/// Return the Nth element from the parameter pack
+template <size_t N, typename T, typename... Ts>
+struct pack_element { using type = typename pack_element<N - 1, Ts...>::type; };
+template <typename T, typename... Ts>
+struct pack_element<0, T, Ts...> { using type = T; };
+
+/// Return the one and only type which matches the predicate, or Default if none match.
+/// If more than one type matches the predicate, fail at compile-time.
+template <template<typename> class Predicate, typename Default, typename... Ts>
+struct exactly_one {
+    static constexpr auto found = constexpr_sum(Predicate<Ts>::value...);
+    static_assert(found <= 1, "Found more than one type matching the predicate");
+
+    static constexpr auto index = found ? constexpr_first<Predicate, Ts...>() : 0;
+    using type = conditional_t<found, typename pack_element<index, Ts...>::type, Default>;
+};
+template <template<typename> class P, typename Default>
+struct exactly_one<P, Default> { using type = Default; };
+
+template <template<typename> class Predicate, typename Default, typename... Ts>
+using exactly_one_t = typename exactly_one<Predicate, Default, Ts...>::type;
+
+/// Defer the evaluation of type T until types Us are instantiated
+template <typename T, typename... /*Us*/> struct deferred_type { using type = T; };
+template <typename T, typename... Us> using deferred_t = typename deferred_type<T, Us...>::type;
+
+/// Like is_base_of, but requires a strict base (i.e. `is_strict_base_of<T, T>::value == false`,
+/// unlike `std::is_base_of`)
+template <typename Base, typename Derived> using is_strict_base_of = bool_constant<
+    std::is_base_of<Base, Derived>::value && !std::is_same<Base, Derived>::value>;
+
+template <template<typename...> class Base>
+struct is_template_base_of_impl {
+    template <typename... Us> static std::true_type check(Base<Us...> *);
+    static std::false_type check(...);
+};
+
+/// Check if a template is the base of a type. For example:
+/// `is_template_base_of<Base, T>` is true if `struct T : Base<U> {}` where U can be anything
+template <template<typename...> class Base, typename T>
+#if !defined(_MSC_VER)
+using is_template_base_of = decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T>*)nullptr));
+#else // MSVC2015 has trouble with decltype in template aliases
+struct is_template_base_of : decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T>*)nullptr)) { };
+#endif
+
+/// Check if T is an instantiation of the template `Class`. For example:
+/// `is_instantiation<shared_ptr, T>` is true if `T == shared_ptr<U>` where U can be anything.
+template <template<typename...> class Class, typename T>
+struct is_instantiation : std::false_type { };
+template <template<typename...> class Class, typename... Us>
+struct is_instantiation<Class, Class<Us...>> : std::true_type { };
+
+/// Check if T is std::shared_ptr<U> where U can be anything
+template <typename T> using is_shared_ptr = is_instantiation<std::shared_ptr, T>;
+
+/// Check if T looks like an input iterator
+template <typename T, typename = void> struct is_input_iterator : std::false_type {};
+template <typename T>
+struct is_input_iterator<T, void_t<decltype(*std::declval<T &>()), decltype(++std::declval<T &>())>>
+    : std::true_type {};
+
+template <typename T> using is_function_pointer = bool_constant<
+    std::is_pointer<T>::value && std::is_function<typename std::remove_pointer<T>::type>::value>;
+
+template <typename F> struct strip_function_object {
+    using type = typename remove_class<decltype(&F::operator())>::type;
+};
+
+// Extracts the function signature from a function, function pointer or lambda.
+template <typename Function, typename F = remove_reference_t<Function>>
+using function_signature_t = conditional_t<
+    std::is_function<F>::value,
+    F,
+    typename conditional_t<
+        std::is_pointer<F>::value || std::is_member_pointer<F>::value,
+        std::remove_pointer<F>,
+        strip_function_object<F>
+    >::type
+>;
+
+/// Returns true if the type looks like a lambda: that is, isn't a function, pointer or member
+/// pointer.  Note that this can catch all sorts of other things, too; this is intended to be used
+/// in a place where passing a lambda makes sense.
+template <typename T> using is_lambda = satisfies_none_of<remove_reference_t<T>,
+        std::is_function, std::is_pointer, std::is_member_pointer>;
+
+/// Ignore that a variable is unused in compiler warnings
+inline void ignore_unused(const int *) { }
+
+/// Apply a function over each element of a parameter pack
+#ifdef __cpp_fold_expressions
+#define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) (((PATTERN), void()), ...)
+#else
+using expand_side_effects = bool[];
+#define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) pybind11::detail::expand_side_effects{ ((PATTERN), void(), false)..., false }
+#endif
+
+NAMESPACE_END(detail)
+
+/// C++ bindings of builtin Python exceptions
+class builtin_exception : public std::runtime_error {
+public:
+    using std::runtime_error::runtime_error;
+    /// Set the error using the Python C API
+    virtual void set_error() const = 0;
+};
+
+#define PYBIND11_RUNTIME_EXCEPTION(name, type) \
+    class name : public builtin_exception { public: \
+        using builtin_exception::builtin_exception; \
+        name() : name("") { } \
+        void set_error() const override { PyErr_SetString(type, what()); } \
+    };
+
+PYBIND11_RUNTIME_EXCEPTION(stop_iteration, PyExc_StopIteration)
+PYBIND11_RUNTIME_EXCEPTION(index_error, PyExc_IndexError)
+PYBIND11_RUNTIME_EXCEPTION(key_error, PyExc_KeyError)
+PYBIND11_RUNTIME_EXCEPTION(value_error, PyExc_ValueError)
+PYBIND11_RUNTIME_EXCEPTION(type_error, PyExc_TypeError)
+PYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_RuntimeError) /// Thrown when pybind11::cast or handle::call fail due to a type casting error
+PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally
+
+[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); }
+[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); }
+
+template <typename T, typename SFINAE = void> struct format_descriptor { };
+
+NAMESPACE_BEGIN(detail)
+// Returns the index of the given type in the type char array below, and in the list in numpy.h
+// The order here is: bool; 8 ints ((signed,unsigned)x(8,16,32,64)bits); float,double,long double;
+// complex float,double,long double.  Note that the long double types only participate when long
+// double is actually longer than double (it isn't under MSVC).
+// NB: not only the string below but also complex.h and numpy.h rely on this order.
+template <typename T, typename SFINAE = void> struct is_fmt_numeric { static constexpr bool value = false; };
+template <typename T> struct is_fmt_numeric<T, enable_if_t<std::is_arithmetic<T>::value>> {
+    static constexpr bool value = true;
+    static constexpr int index = std::is_same<T, bool>::value ? 0 : 1 + (
+        std::is_integral<T>::value ? detail::log2(sizeof(T))*2 + std::is_unsigned<T>::value : 8 + (
+        std::is_same<T, double>::value ? 1 : std::is_same<T, long double>::value ? 2 : 0));
+};
+NAMESPACE_END(detail)
+
+template <typename T> struct format_descriptor<T, detail::enable_if_t<std::is_arithmetic<T>::value>> {
+    static constexpr const char c = "?bBhHiIqQfdg"[detail::is_fmt_numeric<T>::index];
+    static constexpr const char value[2] = { c, '\0' };
+    static std::string format() { return std::string(1, c); }
+};
+
+template <typename T> constexpr const char format_descriptor<
+    T, detail::enable_if_t<std::is_arithmetic<T>::value>>::value[2];
+
+/// RAII wrapper that temporarily clears any Python error state
+struct error_scope {
+    PyObject *type, *value, *trace;
+    error_scope() { PyErr_Fetch(&type, &value, &trace); }
+    ~error_scope() { PyErr_Restore(type, value, trace); }
+};
+
+/// Dummy destructor wrapper that can be used to expose classes with a private destructor
+struct nodelete { template <typename T> void operator()(T*) { } };
+
+// overload_cast requires variable templates: C++14
+#if defined(PYBIND11_CPP14)
+#define PYBIND11_OVERLOAD_CAST 1
+
+NAMESPACE_BEGIN(detail)
+template <typename... Args>
+struct overload_cast_impl {
+    constexpr overload_cast_impl() {} // MSVC 2015 needs this
+
+    template <typename Return>
+    constexpr auto operator()(Return (*pf)(Args...)) const noexcept
+                              -> decltype(pf) { return pf; }
+
+    template <typename Return, typename Class>
+    constexpr auto operator()(Return (Class::*pmf)(Args...), std::false_type = {}) const noexcept
+                              -> decltype(pmf) { return pmf; }
+
+    template <typename Return, typename Class>
+    constexpr auto operator()(Return (Class::*pmf)(Args...) const, std::true_type) const noexcept
+                              -> decltype(pmf) { return pmf; }
+};
+NAMESPACE_END(detail)
+
+/// Syntax sugar for resolving overloaded function pointers:
+///  - regular: static_cast<Return (Class::*)(Arg0, Arg1, Arg2)>(&Class::func)
+///  - sweet:   overload_cast<Arg0, Arg1, Arg2>(&Class::func)
+template <typename... Args>
+static constexpr detail::overload_cast_impl<Args...> overload_cast = {};
+// MSVC 2015 only accepts this particular initialization syntax for this variable template.
+
+/// Const member function selector for overload_cast
+///  - regular: static_cast<Return (Class::*)(Arg) const>(&Class::func)
+///  - sweet:   overload_cast<Arg>(&Class::func, const_)
+static constexpr auto const_ = std::true_type{};
+
+#else // no overload_cast: providing something that static_assert-fails:
+template <typename... Args> struct overload_cast {
+    static_assert(detail::deferred_t<std::false_type, Args...>::value,
+                  "pybind11::overload_cast<...> requires compiling in C++14 mode");
+};
+#endif // overload_cast
+
+NAMESPACE_BEGIN(detail)
+
+// Adaptor for converting arbitrary container arguments into a vector; implicitly convertible from
+// any standard container (or C-style array) supporting std::begin/std::end, any singleton
+// arithmetic type (if T is arithmetic), or explicitly constructible from an iterator pair.
+template <typename T>
+class any_container {
+    std::vector<T> v;
+public:
+    any_container() = default;
+
+    // Can construct from a pair of iterators
+    template <typename It, typename = enable_if_t<is_input_iterator<It>::value>>
+    any_container(It first, It last) : v(first, last) { }
+
+    // Implicit conversion constructor from any arbitrary container type with values convertible to T
+    template <typename Container, typename = enable_if_t<std::is_convertible<decltype(*std::begin(std::declval<const Container &>())), T>::value>>
+    any_container(const Container &c) : any_container(std::begin(c), std::end(c)) { }
+
+    // initializer_list's aren't deducible, so don't get matched by the above template; we need this
+    // to explicitly allow implicit conversion from one:
+    template <typename TIn, typename = enable_if_t<std::is_convertible<TIn, T>::value>>
+    any_container(const std::initializer_list<TIn> &c) : any_container(c.begin(), c.end()) { }
+
+    // Avoid copying if given an rvalue vector of the correct type.
+    any_container(std::vector<T> &&v) : v(std::move(v)) { }
+
+    // Moves the vector out of an rvalue any_container
+    operator std::vector<T> &&() && { return std::move(v); }
+
+    // Dereferencing obtains a reference to the underlying vector
+    std::vector<T> &operator*() { return v; }
+    const std::vector<T> &operator*() const { return v; }
+
+    // -> lets you call methods on the underlying vector
+    std::vector<T> *operator->() { return &v; }
+    const std::vector<T> *operator->() const { return &v; }
+};
+
+NAMESPACE_END(detail)
+
+
+
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/descr.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/descr.h
new file mode 100644
index 0000000000000000000000000000000000000000..e3bf2ba978e9ad78c3ef09699f5565868b1dbc92
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/descr.h
@@ -0,0 +1,185 @@
+/*
+    pybind11/detail/descr.h: Helper type for concatenating type signatures
+    either at runtime (C++11) or compile time (C++14)
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "common.h"
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+NAMESPACE_BEGIN(detail)
+
+/* Concatenate type signatures at compile time using C++14 */
+#if defined(PYBIND11_CPP14) && !defined(_MSC_VER)
+#define PYBIND11_CONSTEXPR_DESCR
+
+template <size_t Size1, size_t Size2> class descr {
+    template <size_t Size1_, size_t Size2_> friend class descr;
+public:
+    constexpr descr(char const (&text) [Size1+1], const std::type_info * const (&types)[Size2+1])
+        : descr(text, types,
+                make_index_sequence<Size1>(),
+                make_index_sequence<Size2>()) { }
+
+    constexpr const char *text() const { return m_text; }
+    constexpr const std::type_info * const * types() const { return m_types; }
+
+    template <size_t OtherSize1, size_t OtherSize2>
+    constexpr descr<Size1 + OtherSize1, Size2 + OtherSize2> operator+(const descr<OtherSize1, OtherSize2> &other) const {
+        return concat(other,
+                      make_index_sequence<Size1>(),
+                      make_index_sequence<Size2>(),
+                      make_index_sequence<OtherSize1>(),
+                      make_index_sequence<OtherSize2>());
+    }
+
+protected:
+    template <size_t... Indices1, size_t... Indices2>
+    constexpr descr(
+        char const (&text) [Size1+1],
+        const std::type_info * const (&types) [Size2+1],
+        index_sequence<Indices1...>, index_sequence<Indices2...>)
+        : m_text{text[Indices1]..., '\0'},
+          m_types{types[Indices2]...,  nullptr } {}
+
+    template <size_t OtherSize1, size_t OtherSize2, size_t... Indices1,
+              size_t... Indices2, size_t... OtherIndices1, size_t... OtherIndices2>
+    constexpr descr<Size1 + OtherSize1, Size2 + OtherSize2>
+    concat(const descr<OtherSize1, OtherSize2> &other,
+           index_sequence<Indices1...>, index_sequence<Indices2...>,
+           index_sequence<OtherIndices1...>, index_sequence<OtherIndices2...>) const {
+        return descr<Size1 + OtherSize1, Size2 + OtherSize2>(
+            { m_text[Indices1]..., other.m_text[OtherIndices1]..., '\0' },
+            { m_types[Indices2]..., other.m_types[OtherIndices2]..., nullptr }
+        );
+    }
+
+protected:
+    char m_text[Size1 + 1];
+    const std::type_info * m_types[Size2 + 1];
+};
+
+template <size_t Size> constexpr descr<Size - 1, 0> _(char const(&text)[Size]) {
+    return descr<Size - 1, 0>(text, { nullptr });
+}
+
+template <size_t Rem, size_t... Digits> struct int_to_str : int_to_str<Rem/10, Rem%10, Digits...> { };
+template <size_t...Digits> struct int_to_str<0, Digits...> {
+    static constexpr auto digits = descr<sizeof...(Digits), 0>({ ('0' + Digits)..., '\0' }, { nullptr });
+};
+
+// Ternary description (like std::conditional)
+template <bool B, size_t Size1, size_t Size2>
+constexpr enable_if_t<B, descr<Size1 - 1, 0>> _(char const(&text1)[Size1], char const(&)[Size2]) {
+    return _(text1);
+}
+template <bool B, size_t Size1, size_t Size2>
+constexpr enable_if_t<!B, descr<Size2 - 1, 0>> _(char const(&)[Size1], char const(&text2)[Size2]) {
+    return _(text2);
+}
+template <bool B, size_t SizeA1, size_t SizeA2, size_t SizeB1, size_t SizeB2>
+constexpr enable_if_t<B, descr<SizeA1, SizeA2>> _(descr<SizeA1, SizeA2> d, descr<SizeB1, SizeB2>) { return d; }
+template <bool B, size_t SizeA1, size_t SizeA2, size_t SizeB1, size_t SizeB2>
+constexpr enable_if_t<!B, descr<SizeB1, SizeB2>> _(descr<SizeA1, SizeA2>, descr<SizeB1, SizeB2> d) { return d; }
+
+template <size_t Size> auto constexpr _() -> decltype(int_to_str<Size / 10, Size % 10>::digits) {
+    return int_to_str<Size / 10, Size % 10>::digits;
+}
+
+template <typename Type> constexpr descr<1, 1> _() {
+    return descr<1, 1>({ '%', '\0' }, { &typeid(Type), nullptr });
+}
+
+inline constexpr descr<0, 0> concat() { return _(""); }
+template <size_t Size1, size_t Size2, typename... Args> auto constexpr concat(descr<Size1, Size2> descr) { return descr; }
+template <size_t Size1, size_t Size2, typename... Args> auto constexpr concat(descr<Size1, Size2> descr, Args&&... args) { return descr + _(", ") + concat(args...); }
+template <size_t Size1, size_t Size2> auto constexpr type_descr(descr<Size1, Size2> descr) { return _("{") + descr + _("}"); }
+
+#define PYBIND11_DESCR constexpr auto
+
+#else /* Simpler C++11 implementation based on run-time memory allocation and copying */
+
+class descr {
+public:
+    PYBIND11_NOINLINE descr(const char *text, const std::type_info * const * types) {
+        size_t nChars = len(text), nTypes = len(types);
+        m_text  = new char[nChars];
+        m_types = new const std::type_info *[nTypes];
+        memcpy(m_text, text, nChars * sizeof(char));
+        memcpy(m_types, types, nTypes * sizeof(const std::type_info *));
+    }
+
+    PYBIND11_NOINLINE descr operator+(descr &&d2) && {
+        descr r;
+
+        size_t nChars1 = len(m_text),    nTypes1 = len(m_types);
+        size_t nChars2 = len(d2.m_text), nTypes2 = len(d2.m_types);
+
+        r.m_text  = new char[nChars1 + nChars2 - 1];
+        r.m_types = new const std::type_info *[nTypes1 + nTypes2 - 1];
+        memcpy(r.m_text, m_text, (nChars1-1) * sizeof(char));
+        memcpy(r.m_text + nChars1 - 1, d2.m_text, nChars2 * sizeof(char));
+        memcpy(r.m_types, m_types, (nTypes1-1) * sizeof(std::type_info *));
+        memcpy(r.m_types + nTypes1 - 1, d2.m_types, nTypes2 * sizeof(std::type_info *));
+
+        delete[] m_text;    delete[] m_types;
+        delete[] d2.m_text; delete[] d2.m_types;
+
+        return r;
+    }
+
+    char *text() { return m_text; }
+    const std::type_info * * types() { return m_types; }
+
+protected:
+    PYBIND11_NOINLINE descr() { }
+
+    template <typename T> static size_t len(const T *ptr) { // return length including null termination
+        const T *it = ptr;
+        while (*it++ != (T) 0)
+            ;
+        return static_cast<size_t>(it - ptr);
+    }
+
+    const std::type_info **m_types = nullptr;
+    char *m_text = nullptr;
+};
+
+/* The 'PYBIND11_NOINLINE inline' combinations below are intentional to get the desired linkage while producing as little object code as possible */
+
+PYBIND11_NOINLINE inline descr _(const char *text) {
+    const std::type_info *types[1] = { nullptr };
+    return descr(text, types);
+}
+
+template <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(const char *text1, const char *) { return _(text1); }
+template <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(char const *, const char *text2) { return _(text2); }
+template <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(descr d, descr) { return d; }
+template <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(descr, descr d) { return d; }
+
+template <typename Type> PYBIND11_NOINLINE descr _() {
+    const std::type_info *types[2] = { &typeid(Type), nullptr };
+    return descr("%", types);
+}
+
+template <size_t Size> PYBIND11_NOINLINE descr _() {
+    const std::type_info *types[1] = { nullptr };
+    return descr(std::to_string(Size).c_str(), types);
+}
+
+PYBIND11_NOINLINE inline descr concat() { return _(""); }
+PYBIND11_NOINLINE inline descr concat(descr &&d) { return d; }
+template <typename... Args> PYBIND11_NOINLINE descr concat(descr &&d, Args&&... args) { return std::move(d) + _(", ") + concat(std::forward<Args>(args)...); }
+PYBIND11_NOINLINE inline descr type_descr(descr&& d) { return _("{") + std::move(d) + _("}"); }
+
+#define PYBIND11_DESCR ::pybind11::detail::descr
+#endif
+
+NAMESPACE_END(detail)
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/init.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/init.h
new file mode 100644
index 0000000000000000000000000000000000000000..82f74076063a8ee4e7b03d75ac8cc7797c5d62ff
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/init.h
@@ -0,0 +1,335 @@
+/*
+    pybind11/detail/init.h: init factory function implementation and support code.
+
+    Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "class.h"
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+NAMESPACE_BEGIN(detail)
+
+template <>
+class type_caster<value_and_holder> {
+public:
+    bool load(handle h, bool) {
+        value = reinterpret_cast<value_and_holder *>(h.ptr());
+        return true;
+    }
+
+    template <typename> using cast_op_type = value_and_holder &;
+    operator value_and_holder &() { return *value; }
+    static PYBIND11_DESCR name() { return type_descr(_<value_and_holder>()); }
+
+private:
+    value_and_holder *value = nullptr;
+};
+
+NAMESPACE_BEGIN(initimpl)
+
+inline void no_nullptr(void *ptr) {
+    if (!ptr) throw type_error("pybind11::init(): factory function returned nullptr");
+}
+
+// Implementing functions for all forms of py::init<...> and py::init(...)
+template <typename Class> using Cpp = typename Class::type;
+template <typename Class> using Alias = typename Class::type_alias;
+template <typename Class> using Holder = typename Class::holder_type;
+
+template <typename Class> using is_alias_constructible = std::is_constructible<Alias<Class>, Cpp<Class> &&>;
+
+// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance.
+template <typename Class, enable_if_t<Class::has_alias, int> = 0>
+bool is_alias(Cpp<Class> *ptr) {
+    return dynamic_cast<Alias<Class> *>(ptr) != nullptr;
+}
+// Failing fallback version of the above for a no-alias class (always returns false)
+template <typename /*Class*/>
+constexpr bool is_alias(void *) { return false; }
+
+// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall
+// back to brace aggregate initiailization so that for aggregate initialization can be used with
+// py::init, e.g.  `py::init<int, int>` to initialize a `struct T { int a; int b; }`.  For
+// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually
+// works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor).
+template <typename Class, typename... Args, detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0>
+inline Class *construct_or_initialize(Args &&...args) { return new Class(std::forward<Args>(args)...); }
+template <typename Class, typename... Args, detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0>
+inline Class *construct_or_initialize(Args &&...args) { return new Class{std::forward<Args>(args)...}; }
+
+// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor.  This allows types with
+// an alias to provide only a single Cpp factory function as long as the Alias can be
+// constructed from an rvalue reference of the base Cpp type.  This means that Alias classes
+// can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to
+// inherit all the base class constructors.
+template <typename Class>
+void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/,
+                              value_and_holder &v_h, Cpp<Class> &&base) {
+    v_h.value_ptr() = new Alias<Class>(std::move(base));
+}
+template <typename Class>
+[[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/,
+                                           value_and_holder &, Cpp<Class> &&) {
+    throw type_error("pybind11::init(): unable to convert returned instance to required "
+                     "alias class: no `Alias<Class>(Class &&)` constructor available");
+}
+
+// Error-generating fallback for factories that don't match one of the below construction
+// mechanisms.
+template <typename Class>
+void construct(...) {
+    static_assert(!std::is_same<Class, Class>::value /* always false */,
+            "pybind11::init(): init function must return a compatible pointer, "
+            "holder, or value");
+}
+
+// Pointer return v1: the factory function returns a class pointer for a registered class.
+// If we don't need an alias (because this class doesn't have one, or because the final type is
+// inherited on the Python side) we can simply take over ownership.  Otherwise we need to try to
+// construct an Alias from the returned base instance.
+template <typename Class>
+void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
+    no_nullptr(ptr);
+    if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
+        // We're going to try to construct an alias by moving the cpp type.  Whether or not
+        // that succeeds, we still need to destroy the original cpp pointer (either the
+        // moved away leftover, if the alias construction works, or the value itself if we
+        // throw an error), but we can't just call `delete ptr`: it might have a special
+        // deleter, or might be shared_from_this.  So we construct a holder around it as if
+        // it was a normal instance, then steal the holder away into a local variable; thus
+        // the holder and destruction happens when we leave the C++ scope, and the holder
+        // class gets to handle the destruction however it likes.
+        v_h.value_ptr() = ptr;
+        v_h.set_instance_registered(true); // To prevent init_instance from registering it
+        v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
+        Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder
+        v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
+        v_h.set_instance_registered(false);
+
+        construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
+    } else {
+        // Otherwise the type isn't inherited, so we don't need an Alias
+        v_h.value_ptr() = ptr;
+    }
+}
+
+// Pointer return v2: a factory that always returns an alias instance ptr.  We simply take over
+// ownership of the pointer.
+template <typename Class, enable_if_t<Class::has_alias, int> = 0>
+void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {
+    no_nullptr(alias_ptr);
+    v_h.value_ptr() = static_cast<Cpp<Class> *>(alias_ptr);
+}
+
+// Holder return: copy its pointer, and move or copy the returned holder into the new instance's
+// holder.  This also handles types like std::shared_ptr<T> and std::unique_ptr<T> where T is a
+// derived type (through those holder's implicit conversion from derived class holder constructors).
+template <typename Class>
+void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
+    auto *ptr = holder_helper<Holder<Class>>::get(holder);
+    // If we need an alias, check that the held pointer is actually an alias instance
+    if (Class::has_alias && need_alias && !is_alias<Class>(ptr))
+        throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
+                         "is not an alias instance");
+
+    v_h.value_ptr() = ptr;
+    v_h.type->init_instance(v_h.inst, &holder);
+}
+
+// return-by-value version 1: returning a cpp class by value.  If the class has an alias and an
+// alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct
+// the alias from the base when needed (i.e. because of Python-side inheritance).  When we don't
+// need it, we simply move-construct the cpp value into a new instance.
+template <typename Class>
+void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
+    static_assert(std::is_move_constructible<Cpp<Class>>::value,
+        "pybind11::init() return-by-value factory function requires a movable class");
+    if (Class::has_alias && need_alias)
+        construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
+    else
+        v_h.value_ptr() = new Cpp<Class>(std::move(result));
+}
+
+// return-by-value version 2: returning a value of the alias type itself.  We move-construct an
+// Alias instance (even if no the python-side inheritance is involved).  The is intended for
+// cases where Alias initialization is always desired.
+template <typename Class>
+void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
+    static_assert(std::is_move_constructible<Alias<Class>>::value,
+        "pybind11::init() return-by-alias-value factory function requires a movable alias class");
+    v_h.value_ptr() = new Alias<Class>(std::move(result));
+}
+
+// Implementing class for py::init<...>()
+template <typename... Args>
+struct constructor {
+    template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0>
+    static void execute(Class &cl, const Extra&... extra) {
+        cl.def("__init__", [](value_and_holder &v_h, Args... args) {
+            v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
+        }, is_new_style_constructor(), extra...);
+    }
+
+    template <typename Class, typename... Extra,
+              enable_if_t<Class::has_alias &&
+                          std::is_constructible<Cpp<Class>, Args...>::value, int> = 0>
+    static void execute(Class &cl, const Extra&... extra) {
+        cl.def("__init__", [](value_and_holder &v_h, Args... args) {
+            if (Py_TYPE(v_h.inst) == v_h.type->type)
+                v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
+            else
+                v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
+        }, is_new_style_constructor(), extra...);
+    }
+
+    template <typename Class, typename... Extra,
+              enable_if_t<Class::has_alias &&
+                          !std::is_constructible<Cpp<Class>, Args...>::value, int> = 0>
+    static void execute(Class &cl, const Extra&... extra) {
+        cl.def("__init__", [](value_and_holder &v_h, Args... args) {
+            v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
+        }, is_new_style_constructor(), extra...);
+    }
+};
+
+// Implementing class for py::init_alias<...>()
+template <typename... Args> struct alias_constructor {
+    template <typename Class, typename... Extra,
+              enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int> = 0>
+    static void execute(Class &cl, const Extra&... extra) {
+        cl.def("__init__", [](value_and_holder &v_h, Args... args) {
+            v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
+        }, is_new_style_constructor(), extra...);
+    }
+};
+
+// Implementation class for py::init(Func) and py::init(Func, AliasFunc)
+template <typename CFunc, typename AFunc = void_type (*)(),
+          typename = function_signature_t<CFunc>, typename = function_signature_t<AFunc>>
+struct factory;
+
+// Specialization for py::init(Func)
+template <typename Func, typename Return, typename... Args>
+struct factory<Func, void_type (*)(), Return(Args...)> {
+    remove_reference_t<Func> class_factory;
+
+    factory(Func &&f) : class_factory(std::forward<Func>(f)) { }
+
+    // The given class either has no alias or has no separate alias factory;
+    // this always constructs the class itself.  If the class is registered with an alias
+    // type and an alias instance is needed (i.e. because the final type is a Python class
+    // inheriting from the C++ type) the returned value needs to either already be an alias
+    // instance, or the alias needs to be constructible from a `Class &&` argument.
+    template <typename Class, typename... Extra>
+    void execute(Class &cl, const Extra &...extra) && {
+        #if defined(PYBIND11_CPP14)
+        cl.def("__init__", [func = std::move(class_factory)]
+        #else
+        auto &func = class_factory;
+        cl.def("__init__", [func]
+        #endif
+        (value_and_holder &v_h, Args... args) {
+            construct<Class>(v_h, func(std::forward<Args>(args)...),
+                             Py_TYPE(v_h.inst) != v_h.type->type);
+        }, is_new_style_constructor(), extra...);
+    }
+};
+
+// Specialization for py::init(Func, AliasFunc)
+template <typename CFunc, typename AFunc,
+          typename CReturn, typename... CArgs, typename AReturn, typename... AArgs>
+struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
+    static_assert(sizeof...(CArgs) == sizeof...(AArgs),
+                  "pybind11::init(class_factory, alias_factory): class and alias factories "
+                  "must have identical argument signatures");
+    static_assert(all_of<std::is_same<CArgs, AArgs>...>::value,
+                  "pybind11::init(class_factory, alias_factory): class and alias factories "
+                  "must have identical argument signatures");
+
+    remove_reference_t<CFunc> class_factory;
+    remove_reference_t<AFunc> alias_factory;
+
+    factory(CFunc &&c, AFunc &&a)
+        : class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) { }
+
+    // The class factory is called when the `self` type passed to `__init__` is the direct
+    // class (i.e. not inherited), the alias factory when `self` is a Python-side subtype.
+    template <typename Class, typename... Extra>
+    void execute(Class &cl, const Extra&... extra) && {
+        static_assert(Class::has_alias, "The two-argument version of `py::init()` can "
+                                        "only be used if the class has an alias");
+        #if defined(PYBIND11_CPP14)
+        cl.def("__init__", [class_func = std::move(class_factory), alias_func = std::move(alias_factory)]
+        #else
+        auto &class_func = class_factory;
+        auto &alias_func = alias_factory;
+        cl.def("__init__", [class_func, alias_func]
+        #endif
+        (value_and_holder &v_h, CArgs... args) {
+            if (Py_TYPE(v_h.inst) == v_h.type->type)
+                // If the instance type equals the registered type we don't have inheritance, so
+                // don't need the alias and can construct using the class function:
+                construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false);
+            else
+                construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true);
+        }, is_new_style_constructor(), extra...);
+    }
+};
+
+/// Set just the C++ state. Same as `__init__`.
+template <typename Class, typename T>
+void setstate(value_and_holder &v_h, T &&result, bool need_alias) {
+    construct<Class>(v_h, std::forward<T>(result), need_alias);
+}
+
+/// Set both the C++ and Python states
+template <typename Class, typename T, typename O,
+          enable_if_t<std::is_convertible<O, handle>::value, int> = 0>
+void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) {
+    construct<Class>(v_h, std::move(result.first), need_alias);
+    setattr((PyObject *) v_h.inst, "__dict__", result.second);
+}
+
+/// Implementation for py::pickle(GetState, SetState)
+template <typename Get, typename Set,
+          typename = function_signature_t<Get>, typename = function_signature_t<Set>>
+struct pickle_factory;
+
+template <typename Get, typename Set,
+          typename RetState, typename Self, typename NewInstance, typename ArgState>
+struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
+    static_assert(std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value,
+                  "The type returned by `__getstate__` must be the same "
+                  "as the argument accepted by `__setstate__`");
+
+    remove_reference_t<Get> get;
+    remove_reference_t<Set> set;
+
+    pickle_factory(Get get, Set set)
+        : get(std::forward<Get>(get)), set(std::forward<Set>(set)) { }
+
+    template <typename Class, typename... Extra>
+    void execute(Class &cl, const Extra &...extra) && {
+        cl.def("__getstate__", std::move(get));
+
+#if defined(PYBIND11_CPP14)
+        cl.def("__setstate__", [func = std::move(set)]
+#else
+        auto &func = set;
+        cl.def("__setstate__", [func]
+#endif
+        (value_and_holder &v_h, ArgState state) {
+            setstate<Class>(v_h, func(std::forward<ArgState>(state)),
+                            Py_TYPE(v_h.inst) != v_h.type->type);
+        }, is_new_style_constructor(), extra...);
+    }
+};
+
+NAMESPACE_END(initimpl)
+NAMESPACE_END(detail)
+NAMESPACE_END(pybind11)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/internals.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/internals.h
new file mode 100644
index 0000000000000000000000000000000000000000..78d4afed018239d75b5a0aa7a15346386359f7c7
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/internals.h
@@ -0,0 +1,285 @@
+/*
+    pybind11/detail/internals.h: Internal data structure and related functions
+
+    Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "../pytypes.h"
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+NAMESPACE_BEGIN(detail)
+// Forward declarations
+inline PyTypeObject *make_static_property_type();
+inline PyTypeObject *make_default_metaclass();
+inline PyObject *make_object_base_type(PyTypeObject *metaclass);
+
+// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
+// Thread Specific Storage (TSS) API.
+#if PY_VERSION_HEX >= 0x03070000
+#    define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr
+#    define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
+#    define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (tstate))
+#    define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
+#else
+    // Usually an int but a long on Cygwin64 with Python 3.x
+#    define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0
+#    define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
+#    if PY_MAJOR_VERSION < 3
+#        define PYBIND11_TLS_DELETE_VALUE(key)                               \
+             PyThread_delete_key_value(key)
+#        define PYBIND11_TLS_REPLACE_VALUE(key, value)                       \
+             do {                                                            \
+                 PyThread_delete_key_value((key));                           \
+                 PyThread_set_key_value((key), (value));                     \
+             } while (false)
+#    else
+#        define PYBIND11_TLS_DELETE_VALUE(key)                               \
+             PyThread_set_key_value((key), nullptr)
+#        define PYBIND11_TLS_REPLACE_VALUE(key, value)                       \
+             PyThread_set_key_value((key), (value))
+#    endif
+#endif
+
+// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
+// other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module
+// even when `A` is the same, non-hidden-visibility type (e.g. from a common include).  Under
+// libstdc++, this doesn't happen: equality and the type_index hash are based on the type name,
+// which works.  If not under a known-good stl, provide our own name-based hash and equality
+// functions that use the type name.
+#if defined(__GLIBCXX__)
+inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; }
+using type_hash = std::hash<std::type_index>;
+using type_equal_to = std::equal_to<std::type_index>;
+#else
+inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) {
+    return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0;
+}
+
+struct type_hash {
+    size_t operator()(const std::type_index &t) const {
+        size_t hash = 5381;
+        const char *ptr = t.name();
+        while (auto c = static_cast<unsigned char>(*ptr++))
+            hash = (hash * 33) ^ c;
+        return hash;
+    }
+};
+
+struct type_equal_to {
+    bool operator()(const std::type_index &lhs, const std::type_index &rhs) const {
+        return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0;
+    }
+};
+#endif
+
+template <typename value_type>
+using type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>;
+
+struct overload_hash {
+    inline size_t operator()(const std::pair<const PyObject *, const char *>& v) const {
+        size_t value = std::hash<const void *>()(v.first);
+        value ^= std::hash<const void *>()(v.second)  + 0x9e3779b9 + (value<<6) + (value>>2);
+        return value;
+    }
+};
+
+/// Internal data structure used to track registered instances and types.
+/// Whenever binary incompatible changes are made to this structure,
+/// `PYBIND11_INTERNALS_VERSION` must be incremented.
+struct internals {
+    type_map<type_info *> registered_types_cpp; // std::type_index -> pybind11's type information
+    std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py; // PyTypeObject* -> base type_info(s)
+    std::unordered_multimap<const void *, instance*> registered_instances; // void * -> instance*
+    std::unordered_set<std::pair<const PyObject *, const char *>, overload_hash> inactive_overload_cache;
+    type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
+    std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
+    std::forward_list<void (*) (std::exception_ptr)> registered_exception_translators;
+    std::unordered_map<std::string, void *> shared_data; // Custom data to be shared across extensions
+    std::vector<PyObject *> loader_patient_stack; // Used by `loader_life_support`
+    std::forward_list<std::string> static_strings; // Stores the std::strings backing detail::c_str()
+    PyTypeObject *static_property_type;
+    PyTypeObject *default_metaclass;
+    PyObject *instance_base;
+#if defined(WITH_THREAD)
+    PYBIND11_TLS_KEY_INIT(tstate);
+    PyInterpreterState *istate = nullptr;
+#endif
+};
+
+/// Additional type information which does not fit into the PyTypeObject.
+/// Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`.
+struct type_info {
+    PyTypeObject *type;
+    const std::type_info *cpptype;
+    size_t type_size, holder_size_in_ptrs;
+    void *(*operator_new)(size_t);
+    void (*init_instance)(instance *, const void *);
+    void (*dealloc)(value_and_holder &v_h);
+    std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions;
+    std::vector<std::pair<const std::type_info *, void *(*)(void *)>> implicit_casts;
+    std::vector<bool (*)(PyObject *, void *&)> *direct_conversions;
+    buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
+    void *get_buffer_data = nullptr;
+    void *(*module_local_load)(PyObject *, const type_info *) = nullptr;
+    /* A simple type never occurs as a (direct or indirect) parent
+     * of a class that makes use of multiple inheritance */
+    bool simple_type : 1;
+    /* True if there is no multiple inheritance in this type's inheritance tree */
+    bool simple_ancestors : 1;
+    /* for base vs derived holder_type checks */
+    bool default_holder : 1;
+    /* true if this is a type registered with py::module_local */
+    bool module_local : 1;
+};
+
+/// Tracks the `internals` and `type_info` ABI version independent of the main library version
+#define PYBIND11_INTERNALS_VERSION 2
+
+#if defined(WITH_THREAD)
+#  define PYBIND11_INTERNALS_KIND ""
+#else
+#  define PYBIND11_INTERNALS_KIND "_without_thread"
+#endif
+
+#define PYBIND11_INTERNALS_ID "__pybind11_internals_v" \
+    PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND "__"
+
+#define PYBIND11_MODULE_LOCAL_ID "__pybind11_module_local_v" \
+    PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND "__"
+
+/// Each module locally stores a pointer to the `internals` data. The data
+/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
+inline internals **&get_internals_pp() {
+    static internals **internals_pp = nullptr;
+    return internals_pp;
+}
+
+/// Return a reference to the current `internals` data
+PYBIND11_NOINLINE inline internals &get_internals() {
+    auto **&internals_pp = get_internals_pp();
+    if (internals_pp && *internals_pp)
+        return **internals_pp;
+
+    constexpr auto *id = PYBIND11_INTERNALS_ID;
+    auto builtins = handle(PyEval_GetBuiltins());
+    if (builtins.contains(id) && isinstance<capsule>(builtins[id])) {
+        internals_pp = static_cast<internals **>(capsule(builtins[id]));
+
+        // We loaded builtins through python's builtins, which means that our `error_already_set`
+        // and `builtin_exception` may be different local classes than the ones set up in the
+        // initial exception translator, below, so add another for our local exception classes.
+        //
+        // libstdc++ doesn't require this (types there are identified only by name)
+#if !defined(__GLIBCXX__)
+        (*internals_pp)->registered_exception_translators.push_front(
+            [](std::exception_ptr p) -> void {
+                try {
+                    if (p) std::rethrow_exception(p);
+                } catch (error_already_set &e)       { e.restore();   return;
+                } catch (const builtin_exception &e) { e.set_error(); return;
+                }
+            }
+        );
+#endif
+    } else {
+        if (!internals_pp) internals_pp = new internals*();
+        auto *&internals_ptr = *internals_pp;
+        internals_ptr = new internals();
+#if defined(WITH_THREAD)
+        PyEval_InitThreads();
+        PyThreadState *tstate = PyThreadState_Get();
+        #if PY_VERSION_HEX >= 0x03070000
+            internals_ptr->tstate = PyThread_tss_alloc();
+            if (!internals_ptr->tstate || PyThread_tss_create(internals_ptr->tstate))
+                pybind11_fail("get_internals: could not successfully initialize the TSS key!");
+            PyThread_tss_set(internals_ptr->tstate, tstate);
+        #else
+            internals_ptr->tstate = PyThread_create_key();
+            if (internals_ptr->tstate == -1)
+                pybind11_fail("get_internals: could not successfully initialize the TLS key!");
+            PyThread_set_key_value(internals_ptr->tstate, tstate);
+        #endif
+        internals_ptr->istate = tstate->interp;
+#endif
+        builtins[id] = capsule(internals_pp);
+        internals_ptr->registered_exception_translators.push_front(
+            [](std::exception_ptr p) -> void {
+                try {
+                    if (p) std::rethrow_exception(p);
+                } catch (error_already_set &e)           { e.restore();                                    return;
+                } catch (const builtin_exception &e)     { e.set_error();                                  return;
+                } catch (const std::bad_alloc &e)        { PyErr_SetString(PyExc_MemoryError,   e.what()); return;
+                } catch (const std::domain_error &e)     { PyErr_SetString(PyExc_ValueError,    e.what()); return;
+                } catch (const std::invalid_argument &e) { PyErr_SetString(PyExc_ValueError,    e.what()); return;
+                } catch (const std::length_error &e)     { PyErr_SetString(PyExc_ValueError,    e.what()); return;
+                } catch (const std::out_of_range &e)     { PyErr_SetString(PyExc_IndexError,    e.what()); return;
+                } catch (const std::range_error &e)      { PyErr_SetString(PyExc_ValueError,    e.what()); return;
+                } catch (const std::exception &e)        { PyErr_SetString(PyExc_RuntimeError,  e.what()); return;
+                } catch (...) {
+                    PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!");
+                    return;
+                }
+            }
+        );
+        internals_ptr->static_property_type = make_static_property_type();
+        internals_ptr->default_metaclass = make_default_metaclass();
+        internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass);
+    }
+    return **internals_pp;
+}
+
+/// Works like `internals.registered_types_cpp`, but for module-local registered types:
+inline type_map<type_info *> &registered_local_types_cpp() {
+    static type_map<type_info *> locals{};
+    return locals;
+}
+
+/// Constructs a std::string with the given arguments, stores it in `internals`, and returns its
+/// `c_str()`.  Such strings objects have a long storage duration -- the internal strings are only
+/// cleared when the program exits or after interpreter shutdown (when embedding), and so are
+/// suitable for c-style strings needed by Python internals (such as PyTypeObject's tp_name).
+template <typename... Args>
+const char *c_str(Args &&...args) {
+    auto &strings = get_internals().static_strings;
+    strings.emplace_front(std::forward<Args>(args)...);
+    return strings.front().c_str();
+}
+
+NAMESPACE_END(detail)
+
+/// Returns a named pointer that is shared among all extension modules (using the same
+/// pybind11 version) running in the current interpreter. Names starting with underscores
+/// are reserved for internal usage. Returns `nullptr` if no matching entry was found.
+inline PYBIND11_NOINLINE void *get_shared_data(const std::string &name) {
+    auto &internals = detail::get_internals();
+    auto it = internals.shared_data.find(name);
+    return it != internals.shared_data.end() ? it->second : nullptr;
+}
+
+/// Set the shared data that can be later recovered by `get_shared_data()`.
+inline PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {
+    detail::get_internals().shared_data[name] = data;
+    return data;
+}
+
+/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if
+/// such entry exists. Otherwise, a new object of default-constructible type `T` is
+/// added to the shared data under the given name and a reference to it is returned.
+template<typename T>
+T &get_or_create_shared_data(const std::string &name) {
+    auto &internals = detail::get_internals();
+    auto it = internals.shared_data.find(name);
+    T *ptr = (T *) (it != internals.shared_data.end() ? it->second : nullptr);
+    if (!ptr) {
+        ptr = new T();
+        internals.shared_data[name] = ptr;
+    }
+    return *ptr;
+}
+
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/typeid.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/typeid.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f36aab7520937d5b7c069c4de9ce15b6199f48f
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/detail/typeid.h
@@ -0,0 +1,53 @@
+/*
+    pybind11/detail/typeid.h: Compiler-independent access to type identifiers
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include <cstdio>
+#include <cstdlib>
+
+#if defined(__GNUG__)
+#include <cxxabi.h>
+#endif
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+NAMESPACE_BEGIN(detail)
+/// Erase all occurrences of a substring
+inline void erase_all(std::string &string, const std::string &search) {
+    for (size_t pos = 0;;) {
+        pos = string.find(search, pos);
+        if (pos == std::string::npos) break;
+        string.erase(pos, search.length());
+    }
+}
+
+PYBIND11_NOINLINE inline void clean_type_id(std::string &name) {
+#if defined(__GNUG__)
+    int status = 0;
+    std::unique_ptr<char, void (*)(void *)> res {
+        abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free };
+    if (status == 0)
+        name = res.get();
+#else
+    detail::erase_all(name, "class ");
+    detail::erase_all(name, "struct ");
+    detail::erase_all(name, "enum ");
+#endif
+    detail::erase_all(name, "pybind11::");
+}
+NAMESPACE_END(detail)
+
+/// Return a string representation of a C++ type
+template <typename T> static std::string type_id() {
+    std::string name(typeid(T).name());
+    detail::clean_type_id(name);
+    return name;
+}
+
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/eigen.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/eigen.h
new file mode 100644
index 0000000000000000000000000000000000000000..0899ec73f718f067fce25a295f6c8923958e9956
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/eigen.h
@@ -0,0 +1,604 @@
+/*
+    pybind11/eigen.h: Transparent conversion for dense and sparse Eigen matrices
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "numpy.h"
+
+#if defined(__INTEL_COMPILER)
+#  pragma warning(disable: 1682) // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem)
+#elif defined(__GNUG__) || defined(__clang__)
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wconversion"
+#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#  if __GNUC__ >= 7
+#    pragma GCC diagnostic ignored "-Wint-in-bool-context"
+#  endif
+#endif
+
+#if defined(_MSC_VER)
+#  pragma warning(push)
+#  pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
+#  pragma warning(disable: 4996) // warning C4996: std::unary_negate is deprecated in C++17
+#endif
+
+#include <Eigen/Core>
+#include <Eigen/SparseCore>
+
+// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit
+// move constructors that break things.  We could detect this an explicitly copy, but an extra copy
+// of matrices seems highly undesirable.
+static_assert(EIGEN_VERSION_AT_LEAST(3,2,7), "Eigen support in pybind11 requires Eigen >= 3.2.7");
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+
+// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides:
+using EigenDStride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;
+template <typename MatrixType> using EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>;
+template <typename MatrixType> using EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>;
+
+NAMESPACE_BEGIN(detail)
+
+#if EIGEN_VERSION_AT_LEAST(3,3,0)
+using EigenIndex = Eigen::Index;
+#else
+using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE;
+#endif
+
+// Matches Eigen::Map, Eigen::Ref, blocks, etc:
+template <typename T> using is_eigen_dense_map = all_of<is_template_base_of<Eigen::DenseBase, T>, std::is_base_of<Eigen::MapBase<T, Eigen::ReadOnlyAccessors>, T>>;
+template <typename T> using is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>;
+template <typename T> using is_eigen_dense_plain = all_of<negation<is_eigen_dense_map<T>>, is_template_base_of<Eigen::PlainObjectBase, T>>;
+template <typename T> using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;
+// Test for objects inheriting from EigenBase<Derived> that aren't captured by the above.  This
+// basically covers anything that can be assigned to a dense matrix but that don't have a typical
+// matrix data layout that can be copied from their .data().  For example, DiagonalMatrix and
+// SelfAdjointView fall into this category.
+template <typename T> using is_eigen_other = all_of<
+    is_template_base_of<Eigen::EigenBase, T>,
+    negation<any_of<is_eigen_dense_map<T>, is_eigen_dense_plain<T>, is_eigen_sparse<T>>>
+>;
+
+// Captures numpy/eigen conformability status (returned by EigenProps::conformable()):
+template <bool EigenRowMajor> struct EigenConformable {
+    bool conformable = false;
+    EigenIndex rows = 0, cols = 0;
+    EigenDStride stride{0, 0};      // Only valid if negativestrides is false!
+    bool negativestrides = false;   // If true, do not use stride!
+
+    EigenConformable(bool fits = false) : conformable{fits} {}
+    // Matrix type:
+    EigenConformable(EigenIndex r, EigenIndex c,
+            EigenIndex rstride, EigenIndex cstride) :
+        conformable{true}, rows{r}, cols{c} {
+        // TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity. http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747
+        if (rstride < 0 || cstride < 0) {
+            negativestrides = true;
+        } else {
+            stride = {EigenRowMajor ? rstride : cstride /* outer stride */,
+                      EigenRowMajor ? cstride : rstride /* inner stride */ };
+        }
+    }
+    // Vector type:
+    EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride)
+        : EigenConformable(r, c, r == 1 ? c*stride : stride, c == 1 ? r : r*stride) {}
+
+    template <typename props> bool stride_compatible() const {
+        // To have compatible strides, we need (on both dimensions) one of fully dynamic strides,
+        // matching strides, or a dimension size of 1 (in which case the stride value is irrelevant)
+        return
+            !negativestrides &&
+            (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner() ||
+                (EigenRowMajor ? cols : rows) == 1) &&
+            (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer() ||
+                (EigenRowMajor ? rows : cols) == 1);
+    }
+    operator bool() const { return conformable; }
+};
+
+template <typename Type> struct eigen_extract_stride { using type = Type; };
+template <typename PlainObjectType, int MapOptions, typename StrideType>
+struct eigen_extract_stride<Eigen::Map<PlainObjectType, MapOptions, StrideType>> { using type = StrideType; };
+template <typename PlainObjectType, int Options, typename StrideType>
+struct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> { using type = StrideType; };
+
+// Helper struct for extracting information from an Eigen type
+template <typename Type_> struct EigenProps {
+    using Type = Type_;
+    using Scalar = typename Type::Scalar;
+    using StrideType = typename eigen_extract_stride<Type>::type;
+    static constexpr EigenIndex
+        rows = Type::RowsAtCompileTime,
+        cols = Type::ColsAtCompileTime,
+        size = Type::SizeAtCompileTime;
+    static constexpr bool
+        row_major = Type::IsRowMajor,
+        vector = Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1
+        fixed_rows = rows != Eigen::Dynamic,
+        fixed_cols = cols != Eigen::Dynamic,
+        fixed = size != Eigen::Dynamic, // Fully-fixed size
+        dynamic = !fixed_rows && !fixed_cols; // Fully-dynamic size
+
+    template <EigenIndex i, EigenIndex ifzero> using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>;
+    static constexpr EigenIndex inner_stride = if_zero<StrideType::InnerStrideAtCompileTime, 1>::value,
+                                outer_stride = if_zero<StrideType::OuterStrideAtCompileTime,
+                                                       vector ? size : row_major ? cols : rows>::value;
+    static constexpr bool dynamic_stride = inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic;
+    static constexpr bool requires_row_major = !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1;
+    static constexpr bool requires_col_major = !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1;
+
+    // Takes an input array and determines whether we can make it fit into the Eigen type.  If
+    // the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector
+    // (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type).
+    static EigenConformable<row_major> conformable(const array &a) {
+        const auto dims = a.ndim();
+        if (dims < 1 || dims > 2)
+            return false;
+
+        if (dims == 2) { // Matrix type: require exact match (or dynamic)
+
+            EigenIndex
+                np_rows = a.shape(0),
+                np_cols = a.shape(1),
+                np_rstride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar)),
+                np_cstride = a.strides(1) / static_cast<ssize_t>(sizeof(Scalar));
+            if ((fixed_rows && np_rows != rows) || (fixed_cols && np_cols != cols))
+                return false;
+
+            return {np_rows, np_cols, np_rstride, np_cstride};
+        }
+
+        // Otherwise we're storing an n-vector.  Only one of the strides will be used, but whichever
+        // is used, we want the (single) numpy stride value.
+        const EigenIndex n = a.shape(0),
+              stride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar));
+
+        if (vector) { // Eigen type is a compile-time vector
+            if (fixed && size != n)
+                return false; // Vector size mismatch
+            return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride};
+        }
+        else if (fixed) {
+            // The type has a fixed size, but is not a vector: abort
+            return false;
+        }
+        else if (fixed_cols) {
+            // Since this isn't a vector, cols must be != 1.  We allow this only if it exactly
+            // equals the number of elements (rows is Dynamic, and so 1 row is allowed).
+            if (cols != n) return false;
+            return {1, n, stride};
+        }
+        else {
+            // Otherwise it's either fully dynamic, or column dynamic; both become a column vector
+            if (fixed_rows && rows != n) return false;
+            return {n, 1, stride};
+        }
+    }
+
+    static PYBIND11_DESCR descriptor() {
+        constexpr bool show_writeable = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
+        constexpr bool show_order = is_eigen_dense_map<Type>::value;
+        constexpr bool show_c_contiguous = show_order && requires_row_major;
+        constexpr bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major;
+
+        return type_descr(_("numpy.ndarray[") + npy_format_descriptor<Scalar>::name() +
+            _("[")  + _<fixed_rows>(_<(size_t) rows>(), _("m")) +
+            _(", ") + _<fixed_cols>(_<(size_t) cols>(), _("n")) +
+            _("]") +
+            // For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to be
+            // satisfied: writeable=True (for a mutable reference), and, depending on the map's stride
+            // options, possibly f_contiguous or c_contiguous.  We include them in the descriptor output
+            // to provide some hint as to why a TypeError is occurring (otherwise it can be confusing to
+            // see that a function accepts a 'numpy.ndarray[float64[3,2]]' and an error message that you
+            // *gave* a numpy.ndarray of the right type and dimensions.
+            _<show_writeable>(", flags.writeable", "") +
+            _<show_c_contiguous>(", flags.c_contiguous", "") +
+            _<show_f_contiguous>(", flags.f_contiguous", "") +
+            _("]")
+        );
+    }
+};
+
+// Casts an Eigen type to numpy array.  If given a base, the numpy array references the src data,
+// otherwise it'll make a copy.  writeable lets you turn off the writeable flag for the array.
+template <typename props> handle eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
+    constexpr ssize_t elem_size = sizeof(typename props::Scalar);
+    array a;
+    if (props::vector)
+        a = array({ src.size() }, { elem_size * src.innerStride() }, src.data(), base);
+    else
+        a = array({ src.rows(), src.cols() }, { elem_size * src.rowStride(), elem_size * src.colStride() },
+                  src.data(), base);
+
+    if (!writeable)
+        array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
+
+    return a.release();
+}
+
+// Takes an lvalue ref to some Eigen type and a (python) base object, creating a numpy array that
+// reference the Eigen object's data with `base` as the python-registered base class (if omitted,
+// the base will be set to None, and lifetime management is up to the caller).  The numpy array is
+// non-writeable if the given type is const.
+template <typename props, typename Type>
+handle eigen_ref_array(Type &src, handle parent = none()) {
+    // none here is to get past array's should-we-copy detection, which currently always
+    // copies when there is no base.  Setting the base to None should be harmless.
+    return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value);
+}
+
+// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a numpy
+// array that references the encapsulated data with a python-side reference to the capsule to tie
+// its destruction to that of any dependent python objects.  Const-ness is determined by whether or
+// not the Type of the pointer given is const.
+template <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>>
+handle eigen_encapsulate(Type *src) {
+    capsule base(src, [](void *o) { delete static_cast<Type *>(o); });
+    return eigen_ref_array<props>(*src, base);
+}
+
+// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense
+// types.
+template<typename Type>
+struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
+    using Scalar = typename Type::Scalar;
+    using props = EigenProps<Type>;
+
+    bool load(handle src, bool convert) {
+        // If we're in no-convert mode, only load if given an array of the correct type
+        if (!convert && !isinstance<array_t<Scalar>>(src))
+            return false;
+
+        // Coerce into an array, but don't do type conversion yet; the copy below handles it.
+        auto buf = array::ensure(src);
+
+        if (!buf)
+            return false;
+
+        auto dims = buf.ndim();
+        if (dims < 1 || dims > 2)
+            return false;
+
+        auto fits = props::conformable(buf);
+        if (!fits)
+            return false;
+
+        // Allocate the new type, then build a numpy reference into it
+        value = Type(fits.rows, fits.cols);
+        auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value));
+        if (dims == 1) ref = ref.squeeze();
+        else if (ref.ndim() == 1) buf = buf.squeeze();
+
+        int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr());
+
+        if (result < 0) { // Copy failed!
+            PyErr_Clear();
+            return false;
+        }
+
+        return true;
+    }
+
+private:
+
+    // Cast implementation
+    template <typename CType>
+    static handle cast_impl(CType *src, return_value_policy policy, handle parent) {
+        switch (policy) {
+            case return_value_policy::take_ownership:
+            case return_value_policy::automatic:
+                return eigen_encapsulate<props>(src);
+            case return_value_policy::move:
+                return eigen_encapsulate<props>(new CType(std::move(*src)));
+            case return_value_policy::copy:
+                return eigen_array_cast<props>(*src);
+            case return_value_policy::reference:
+            case return_value_policy::automatic_reference:
+                return eigen_ref_array<props>(*src);
+            case return_value_policy::reference_internal:
+                return eigen_ref_array<props>(*src, parent);
+            default:
+                throw cast_error("unhandled return_value_policy: should not happen!");
+        };
+    }
+
+public:
+
+    // Normal returned non-reference, non-const value:
+    static handle cast(Type &&src, return_value_policy /* policy */, handle parent) {
+        return cast_impl(&src, return_value_policy::move, parent);
+    }
+    // If you return a non-reference const, we mark the numpy array readonly:
+    static handle cast(const Type &&src, return_value_policy /* policy */, handle parent) {
+        return cast_impl(&src, return_value_policy::move, parent);
+    }
+    // lvalue reference return; default (automatic) becomes copy
+    static handle cast(Type &src, return_value_policy policy, handle parent) {
+        if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference)
+            policy = return_value_policy::copy;
+        return cast_impl(&src, policy, parent);
+    }
+    // const lvalue reference return; default (automatic) becomes copy
+    static handle cast(const Type &src, return_value_policy policy, handle parent) {
+        if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference)
+            policy = return_value_policy::copy;
+        return cast(&src, policy, parent);
+    }
+    // non-const pointer return
+    static handle cast(Type *src, return_value_policy policy, handle parent) {
+        return cast_impl(src, policy, parent);
+    }
+    // const pointer return
+    static handle cast(const Type *src, return_value_policy policy, handle parent) {
+        return cast_impl(src, policy, parent);
+    }
+
+    static PYBIND11_DESCR name() { return props::descriptor(); }
+
+    operator Type*() { return &value; }
+    operator Type&() { return value; }
+    operator Type&&() && { return std::move(value); }
+    template <typename T> using cast_op_type = movable_cast_op_type<T>;
+
+private:
+    Type value;
+};
+
+// Base class for casting reference/map/block/etc. objects back to python.
+template <typename MapType> struct eigen_map_caster {
+private:
+    using props = EigenProps<MapType>;
+
+public:
+
+    // Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has
+    // to stay around), but we'll allow it under the assumption that you know what you're doing (and
+    // have an appropriate keep_alive in place).  We return a numpy array pointing directly at the
+    // ref's data (The numpy array ends up read-only if the ref was to a const matrix type.) Note
+    // that this means you need to ensure you don't destroy the object in some other way (e.g. with
+    // an appropriate keep_alive, or with a reference to a statically allocated matrix).
+    static handle cast(const MapType &src, return_value_policy policy, handle parent) {
+        switch (policy) {
+            case return_value_policy::copy:
+                return eigen_array_cast<props>(src);
+            case return_value_policy::reference_internal:
+                return eigen_array_cast<props>(src, parent, is_eigen_mutable_map<MapType>::value);
+            case return_value_policy::reference:
+            case return_value_policy::automatic:
+            case return_value_policy::automatic_reference:
+                return eigen_array_cast<props>(src, none(), is_eigen_mutable_map<MapType>::value);
+            default:
+                // move, take_ownership don't make any sense for a ref/map:
+                pybind11_fail("Invalid return_value_policy for Eigen Map/Ref/Block type");
+        }
+    }
+
+    static PYBIND11_DESCR name() { return props::descriptor(); }
+
+    // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
+    // types but not bound arguments).  We still provide them (with an explicitly delete) so that
+    // you end up here if you try anyway.
+    bool load(handle, bool) = delete;
+    operator MapType() = delete;
+    template <typename> using cast_op_type = MapType;
+};
+
+// We can return any map-like object (but can only load Refs, specialized next):
+template <typename Type> struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>>
+    : eigen_map_caster<Type> {};
+
+// Loader for Ref<...> arguments.  See the documentation for info on how to make this work without
+// copying (it requires some extra effort in many cases).
+template <typename PlainObjectType, typename StrideType>
+struct type_caster<
+    Eigen::Ref<PlainObjectType, 0, StrideType>,
+    enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>
+> : public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> {
+private:
+    using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;
+    using props = EigenProps<Type>;
+    using Scalar = typename props::Scalar;
+    using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;
+    using Array = array_t<Scalar, array::forcecast |
+                ((props::row_major ? props::inner_stride : props::outer_stride) == 1 ? array::c_style :
+                 (props::row_major ? props::outer_stride : props::inner_stride) == 1 ? array::f_style : 0)>;
+    static constexpr bool need_writeable = is_eigen_mutable_map<Type>::value;
+    // Delay construction (these have no default constructor)
+    std::unique_ptr<MapType> map;
+    std::unique_ptr<Type> ref;
+    // Our array.  When possible, this is just a numpy array pointing to the source data, but
+    // sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an incompatible
+    // layout, or is an array of a type that needs to be converted).  Using a numpy temporary
+    // (rather than an Eigen temporary) saves an extra copy when we need both type conversion and
+    // storage order conversion.  (Note that we refuse to use this temporary copy when loading an
+    // argument for a Ref<M> with M non-const, i.e. a read-write reference).
+    Array copy_or_ref;
+public:
+    bool load(handle src, bool convert) {
+        // First check whether what we have is already an array of the right type.  If not, we can't
+        // avoid a copy (because the copy is also going to do type conversion).
+        bool need_copy = !isinstance<Array>(src);
+
+        EigenConformable<props::row_major> fits;
+        if (!need_copy) {
+            // We don't need a converting copy, but we also need to check whether the strides are
+            // compatible with the Ref's stride requirements
+            Array aref = reinterpret_borrow<Array>(src);
+
+            if (aref && (!need_writeable || aref.writeable())) {
+                fits = props::conformable(aref);
+                if (!fits) return false; // Incompatible dimensions
+                if (!fits.template stride_compatible<props>())
+                    need_copy = true;
+                else
+                    copy_or_ref = std::move(aref);
+            }
+            else {
+                need_copy = true;
+            }
+        }
+
+        if (need_copy) {
+            // We need to copy: If we need a mutable reference, or we're not supposed to convert
+            // (either because we're in the no-convert overload pass, or because we're explicitly
+            // instructed not to copy (via `py::arg().noconvert()`) we have to fail loading.
+            if (!convert || need_writeable) return false;
+
+            Array copy = Array::ensure(src);
+            if (!copy) return false;
+            fits = props::conformable(copy);
+            if (!fits || !fits.template stride_compatible<props>())
+                return false;
+            copy_or_ref = std::move(copy);
+            loader_life_support::add_patient(copy_or_ref);
+        }
+
+        ref.reset();
+        map.reset(new MapType(data(copy_or_ref), fits.rows, fits.cols, make_stride(fits.stride.outer(), fits.stride.inner())));
+        ref.reset(new Type(*map));
+
+        return true;
+    }
+
+    operator Type*() { return ref.get(); }
+    operator Type&() { return *ref; }
+    template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>;
+
+private:
+    template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value, int> = 0>
+    Scalar *data(Array &a) { return a.mutable_data(); }
+
+    template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value, int> = 0>
+    const Scalar *data(Array &a) { return a.data(); }
+
+    // Attempt to figure out a constructor of `Stride` that will work.
+    // If both strides are fixed, use a default constructor:
+    template <typename S> using stride_ctor_default = bool_constant<
+        S::InnerStrideAtCompileTime != Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic &&
+        std::is_default_constructible<S>::value>;
+    // Otherwise, if there is a two-index constructor, assume it is (outer,inner) like
+    // Eigen::Stride, and use it:
+    template <typename S> using stride_ctor_dual = bool_constant<
+        !stride_ctor_default<S>::value && std::is_constructible<S, EigenIndex, EigenIndex>::value>;
+    // Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use
+    // it (passing whichever stride is dynamic).
+    template <typename S> using stride_ctor_outer = bool_constant<
+        !any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value &&
+        S::OuterStrideAtCompileTime == Eigen::Dynamic && S::InnerStrideAtCompileTime != Eigen::Dynamic &&
+        std::is_constructible<S, EigenIndex>::value>;
+    template <typename S> using stride_ctor_inner = bool_constant<
+        !any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value &&
+        S::InnerStrideAtCompileTime == Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic &&
+        std::is_constructible<S, EigenIndex>::value>;
+
+    template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value, int> = 0>
+    static S make_stride(EigenIndex, EigenIndex) { return S(); }
+    template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value, int> = 0>
+    static S make_stride(EigenIndex outer, EigenIndex inner) { return S(outer, inner); }
+    template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value, int> = 0>
+    static S make_stride(EigenIndex outer, EigenIndex) { return S(outer); }
+    template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value, int> = 0>
+    static S make_stride(EigenIndex, EigenIndex inner) { return S(inner); }
+
+};
+
+// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not
+// EigenDense (i.e. they don't have a data(), at least not with the usual matrix layout).
+// load() is not supported, but we can cast them into the python domain by first copying to a
+// regular Eigen::Matrix, then casting that.
+template <typename Type>
+struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
+protected:
+    using Matrix = Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
+    using props = EigenProps<Matrix>;
+public:
+    static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
+        handle h = eigen_encapsulate<props>(new Matrix(src));
+        return h;
+    }
+    static handle cast(const Type *src, return_value_policy policy, handle parent) { return cast(*src, policy, parent); }
+
+    static PYBIND11_DESCR name() { return props::descriptor(); }
+
+    // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
+    // types but not bound arguments).  We still provide them (with an explicitly delete) so that
+    // you end up here if you try anyway.
+    bool load(handle, bool) = delete;
+    operator Type() = delete;
+    template <typename> using cast_op_type = Type;
+};
+
+template<typename Type>
+struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
+    typedef typename Type::Scalar Scalar;
+    typedef remove_reference_t<decltype(*std::declval<Type>().outerIndexPtr())> StorageIndex;
+    typedef typename Type::Index Index;
+    static constexpr bool rowMajor = Type::IsRowMajor;
+
+    bool load(handle src, bool) {
+        if (!src)
+            return false;
+
+        auto obj = reinterpret_borrow<object>(src);
+        object sparse_module = module::import("scipy.sparse");
+        object matrix_type = sparse_module.attr(
+            rowMajor ? "csr_matrix" : "csc_matrix");
+
+        if (!obj.get_type().is(matrix_type)) {
+            try {
+                obj = matrix_type(obj);
+            } catch (const error_already_set &) {
+                return false;
+            }
+        }
+
+        auto values = array_t<Scalar>((object) obj.attr("data"));
+        auto innerIndices = array_t<StorageIndex>((object) obj.attr("indices"));
+        auto outerIndices = array_t<StorageIndex>((object) obj.attr("indptr"));
+        auto shape = pybind11::tuple((pybind11::object) obj.attr("shape"));
+        auto nnz = obj.attr("nnz").cast<Index>();
+
+        if (!values || !innerIndices || !outerIndices)
+            return false;
+
+        value = Eigen::MappedSparseMatrix<Scalar, Type::Flags, StorageIndex>(
+            shape[0].cast<Index>(), shape[1].cast<Index>(), nnz,
+            outerIndices.mutable_data(), innerIndices.mutable_data(), values.mutable_data());
+
+        return true;
+    }
+
+    static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
+        const_cast<Type&>(src).makeCompressed();
+
+        object matrix_type = module::import("scipy.sparse").attr(
+            rowMajor ? "csr_matrix" : "csc_matrix");
+
+        array data(src.nonZeros(), src.valuePtr());
+        array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
+        array innerIndices(src.nonZeros(), src.innerIndexPtr());
+
+        return matrix_type(
+            std::make_tuple(data, innerIndices, outerIndices),
+            std::make_pair(src.rows(), src.cols())
+        ).release();
+    }
+
+    PYBIND11_TYPE_CASTER(Type, _<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[")
+            + npy_format_descriptor<Scalar>::name() + _("]"));
+};
+
+NAMESPACE_END(detail)
+NAMESPACE_END(PYBIND11_NAMESPACE)
+
+#if defined(__GNUG__) || defined(__clang__)
+#  pragma GCC diagnostic pop
+#elif defined(_MSC_VER)
+#  pragma warning(pop)
+#endif
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/embed.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/embed.h
new file mode 100644
index 0000000000000000000000000000000000000000..9abc61c3452a94f05e500cbe2289415efaca7ea8
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/embed.h
@@ -0,0 +1,194 @@
+/*
+    pybind11/embed.h: Support for embedding the interpreter
+
+    Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "pybind11.h"
+#include "eval.h"
+
+#if defined(PYPY_VERSION)
+#  error Embedding the interpreter is not supported with PyPy
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+#  define PYBIND11_EMBEDDED_MODULE_IMPL(name)            \
+      extern "C" PyObject *pybind11_init_impl_##name() { \
+          return pybind11_init_wrapper_##name();         \
+      }
+#else
+#  define PYBIND11_EMBEDDED_MODULE_IMPL(name)            \
+      extern "C" void pybind11_init_impl_##name() {      \
+          pybind11_init_wrapper_##name();                \
+      }
+#endif
+
+/** \rst
+    Add a new module to the table of builtins for the interpreter. Must be
+    defined in global scope. The first macro parameter is the name of the
+    module (without quotes). The second parameter is the variable which will
+    be used as the interface to add functions and classes to the module.
+
+    .. code-block:: cpp
+
+        PYBIND11_EMBEDDED_MODULE(example, m) {
+            // ... initialize functions and classes here
+            m.def("foo", []() {
+                return "Hello, World!";
+            });
+        }
+ \endrst */
+#define PYBIND11_EMBEDDED_MODULE(name, variable)                              \
+    static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &);    \
+    static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() {        \
+        auto m = pybind11::module(PYBIND11_TOSTRING(name));                   \
+        try {                                                                 \
+            PYBIND11_CONCAT(pybind11_init_, name)(m);                         \
+            return m.ptr();                                                   \
+        } catch (pybind11::error_already_set &e) {                            \
+            PyErr_SetString(PyExc_ImportError, e.what());                     \
+            return nullptr;                                                   \
+        } catch (const std::exception &e) {                                   \
+            PyErr_SetString(PyExc_ImportError, e.what());                     \
+            return nullptr;                                                   \
+        }                                                                     \
+    }                                                                         \
+    PYBIND11_EMBEDDED_MODULE_IMPL(name)                                       \
+    pybind11::detail::embedded_module name(PYBIND11_TOSTRING(name),           \
+                               PYBIND11_CONCAT(pybind11_init_impl_, name));   \
+    void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &variable)
+
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+NAMESPACE_BEGIN(detail)
+
+/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks.
+struct embedded_module {
+#if PY_MAJOR_VERSION >= 3
+    using init_t = PyObject *(*)();
+#else
+    using init_t = void (*)();
+#endif
+    embedded_module(const char *name, init_t init) {
+        if (Py_IsInitialized())
+            pybind11_fail("Can't add new modules after the interpreter has been initialized");
+
+        auto result = PyImport_AppendInittab(name, init);
+        if (result == -1)
+            pybind11_fail("Insufficient memory to add a new module");
+    }
+};
+
+NAMESPACE_END(detail)
+
+/** \rst
+    Initialize the Python interpreter. No other pybind11 or CPython API functions can be
+    called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
+    optional parameter can be used to skip the registration of signal handlers (see the
+    Python documentation for details). Calling this function again after the interpreter
+    has already been initialized is a fatal error.
+ \endrst */
+inline void initialize_interpreter(bool init_signal_handlers = true) {
+    if (Py_IsInitialized())
+        pybind11_fail("The interpreter is already running");
+
+    Py_InitializeEx(init_signal_handlers ? 1 : 0);
+
+    // Make .py files in the working directory available by default
+    module::import("sys").attr("path").cast<list>().append(".");
+}
+
+/** \rst
+    Shut down the Python interpreter. No pybind11 or CPython API functions can be called
+    after this. In addition, pybind11 objects must not outlive the interpreter:
+
+    .. code-block:: cpp
+
+        { // BAD
+            py::initialize_interpreter();
+            auto hello = py::str("Hello, World!");
+            py::finalize_interpreter();
+        } // <-- BOOM, hello's destructor is called after interpreter shutdown
+
+        { // GOOD
+            py::initialize_interpreter();
+            { // scoped
+                auto hello = py::str("Hello, World!");
+            } // <-- OK, hello is cleaned up properly
+            py::finalize_interpreter();
+        }
+
+        { // BETTER
+            py::scoped_interpreter guard{};
+            auto hello = py::str("Hello, World!");
+        }
+
+    .. warning::
+
+        The interpreter can be restarted by calling `initialize_interpreter` again.
+        Modules created using pybind11 can be safely re-initialized. However, Python
+        itself cannot completely unload binary extension modules and there are several
+        caveats with regard to interpreter restarting. All the details can be found
+        in the CPython documentation. In short, not all interpreter memory may be
+        freed, either due to reference cycles or user-created global data.
+
+ \endrst */
+inline void finalize_interpreter() {
+    handle builtins(PyEval_GetBuiltins());
+    const char *id = PYBIND11_INTERNALS_ID;
+
+    // Get the internals pointer (without creating it if it doesn't exist).  It's possible for the
+    // internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()`
+    // during destruction), so we get the pointer-pointer here and check it after Py_Finalize().
+    detail::internals **internals_ptr_ptr = detail::get_internals_pp();
+    // It could also be stashed in builtins, so look there too:
+    if (builtins.contains(id) && isinstance<capsule>(builtins[id]))
+        internals_ptr_ptr = capsule(builtins[id]);
+
+    Py_Finalize();
+
+    if (internals_ptr_ptr) {
+        delete *internals_ptr_ptr;
+        *internals_ptr_ptr = nullptr;
+    }
+}
+
+/** \rst
+    Scope guard version of `initialize_interpreter` and `finalize_interpreter`.
+    This a move-only guard and only a single instance can exist.
+
+    .. code-block:: cpp
+
+        #include <pybind11/embed.h>
+
+        int main() {
+            py::scoped_interpreter guard{};
+            py::print(Hello, World!);
+        } // <-- interpreter shutdown
+ \endrst */
+class scoped_interpreter {
+public:
+    scoped_interpreter(bool init_signal_handlers = true) {
+        initialize_interpreter(init_signal_handlers);
+    }
+
+    scoped_interpreter(const scoped_interpreter &) = delete;
+    scoped_interpreter(scoped_interpreter &&other) noexcept { other.is_valid = false; }
+    scoped_interpreter &operator=(const scoped_interpreter &) = delete;
+    scoped_interpreter &operator=(scoped_interpreter &&) = delete;
+
+    ~scoped_interpreter() {
+        if (is_valid)
+            finalize_interpreter();
+    }
+
+private:
+    bool is_valid = true;
+};
+
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/eval.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/eval.h
new file mode 100644
index 0000000000000000000000000000000000000000..ea85ba1dbee607bda225cdbdb7b0341f54f1215f
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/eval.h
@@ -0,0 +1,117 @@
+/*
+    pybind11/exec.h: Support for evaluating Python expressions and statements
+    from strings and files
+
+    Copyright (c) 2016 Klemens Morgenstern <klemens.morgenstern@ed-chemnitz.de> and
+                       Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "pybind11.h"
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+
+enum eval_mode {
+    /// Evaluate a string containing an isolated expression
+    eval_expr,
+
+    /// Evaluate a string containing a single statement. Returns \c none
+    eval_single_statement,
+
+    /// Evaluate a string containing a sequence of statement. Returns \c none
+    eval_statements
+};
+
+template <eval_mode mode = eval_expr>
+object eval(str expr, object global = globals(), object local = object()) {
+    if (!local)
+        local = global;
+
+    /* PyRun_String does not accept a PyObject / encoding specifier,
+       this seems to be the only alternative */
+    std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr;
+
+    int start;
+    switch (mode) {
+        case eval_expr:             start = Py_eval_input;   break;
+        case eval_single_statement: start = Py_single_input; break;
+        case eval_statements:       start = Py_file_input;   break;
+        default: pybind11_fail("invalid evaluation mode");
+    }
+
+    PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());
+    if (!result)
+        throw error_already_set();
+    return reinterpret_steal<object>(result);
+}
+
+template <eval_mode mode = eval_expr, size_t N>
+object eval(const char (&s)[N], object global = globals(), object local = object()) {
+    /* Support raw string literals by removing common leading whitespace */
+    auto expr = (s[0] == '\n') ? str(module::import("textwrap").attr("dedent")(s))
+                               : str(s);
+    return eval<mode>(expr, global, local);
+}
+
+inline void exec(str expr, object global = globals(), object local = object()) {
+    eval<eval_statements>(expr, global, local);
+}
+
+template <size_t N>
+void exec(const char (&s)[N], object global = globals(), object local = object()) {
+    eval<eval_statements>(s, global, local);
+}
+
+template <eval_mode mode = eval_statements>
+object eval_file(str fname, object global = globals(), object local = object()) {
+    if (!local)
+        local = global;
+
+    int start;
+    switch (mode) {
+        case eval_expr:             start = Py_eval_input;   break;
+        case eval_single_statement: start = Py_single_input; break;
+        case eval_statements:       start = Py_file_input;   break;
+        default: pybind11_fail("invalid evaluation mode");
+    }
+
+    int closeFile = 1;
+    std::string fname_str = (std::string) fname;
+#if PY_VERSION_HEX >= 0x03040000
+    FILE *f = _Py_fopen_obj(fname.ptr(), "r");
+#elif PY_VERSION_HEX >= 0x03000000
+    FILE *f = _Py_fopen(fname.ptr(), "r");
+#else
+    /* No unicode support in open() :( */
+    auto fobj = reinterpret_steal<object>(PyFile_FromString(
+        const_cast<char *>(fname_str.c_str()),
+        const_cast<char*>("r")));
+    FILE *f = nullptr;
+    if (fobj)
+        f = PyFile_AsFile(fobj.ptr());
+    closeFile = 0;
+#endif
+    if (!f) {
+        PyErr_Clear();
+        pybind11_fail("File \"" + fname_str + "\" could not be opened!");
+    }
+
+#if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION)
+    PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(),
+                                  local.ptr());
+    (void) closeFile;
+#else
+    PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(),
+                                    local.ptr(), closeFile);
+#endif
+
+    if (!result)
+        throw error_already_set();
+    return reinterpret_steal<object>(result);
+}
+
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/functional.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/functional.h
new file mode 100644
index 0000000000000000000000000000000000000000..eda14ba58326d7017716516bdba24e81030b6fdb
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/functional.h
@@ -0,0 +1,85 @@
+/*
+    pybind11/functional.h: std::function<> support
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "pybind11.h"
+#include <functional>
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+NAMESPACE_BEGIN(detail)
+
+template <typename Return, typename... Args>
+struct type_caster<std::function<Return(Args...)>> {
+    using type = std::function<Return(Args...)>;
+    using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
+    using function_type = Return (*) (Args...);
+
+public:
+    bool load(handle src, bool convert) {
+        if (src.is_none()) {
+            // Defer accepting None to other overloads (if we aren't in convert mode):
+            if (!convert) return false;
+            return true;
+        }
+
+        if (!isinstance<function>(src))
+            return false;
+
+        auto func = reinterpret_borrow<function>(src);
+
+        /*
+           When passing a C++ function as an argument to another C++
+           function via Python, every function call would normally involve
+           a full C++ -> Python -> C++ roundtrip, which can be prohibitive.
+           Here, we try to at least detect the case where the function is
+           stateless (i.e. function pointer or lambda function without
+           captured variables), in which case the roundtrip can be avoided.
+         */
+        if (auto cfunc = func.cpp_function()) {
+            auto c = reinterpret_borrow<capsule>(PyCFunction_GET_SELF(cfunc.ptr()));
+            auto rec = (function_record *) c;
+
+            if (rec && rec->is_stateless &&
+                    same_type(typeid(function_type), *reinterpret_cast<const std::type_info *>(rec->data[1]))) {
+                struct capture { function_type f; };
+                value = ((capture *) &rec->data)->f;
+                return true;
+            }
+        }
+
+        value = [func](Args... args) -> Return {
+            gil_scoped_acquire acq;
+            object retval(func(std::forward<Args>(args)...));
+            /* Visual studio 2015 parser issue: need parentheses around this expression */
+            return (retval.template cast<Return>());
+        };
+        return true;
+    }
+
+    template <typename Func>
+    static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
+        if (!f_)
+            return none().inc_ref();
+
+        auto result = f_.template target<function_type>();
+        if (result)
+            return cpp_function(*result, policy).release();
+        else
+            return cpp_function(std::forward<Func>(f_), policy).release();
+    }
+
+    PYBIND11_TYPE_CASTER(type, _("Callable[[") +
+            argument_loader<Args...>::arg_names() + _("], ") +
+            make_caster<retval_type>::name() +
+            _("]"));
+};
+
+NAMESPACE_END(detail)
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/iostream.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/iostream.h
new file mode 100644
index 0000000000000000000000000000000000000000..3caf5563928aebf25a3653581ce0c6d2229619ed
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/iostream.h
@@ -0,0 +1,200 @@
+/*
+    pybind11/iostream.h -- Tools to assist with redirecting cout and cerr to Python
+
+    Copyright (c) 2017 Henry F. Schreiner
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "pybind11.h"
+
+#include <streambuf>
+#include <ostream>
+#include <string>
+#include <memory>
+#include <iostream>
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+NAMESPACE_BEGIN(detail)
+
+// Buffer that writes to Python instead of C++
+class pythonbuf : public std::streambuf {
+private:
+    using traits_type = std::streambuf::traits_type;
+
+    char d_buffer[1024];
+    object pywrite;
+    object pyflush;
+
+    int overflow(int c) {
+        if (!traits_type::eq_int_type(c, traits_type::eof())) {
+            *pptr() = traits_type::to_char_type(c);
+            pbump(1);
+        }
+        return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof();
+    }
+
+    int sync() {
+        if (pbase() != pptr()) {
+            // This subtraction cannot be negative, so dropping the sign
+            str line(pbase(), static_cast<size_t>(pptr() - pbase()));
+
+            pywrite(line);
+            pyflush();
+
+            setp(pbase(), epptr());
+        }
+        return 0;
+    }
+
+public:
+    pythonbuf(object pyostream)
+        : pywrite(pyostream.attr("write")),
+          pyflush(pyostream.attr("flush")) {
+        setp(d_buffer, d_buffer + sizeof(d_buffer) - 1);
+    }
+
+    /// Sync before destroy
+    ~pythonbuf() {
+        sync();
+    }
+};
+
+NAMESPACE_END(detail)
+
+
+/** \rst
+    This a move-only guard that redirects output.
+
+    .. code-block:: cpp
+
+        #include <pybind11/iostream.h>
+
+        ...
+
+        {
+            py::scoped_ostream_redirect output;
+            std::cout << "Hello, World!"; // Python stdout
+        } // <-- return std::cout to normal
+
+    You can explicitly pass the c++ stream and the python object,
+    for example to guard stderr instead.
+
+    .. code-block:: cpp
+
+        {
+            py::scoped_ostream_redirect output{std::cerr, py::module::import("sys").attr("stderr")};
+            std::cerr << "Hello, World!";
+        }
+ \endrst */
+class scoped_ostream_redirect {
+protected:
+    std::streambuf *old;
+    std::ostream &costream;
+    detail::pythonbuf buffer;
+
+public:
+    scoped_ostream_redirect(
+            std::ostream &costream = std::cout,
+            object pyostream = module::import("sys").attr("stdout"))
+        : costream(costream), buffer(pyostream) {
+        old = costream.rdbuf(&buffer);
+    }
+
+    ~scoped_ostream_redirect() {
+        costream.rdbuf(old);
+    }
+
+    scoped_ostream_redirect(const scoped_ostream_redirect &) = delete;
+    scoped_ostream_redirect(scoped_ostream_redirect &&other) = default;
+    scoped_ostream_redirect &operator=(const scoped_ostream_redirect &) = delete;
+    scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete;
+};
+
+
+/** \rst
+    Like `scoped_ostream_redirect`, but redirects cerr by default. This class
+    is provided primary to make ``py::call_guard`` easier to make.
+
+    .. code-block:: cpp
+
+     m.def("noisy_func", &noisy_func,
+           py::call_guard<scoped_ostream_redirect,
+                          scoped_estream_redirect>());
+
+\endrst */
+class scoped_estream_redirect : public scoped_ostream_redirect {
+public:
+    scoped_estream_redirect(
+            std::ostream &costream = std::cerr,
+            object pyostream = module::import("sys").attr("stderr"))
+        : scoped_ostream_redirect(costream,pyostream) {}
+};
+
+
+NAMESPACE_BEGIN(detail)
+
+// Class to redirect output as a context manager. C++ backend.
+class OstreamRedirect {
+    bool do_stdout_;
+    bool do_stderr_;
+    std::unique_ptr<scoped_ostream_redirect> redirect_stdout;
+    std::unique_ptr<scoped_estream_redirect> redirect_stderr;
+
+public:
+    OstreamRedirect(bool do_stdout = true, bool do_stderr = true)
+        : do_stdout_(do_stdout), do_stderr_(do_stderr) {}
+
+    void enter() {
+        if (do_stdout_)
+            redirect_stdout.reset(new scoped_ostream_redirect());
+        if (do_stderr_)
+            redirect_stderr.reset(new scoped_estream_redirect());
+    }
+
+    void exit() {
+        redirect_stdout.reset();
+        redirect_stderr.reset();
+    }
+};
+
+NAMESPACE_END(detail)
+
+/** \rst
+    This is a helper function to add a C++ redirect context manager to Python
+    instead of using a C++ guard. To use it, add the following to your binding code:
+
+    .. code-block:: cpp
+
+        #include <pybind11/iostream.h>
+
+        ...
+
+        py::add_ostream_redirect(m, "ostream_redirect");
+
+    You now have a Python context manager that redirects your output:
+
+    .. code-block:: python
+
+        with m.ostream_redirect():
+            m.print_to_cout_function()
+
+    This manager can optionally be told which streams to operate on:
+
+    .. code-block:: python
+
+        with m.ostream_redirect(stdout=true, stderr=true):
+            m.noisy_function_with_error_printing()
+
+ \endrst */
+inline class_<detail::OstreamRedirect> add_ostream_redirect(module m, std::string name = "ostream_redirect") {
+    return class_<detail::OstreamRedirect>(m, name.c_str(), module_local())
+        .def(init<bool,bool>(), arg("stdout")=true, arg("stderr")=true)
+        .def("__enter__", &detail::OstreamRedirect::enter)
+        .def("__exit__", [](detail::OstreamRedirect &self, args) { self.exit(); });
+}
+
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/numpy.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/numpy.h
new file mode 100644
index 0000000000000000000000000000000000000000..9df4934991ce011bfa6030d99021621fca6cee98
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/numpy.h
@@ -0,0 +1,1601 @@
+/*
+    pybind11/numpy.h: Basic NumPy support, vectorize() wrapper
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "pybind11.h"
+#include "complex.h"
+#include <numeric>
+#include <algorithm>
+#include <array>
+#include <cstdlib>
+#include <cstring>
+#include <sstream>
+#include <string>
+#include <initializer_list>
+#include <functional>
+#include <utility>
+#include <typeindex>
+
+#if defined(_MSC_VER)
+#  pragma warning(push)
+#  pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
+#endif
+
+/* This will be true on all flat address space platforms and allows us to reduce the
+   whole npy_intp / ssize_t / Py_intptr_t business down to just ssize_t for all size
+   and dimension types (e.g. shape, strides, indexing), instead of inflicting this
+   upon the library user. */
+static_assert(sizeof(ssize_t) == sizeof(Py_intptr_t), "ssize_t != Py_intptr_t");
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+
+class array; // Forward declaration
+
+NAMESPACE_BEGIN(detail)
+template <typename type, typename SFINAE = void> struct npy_format_descriptor;
+
+struct PyArrayDescr_Proxy {
+    PyObject_HEAD
+    PyObject *typeobj;
+    char kind;
+    char type;
+    char byteorder;
+    char flags;
+    int type_num;
+    int elsize;
+    int alignment;
+    char *subarray;
+    PyObject *fields;
+    PyObject *names;
+};
+
+struct PyArray_Proxy {
+    PyObject_HEAD
+    char *data;
+    int nd;
+    ssize_t *dimensions;
+    ssize_t *strides;
+    PyObject *base;
+    PyObject *descr;
+    int flags;
+};
+
+struct PyVoidScalarObject_Proxy {
+    PyObject_VAR_HEAD
+    char *obval;
+    PyArrayDescr_Proxy *descr;
+    int flags;
+    PyObject *base;
+};
+
+struct numpy_type_info {
+    PyObject* dtype_ptr;
+    std::string format_str;
+};
+
+struct numpy_internals {
+    std::unordered_map<std::type_index, numpy_type_info> registered_dtypes;
+
+    numpy_type_info *get_type_info(const std::type_info& tinfo, bool throw_if_missing = true) {
+        auto it = registered_dtypes.find(std::type_index(tinfo));
+        if (it != registered_dtypes.end())
+            return &(it->second);
+        if (throw_if_missing)
+            pybind11_fail(std::string("NumPy type info missing for ") + tinfo.name());
+        return nullptr;
+    }
+
+    template<typename T> numpy_type_info *get_type_info(bool throw_if_missing = true) {
+        return get_type_info(typeid(typename std::remove_cv<T>::type), throw_if_missing);
+    }
+};
+
+inline PYBIND11_NOINLINE void load_numpy_internals(numpy_internals* &ptr) {
+    ptr = &get_or_create_shared_data<numpy_internals>("_numpy_internals");
+}
+
+inline numpy_internals& get_numpy_internals() {
+    static numpy_internals* ptr = nullptr;
+    if (!ptr)
+        load_numpy_internals(ptr);
+    return *ptr;
+}
+
+struct npy_api {
+    enum constants {
+        NPY_ARRAY_C_CONTIGUOUS_ = 0x0001,
+        NPY_ARRAY_F_CONTIGUOUS_ = 0x0002,
+        NPY_ARRAY_OWNDATA_ = 0x0004,
+        NPY_ARRAY_FORCECAST_ = 0x0010,
+        NPY_ARRAY_ENSUREARRAY_ = 0x0040,
+        NPY_ARRAY_ALIGNED_ = 0x0100,
+        NPY_ARRAY_WRITEABLE_ = 0x0400,
+        NPY_BOOL_ = 0,
+        NPY_BYTE_, NPY_UBYTE_,
+        NPY_SHORT_, NPY_USHORT_,
+        NPY_INT_, NPY_UINT_,
+        NPY_LONG_, NPY_ULONG_,
+        NPY_LONGLONG_, NPY_ULONGLONG_,
+        NPY_FLOAT_, NPY_DOUBLE_, NPY_LONGDOUBLE_,
+        NPY_CFLOAT_, NPY_CDOUBLE_, NPY_CLONGDOUBLE_,
+        NPY_OBJECT_ = 17,
+        NPY_STRING_, NPY_UNICODE_, NPY_VOID_
+    };
+
+    typedef struct {
+        Py_intptr_t *ptr;
+        int len;
+    } PyArray_Dims;
+
+    static npy_api& get() {
+        static npy_api api = lookup();
+        return api;
+    }
+
+    bool PyArray_Check_(PyObject *obj) const {
+        return (bool) PyObject_TypeCheck(obj, PyArray_Type_);
+    }
+    bool PyArrayDescr_Check_(PyObject *obj) const {
+        return (bool) PyObject_TypeCheck(obj, PyArrayDescr_Type_);
+    }
+
+    unsigned int (*PyArray_GetNDArrayCFeatureVersion_)();
+    PyObject *(*PyArray_DescrFromType_)(int);
+    PyObject *(*PyArray_NewFromDescr_)
+        (PyTypeObject *, PyObject *, int, Py_intptr_t *,
+         Py_intptr_t *, void *, int, PyObject *);
+    PyObject *(*PyArray_DescrNewFromType_)(int);
+    int (*PyArray_CopyInto_)(PyObject *, PyObject *);
+    PyObject *(*PyArray_NewCopy_)(PyObject *, int);
+    PyTypeObject *PyArray_Type_;
+    PyTypeObject *PyVoidArrType_Type_;
+    PyTypeObject *PyArrayDescr_Type_;
+    PyObject *(*PyArray_DescrFromScalar_)(PyObject *);
+    PyObject *(*PyArray_FromAny_) (PyObject *, PyObject *, int, int, int, PyObject *);
+    int (*PyArray_DescrConverter_) (PyObject *, PyObject **);
+    bool (*PyArray_EquivTypes_) (PyObject *, PyObject *);
+    int (*PyArray_GetArrayParamsFromObject_)(PyObject *, PyObject *, char, PyObject **, int *,
+                                             Py_ssize_t *, PyObject **, PyObject *);
+    PyObject *(*PyArray_Squeeze_)(PyObject *);
+    int (*PyArray_SetBaseObject_)(PyObject *, PyObject *);
+    PyObject* (*PyArray_Resize_)(PyObject*, PyArray_Dims*, int, int);
+private:
+    enum functions {
+        API_PyArray_GetNDArrayCFeatureVersion = 211,
+        API_PyArray_Type = 2,
+        API_PyArrayDescr_Type = 3,
+        API_PyVoidArrType_Type = 39,
+        API_PyArray_DescrFromType = 45,
+        API_PyArray_DescrFromScalar = 57,
+        API_PyArray_FromAny = 69,
+        API_PyArray_Resize = 80,
+        API_PyArray_CopyInto = 82,
+        API_PyArray_NewCopy = 85,
+        API_PyArray_NewFromDescr = 94,
+        API_PyArray_DescrNewFromType = 9,
+        API_PyArray_DescrConverter = 174,
+        API_PyArray_EquivTypes = 182,
+        API_PyArray_GetArrayParamsFromObject = 278,
+        API_PyArray_Squeeze = 136,
+        API_PyArray_SetBaseObject = 282
+    };
+
+    static npy_api lookup() {
+        module m = module::import("numpy.core.multiarray");
+        auto c = m.attr("_ARRAY_API");
+#if PY_MAJOR_VERSION >= 3
+        void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), NULL);
+#else
+        void **api_ptr = (void **) PyCObject_AsVoidPtr(c.ptr());
+#endif
+        npy_api api;
+#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
+        DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion);
+        if (api.PyArray_GetNDArrayCFeatureVersion_() < 0x7)
+            pybind11_fail("pybind11 numpy support requires numpy >= 1.7.0");
+        DECL_NPY_API(PyArray_Type);
+        DECL_NPY_API(PyVoidArrType_Type);
+        DECL_NPY_API(PyArrayDescr_Type);
+        DECL_NPY_API(PyArray_DescrFromType);
+        DECL_NPY_API(PyArray_DescrFromScalar);
+        DECL_NPY_API(PyArray_FromAny);
+        DECL_NPY_API(PyArray_Resize);
+        DECL_NPY_API(PyArray_CopyInto);
+        DECL_NPY_API(PyArray_NewCopy);
+        DECL_NPY_API(PyArray_NewFromDescr);
+        DECL_NPY_API(PyArray_DescrNewFromType);
+        DECL_NPY_API(PyArray_DescrConverter);
+        DECL_NPY_API(PyArray_EquivTypes);
+        DECL_NPY_API(PyArray_GetArrayParamsFromObject);
+        DECL_NPY_API(PyArray_Squeeze);
+        DECL_NPY_API(PyArray_SetBaseObject);
+#undef DECL_NPY_API
+        return api;
+    }
+};
+
+inline PyArray_Proxy* array_proxy(void* ptr) {
+    return reinterpret_cast<PyArray_Proxy*>(ptr);
+}
+
+inline const PyArray_Proxy* array_proxy(const void* ptr) {
+    return reinterpret_cast<const PyArray_Proxy*>(ptr);
+}
+
+inline PyArrayDescr_Proxy* array_descriptor_proxy(PyObject* ptr) {
+   return reinterpret_cast<PyArrayDescr_Proxy*>(ptr);
+}
+
+inline const PyArrayDescr_Proxy* array_descriptor_proxy(const PyObject* ptr) {
+   return reinterpret_cast<const PyArrayDescr_Proxy*>(ptr);
+}
+
+inline bool check_flags(const void* ptr, int flag) {
+    return (flag == (array_proxy(ptr)->flags & flag));
+}
+
+template <typename T> struct is_std_array : std::false_type { };
+template <typename T, size_t N> struct is_std_array<std::array<T, N>> : std::true_type { };
+template <typename T> struct is_complex : std::false_type { };
+template <typename T> struct is_complex<std::complex<T>> : std::true_type { };
+
+template <typename T> struct array_info_scalar {
+    typedef T type;
+    static constexpr bool is_array = false;
+    static constexpr bool is_empty = false;
+    static PYBIND11_DESCR extents() { return _(""); }
+    static void append_extents(list& /* shape */) { }
+};
+// Computes underlying type and a comma-separated list of extents for array
+// types (any mix of std::array and built-in arrays). An array of char is
+// treated as scalar because it gets special handling.
+template <typename T> struct array_info : array_info_scalar<T> { };
+template <typename T, size_t N> struct array_info<std::array<T, N>> {
+    using type = typename array_info<T>::type;
+    static constexpr bool is_array = true;
+    static constexpr bool is_empty = (N == 0) || array_info<T>::is_empty;
+    static constexpr size_t extent = N;
+
+    // appends the extents to shape
+    static void append_extents(list& shape) {
+        shape.append(N);
+        array_info<T>::append_extents(shape);
+    }
+
+    template<typename T2 = T, enable_if_t<!array_info<T2>::is_array, int> = 0>
+    static PYBIND11_DESCR extents() {
+        return _<N>();
+    }
+
+    template<typename T2 = T, enable_if_t<array_info<T2>::is_array, int> = 0>
+    static PYBIND11_DESCR extents() {
+        return concat(_<N>(), array_info<T>::extents());
+    }
+};
+// For numpy we have special handling for arrays of characters, so we don't include
+// the size in the array extents.
+template <size_t N> struct array_info<char[N]> : array_info_scalar<char[N]> { };
+template <size_t N> struct array_info<std::array<char, N>> : array_info_scalar<std::array<char, N>> { };
+template <typename T, size_t N> struct array_info<T[N]> : array_info<std::array<T, N>> { };
+template <typename T> using remove_all_extents_t = typename array_info<T>::type;
+
+template <typename T> using is_pod_struct = all_of<
+    std::is_standard_layout<T>,     // since we're accessing directly in memory we need a standard layout type
+#if !defined(__GNUG__) || defined(_LIBCPP_VERSION) || defined(_GLIBCXX_USE_CXX11_ABI)
+    // _GLIBCXX_USE_CXX11_ABI indicates that we're using libstdc++ from GCC 5 or newer, independent
+    // of the actual compiler (Clang can also use libstdc++, but it always defines __GNUC__ == 4).
+    std::is_trivially_copyable<T>,
+#else
+    // GCC 4 doesn't implement is_trivially_copyable, so approximate it
+    std::is_trivially_destructible<T>,
+    satisfies_any_of<T, std::has_trivial_copy_constructor, std::has_trivial_copy_assign>,
+#endif
+    satisfies_none_of<T, std::is_reference, std::is_array, is_std_array, std::is_arithmetic, is_complex, std::is_enum>
+>;
+
+template <ssize_t Dim = 0, typename Strides> ssize_t byte_offset_unsafe(const Strides &) { return 0; }
+template <ssize_t Dim = 0, typename Strides, typename... Ix>
+ssize_t byte_offset_unsafe(const Strides &strides, ssize_t i, Ix... index) {
+    return i * strides[Dim] + byte_offset_unsafe<Dim + 1>(strides, index...);
+}
+
+/**
+ * Proxy class providing unsafe, unchecked const access to array data.  This is constructed through
+ * the `unchecked<T, N>()` method of `array` or the `unchecked<N>()` method of `array_t<T>`.  `Dims`
+ * will be -1 for dimensions determined at runtime.
+ */
+template <typename T, ssize_t Dims>
+class unchecked_reference {
+protected:
+    static constexpr bool Dynamic = Dims < 0;
+    const unsigned char *data_;
+    // Storing the shape & strides in local variables (i.e. these arrays) allows the compiler to
+    // make large performance gains on big, nested loops, but requires compile-time dimensions
+    conditional_t<Dynamic, const ssize_t *, std::array<ssize_t, (size_t) Dims>>
+            shape_, strides_;
+    const ssize_t dims_;
+
+    friend class pybind11::array;
+    // Constructor for compile-time dimensions:
+    template <bool Dyn = Dynamic>
+    unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t<!Dyn, ssize_t>)
+    : data_{reinterpret_cast<const unsigned char *>(data)}, dims_{Dims} {
+        for (size_t i = 0; i < (size_t) dims_; i++) {
+            shape_[i] = shape[i];
+            strides_[i] = strides[i];
+        }
+    }
+    // Constructor for runtime dimensions:
+    template <bool Dyn = Dynamic>
+    unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t<Dyn, ssize_t> dims)
+    : data_{reinterpret_cast<const unsigned char *>(data)}, shape_{shape}, strides_{strides}, dims_{dims} {}
+
+public:
+    /**
+     * Unchecked const reference access to data at the given indices.  For a compile-time known
+     * number of dimensions, this requires the correct number of arguments; for run-time
+     * dimensionality, this is not checked (and so is up to the caller to use safely).
+     */
+    template <typename... Ix> const T &operator()(Ix... index) const {
+        static_assert(ssize_t{sizeof...(Ix)} == Dims || Dynamic,
+                "Invalid number of indices for unchecked array reference");
+        return *reinterpret_cast<const T *>(data_ + byte_offset_unsafe(strides_, ssize_t(index)...));
+    }
+    /**
+     * Unchecked const reference access to data; this operator only participates if the reference
+     * is to a 1-dimensional array.  When present, this is exactly equivalent to `obj(index)`.
+     */
+    template <ssize_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
+    const T &operator[](ssize_t index) const { return operator()(index); }
+
+    /// Pointer access to the data at the given indices.
+    template <typename... Ix> const T *data(Ix... ix) const { return &operator()(ssize_t(ix)...); }
+
+    /// Returns the item size, i.e. sizeof(T)
+    constexpr static ssize_t itemsize() { return sizeof(T); }
+
+    /// Returns the shape (i.e. size) of dimension `dim`
+    ssize_t shape(ssize_t dim) const { return shape_[(size_t) dim]; }
+
+    /// Returns the number of dimensions of the array
+    ssize_t ndim() const { return dims_; }
+
+    /// Returns the total number of elements in the referenced array, i.e. the product of the shapes
+    template <bool Dyn = Dynamic>
+    enable_if_t<!Dyn, ssize_t> size() const {
+        return std::accumulate(shape_.begin(), shape_.end(), (ssize_t) 1, std::multiplies<ssize_t>());
+    }
+    template <bool Dyn = Dynamic>
+    enable_if_t<Dyn, ssize_t> size() const {
+        return std::accumulate(shape_, shape_ + ndim(), (ssize_t) 1, std::multiplies<ssize_t>());
+    }
+
+    /// Returns the total number of bytes used by the referenced data.  Note that the actual span in
+    /// memory may be larger if the referenced array has non-contiguous strides (e.g. for a slice).
+    ssize_t nbytes() const {
+        return size() * itemsize();
+    }
+};
+
+template <typename T, ssize_t Dims>
+class unchecked_mutable_reference : public unchecked_reference<T, Dims> {
+    friend class pybind11::array;
+    using ConstBase = unchecked_reference<T, Dims>;
+    using ConstBase::ConstBase;
+    using ConstBase::Dynamic;
+public:
+    /// Mutable, unchecked access to data at the given indices.
+    template <typename... Ix> T& operator()(Ix... index) {
+        static_assert(ssize_t{sizeof...(Ix)} == Dims || Dynamic,
+                "Invalid number of indices for unchecked array reference");
+        return const_cast<T &>(ConstBase::operator()(index...));
+    }
+    /**
+     * Mutable, unchecked access data at the given index; this operator only participates if the
+     * reference is to a 1-dimensional array (or has runtime dimensions).  When present, this is
+     * exactly equivalent to `obj(index)`.
+     */
+    template <ssize_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
+    T &operator[](ssize_t index) { return operator()(index); }
+
+    /// Mutable pointer access to the data at the given indices.
+    template <typename... Ix> T *mutable_data(Ix... ix) { return &operator()(ssize_t(ix)...); }
+};
+
+template <typename T, ssize_t Dim>
+struct type_caster<unchecked_reference<T, Dim>> {
+    static_assert(Dim == 0 && Dim > 0 /* always fail */, "unchecked array proxy object is not castable");
+};
+template <typename T, ssize_t Dim>
+struct type_caster<unchecked_mutable_reference<T, Dim>> : type_caster<unchecked_reference<T, Dim>> {};
+
+NAMESPACE_END(detail)
+
+class dtype : public object {
+public:
+    PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_);
+
+    explicit dtype(const buffer_info &info) {
+        dtype descr(_dtype_from_pep3118()(PYBIND11_STR_TYPE(info.format)));
+        // If info.itemsize == 0, use the value calculated from the format string
+        m_ptr = descr.strip_padding(info.itemsize ? info.itemsize : descr.itemsize()).release().ptr();
+    }
+
+    explicit dtype(const std::string &format) {
+        m_ptr = from_args(pybind11::str(format)).release().ptr();
+    }
+
+    dtype(const char *format) : dtype(std::string(format)) { }
+
+    dtype(list names, list formats, list offsets, ssize_t itemsize) {
+        dict args;
+        args["names"] = names;
+        args["formats"] = formats;
+        args["offsets"] = offsets;
+        args["itemsize"] = pybind11::int_(itemsize);
+        m_ptr = from_args(args).release().ptr();
+    }
+
+    /// This is essentially the same as calling numpy.dtype(args) in Python.
+    static dtype from_args(object args) {
+        PyObject *ptr = nullptr;
+        if (!detail::npy_api::get().PyArray_DescrConverter_(args.release().ptr(), &ptr) || !ptr)
+            throw error_already_set();
+        return reinterpret_steal<dtype>(ptr);
+    }
+
+    /// Return dtype associated with a C++ type.
+    template <typename T> static dtype of() {
+        return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::dtype();
+    }
+
+    /// Size of the data type in bytes.
+    ssize_t itemsize() const {
+        return detail::array_descriptor_proxy(m_ptr)->elsize;
+    }
+
+    /// Returns true for structured data types.
+    bool has_fields() const {
+        return detail::array_descriptor_proxy(m_ptr)->names != nullptr;
+    }
+
+    /// Single-character type code.
+    char kind() const {
+        return detail::array_descriptor_proxy(m_ptr)->kind;
+    }
+
+private:
+    static object _dtype_from_pep3118() {
+        static PyObject *obj = module::import("numpy.core._internal")
+            .attr("_dtype_from_pep3118").cast<object>().release().ptr();
+        return reinterpret_borrow<object>(obj);
+    }
+
+    dtype strip_padding(ssize_t itemsize) {
+        // Recursively strip all void fields with empty names that are generated for
+        // padding fields (as of NumPy v1.11).
+        if (!has_fields())
+            return *this;
+
+        struct field_descr { PYBIND11_STR_TYPE name; object format; pybind11::int_ offset; };
+        std::vector<field_descr> field_descriptors;
+
+        for (auto field : attr("fields").attr("items")()) {
+            auto spec = field.cast<tuple>();
+            auto name = spec[0].cast<pybind11::str>();
+            auto format = spec[1].cast<tuple>()[0].cast<dtype>();
+            auto offset = spec[1].cast<tuple>()[1].cast<pybind11::int_>();
+            if (!len(name) && format.kind() == 'V')
+                continue;
+            field_descriptors.push_back({(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset});
+        }
+
+        std::sort(field_descriptors.begin(), field_descriptors.end(),
+                  [](const field_descr& a, const field_descr& b) {
+                      return a.offset.cast<int>() < b.offset.cast<int>();
+                  });
+
+        list names, formats, offsets;
+        for (auto& descr : field_descriptors) {
+            names.append(descr.name);
+            formats.append(descr.format);
+            offsets.append(descr.offset);
+        }
+        return dtype(names, formats, offsets, itemsize);
+    }
+};
+
+class array : public buffer {
+public:
+    PYBIND11_OBJECT_CVT(array, buffer, detail::npy_api::get().PyArray_Check_, raw_array)
+
+    enum {
+        c_style = detail::npy_api::NPY_ARRAY_C_CONTIGUOUS_,
+        f_style = detail::npy_api::NPY_ARRAY_F_CONTIGUOUS_,
+        forcecast = detail::npy_api::NPY_ARRAY_FORCECAST_
+    };
+
+    array() : array({{0}}, static_cast<const double *>(nullptr)) {}
+
+    using ShapeContainer = detail::any_container<ssize_t>;
+    using StridesContainer = detail::any_container<ssize_t>;
+
+    // Constructs an array taking shape/strides from arbitrary container types
+    array(const pybind11::dtype &dt, ShapeContainer shape, StridesContainer strides,
+          const void *ptr = nullptr, handle base = handle()) {
+
+        if (strides->empty())
+            *strides = c_strides(*shape, dt.itemsize());
+
+        auto ndim = shape->size();
+        if (ndim != strides->size())
+            pybind11_fail("NumPy: shape ndim doesn't match strides ndim");
+        auto descr = dt;
+
+        int flags = 0;
+        if (base && ptr) {
+            if (isinstance<array>(base))
+                /* Copy flags from base (except ownership bit) */
+                flags = reinterpret_borrow<array>(base).flags() & ~detail::npy_api::NPY_ARRAY_OWNDATA_;
+            else
+                /* Writable by default, easy to downgrade later on if needed */
+                flags = detail::npy_api::NPY_ARRAY_WRITEABLE_;
+        }
+
+        auto &api = detail::npy_api::get();
+        auto tmp = reinterpret_steal<object>(api.PyArray_NewFromDescr_(
+            api.PyArray_Type_, descr.release().ptr(), (int) ndim, shape->data(), strides->data(),
+            const_cast<void *>(ptr), flags, nullptr));
+        if (!tmp)
+            throw error_already_set();
+        if (ptr) {
+            if (base) {
+                api.PyArray_SetBaseObject_(tmp.ptr(), base.inc_ref().ptr());
+            } else {
+                tmp = reinterpret_steal<object>(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */));
+            }
+        }
+        m_ptr = tmp.release().ptr();
+    }
+
+    array(const pybind11::dtype &dt, ShapeContainer shape, const void *ptr = nullptr, handle base = handle())
+        : array(dt, std::move(shape), {}, ptr, base) { }
+
+    template <typename T, typename = detail::enable_if_t<std::is_integral<T>::value && !std::is_same<bool, T>::value>>
+    array(const pybind11::dtype &dt, T count, const void *ptr = nullptr, handle base = handle())
+        : array(dt, {{count}}, ptr, base) { }
+
+    template <typename T>
+    array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle())
+        : array(pybind11::dtype::of<T>(), std::move(shape), std::move(strides), ptr, base) { }
+
+    template <typename T>
+    array(ShapeContainer shape, const T *ptr, handle base = handle())
+        : array(std::move(shape), {}, ptr, base) { }
+
+    template <typename T>
+    explicit array(ssize_t count, const T *ptr, handle base = handle()) : array({count}, {}, ptr, base) { }
+
+    explicit array(const buffer_info &info)
+    : array(pybind11::dtype(info), info.shape, info.strides, info.ptr) { }
+
+    /// Array descriptor (dtype)
+    pybind11::dtype dtype() const {
+        return reinterpret_borrow<pybind11::dtype>(detail::array_proxy(m_ptr)->descr);
+    }
+
+    /// Total number of elements
+    ssize_t size() const {
+        return std::accumulate(shape(), shape() + ndim(), (ssize_t) 1, std::multiplies<ssize_t>());
+    }
+
+    /// Byte size of a single element
+    ssize_t itemsize() const {
+        return detail::array_descriptor_proxy(detail::array_proxy(m_ptr)->descr)->elsize;
+    }
+
+    /// Total number of bytes
+    ssize_t nbytes() const {
+        return size() * itemsize();
+    }
+
+    /// Number of dimensions
+    ssize_t ndim() const {
+        return detail::array_proxy(m_ptr)->nd;
+    }
+
+    /// Base object
+    object base() const {
+        return reinterpret_borrow<object>(detail::array_proxy(m_ptr)->base);
+    }
+
+    /// Dimensions of the array
+    const ssize_t* shape() const {
+        return detail::array_proxy(m_ptr)->dimensions;
+    }
+
+    /// Dimension along a given axis
+    ssize_t shape(ssize_t dim) const {
+        if (dim >= ndim())
+            fail_dim_check(dim, "invalid axis");
+        return shape()[dim];
+    }
+
+    /// Strides of the array
+    const ssize_t* strides() const {
+        return detail::array_proxy(m_ptr)->strides;
+    }
+
+    /// Stride along a given axis
+    ssize_t strides(ssize_t dim) const {
+        if (dim >= ndim())
+            fail_dim_check(dim, "invalid axis");
+        return strides()[dim];
+    }
+
+    /// Return the NumPy array flags
+    int flags() const {
+        return detail::array_proxy(m_ptr)->flags;
+    }
+
+    /// If set, the array is writeable (otherwise the buffer is read-only)
+    bool writeable() const {
+        return detail::check_flags(m_ptr, detail::npy_api::NPY_ARRAY_WRITEABLE_);
+    }
+
+    /// If set, the array owns the data (will be freed when the array is deleted)
+    bool owndata() const {
+        return detail::check_flags(m_ptr, detail::npy_api::NPY_ARRAY_OWNDATA_);
+    }
+
+    /// Pointer to the contained data. If index is not provided, points to the
+    /// beginning of the buffer. May throw if the index would lead to out of bounds access.
+    template<typename... Ix> const void* data(Ix... index) const {
+        return static_cast<const void *>(detail::array_proxy(m_ptr)->data + offset_at(index...));
+    }
+
+    /// Mutable pointer to the contained data. If index is not provided, points to the
+    /// beginning of the buffer. May throw if the index would lead to out of bounds access.
+    /// May throw if the array is not writeable.
+    template<typename... Ix> void* mutable_data(Ix... index) {
+        check_writeable();
+        return static_cast<void *>(detail::array_proxy(m_ptr)->data + offset_at(index...));
+    }
+
+    /// Byte offset from beginning of the array to a given index (full or partial).
+    /// May throw if the index would lead to out of bounds access.
+    template<typename... Ix> ssize_t offset_at(Ix... index) const {
+        if ((ssize_t) sizeof...(index) > ndim())
+            fail_dim_check(sizeof...(index), "too many indices for an array");
+        return byte_offset(ssize_t(index)...);
+    }
+
+    ssize_t offset_at() const { return 0; }
+
+    /// Item count from beginning of the array to a given index (full or partial).
+    /// May throw if the index would lead to out of bounds access.
+    template<typename... Ix> ssize_t index_at(Ix... index) const {
+        return offset_at(index...) / itemsize();
+    }
+
+    /**
+     * Returns a proxy object that provides access to the array's data without bounds or
+     * dimensionality checking.  Will throw if the array is missing the `writeable` flag.  Use with
+     * care: the array must not be destroyed or reshaped for the duration of the returned object,
+     * and the caller must take care not to access invalid dimensions or dimension indices.
+     */
+    template <typename T, ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() & {
+        if (Dims >= 0 && ndim() != Dims)
+            throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) +
+                    "; expected " + std::to_string(Dims));
+        return detail::unchecked_mutable_reference<T, Dims>(mutable_data(), shape(), strides(), ndim());
+    }
+
+    /**
+     * Returns a proxy object that provides const access to the array's data without bounds or
+     * dimensionality checking.  Unlike `mutable_unchecked()`, this does not require that the
+     * underlying array have the `writable` flag.  Use with care: the array must not be destroyed or
+     * reshaped for the duration of the returned object, and the caller must take care not to access
+     * invalid dimensions or dimension indices.
+     */
+    template <typename T, ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const & {
+        if (Dims >= 0 && ndim() != Dims)
+            throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) +
+                    "; expected " + std::to_string(Dims));
+        return detail::unchecked_reference<T, Dims>(data(), shape(), strides(), ndim());
+    }
+
+    /// Return a new view with all of the dimensions of length 1 removed
+    array squeeze() {
+        auto& api = detail::npy_api::get();
+        return reinterpret_steal<array>(api.PyArray_Squeeze_(m_ptr));
+    }
+
+    /// Resize array to given shape
+    /// If refcheck is true and more that one reference exist to this array
+    /// then resize will succeed only if it makes a reshape, i.e. original size doesn't change
+    void resize(ShapeContainer new_shape, bool refcheck = true) {
+        detail::npy_api::PyArray_Dims d = {
+            new_shape->data(), int(new_shape->size())
+        };
+        // try to resize, set ordering param to -1 cause it's not used anyway
+        object new_array = reinterpret_steal<object>(
+            detail::npy_api::get().PyArray_Resize_(m_ptr, &d, int(refcheck), -1)
+        );
+        if (!new_array) throw error_already_set();
+        if (isinstance<array>(new_array)) { *this = std::move(new_array); }
+    }
+
+    /// Ensure that the argument is a NumPy array
+    /// In case of an error, nullptr is returned and the Python error is cleared.
+    static array ensure(handle h, int ExtraFlags = 0) {
+        auto result = reinterpret_steal<array>(raw_array(h.ptr(), ExtraFlags));
+        if (!result)
+            PyErr_Clear();
+        return result;
+    }
+
+protected:
+    template<typename, typename> friend struct detail::npy_format_descriptor;
+
+    void fail_dim_check(ssize_t dim, const std::string& msg) const {
+        throw index_error(msg + ": " + std::to_string(dim) +
+                          " (ndim = " + std::to_string(ndim()) + ")");
+    }
+
+    template<typename... Ix> ssize_t byte_offset(Ix... index) const {
+        check_dimensions(index...);
+        return detail::byte_offset_unsafe(strides(), ssize_t(index)...);
+    }
+
+    void check_writeable() const {
+        if (!writeable())
+            throw std::domain_error("array is not writeable");
+    }
+
+    // Default, C-style strides
+    static std::vector<ssize_t> c_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) {
+        auto ndim = shape.size();
+        std::vector<ssize_t> strides(ndim, itemsize);
+        if (ndim > 0)
+            for (size_t i = ndim - 1; i > 0; --i)
+                strides[i - 1] = strides[i] * shape[i];
+        return strides;
+    }
+
+    // F-style strides; default when constructing an array_t with `ExtraFlags & f_style`
+    static std::vector<ssize_t> f_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) {
+        auto ndim = shape.size();
+        std::vector<ssize_t> strides(ndim, itemsize);
+        for (size_t i = 1; i < ndim; ++i)
+            strides[i] = strides[i - 1] * shape[i - 1];
+        return strides;
+    }
+
+    template<typename... Ix> void check_dimensions(Ix... index) const {
+        check_dimensions_impl(ssize_t(0), shape(), ssize_t(index)...);
+    }
+
+    void check_dimensions_impl(ssize_t, const ssize_t*) const { }
+
+    template<typename... Ix> void check_dimensions_impl(ssize_t axis, const ssize_t* shape, ssize_t i, Ix... index) const {
+        if (i >= *shape) {
+            throw index_error(std::string("index ") + std::to_string(i) +
+                              " is out of bounds for axis " + std::to_string(axis) +
+                              " with size " + std::to_string(*shape));
+        }
+        check_dimensions_impl(axis + 1, shape + 1, index...);
+    }
+
+    /// Create array from any object -- always returns a new reference
+    static PyObject *raw_array(PyObject *ptr, int ExtraFlags = 0) {
+        if (ptr == nullptr) {
+            PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array from a nullptr");
+            return nullptr;
+        }
+        return detail::npy_api::get().PyArray_FromAny_(
+            ptr, nullptr, 0, 0, detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr);
+    }
+};
+
+template <typename T, int ExtraFlags = array::forcecast> class array_t : public array {
+private:
+    struct private_ctor {};
+    // Delegating constructor needed when both moving and accessing in the same constructor
+    array_t(private_ctor, ShapeContainer &&shape, StridesContainer &&strides, const T *ptr, handle base)
+        : array(std::move(shape), std::move(strides), ptr, base) {}
+public:
+    static_assert(!detail::array_info<T>::is_array, "Array types cannot be used with array_t");
+
+    using value_type = T;
+
+    array_t() : array(0, static_cast<const T *>(nullptr)) {}
+    array_t(handle h, borrowed_t) : array(h, borrowed_t{}) { }
+    array_t(handle h, stolen_t) : array(h, stolen_t{}) { }
+
+    PYBIND11_DEPRECATED("Use array_t<T>::ensure() instead")
+    array_t(handle h, bool is_borrowed) : array(raw_array_t(h.ptr()), stolen_t{}) {
+        if (!m_ptr) PyErr_Clear();
+        if (!is_borrowed) Py_XDECREF(h.ptr());
+    }
+
+    array_t(const object &o) : array(raw_array_t(o.ptr()), stolen_t{}) {
+        if (!m_ptr) throw error_already_set();
+    }
+
+    explicit array_t(const buffer_info& info) : array(info) { }
+
+    array_t(ShapeContainer shape, StridesContainer strides, const T *ptr = nullptr, handle base = handle())
+        : array(std::move(shape), std::move(strides), ptr, base) { }
+
+    explicit array_t(ShapeContainer shape, const T *ptr = nullptr, handle base = handle())
+        : array_t(private_ctor{}, std::move(shape),
+                ExtraFlags & f_style ? f_strides(*shape, itemsize()) : c_strides(*shape, itemsize()),
+                ptr, base) { }
+
+    explicit array_t(size_t count, const T *ptr = nullptr, handle base = handle())
+        : array({count}, {}, ptr, base) { }
+
+    constexpr ssize_t itemsize() const {
+        return sizeof(T);
+    }
+
+    template<typename... Ix> ssize_t index_at(Ix... index) const {
+        return offset_at(index...) / itemsize();
+    }
+
+    template<typename... Ix> const T* data(Ix... index) const {
+        return static_cast<const T*>(array::data(index...));
+    }
+
+    template<typename... Ix> T* mutable_data(Ix... index) {
+        return static_cast<T*>(array::mutable_data(index...));
+    }
+
+    // Reference to element at a given index
+    template<typename... Ix> const T& at(Ix... index) const {
+        if (sizeof...(index) != ndim())
+            fail_dim_check(sizeof...(index), "index dimension mismatch");
+        return *(static_cast<const T*>(array::data()) + byte_offset(ssize_t(index)...) / itemsize());
+    }
+
+    // Mutable reference to element at a given index
+    template<typename... Ix> T& mutable_at(Ix... index) {
+        if (sizeof...(index) != ndim())
+            fail_dim_check(sizeof...(index), "index dimension mismatch");
+        return *(static_cast<T*>(array::mutable_data()) + byte_offset(ssize_t(index)...) / itemsize());
+    }
+
+    /**
+     * Returns a proxy object that provides access to the array's data without bounds or
+     * dimensionality checking.  Will throw if the array is missing the `writeable` flag.  Use with
+     * care: the array must not be destroyed or reshaped for the duration of the returned object,
+     * and the caller must take care not to access invalid dimensions or dimension indices.
+     */
+    template <ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() & {
+        return array::mutable_unchecked<T, Dims>();
+    }
+
+    /**
+     * Returns a proxy object that provides const access to the array's data without bounds or
+     * dimensionality checking.  Unlike `unchecked()`, this does not require that the underlying
+     * array have the `writable` flag.  Use with care: the array must not be destroyed or reshaped
+     * for the duration of the returned object, and the caller must take care not to access invalid
+     * dimensions or dimension indices.
+     */
+    template <ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const & {
+        return array::unchecked<T, Dims>();
+    }
+
+    /// Ensure that the argument is a NumPy array of the correct dtype (and if not, try to convert
+    /// it).  In case of an error, nullptr is returned and the Python error is cleared.
+    static array_t ensure(handle h) {
+        auto result = reinterpret_steal<array_t>(raw_array_t(h.ptr()));
+        if (!result)
+            PyErr_Clear();
+        return result;
+    }
+
+    static bool check_(handle h) {
+        const auto &api = detail::npy_api::get();
+        return api.PyArray_Check_(h.ptr())
+               && api.PyArray_EquivTypes_(detail::array_proxy(h.ptr())->descr, dtype::of<T>().ptr());
+    }
+
+protected:
+    /// Create array from any object -- always returns a new reference
+    static PyObject *raw_array_t(PyObject *ptr) {
+        if (ptr == nullptr) {
+            PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array_t from a nullptr");
+            return nullptr;
+        }
+        return detail::npy_api::get().PyArray_FromAny_(
+            ptr, dtype::of<T>().release().ptr(), 0, 0,
+            detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr);
+    }
+};
+
+template <typename T>
+struct format_descriptor<T, detail::enable_if_t<detail::is_pod_struct<T>::value>> {
+    static std::string format() {
+        return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::format();
+    }
+};
+
+template <size_t N> struct format_descriptor<char[N]> {
+    static std::string format() { return std::to_string(N) + "s"; }
+};
+template <size_t N> struct format_descriptor<std::array<char, N>> {
+    static std::string format() { return std::to_string(N) + "s"; }
+};
+
+template <typename T>
+struct format_descriptor<T, detail::enable_if_t<std::is_enum<T>::value>> {
+    static std::string format() {
+        return format_descriptor<
+            typename std::remove_cv<typename std::underlying_type<T>::type>::type>::format();
+    }
+};
+
+template <typename T>
+struct format_descriptor<T, detail::enable_if_t<detail::array_info<T>::is_array>> {
+    static std::string format() {
+        using namespace detail;
+        PYBIND11_DESCR extents = _("(") + array_info<T>::extents() + _(")");
+        return extents.text() + format_descriptor<remove_all_extents_t<T>>::format();
+    }
+};
+
+NAMESPACE_BEGIN(detail)
+template <typename T, int ExtraFlags>
+struct pyobject_caster<array_t<T, ExtraFlags>> {
+    using type = array_t<T, ExtraFlags>;
+
+    bool load(handle src, bool convert) {
+        if (!convert && !type::check_(src))
+            return false;
+        value = type::ensure(src);
+        return static_cast<bool>(value);
+    }
+
+    static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {
+        return src.inc_ref();
+    }
+    PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name());
+};
+
+template <typename T>
+struct compare_buffer_info<T, detail::enable_if_t<detail::is_pod_struct<T>::value>> {
+    static bool compare(const buffer_info& b) {
+        return npy_api::get().PyArray_EquivTypes_(dtype::of<T>().ptr(), dtype(b).ptr());
+    }
+};
+
+template <typename T> struct npy_format_descriptor<T, enable_if_t<satisfies_any_of<T, std::is_arithmetic, is_complex>::value>> {
+private:
+    // NB: the order here must match the one in common.h
+    constexpr static const int values[15] = {
+        npy_api::NPY_BOOL_,
+        npy_api::NPY_BYTE_,   npy_api::NPY_UBYTE_,   npy_api::NPY_SHORT_,    npy_api::NPY_USHORT_,
+        npy_api::NPY_INT_,    npy_api::NPY_UINT_,    npy_api::NPY_LONGLONG_, npy_api::NPY_ULONGLONG_,
+        npy_api::NPY_FLOAT_,  npy_api::NPY_DOUBLE_,  npy_api::NPY_LONGDOUBLE_,
+        npy_api::NPY_CFLOAT_, npy_api::NPY_CDOUBLE_, npy_api::NPY_CLONGDOUBLE_
+    };
+
+public:
+    static constexpr int value = values[detail::is_fmt_numeric<T>::index];
+
+    static pybind11::dtype dtype() {
+        if (auto ptr = npy_api::get().PyArray_DescrFromType_(value))
+            return reinterpret_borrow<pybind11::dtype>(ptr);
+        pybind11_fail("Unsupported buffer format!");
+    }
+    template <typename T2 = T, enable_if_t<std::is_integral<T2>::value, int> = 0>
+    static PYBIND11_DESCR name() {
+        return _<std::is_same<T, bool>::value>(_("bool"),
+            _<std::is_signed<T>::value>("int", "uint") + _<sizeof(T)*8>());
+    }
+    template <typename T2 = T, enable_if_t<std::is_floating_point<T2>::value, int> = 0>
+    static PYBIND11_DESCR name() {
+        return _<std::is_same<T, float>::value || std::is_same<T, double>::value>(
+                _("float") + _<sizeof(T)*8>(), _("longdouble"));
+    }
+    template <typename T2 = T, enable_if_t<is_complex<T2>::value, int> = 0>
+    static PYBIND11_DESCR name() {
+        return _<std::is_same<typename T2::value_type, float>::value || std::is_same<typename T2::value_type, double>::value>(
+                _("complex") + _<sizeof(typename T2::value_type)*16>(), _("longcomplex"));
+    }
+};
+
+#define PYBIND11_DECL_CHAR_FMT \
+    static PYBIND11_DESCR name() { return _("S") + _<N>(); } \
+    static pybind11::dtype dtype() { return pybind11::dtype(std::string("S") + std::to_string(N)); }
+template <size_t N> struct npy_format_descriptor<char[N]> { PYBIND11_DECL_CHAR_FMT };
+template <size_t N> struct npy_format_descriptor<std::array<char, N>> { PYBIND11_DECL_CHAR_FMT };
+#undef PYBIND11_DECL_CHAR_FMT
+
+template<typename T> struct npy_format_descriptor<T, enable_if_t<array_info<T>::is_array>> {
+private:
+    using base_descr = npy_format_descriptor<typename array_info<T>::type>;
+public:
+    static_assert(!array_info<T>::is_empty, "Zero-sized arrays are not supported");
+
+    static PYBIND11_DESCR name() { return _("(") + array_info<T>::extents() + _(")") + base_descr::name(); }
+    static pybind11::dtype dtype() {
+        list shape;
+        array_info<T>::append_extents(shape);
+        return pybind11::dtype::from_args(pybind11::make_tuple(base_descr::dtype(), shape));
+    }
+};
+
+template<typename T> struct npy_format_descriptor<T, enable_if_t<std::is_enum<T>::value>> {
+private:
+    using base_descr = npy_format_descriptor<typename std::underlying_type<T>::type>;
+public:
+    static PYBIND11_DESCR name() { return base_descr::name(); }
+    static pybind11::dtype dtype() { return base_descr::dtype(); }
+};
+
+struct field_descriptor {
+    const char *name;
+    ssize_t offset;
+    ssize_t size;
+    std::string format;
+    dtype descr;
+};
+
+inline PYBIND11_NOINLINE void register_structured_dtype(
+    const std::initializer_list<field_descriptor>& fields,
+    const std::type_info& tinfo, ssize_t itemsize,
+    bool (*direct_converter)(PyObject *, void *&)) {
+
+    auto& numpy_internals = get_numpy_internals();
+    if (numpy_internals.get_type_info(tinfo, false))
+        pybind11_fail("NumPy: dtype is already registered");
+
+    list names, formats, offsets;
+    for (auto field : fields) {
+        if (!field.descr)
+            pybind11_fail(std::string("NumPy: unsupported field dtype: `") +
+                            field.name + "` @ " + tinfo.name());
+        names.append(PYBIND11_STR_TYPE(field.name));
+        formats.append(field.descr);
+        offsets.append(pybind11::int_(field.offset));
+    }
+    auto dtype_ptr = pybind11::dtype(names, formats, offsets, itemsize).release().ptr();
+
+    // There is an existing bug in NumPy (as of v1.11): trailing bytes are
+    // not encoded explicitly into the format string. This will supposedly
+    // get fixed in v1.12; for further details, see these:
+    // - https://github.com/numpy/numpy/issues/7797
+    // - https://github.com/numpy/numpy/pull/7798
+    // Because of this, we won't use numpy's logic to generate buffer format
+    // strings and will just do it ourselves.
+    std::vector<field_descriptor> ordered_fields(fields);
+    std::sort(ordered_fields.begin(), ordered_fields.end(),
+        [](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; });
+    ssize_t offset = 0;
+    std::ostringstream oss;
+    // mark the structure as unaligned with '^', because numpy and C++ don't
+    // always agree about alignment (particularly for complex), and we're
+    // explicitly listing all our padding. This depends on none of the fields
+    // overriding the endianness. Putting the ^ in front of individual fields
+    // isn't guaranteed to work due to https://github.com/numpy/numpy/issues/9049
+    oss << "^T{";
+    for (auto& field : ordered_fields) {
+        if (field.offset > offset)
+            oss << (field.offset - offset) << 'x';
+        oss << field.format << ':' << field.name << ':';
+        offset = field.offset + field.size;
+    }
+    if (itemsize > offset)
+        oss << (itemsize - offset) << 'x';
+    oss << '}';
+    auto format_str = oss.str();
+
+    // Sanity check: verify that NumPy properly parses our buffer format string
+    auto& api = npy_api::get();
+    auto arr =  array(buffer_info(nullptr, itemsize, format_str, 1));
+    if (!api.PyArray_EquivTypes_(dtype_ptr, arr.dtype().ptr()))
+        pybind11_fail("NumPy: invalid buffer descriptor!");
+
+    auto tindex = std::type_index(tinfo);
+    numpy_internals.registered_dtypes[tindex] = { dtype_ptr, format_str };
+    get_internals().direct_conversions[tindex].push_back(direct_converter);
+}
+
+template <typename T, typename SFINAE> struct npy_format_descriptor {
+    static_assert(is_pod_struct<T>::value, "Attempt to use a non-POD or unimplemented POD type as a numpy dtype");
+
+    static PYBIND11_DESCR name() { return make_caster<T>::name(); }
+
+    static pybind11::dtype dtype() {
+        return reinterpret_borrow<pybind11::dtype>(dtype_ptr());
+    }
+
+    static std::string format() {
+        static auto format_str = get_numpy_internals().get_type_info<T>(true)->format_str;
+        return format_str;
+    }
+
+    static void register_dtype(const std::initializer_list<field_descriptor>& fields) {
+        register_structured_dtype(fields, typeid(typename std::remove_cv<T>::type),
+                                  sizeof(T), &direct_converter);
+    }
+
+private:
+    static PyObject* dtype_ptr() {
+        static PyObject* ptr = get_numpy_internals().get_type_info<T>(true)->dtype_ptr;
+        return ptr;
+    }
+
+    static bool direct_converter(PyObject *obj, void*& value) {
+        auto& api = npy_api::get();
+        if (!PyObject_TypeCheck(obj, api.PyVoidArrType_Type_))
+            return false;
+        if (auto descr = reinterpret_steal<object>(api.PyArray_DescrFromScalar_(obj))) {
+            if (api.PyArray_EquivTypes_(dtype_ptr(), descr.ptr())) {
+                value = ((PyVoidScalarObject_Proxy *) obj)->obval;
+                return true;
+            }
+        }
+        return false;
+    }
+};
+
+#ifdef __CLION_IDE__ // replace heavy macro with dummy code for the IDE (doesn't affect code)
+# define PYBIND11_NUMPY_DTYPE(Type, ...) ((void)0)
+# define PYBIND11_NUMPY_DTYPE_EX(Type, ...) ((void)0)
+#else
+
+#define PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, Name)                                          \
+    ::pybind11::detail::field_descriptor {                                                    \
+        Name, offsetof(T, Field), sizeof(decltype(std::declval<T>().Field)),                  \
+        ::pybind11::format_descriptor<decltype(std::declval<T>().Field)>::format(),           \
+        ::pybind11::detail::npy_format_descriptor<decltype(std::declval<T>().Field)>::dtype() \
+    }
+
+// Extract name, offset and format descriptor for a struct field
+#define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, #Field)
+
+// The main idea of this macro is borrowed from https://github.com/swansontec/map-macro
+// (C) William Swanson, Paul Fultz
+#define PYBIND11_EVAL0(...) __VA_ARGS__
+#define PYBIND11_EVAL1(...) PYBIND11_EVAL0 (PYBIND11_EVAL0 (PYBIND11_EVAL0 (__VA_ARGS__)))
+#define PYBIND11_EVAL2(...) PYBIND11_EVAL1 (PYBIND11_EVAL1 (PYBIND11_EVAL1 (__VA_ARGS__)))
+#define PYBIND11_EVAL3(...) PYBIND11_EVAL2 (PYBIND11_EVAL2 (PYBIND11_EVAL2 (__VA_ARGS__)))
+#define PYBIND11_EVAL4(...) PYBIND11_EVAL3 (PYBIND11_EVAL3 (PYBIND11_EVAL3 (__VA_ARGS__)))
+#define PYBIND11_EVAL(...)  PYBIND11_EVAL4 (PYBIND11_EVAL4 (PYBIND11_EVAL4 (__VA_ARGS__)))
+#define PYBIND11_MAP_END(...)
+#define PYBIND11_MAP_OUT
+#define PYBIND11_MAP_COMMA ,
+#define PYBIND11_MAP_GET_END() 0, PYBIND11_MAP_END
+#define PYBIND11_MAP_NEXT0(test, next, ...) next PYBIND11_MAP_OUT
+#define PYBIND11_MAP_NEXT1(test, next) PYBIND11_MAP_NEXT0 (test, next, 0)
+#define PYBIND11_MAP_NEXT(test, next)  PYBIND11_MAP_NEXT1 (PYBIND11_MAP_GET_END test, next)
+#ifdef _MSC_VER // MSVC is not as eager to expand macros, hence this workaround
+#define PYBIND11_MAP_LIST_NEXT1(test, next) \
+    PYBIND11_EVAL0 (PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0))
+#else
+#define PYBIND11_MAP_LIST_NEXT1(test, next) \
+    PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0)
+#endif
+#define PYBIND11_MAP_LIST_NEXT(test, next) \
+    PYBIND11_MAP_LIST_NEXT1 (PYBIND11_MAP_GET_END test, next)
+#define PYBIND11_MAP_LIST0(f, t, x, peek, ...) \
+    f(t, x) PYBIND11_MAP_LIST_NEXT (peek, PYBIND11_MAP_LIST1) (f, t, peek, __VA_ARGS__)
+#define PYBIND11_MAP_LIST1(f, t, x, peek, ...) \
+    f(t, x) PYBIND11_MAP_LIST_NEXT (peek, PYBIND11_MAP_LIST0) (f, t, peek, __VA_ARGS__)
+// PYBIND11_MAP_LIST(f, t, a1, a2, ...) expands to f(t, a1), f(t, a2), ...
+#define PYBIND11_MAP_LIST(f, t, ...) \
+    PYBIND11_EVAL (PYBIND11_MAP_LIST1 (f, t, __VA_ARGS__, (), 0))
+
+#define PYBIND11_NUMPY_DTYPE(Type, ...) \
+    ::pybind11::detail::npy_format_descriptor<Type>::register_dtype \
+        ({PYBIND11_MAP_LIST (PYBIND11_FIELD_DESCRIPTOR, Type, __VA_ARGS__)})
+
+#ifdef _MSC_VER
+#define PYBIND11_MAP2_LIST_NEXT1(test, next) \
+    PYBIND11_EVAL0 (PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0))
+#else
+#define PYBIND11_MAP2_LIST_NEXT1(test, next) \
+    PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0)
+#endif
+#define PYBIND11_MAP2_LIST_NEXT(test, next) \
+    PYBIND11_MAP2_LIST_NEXT1 (PYBIND11_MAP_GET_END test, next)
+#define PYBIND11_MAP2_LIST0(f, t, x1, x2, peek, ...) \
+    f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT (peek, PYBIND11_MAP2_LIST1) (f, t, peek, __VA_ARGS__)
+#define PYBIND11_MAP2_LIST1(f, t, x1, x2, peek, ...) \
+    f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT (peek, PYBIND11_MAP2_LIST0) (f, t, peek, __VA_ARGS__)
+// PYBIND11_MAP2_LIST(f, t, a1, a2, ...) expands to f(t, a1, a2), f(t, a3, a4), ...
+#define PYBIND11_MAP2_LIST(f, t, ...) \
+    PYBIND11_EVAL (PYBIND11_MAP2_LIST1 (f, t, __VA_ARGS__, (), 0))
+
+#define PYBIND11_NUMPY_DTYPE_EX(Type, ...) \
+    ::pybind11::detail::npy_format_descriptor<Type>::register_dtype \
+        ({PYBIND11_MAP2_LIST (PYBIND11_FIELD_DESCRIPTOR_EX, Type, __VA_ARGS__)})
+
+#endif // __CLION_IDE__
+
+template  <class T>
+using array_iterator = typename std::add_pointer<T>::type;
+
+template <class T>
+array_iterator<T> array_begin(const buffer_info& buffer) {
+    return array_iterator<T>(reinterpret_cast<T*>(buffer.ptr));
+}
+
+template <class T>
+array_iterator<T> array_end(const buffer_info& buffer) {
+    return array_iterator<T>(reinterpret_cast<T*>(buffer.ptr) + buffer.size);
+}
+
+class common_iterator {
+public:
+    using container_type = std::vector<ssize_t>;
+    using value_type = container_type::value_type;
+    using size_type = container_type::size_type;
+
+    common_iterator() : p_ptr(0), m_strides() {}
+
+    common_iterator(void* ptr, const container_type& strides, const container_type& shape)
+        : p_ptr(reinterpret_cast<char*>(ptr)), m_strides(strides.size()) {
+        m_strides.back() = static_cast<value_type>(strides.back());
+        for (size_type i = m_strides.size() - 1; i != 0; --i) {
+            size_type j = i - 1;
+            value_type s = static_cast<value_type>(shape[i]);
+            m_strides[j] = strides[j] + m_strides[i] - strides[i] * s;
+        }
+    }
+
+    void increment(size_type dim) {
+        p_ptr += m_strides[dim];
+    }
+
+    void* data() const {
+        return p_ptr;
+    }
+
+private:
+    char* p_ptr;
+    container_type m_strides;
+};
+
+template <size_t N> class multi_array_iterator {
+public:
+    using container_type = std::vector<ssize_t>;
+
+    multi_array_iterator(const std::array<buffer_info, N> &buffers,
+                         const container_type &shape)
+        : m_shape(shape.size()), m_index(shape.size(), 0),
+          m_common_iterator() {
+
+        // Manual copy to avoid conversion warning if using std::copy
+        for (size_t i = 0; i < shape.size(); ++i)
+            m_shape[i] = shape[i];
+
+        container_type strides(shape.size());
+        for (size_t i = 0; i < N; ++i)
+            init_common_iterator(buffers[i], shape, m_common_iterator[i], strides);
+    }
+
+    multi_array_iterator& operator++() {
+        for (size_t j = m_index.size(); j != 0; --j) {
+            size_t i = j - 1;
+            if (++m_index[i] != m_shape[i]) {
+                increment_common_iterator(i);
+                break;
+            } else {
+                m_index[i] = 0;
+            }
+        }
+        return *this;
+    }
+
+    template <size_t K, class T = void> T* data() const {
+        return reinterpret_cast<T*>(m_common_iterator[K].data());
+    }
+
+private:
+
+    using common_iter = common_iterator;
+
+    void init_common_iterator(const buffer_info &buffer,
+                              const container_type &shape,
+                              common_iter &iterator,
+                              container_type &strides) {
+        auto buffer_shape_iter = buffer.shape.rbegin();
+        auto buffer_strides_iter = buffer.strides.rbegin();
+        auto shape_iter = shape.rbegin();
+        auto strides_iter = strides.rbegin();
+
+        while (buffer_shape_iter != buffer.shape.rend()) {
+            if (*shape_iter == *buffer_shape_iter)
+                *strides_iter = *buffer_strides_iter;
+            else
+                *strides_iter = 0;
+
+            ++buffer_shape_iter;
+            ++buffer_strides_iter;
+            ++shape_iter;
+            ++strides_iter;
+        }
+
+        std::fill(strides_iter, strides.rend(), 0);
+        iterator = common_iter(buffer.ptr, strides, shape);
+    }
+
+    void increment_common_iterator(size_t dim) {
+        for (auto &iter : m_common_iterator)
+            iter.increment(dim);
+    }
+
+    container_type m_shape;
+    container_type m_index;
+    std::array<common_iter, N> m_common_iterator;
+};
+
+enum class broadcast_trivial { non_trivial, c_trivial, f_trivial };
+
+// Populates the shape and number of dimensions for the set of buffers.  Returns a broadcast_trivial
+// enum value indicating whether the broadcast is "trivial"--that is, has each buffer being either a
+// singleton or a full-size, C-contiguous (`c_trivial`) or Fortran-contiguous (`f_trivial`) storage
+// buffer; returns `non_trivial` otherwise.
+template <size_t N>
+broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t &ndim, std::vector<ssize_t> &shape) {
+    ndim = std::accumulate(buffers.begin(), buffers.end(), ssize_t(0), [](ssize_t res, const buffer_info &buf) {
+        return std::max(res, buf.ndim);
+    });
+
+    shape.clear();
+    shape.resize((size_t) ndim, 1);
+
+    // Figure out the output size, and make sure all input arrays conform (i.e. are either size 1 or
+    // the full size).
+    for (size_t i = 0; i < N; ++i) {
+        auto res_iter = shape.rbegin();
+        auto end = buffers[i].shape.rend();
+        for (auto shape_iter = buffers[i].shape.rbegin(); shape_iter != end; ++shape_iter, ++res_iter) {
+            const auto &dim_size_in = *shape_iter;
+            auto &dim_size_out = *res_iter;
+
+            // Each input dimension can either be 1 or `n`, but `n` values must match across buffers
+            if (dim_size_out == 1)
+                dim_size_out = dim_size_in;
+            else if (dim_size_in != 1 && dim_size_in != dim_size_out)
+                pybind11_fail("pybind11::vectorize: incompatible size/dimension of inputs!");
+        }
+    }
+
+    bool trivial_broadcast_c = true;
+    bool trivial_broadcast_f = true;
+    for (size_t i = 0; i < N && (trivial_broadcast_c || trivial_broadcast_f); ++i) {
+        if (buffers[i].size == 1)
+            continue;
+
+        // Require the same number of dimensions:
+        if (buffers[i].ndim != ndim)
+            return broadcast_trivial::non_trivial;
+
+        // Require all dimensions be full-size:
+        if (!std::equal(buffers[i].shape.cbegin(), buffers[i].shape.cend(), shape.cbegin()))
+            return broadcast_trivial::non_trivial;
+
+        // Check for C contiguity (but only if previous inputs were also C contiguous)
+        if (trivial_broadcast_c) {
+            ssize_t expect_stride = buffers[i].itemsize;
+            auto end = buffers[i].shape.crend();
+            for (auto shape_iter = buffers[i].shape.crbegin(), stride_iter = buffers[i].strides.crbegin();
+                    trivial_broadcast_c && shape_iter != end; ++shape_iter, ++stride_iter) {
+                if (expect_stride == *stride_iter)
+                    expect_stride *= *shape_iter;
+                else
+                    trivial_broadcast_c = false;
+            }
+        }
+
+        // Check for Fortran contiguity (if previous inputs were also F contiguous)
+        if (trivial_broadcast_f) {
+            ssize_t expect_stride = buffers[i].itemsize;
+            auto end = buffers[i].shape.cend();
+            for (auto shape_iter = buffers[i].shape.cbegin(), stride_iter = buffers[i].strides.cbegin();
+                    trivial_broadcast_f && shape_iter != end; ++shape_iter, ++stride_iter) {
+                if (expect_stride == *stride_iter)
+                    expect_stride *= *shape_iter;
+                else
+                    trivial_broadcast_f = false;
+            }
+        }
+    }
+
+    return
+        trivial_broadcast_c ? broadcast_trivial::c_trivial :
+        trivial_broadcast_f ? broadcast_trivial::f_trivial :
+        broadcast_trivial::non_trivial;
+}
+
+template <typename T>
+struct vectorize_arg {
+    static_assert(!std::is_rvalue_reference<T>::value, "Functions with rvalue reference arguments cannot be vectorized");
+    // The wrapped function gets called with this type:
+    using call_type = remove_reference_t<T>;
+    // Is this a vectorized argument?
+    static constexpr bool vectorize =
+        satisfies_any_of<call_type, std::is_arithmetic, is_complex, std::is_pod>::value &&
+        satisfies_none_of<call_type, std::is_pointer, std::is_array, is_std_array, std::is_enum>::value &&
+        (!std::is_reference<T>::value ||
+         (std::is_lvalue_reference<T>::value && std::is_const<call_type>::value));
+    // Accept this type: an array for vectorized types, otherwise the type as-is:
+    using type = conditional_t<vectorize, array_t<remove_cv_t<call_type>, array::forcecast>, T>;
+};
+
+template <typename Func, typename Return, typename... Args>
+struct vectorize_helper {
+private:
+    static constexpr size_t N = sizeof...(Args);
+    static constexpr size_t NVectorized = constexpr_sum(vectorize_arg<Args>::vectorize...);
+    static_assert(NVectorized >= 1,
+            "pybind11::vectorize(...) requires a function with at least one vectorizable argument");
+
+public:
+    template <typename T>
+    explicit vectorize_helper(T &&f) : f(std::forward<T>(f)) { }
+
+    object operator()(typename vectorize_arg<Args>::type... args) {
+        return run(args...,
+                   make_index_sequence<N>(),
+                   select_indices<vectorize_arg<Args>::vectorize...>(),
+                   make_index_sequence<NVectorized>());
+    }
+
+private:
+    remove_reference_t<Func> f;
+
+    template <size_t Index> using param_n_t = typename pack_element<Index, typename vectorize_arg<Args>::call_type...>::type;
+
+    // Runs a vectorized function given arguments tuple and three index sequences:
+    //     - Index is the full set of 0 ... (N-1) argument indices;
+    //     - VIndex is the subset of argument indices with vectorized parameters, letting us access
+    //       vectorized arguments (anything not in this sequence is passed through)
+    //     - BIndex is a incremental sequence (beginning at 0) of the same size as VIndex, so that
+    //       we can store vectorized buffer_infos in an array (argument VIndex has its buffer at
+    //       index BIndex in the array).
+    template <size_t... Index, size_t... VIndex, size_t... BIndex> object run(
+            typename vectorize_arg<Args>::type &...args,
+            index_sequence<Index...> i_seq, index_sequence<VIndex...> vi_seq, index_sequence<BIndex...> bi_seq) {
+
+        // Pointers to values the function was called with; the vectorized ones set here will start
+        // out as array_t<T> pointers, but they will be changed them to T pointers before we make
+        // call the wrapped function.  Non-vectorized pointers are left as-is.
+        std::array<void *, N> params{{ &args... }};
+
+        // The array of `buffer_info`s of vectorized arguments:
+        std::array<buffer_info, NVectorized> buffers{{ reinterpret_cast<array *>(params[VIndex])->request()... }};
+
+        /* Determine dimensions parameters of output array */
+        ssize_t nd = 0;
+        std::vector<ssize_t> shape(0);
+        auto trivial = broadcast(buffers, nd, shape);
+        size_t ndim = (size_t) nd;
+
+        size_t size = std::accumulate(shape.begin(), shape.end(), (size_t) 1, std::multiplies<size_t>());
+
+        // If all arguments are 0-dimension arrays (i.e. single values) return a plain value (i.e.
+        // not wrapped in an array).
+        if (size == 1 && ndim == 0) {
+            PYBIND11_EXPAND_SIDE_EFFECTS(params[VIndex] = buffers[BIndex].ptr);
+            return cast(f(*reinterpret_cast<param_n_t<Index> *>(params[Index])...));
+        }
+
+        array_t<Return> result;
+        if (trivial == broadcast_trivial::f_trivial) result = array_t<Return, array::f_style>(shape);
+        else result = array_t<Return>(shape);
+
+        if (size == 0) return result;
+
+        /* Call the function */
+        if (trivial == broadcast_trivial::non_trivial)
+            apply_broadcast(buffers, params, result, i_seq, vi_seq, bi_seq);
+        else
+            apply_trivial(buffers, params, result.mutable_data(), size, i_seq, vi_seq, bi_seq);
+
+        return result;
+    }
+
+    template <size_t... Index, size_t... VIndex, size_t... BIndex>
+    void apply_trivial(std::array<buffer_info, NVectorized> &buffers,
+                       std::array<void *, N> &params,
+                       Return *out,
+                       size_t size,
+                       index_sequence<Index...>, index_sequence<VIndex...>, index_sequence<BIndex...>) {
+
+        // Initialize an array of mutable byte references and sizes with references set to the
+        // appropriate pointer in `params`; as we iterate, we'll increment each pointer by its size
+        // (except for singletons, which get an increment of 0).
+        std::array<std::pair<unsigned char *&, const size_t>, NVectorized> vecparams{{
+            std::pair<unsigned char *&, const size_t>(
+                    reinterpret_cast<unsigned char *&>(params[VIndex] = buffers[BIndex].ptr),
+                    buffers[BIndex].size == 1 ? 0 : sizeof(param_n_t<VIndex>)
+            )...
+        }};
+
+        for (size_t i = 0; i < size; ++i) {
+            out[i] = f(*reinterpret_cast<param_n_t<Index> *>(params[Index])...);
+            for (auto &x : vecparams) x.first += x.second;
+        }
+    }
+
+    template <size_t... Index, size_t... VIndex, size_t... BIndex>
+    void apply_broadcast(std::array<buffer_info, NVectorized> &buffers,
+                         std::array<void *, N> &params,
+                         array_t<Return> &output_array,
+                         index_sequence<Index...>, index_sequence<VIndex...>, index_sequence<BIndex...>) {
+
+        buffer_info output = output_array.request();
+        multi_array_iterator<NVectorized> input_iter(buffers, output.shape);
+
+        for (array_iterator<Return> iter = array_begin<Return>(output), end = array_end<Return>(output);
+             iter != end;
+             ++iter, ++input_iter) {
+            PYBIND11_EXPAND_SIDE_EFFECTS((
+                params[VIndex] = input_iter.template data<BIndex>()
+            ));
+            *iter = f(*reinterpret_cast<param_n_t<Index> *>(std::get<Index>(params))...);
+        }
+    }
+};
+
+template <typename Func, typename Return, typename... Args>
+vectorize_helper<Func, Return, Args...>
+vectorize_extractor(const Func &f, Return (*) (Args ...)) {
+    return detail::vectorize_helper<Func, Return, Args...>(f);
+}
+
+template <typename T, int Flags> struct handle_type_name<array_t<T, Flags>> {
+    static PYBIND11_DESCR name() {
+        return _("numpy.ndarray[") + npy_format_descriptor<T>::name() + _("]");
+    }
+};
+
+NAMESPACE_END(detail)
+
+// Vanilla pointer vectorizer:
+template <typename Return, typename... Args>
+detail::vectorize_helper<Return (*)(Args...), Return, Args...>
+vectorize(Return (*f) (Args ...)) {
+    return detail::vectorize_helper<Return (*)(Args...), Return, Args...>(f);
+}
+
+// lambda vectorizer:
+template <typename Func, detail::enable_if_t<detail::is_lambda<Func>::value, int> = 0>
+auto vectorize(Func &&f) -> decltype(
+        detail::vectorize_extractor(std::forward<Func>(f), (detail::function_signature_t<Func> *) nullptr)) {
+    return detail::vectorize_extractor(std::forward<Func>(f), (detail::function_signature_t<Func> *) nullptr);
+}
+
+// Vectorize a class method (non-const):
+template <typename Return, typename Class, typename... Args,
+          typename Helper = detail::vectorize_helper<decltype(std::mem_fn(std::declval<Return (Class::*)(Args...)>())), Return, Class *, Args...>>
+Helper vectorize(Return (Class::*f)(Args...)) {
+    return Helper(std::mem_fn(f));
+}
+
+// Vectorize a class method (const):
+template <typename Return, typename Class, typename... Args,
+          typename Helper = detail::vectorize_helper<decltype(std::mem_fn(std::declval<Return (Class::*)(Args...) const>())), Return, const Class *, Args...>>
+Helper vectorize(Return (Class::*f)(Args...) const) {
+    return Helper(std::mem_fn(f));
+}
+
+NAMESPACE_END(PYBIND11_NAMESPACE)
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/operators.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/operators.h
new file mode 100644
index 0000000000000000000000000000000000000000..b3dd62c3b6452467838f48380c91661b429bfc7b
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/operators.h
@@ -0,0 +1,168 @@
+/*
+    pybind11/operator.h: Metatemplates for operator overloading
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "pybind11.h"
+
+#if defined(__clang__) && !defined(__INTEL_COMPILER)
+#  pragma clang diagnostic ignored "-Wunsequenced" // multiple unsequenced modifications to 'self' (when using def(py::self OP Type()))
+#elif defined(_MSC_VER)
+#  pragma warning(push)
+#  pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
+#endif
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+NAMESPACE_BEGIN(detail)
+
+/// Enumeration with all supported operator types
+enum op_id : int {
+    op_add, op_sub, op_mul, op_div, op_mod, op_divmod, op_pow, op_lshift,
+    op_rshift, op_and, op_xor, op_or, op_neg, op_pos, op_abs, op_invert,
+    op_int, op_long, op_float, op_str, op_cmp, op_gt, op_ge, op_lt, op_le,
+    op_eq, op_ne, op_iadd, op_isub, op_imul, op_idiv, op_imod, op_ilshift,
+    op_irshift, op_iand, op_ixor, op_ior, op_complex, op_bool, op_nonzero,
+    op_repr, op_truediv, op_itruediv, op_hash
+};
+
+enum op_type : int {
+    op_l, /* base type on left */
+    op_r, /* base type on right */
+    op_u  /* unary operator */
+};
+
+struct self_t { };
+static const self_t self = self_t();
+
+/// Type for an unused type slot
+struct undefined_t { };
+
+/// Don't warn about an unused variable
+inline self_t __self() { return self; }
+
+/// base template of operator implementations
+template <op_id, op_type, typename B, typename L, typename R> struct op_impl { };
+
+/// Operator implementation generator
+template <op_id id, op_type ot, typename L, typename R> struct op_ {
+    template <typename Class, typename... Extra> void execute(Class &cl, const Extra&... extra) const {
+        using Base = typename Class::type;
+        using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
+        using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
+        using op = op_impl<id, ot, Base, L_type, R_type>;
+        cl.def(op::name(), &op::execute, is_operator(), extra...);
+        #if PY_MAJOR_VERSION < 3
+        if (id == op_truediv || id == op_itruediv)
+            cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__",
+                    &op::execute, is_operator(), extra...);
+        #endif
+    }
+    template <typename Class, typename... Extra> void execute_cast(Class &cl, const Extra&... extra) const {
+        using Base = typename Class::type;
+        using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
+        using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
+        using op = op_impl<id, ot, Base, L_type, R_type>;
+        cl.def(op::name(), &op::execute_cast, is_operator(), extra...);
+        #if PY_MAJOR_VERSION < 3
+        if (id == op_truediv || id == op_itruediv)
+            cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__",
+                    &op::execute, is_operator(), extra...);
+        #endif
+    }
+};
+
+#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr)                                    \
+template <typename B, typename L, typename R> struct op_impl<op_##id, op_l, B, L, R> { \
+    static char const* name() { return "__" #id "__"; }                                \
+    static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); }   \
+    static B execute_cast(const L &l, const R &r) { return B(expr); }                  \
+};                                                                                     \
+template <typename B, typename L, typename R> struct op_impl<op_##id, op_r, B, L, R> { \
+    static char const* name() { return "__" #rid "__"; }                               \
+    static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); }   \
+    static B execute_cast(const R &r, const L &l) { return B(expr); }                  \
+};                                                                                     \
+inline op_<op_##id, op_l, self_t, self_t> op(const self_t &, const self_t &) {         \
+    return op_<op_##id, op_l, self_t, self_t>();                                       \
+}                                                                                      \
+template <typename T> op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) {    \
+    return op_<op_##id, op_l, self_t, T>();                                            \
+}                                                                                      \
+template <typename T> op_<op_##id, op_r, T, self_t> op(const T &, const self_t &) {    \
+    return op_<op_##id, op_r, T, self_t>();                                            \
+}
+
+#define PYBIND11_INPLACE_OPERATOR(id, op, expr)                                        \
+template <typename B, typename L, typename R> struct op_impl<op_##id, op_l, B, L, R> { \
+    static char const* name() { return "__" #id "__"; }                                \
+    static auto execute(L &l, const R &r) -> decltype(expr) { return expr; }           \
+    static B execute_cast(L &l, const R &r) { return B(expr); }                        \
+};                                                                                     \
+template <typename T> op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) {    \
+    return op_<op_##id, op_l, self_t, T>();                                            \
+}
+
+#define PYBIND11_UNARY_OPERATOR(id, op, expr)                                          \
+template <typename B, typename L> struct op_impl<op_##id, op_u, B, L, undefined_t> {   \
+    static char const* name() { return "__" #id "__"; }                                \
+    static auto execute(const L &l) -> decltype(expr) { return expr; }                 \
+    static B execute_cast(const L &l) { return B(expr); }                              \
+};                                                                                     \
+inline op_<op_##id, op_u, self_t, undefined_t> op(const self_t &) {                    \
+    return op_<op_##id, op_u, self_t, undefined_t>();                                  \
+}
+
+PYBIND11_BINARY_OPERATOR(sub,       rsub,         operator-,    l - r)
+PYBIND11_BINARY_OPERATOR(add,       radd,         operator+,    l + r)
+PYBIND11_BINARY_OPERATOR(mul,       rmul,         operator*,    l * r)
+PYBIND11_BINARY_OPERATOR(truediv,   rtruediv,     operator/,    l / r)
+PYBIND11_BINARY_OPERATOR(mod,       rmod,         operator%,    l % r)
+PYBIND11_BINARY_OPERATOR(lshift,    rlshift,      operator<<,   l << r)
+PYBIND11_BINARY_OPERATOR(rshift,    rrshift,      operator>>,   l >> r)
+PYBIND11_BINARY_OPERATOR(and,       rand,         operator&,    l & r)
+PYBIND11_BINARY_OPERATOR(xor,       rxor,         operator^,    l ^ r)
+PYBIND11_BINARY_OPERATOR(eq,        eq,           operator==,   l == r)
+PYBIND11_BINARY_OPERATOR(ne,        ne,           operator!=,   l != r)
+PYBIND11_BINARY_OPERATOR(or,        ror,          operator|,    l | r)
+PYBIND11_BINARY_OPERATOR(gt,        lt,           operator>,    l > r)
+PYBIND11_BINARY_OPERATOR(ge,        le,           operator>=,   l >= r)
+PYBIND11_BINARY_OPERATOR(lt,        gt,           operator<,    l < r)
+PYBIND11_BINARY_OPERATOR(le,        ge,           operator<=,   l <= r)
+//PYBIND11_BINARY_OPERATOR(pow,       rpow,         pow,          std::pow(l,  r))
+PYBIND11_INPLACE_OPERATOR(iadd,     operator+=,   l += r)
+PYBIND11_INPLACE_OPERATOR(isub,     operator-=,   l -= r)
+PYBIND11_INPLACE_OPERATOR(imul,     operator*=,   l *= r)
+PYBIND11_INPLACE_OPERATOR(itruediv, operator/=,   l /= r)
+PYBIND11_INPLACE_OPERATOR(imod,     operator%=,   l %= r)
+PYBIND11_INPLACE_OPERATOR(ilshift,  operator<<=,  l <<= r)
+PYBIND11_INPLACE_OPERATOR(irshift,  operator>>=,  l >>= r)
+PYBIND11_INPLACE_OPERATOR(iand,     operator&=,   l &= r)
+PYBIND11_INPLACE_OPERATOR(ixor,     operator^=,   l ^= r)
+PYBIND11_INPLACE_OPERATOR(ior,      operator|=,   l |= r)
+PYBIND11_UNARY_OPERATOR(neg,        operator-,    -l)
+PYBIND11_UNARY_OPERATOR(pos,        operator+,    +l)
+PYBIND11_UNARY_OPERATOR(abs,        abs,          std::abs(l))
+PYBIND11_UNARY_OPERATOR(hash,       hash,         std::hash<L>()(l))
+PYBIND11_UNARY_OPERATOR(invert,     operator~,    (~l))
+PYBIND11_UNARY_OPERATOR(bool,       operator!,    !!l)
+PYBIND11_UNARY_OPERATOR(int,        int_,         (int) l)
+PYBIND11_UNARY_OPERATOR(float,      float_,       (double) l)
+
+#undef PYBIND11_BINARY_OPERATOR
+#undef PYBIND11_INPLACE_OPERATOR
+#undef PYBIND11_UNARY_OPERATOR
+NAMESPACE_END(detail)
+
+using detail::self;
+
+NAMESPACE_END(PYBIND11_NAMESPACE)
+
+#if defined(_MSC_VER)
+#  pragma warning(pop)
+#endif
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/options.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/options.h
new file mode 100644
index 0000000000000000000000000000000000000000..cc1e1f6f0f28950729baacc1ddf1ac8fe78ad421
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/options.h
@@ -0,0 +1,65 @@
+/*
+    pybind11/options.h: global settings that are configurable at runtime.
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "detail/common.h"
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+
+class options {
+public:
+
+    // Default RAII constructor, which leaves settings as they currently are.
+    options() : previous_state(global_state()) {}
+
+    // Class is non-copyable.
+    options(const options&) = delete;
+    options& operator=(const options&) = delete;
+
+    // Destructor, which restores settings that were in effect before.
+    ~options() {
+        global_state() = previous_state;
+    }
+
+    // Setter methods (affect the global state):
+
+    options& disable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = false; return *this; }
+
+    options& enable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = true; return *this; }
+
+    options& disable_function_signatures() & { global_state().show_function_signatures = false; return *this; }
+
+    options& enable_function_signatures() & { global_state().show_function_signatures = true; return *this; }
+
+    // Getter methods (return the global state):
+
+    static bool show_user_defined_docstrings() { return global_state().show_user_defined_docstrings; }
+
+    static bool show_function_signatures() { return global_state().show_function_signatures; }
+
+    // This type is not meant to be allocated on the heap.
+    void* operator new(size_t) = delete;
+
+private:
+
+    struct state {
+        bool show_user_defined_docstrings = true;  //< Include user-supplied texts in docstrings.
+        bool show_function_signatures = true;      //< Include auto-generated function signatures in docstrings.
+    };
+
+    static state &global_state() {
+        static state instance;
+        return instance;
+    }
+
+    state previous_state;
+};
+
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/pybind11.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/pybind11.h
new file mode 100644
index 0000000000000000000000000000000000000000..9094fc4244cfaed45874cecae84ef4b9024766a0
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/pybind11.h
@@ -0,0 +1,1965 @@
+/*
+    pybind11/pybind11.h: Main header file of the C++11 python
+    binding generator library
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#if defined(_MSC_VER)
+#  pragma warning(push)
+#  pragma warning(disable: 4100) // warning C4100: Unreferenced formal parameter
+#  pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
+#  pragma warning(disable: 4512) // warning C4512: Assignment operator was implicitly defined as deleted
+#  pragma warning(disable: 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning)
+#  pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name
+#  pragma warning(disable: 4702) // warning C4702: unreachable code
+#  pragma warning(disable: 4522) // warning C4522: multiple assignment operators specified
+#elif defined(__INTEL_COMPILER)
+#  pragma warning(push)
+#  pragma warning(disable: 68)    // integer conversion resulted in a change of sign
+#  pragma warning(disable: 186)   // pointless comparison of unsigned integer with zero
+#  pragma warning(disable: 878)   // incompatible exception specifications
+#  pragma warning(disable: 1334)  // the "template" keyword used for syntactic disambiguation may only be used within a template
+#  pragma warning(disable: 1682)  // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem)
+#  pragma warning(disable: 1875)  // offsetof applied to non-POD (Plain Old Data) types is nonstandard
+#  pragma warning(disable: 2196)  // warning #2196: routine is both "inline" and "noinline"
+#elif defined(__GNUG__) && !defined(__clang__)
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
+#  pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#  pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#  pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#  pragma GCC diagnostic ignored "-Wattributes"
+#  if __GNUC__ >= 7
+#    pragma GCC diagnostic ignored "-Wnoexcept-type"
+#  endif
+#endif
+
+#include "attr.h"
+#include "options.h"
+#include "detail/class.h"
+#include "detail/init.h"
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+
+/// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object
+class cpp_function : public function {
+public:
+    cpp_function() { }
+
+    /// Construct a cpp_function from a vanilla function pointer
+    template <typename Return, typename... Args, typename... Extra>
+    cpp_function(Return (*f)(Args...), const Extra&... extra) {
+        initialize(f, f, extra...);
+    }
+
+    /// Construct a cpp_function from a lambda function (possibly with internal state)
+    template <typename Func, typename... Extra,
+              typename = detail::enable_if_t<detail::is_lambda<Func>::value>>
+    cpp_function(Func &&f, const Extra&... extra) {
+        initialize(std::forward<Func>(f),
+                   (detail::function_signature_t<Func> *) nullptr, extra...);
+    }
+
+    /// Construct a cpp_function from a class method (non-const)
+    template <typename Return, typename Class, typename... Arg, typename... Extra>
+    cpp_function(Return (Class::*f)(Arg...), const Extra&... extra) {
+        initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); },
+                   (Return (*) (Class *, Arg...)) nullptr, extra...);
+    }
+
+    /// Construct a cpp_function from a class method (const)
+    template <typename Return, typename Class, typename... Arg, typename... Extra>
+    cpp_function(Return (Class::*f)(Arg...) const, const Extra&... extra) {
+        initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); },
+                   (Return (*)(const Class *, Arg ...)) nullptr, extra...);
+    }
+
+    /// Return the function name
+    object name() const { return attr("__name__"); }
+
+protected:
+    /// Space optimization: don't inline this frequently instantiated fragment
+    PYBIND11_NOINLINE detail::function_record *make_function_record() {
+        return new detail::function_record();
+    }
+
+    /// Special internal constructor for functors, lambda functions, etc.
+    template <typename Func, typename Return, typename... Args, typename... Extra>
+    void initialize(Func &&f, Return (*)(Args...), const Extra&... extra) {
+        using namespace detail;
+
+        struct capture { remove_reference_t<Func> f; };
+
+        /* Store the function including any extra state it might have (e.g. a lambda capture object) */
+        auto rec = make_function_record();
+
+        /* Store the capture object directly in the function record if there is enough space */
+        if (sizeof(capture) <= sizeof(rec->data)) {
+            /* Without these pragmas, GCC warns that there might not be
+               enough space to use the placement new operator. However, the
+               'if' statement above ensures that this is the case. */
+#if defined(__GNUG__) && !defined(__clang__) && __GNUC__ >= 6
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wplacement-new"
+#endif
+            new ((capture *) &rec->data) capture { std::forward<Func>(f) };
+#if defined(__GNUG__) && !defined(__clang__) && __GNUC__ >= 6
+#  pragma GCC diagnostic pop
+#endif
+            if (!std::is_trivially_destructible<Func>::value)
+                rec->free_data = [](function_record *r) { ((capture *) &r->data)->~capture(); };
+        } else {
+            rec->data[0] = new capture { std::forward<Func>(f) };
+            rec->free_data = [](function_record *r) { delete ((capture *) r->data[0]); };
+        }
+
+        /* Type casters for the function arguments and return value */
+        using cast_in = argument_loader<Args...>;
+        using cast_out = make_caster<
+            conditional_t<std::is_void<Return>::value, void_type, Return>
+        >;
+
+        static_assert(expected_num_args<Extra...>(sizeof...(Args), cast_in::has_args, cast_in::has_kwargs),
+                      "The number of argument annotations does not match the number of function arguments");
+
+        /* Dispatch code which converts function arguments and performs the actual function call */
+        rec->impl = [](function_call &call) -> handle {
+            cast_in args_converter;
+
+            /* Try to cast the function arguments into the C++ domain */
+            if (!args_converter.load_args(call))
+                return PYBIND11_TRY_NEXT_OVERLOAD;
+
+            /* Invoke call policy pre-call hook */
+            process_attributes<Extra...>::precall(call);
+
+            /* Get a pointer to the capture object */
+            auto data = (sizeof(capture) <= sizeof(call.func.data)
+                         ? &call.func.data : call.func.data[0]);
+            capture *cap = const_cast<capture *>(reinterpret_cast<const capture *>(data));
+
+            /* Override policy for rvalues -- usually to enforce rvp::move on an rvalue */
+            return_value_policy policy = return_value_policy_override<Return>::policy(call.func.policy);
+
+            /* Function scope guard -- defaults to the compile-to-nothing `void_type` */
+            using Guard = extract_guard_t<Extra...>;
+
+            /* Perform the function call */
+            handle result = cast_out::cast(
+                std::move(args_converter).template call<Return, Guard>(cap->f), policy, call.parent);
+
+            /* Invoke call policy post-call hook */
+            process_attributes<Extra...>::postcall(call, result);
+
+            return result;
+        };
+
+        /* Process any user-provided function attributes */
+        process_attributes<Extra...>::init(extra..., rec);
+
+        /* Generate a readable signature describing the function's arguments and return value types */
+        PYBIND11_DESCR signature = _("(") + cast_in::arg_names() + _(") -> ") + cast_out::name();
+
+        /* Register the function with Python from generic (non-templated) code */
+        initialize_generic(rec, signature.text(), signature.types(), sizeof...(Args));
+
+        if (cast_in::has_args) rec->has_args = true;
+        if (cast_in::has_kwargs) rec->has_kwargs = true;
+
+        /* Stash some additional information used by an important optimization in 'functional.h' */
+        using FunctionType = Return (*)(Args...);
+        constexpr bool is_function_ptr =
+            std::is_convertible<Func, FunctionType>::value &&
+            sizeof(capture) == sizeof(void *);
+        if (is_function_ptr) {
+            rec->is_stateless = true;
+            rec->data[1] = const_cast<void *>(reinterpret_cast<const void *>(&typeid(FunctionType)));
+        }
+    }
+
+    /// Register a function call with Python (generic non-templated code goes here)
+    void initialize_generic(detail::function_record *rec, const char *text,
+                            const std::type_info *const *types, size_t args) {
+
+        /* Create copies of all referenced C-style strings */
+        rec->name = strdup(rec->name ? rec->name : "");
+        if (rec->doc) rec->doc = strdup(rec->doc);
+        for (auto &a: rec->args) {
+            if (a.name)
+                a.name = strdup(a.name);
+            if (a.descr)
+                a.descr = strdup(a.descr);
+            else if (a.value)
+                a.descr = strdup(a.value.attr("__repr__")().cast<std::string>().c_str());
+        }
+
+        rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__");
+
+#if !defined(NDEBUG) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING)
+        if (rec->is_constructor && !rec->is_new_style_constructor) {
+            const auto class_name = std::string(((PyTypeObject *) rec->scope.ptr())->tp_name);
+            const auto func_name = std::string(rec->name);
+            PyErr_WarnEx(
+                PyExc_FutureWarning,
+                ("pybind11-bound class '" + class_name + "' is using an old-style "
+                 "placement-new '" + func_name + "' which has been deprecated. See "
+                 "the upgrade guide in pybind11's docs. This message is only visible "
+                 "when compiled in debug mode.").c_str(), 0
+            );
+        }
+#endif
+
+        /* Generate a proper function signature */
+        std::string signature;
+        size_t type_depth = 0, char_index = 0, type_index = 0, arg_index = 0;
+        while (true) {
+            char c = text[char_index++];
+            if (c == '\0')
+                break;
+
+            if (c == '{') {
+                // Write arg name for everything except *args, **kwargs and return type.
+                if (type_depth == 0 && text[char_index] != '*' && arg_index < args) {
+                    if (!rec->args.empty() && rec->args[arg_index].name) {
+                        signature += rec->args[arg_index].name;
+                    } else if (arg_index == 0 && rec->is_method) {
+                        signature += "self";
+                    } else {
+                        signature += "arg" + std::to_string(arg_index - (rec->is_method ? 1 : 0));
+                    }
+                    signature += ": ";
+                }
+                ++type_depth;
+            } else if (c == '}') {
+                --type_depth;
+                if (type_depth == 0) {
+                    if (arg_index < rec->args.size() && rec->args[arg_index].descr) {
+                        signature += "=";
+                        signature += rec->args[arg_index].descr;
+                    }
+                    arg_index++;
+                }
+            } else if (c == '%') {
+                const std::type_info *t = types[type_index++];
+                if (!t)
+                    pybind11_fail("Internal error while parsing type signature (1)");
+                if (auto tinfo = detail::get_type_info(*t)) {
+                    handle th((PyObject *) tinfo->type);
+                    signature +=
+                        th.attr("__module__").cast<std::string>() + "." +
+                        th.attr("__qualname__").cast<std::string>(); // Python 3.3+, but we backport it to earlier versions
+                } else if (rec->is_new_style_constructor && arg_index == 0) {
+                    // A new-style `__init__` takes `self` as `value_and_holder`.
+                    // Rewrite it to the proper class type.
+                    signature +=
+                        rec->scope.attr("__module__").cast<std::string>() + "." +
+                        rec->scope.attr("__qualname__").cast<std::string>();
+                } else {
+                    std::string tname(t->name());
+                    detail::clean_type_id(tname);
+                    signature += tname;
+                }
+            } else {
+                signature += c;
+            }
+        }
+        if (type_depth != 0 || types[type_index] != nullptr)
+            pybind11_fail("Internal error while parsing type signature (2)");
+
+        #if !defined(PYBIND11_CONSTEXPR_DESCR)
+            delete[] types;
+            delete[] text;
+        #endif
+
+#if PY_MAJOR_VERSION < 3
+        if (strcmp(rec->name, "__next__") == 0) {
+            std::free(rec->name);
+            rec->name = strdup("next");
+        } else if (strcmp(rec->name, "__bool__") == 0) {
+            std::free(rec->name);
+            rec->name = strdup("__nonzero__");
+        }
+#endif
+        rec->signature = strdup(signature.c_str());
+        rec->args.shrink_to_fit();
+        rec->nargs = (std::uint16_t) args;
+
+        if (rec->sibling && PYBIND11_INSTANCE_METHOD_CHECK(rec->sibling.ptr()))
+            rec->sibling = PYBIND11_INSTANCE_METHOD_GET_FUNCTION(rec->sibling.ptr());
+
+        detail::function_record *chain = nullptr, *chain_start = rec;
+        if (rec->sibling) {
+            if (PyCFunction_Check(rec->sibling.ptr())) {
+                auto rec_capsule = reinterpret_borrow<capsule>(PyCFunction_GET_SELF(rec->sibling.ptr()));
+                chain = (detail::function_record *) rec_capsule;
+                /* Never append a method to an overload chain of a parent class;
+                   instead, hide the parent's overloads in this case */
+                if (!chain->scope.is(rec->scope))
+                    chain = nullptr;
+            }
+            // Don't trigger for things like the default __init__, which are wrapper_descriptors that we are intentionally replacing
+            else if (!rec->sibling.is_none() && rec->name[0] != '_')
+                pybind11_fail("Cannot overload existing non-function object \"" + std::string(rec->name) +
+                        "\" with a function of the same name");
+        }
+
+        if (!chain) {
+            /* No existing overload was found, create a new function object */
+            rec->def = new PyMethodDef();
+            std::memset(rec->def, 0, sizeof(PyMethodDef));
+            rec->def->ml_name = rec->name;
+            rec->def->ml_meth = reinterpret_cast<PyCFunction>(reinterpret_cast<void (*) (void)>(*dispatcher));
+            rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS;
+
+            capsule rec_capsule(rec, [](void *ptr) {
+                destruct((detail::function_record *) ptr);
+            });
+
+            object scope_module;
+            if (rec->scope) {
+                if (hasattr(rec->scope, "__module__")) {
+                    scope_module = rec->scope.attr("__module__");
+                } else if (hasattr(rec->scope, "__name__")) {
+                    scope_module = rec->scope.attr("__name__");
+                }
+            }
+
+            m_ptr = PyCFunction_NewEx(rec->def, rec_capsule.ptr(), scope_module.ptr());
+            if (!m_ptr)
+                pybind11_fail("cpp_function::cpp_function(): Could not allocate function object");
+        } else {
+            /* Append at the end of the overload chain */
+            m_ptr = rec->sibling.ptr();
+            inc_ref();
+            chain_start = chain;
+            if (chain->is_method != rec->is_method)
+                pybind11_fail("overloading a method with both static and instance methods is not supported; "
+                    #if defined(NDEBUG)
+                        "compile in debug mode for more details"
+                    #else
+                        "error while attempting to bind " + std::string(rec->is_method ? "instance" : "static") + " method " +
+                        std::string(pybind11::str(rec->scope.attr("__name__"))) + "." + std::string(rec->name) + signature
+                    #endif
+                );
+            while (chain->next)
+                chain = chain->next;
+            chain->next = rec;
+        }
+
+        std::string signatures;
+        int index = 0;
+        /* Create a nice pydoc rec including all signatures and
+           docstrings of the functions in the overload chain */
+        if (chain && options::show_function_signatures()) {
+            // First a generic signature
+            signatures += rec->name;
+            signatures += "(*args, **kwargs)\n";
+            signatures += "Overloaded function.\n\n";
+        }
+        // Then specific overload signatures
+        bool first_user_def = true;
+        for (auto it = chain_start; it != nullptr; it = it->next) {
+            if (options::show_function_signatures()) {
+                if (index > 0) signatures += "\n";
+                if (chain)
+                    signatures += std::to_string(++index) + ". ";
+                signatures += rec->name;
+                signatures += it->signature;
+                signatures += "\n";
+            }
+            if (it->doc && strlen(it->doc) > 0 && options::show_user_defined_docstrings()) {
+                // If we're appending another docstring, and aren't printing function signatures, we
+                // need to append a newline first:
+                if (!options::show_function_signatures()) {
+                    if (first_user_def) first_user_def = false;
+                    else signatures += "\n";
+                }
+                if (options::show_function_signatures()) signatures += "\n";
+                signatures += it->doc;
+                if (options::show_function_signatures()) signatures += "\n";
+            }
+        }
+
+        /* Install docstring */
+        PyCFunctionObject *func = (PyCFunctionObject *) m_ptr;
+        if (func->m_ml->ml_doc)
+            std::free(const_cast<char *>(func->m_ml->ml_doc));
+        func->m_ml->ml_doc = strdup(signatures.c_str());
+
+        if (rec->is_method) {
+            m_ptr = PYBIND11_INSTANCE_METHOD_NEW(m_ptr, rec->scope.ptr());
+            if (!m_ptr)
+                pybind11_fail("cpp_function::cpp_function(): Could not allocate instance method object");
+            Py_DECREF(func);
+        }
+    }
+
+    /// When a cpp_function is GCed, release any memory allocated by pybind11
+    static void destruct(detail::function_record *rec) {
+        while (rec) {
+            detail::function_record *next = rec->next;
+            if (rec->free_data)
+                rec->free_data(rec);
+            std::free((char *) rec->name);
+            std::free((char *) rec->doc);
+            std::free((char *) rec->signature);
+            for (auto &arg: rec->args) {
+                std::free(const_cast<char *>(arg.name));
+                std::free(const_cast<char *>(arg.descr));
+                arg.value.dec_ref();
+            }
+            if (rec->def) {
+                std::free(const_cast<char *>(rec->def->ml_doc));
+                delete rec->def;
+            }
+            delete rec;
+            rec = next;
+        }
+    }
+
+    /// Main dispatch logic for calls to functions bound using pybind11
+    static PyObject *dispatcher(PyObject *self, PyObject *args_in, PyObject *kwargs_in) {
+        using namespace detail;
+
+        /* Iterator over the list of potentially admissible overloads */
+        function_record *overloads = (function_record *) PyCapsule_GetPointer(self, nullptr),
+                        *it = overloads;
+
+        /* Need to know how many arguments + keyword arguments there are to pick the right overload */
+        const size_t n_args_in = (size_t) PyTuple_GET_SIZE(args_in);
+
+        handle parent = n_args_in > 0 ? PyTuple_GET_ITEM(args_in, 0) : nullptr,
+               result = PYBIND11_TRY_NEXT_OVERLOAD;
+
+        auto self_value_and_holder = value_and_holder();
+        if (overloads->is_constructor) {
+            const auto tinfo = get_type_info((PyTypeObject *) overloads->scope.ptr());
+            const auto pi = reinterpret_cast<instance *>(parent.ptr());
+            self_value_and_holder = pi->get_value_and_holder(tinfo, false);
+
+            if (!self_value_and_holder.type || !self_value_and_holder.inst) {
+                PyErr_SetString(PyExc_TypeError, "__init__(self, ...) called with invalid `self` argument");
+                return nullptr;
+            }
+
+            // If this value is already registered it must mean __init__ is invoked multiple times;
+            // we really can't support that in C++, so just ignore the second __init__.
+            if (self_value_and_holder.instance_registered())
+                return none().release().ptr();
+        }
+
+        try {
+            // We do this in two passes: in the first pass, we load arguments with `convert=false`;
+            // in the second, we allow conversion (except for arguments with an explicit
+            // py::arg().noconvert()).  This lets us prefer calls without conversion, with
+            // conversion as a fallback.
+            std::vector<function_call> second_pass;
+
+            // However, if there are no overloads, we can just skip the no-convert pass entirely
+            const bool overloaded = it != nullptr && it->next != nullptr;
+
+            for (; it != nullptr; it = it->next) {
+
+                /* For each overload:
+                   1. Copy all positional arguments we were given, also checking to make sure that
+                      named positional arguments weren't *also* specified via kwarg.
+                   2. If we weren't given enough, try to make up the omitted ones by checking
+                      whether they were provided by a kwarg matching the `py::arg("name")` name.  If
+                      so, use it (and remove it from kwargs; if not, see if the function binding
+                      provided a default that we can use.
+                   3. Ensure that either all keyword arguments were "consumed", or that the function
+                      takes a kwargs argument to accept unconsumed kwargs.
+                   4. Any positional arguments still left get put into a tuple (for args), and any
+                      leftover kwargs get put into a dict.
+                   5. Pack everything into a vector; if we have py::args or py::kwargs, they are an
+                      extra tuple or dict at the end of the positional arguments.
+                   6. Call the function call dispatcher (function_record::impl)
+
+                   If one of these fail, move on to the next overload and keep trying until we get a
+                   result other than PYBIND11_TRY_NEXT_OVERLOAD.
+                 */
+
+                function_record &func = *it;
+                size_t pos_args = func.nargs;    // Number of positional arguments that we need
+                if (func.has_args) --pos_args;   // (but don't count py::args
+                if (func.has_kwargs) --pos_args; //  or py::kwargs)
+
+                if (!func.has_args && n_args_in > pos_args)
+                    continue; // Too many arguments for this overload
+
+                if (n_args_in < pos_args && func.args.size() < pos_args)
+                    continue; // Not enough arguments given, and not enough defaults to fill in the blanks
+
+                function_call call(func, parent);
+
+                size_t args_to_copy = std::min(pos_args, n_args_in);
+                size_t args_copied = 0;
+
+                // 0. Inject new-style `self` argument
+                if (func.is_new_style_constructor) {
+                    // The `value` may have been preallocated by an old-style `__init__`
+                    // if it was a preceding candidate for overload resolution.
+                    if (self_value_and_holder)
+                        self_value_and_holder.type->dealloc(self_value_and_holder);
+
+                    call.init_self = PyTuple_GET_ITEM(args_in, 0);
+                    call.args.push_back(reinterpret_cast<PyObject *>(&self_value_and_holder));
+                    call.args_convert.push_back(false);
+                    ++args_copied;
+                }
+
+                // 1. Copy any position arguments given.
+                bool bad_arg = false;
+                for (; args_copied < args_to_copy; ++args_copied) {
+                    argument_record *arg_rec = args_copied < func.args.size() ? &func.args[args_copied] : nullptr;
+                    if (kwargs_in && arg_rec && arg_rec->name && PyDict_GetItemString(kwargs_in, arg_rec->name)) {
+                        bad_arg = true;
+                        break;
+                    }
+
+                    handle arg(PyTuple_GET_ITEM(args_in, args_copied));
+                    if (arg_rec && !arg_rec->none && arg.is_none()) {
+                        bad_arg = true;
+                        break;
+                    }
+                    call.args.push_back(arg);
+                    call.args_convert.push_back(arg_rec ? arg_rec->convert : true);
+                }
+                if (bad_arg)
+                    continue; // Maybe it was meant for another overload (issue #688)
+
+                // We'll need to copy this if we steal some kwargs for defaults
+                dict kwargs = reinterpret_borrow<dict>(kwargs_in);
+
+                // 2. Check kwargs and, failing that, defaults that may help complete the list
+                if (args_copied < pos_args) {
+                    bool copied_kwargs = false;
+
+                    for (; args_copied < pos_args; ++args_copied) {
+                        const auto &arg = func.args[args_copied];
+
+                        handle value;
+                        if (kwargs_in && arg.name)
+                            value = PyDict_GetItemString(kwargs.ptr(), arg.name);
+
+                        if (value) {
+                            // Consume a kwargs value
+                            if (!copied_kwargs) {
+                                kwargs = reinterpret_steal<dict>(PyDict_Copy(kwargs.ptr()));
+                                copied_kwargs = true;
+                            }
+                            PyDict_DelItemString(kwargs.ptr(), arg.name);
+                        } else if (arg.value) {
+                            value = arg.value;
+                        }
+
+                        if (value) {
+                            call.args.push_back(value);
+                            call.args_convert.push_back(arg.convert);
+                        }
+                        else
+                            break;
+                    }
+
+                    if (args_copied < pos_args)
+                        continue; // Not enough arguments, defaults, or kwargs to fill the positional arguments
+                }
+
+                // 3. Check everything was consumed (unless we have a kwargs arg)
+                if (kwargs && kwargs.size() > 0 && !func.has_kwargs)
+                    continue; // Unconsumed kwargs, but no py::kwargs argument to accept them
+
+                // 4a. If we have a py::args argument, create a new tuple with leftovers
+                if (func.has_args) {
+                    tuple extra_args;
+                    if (args_to_copy == 0) {
+                        // We didn't copy out any position arguments from the args_in tuple, so we
+                        // can reuse it directly without copying:
+                        extra_args = reinterpret_borrow<tuple>(args_in);
+                    } else if (args_copied >= n_args_in) {
+                        extra_args = tuple(0);
+                    } else {
+                        size_t args_size = n_args_in - args_copied;
+                        extra_args = tuple(args_size);
+                        for (size_t i = 0; i < args_size; ++i) {
+                            extra_args[i] = PyTuple_GET_ITEM(args_in, args_copied + i);
+                        }
+                    }
+                    call.args.push_back(extra_args);
+                    call.args_convert.push_back(false);
+                    call.args_ref = std::move(extra_args);
+                }
+
+                // 4b. If we have a py::kwargs, pass on any remaining kwargs
+                if (func.has_kwargs) {
+                    if (!kwargs.ptr())
+                        kwargs = dict(); // If we didn't get one, send an empty one
+                    call.args.push_back(kwargs);
+                    call.args_convert.push_back(false);
+                    call.kwargs_ref = std::move(kwargs);
+                }
+
+                // 5. Put everything in a vector.  Not technically step 5, we've been building it
+                // in `call.args` all along.
+                #if !defined(NDEBUG)
+                if (call.args.size() != func.nargs || call.args_convert.size() != func.nargs)
+                    pybind11_fail("Internal error: function call dispatcher inserted wrong number of arguments!");
+                #endif
+
+                std::vector<bool> second_pass_convert;
+                if (overloaded) {
+                    // We're in the first no-convert pass, so swap out the conversion flags for a
+                    // set of all-false flags.  If the call fails, we'll swap the flags back in for
+                    // the conversion-allowed call below.
+                    second_pass_convert.resize(func.nargs, false);
+                    call.args_convert.swap(second_pass_convert);
+                }
+
+                // 6. Call the function.
+                try {
+                    loader_life_support guard{};
+                    result = func.impl(call);
+                } catch (reference_cast_error &) {
+                    result = PYBIND11_TRY_NEXT_OVERLOAD;
+                }
+
+                if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD)
+                    break;
+
+                if (overloaded) {
+                    // The (overloaded) call failed; if the call has at least one argument that
+                    // permits conversion (i.e. it hasn't been explicitly specified `.noconvert()`)
+                    // then add this call to the list of second pass overloads to try.
+                    for (size_t i = func.is_method ? 1 : 0; i < pos_args; i++) {
+                        if (second_pass_convert[i]) {
+                            // Found one: swap the converting flags back in and store the call for
+                            // the second pass.
+                            call.args_convert.swap(second_pass_convert);
+                            second_pass.push_back(std::move(call));
+                            break;
+                        }
+                    }
+                }
+            }
+
+            if (overloaded && !second_pass.empty() && result.ptr() == PYBIND11_TRY_NEXT_OVERLOAD) {
+                // The no-conversion pass finished without success, try again with conversion allowed
+                for (auto &call : second_pass) {
+                    try {
+                        loader_life_support guard{};
+                        result = call.func.impl(call);
+                    } catch (reference_cast_error &) {
+                        result = PYBIND11_TRY_NEXT_OVERLOAD;
+                    }
+
+                    if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD)
+                        break;
+                }
+            }
+        } catch (error_already_set &e) {
+            e.restore();
+            return nullptr;
+        } catch (...) {
+            /* When an exception is caught, give each registered exception
+               translator a chance to translate it to a Python exception
+               in reverse order of registration.
+
+               A translator may choose to do one of the following:
+
+                - catch the exception and call PyErr_SetString or PyErr_SetObject
+                  to set a standard (or custom) Python exception, or
+                - do nothing and let the exception fall through to the next translator, or
+                - delegate translation to the next translator by throwing a new type of exception. */
+
+            auto last_exception = std::current_exception();
+            auto &registered_exception_translators = get_internals().registered_exception_translators;
+            for (auto& translator : registered_exception_translators) {
+                try {
+                    translator(last_exception);
+                } catch (...) {
+                    last_exception = std::current_exception();
+                    continue;
+                }
+                return nullptr;
+            }
+            PyErr_SetString(PyExc_SystemError, "Exception escaped from default exception translator!");
+            return nullptr;
+        }
+
+        auto append_note_if_missing_header_is_suspected = [](std::string &msg) {
+            if (msg.find("std::") != std::string::npos) {
+                msg += "\n\n"
+                       "Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,\n"
+                       "<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic\n"
+                       "conversions are optional and require extra headers to be included\n"
+                       "when compiling your pybind11 module.";
+            }
+        };
+
+        if (result.ptr() == PYBIND11_TRY_NEXT_OVERLOAD) {
+            if (overloads->is_operator)
+                return handle(Py_NotImplemented).inc_ref().ptr();
+
+            std::string msg = std::string(overloads->name) + "(): incompatible " +
+                std::string(overloads->is_constructor ? "constructor" : "function") +
+                " arguments. The following argument types are supported:\n";
+
+            int ctr = 0;
+            for (function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) {
+                msg += "    "+ std::to_string(++ctr) + ". ";
+
+                bool wrote_sig = false;
+                if (overloads->is_constructor) {
+                    // For a constructor, rewrite `(self: Object, arg0, ...) -> NoneType` as `Object(arg0, ...)`
+                    std::string sig = it2->signature;
+                    size_t start = sig.find('(') + 7; // skip "(self: "
+                    if (start < sig.size()) {
+                        // End at the , for the next argument
+                        size_t end = sig.find(", "), next = end + 2;
+                        size_t ret = sig.rfind(" -> ");
+                        // Or the ), if there is no comma:
+                        if (end >= sig.size()) next = end = sig.find(')');
+                        if (start < end && next < sig.size()) {
+                            msg.append(sig, start, end - start);
+                            msg += '(';
+                            msg.append(sig, next, ret - next);
+                            wrote_sig = true;
+                        }
+                    }
+                }
+                if (!wrote_sig) msg += it2->signature;
+
+                msg += "\n";
+            }
+            msg += "\nInvoked with: ";
+            auto args_ = reinterpret_borrow<tuple>(args_in);
+            bool some_args = false;
+            for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) {
+                if (!some_args) some_args = true;
+                else msg += ", ";
+                msg += pybind11::repr(args_[ti]);
+            }
+            if (kwargs_in) {
+                auto kwargs = reinterpret_borrow<dict>(kwargs_in);
+                if (kwargs.size() > 0) {
+                    if (some_args) msg += "; ";
+                    msg += "kwargs: ";
+                    bool first = true;
+                    for (auto kwarg : kwargs) {
+                        if (first) first = false;
+                        else msg += ", ";
+                        msg += pybind11::str("{}={!r}").format(kwarg.first, kwarg.second);
+                    }
+                }
+            }
+
+            append_note_if_missing_header_is_suspected(msg);
+            PyErr_SetString(PyExc_TypeError, msg.c_str());
+            return nullptr;
+        } else if (!result) {
+            std::string msg = "Unable to convert function return value to a "
+                              "Python type! The signature was\n\t";
+            msg += it->signature;
+            append_note_if_missing_header_is_suspected(msg);
+            PyErr_SetString(PyExc_TypeError, msg.c_str());
+            return nullptr;
+        } else {
+            if (overloads->is_constructor && !self_value_and_holder.holder_constructed()) {
+                auto *pi = reinterpret_cast<instance *>(parent.ptr());
+                self_value_and_holder.type->init_instance(pi, nullptr);
+            }
+            return result.ptr();
+        }
+    }
+};
+
+/// Wrapper for Python extension modules
+class module : public object {
+public:
+    PYBIND11_OBJECT_DEFAULT(module, object, PyModule_Check)
+
+    /// Create a new top-level Python module with the given name and docstring
+    explicit module(const char *name, const char *doc = nullptr) {
+        if (!options::show_user_defined_docstrings()) doc = nullptr;
+#if PY_MAJOR_VERSION >= 3
+        PyModuleDef *def = new PyModuleDef();
+        std::memset(def, 0, sizeof(PyModuleDef));
+        def->m_name = name;
+        def->m_doc = doc;
+        def->m_size = -1;
+        Py_INCREF(def);
+        m_ptr = PyModule_Create(def);
+#else
+        m_ptr = Py_InitModule3(name, nullptr, doc);
+#endif
+        if (m_ptr == nullptr)
+            pybind11_fail("Internal error in module::module()");
+        inc_ref();
+    }
+
+    /** \rst
+        Create Python binding for a new function within the module scope. ``Func``
+        can be a plain C++ function, a function pointer, or a lambda function. For
+        details on the ``Extra&& ... extra`` argument, see section :ref:`extras`.
+    \endrst */
+    template <typename Func, typename... Extra>
+    module &def(const char *name_, Func &&f, const Extra& ... extra) {
+        cpp_function func(std::forward<Func>(f), name(name_), scope(*this),
+                          sibling(getattr(*this, name_, none())), extra...);
+        // NB: allow overwriting here because cpp_function sets up a chain with the intention of
+        // overwriting (and has already checked internally that it isn't overwriting non-functions).
+        add_object(name_, func, true /* overwrite */);
+        return *this;
+    }
+
+    /** \rst
+        Create and return a new Python submodule with the given name and docstring.
+        This also works recursively, i.e.
+
+        .. code-block:: cpp
+
+            py::module m("example", "pybind11 example plugin");
+            py::module m2 = m.def_submodule("sub", "A submodule of 'example'");
+            py::module m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'");
+    \endrst */
+    module def_submodule(const char *name, const char *doc = nullptr) {
+        std::string full_name = std::string(PyModule_GetName(m_ptr))
+            + std::string(".") + std::string(name);
+        auto result = reinterpret_borrow<module>(PyImport_AddModule(full_name.c_str()));
+        if (doc && options::show_user_defined_docstrings())
+            result.attr("__doc__") = pybind11::str(doc);
+        attr(name) = result;
+        return result;
+    }
+
+    /// Import and return a module or throws `error_already_set`.
+    static module import(const char *name) {
+        PyObject *obj = PyImport_ImportModule(name);
+        if (!obj)
+            throw error_already_set();
+        return reinterpret_steal<module>(obj);
+    }
+
+    /// Reload the module or throws `error_already_set`.
+    void reload() {
+        PyObject *obj = PyImport_ReloadModule(ptr());
+        if (!obj)
+            throw error_already_set();
+        *this = reinterpret_steal<module>(obj);
+    }
+
+    // Adds an object to the module using the given name.  Throws if an object with the given name
+    // already exists.
+    //
+    // overwrite should almost always be false: attempting to overwrite objects that pybind11 has
+    // established will, in most cases, break things.
+    PYBIND11_NOINLINE void add_object(const char *name, handle obj, bool overwrite = false) {
+        if (!overwrite && hasattr(*this, name))
+            pybind11_fail("Error during initialization: multiple incompatible definitions with name \"" +
+                    std::string(name) + "\"");
+
+        PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */);
+    }
+};
+
+/// \ingroup python_builtins
+/// Return a dictionary representing the global variables in the current execution frame,
+/// or ``__main__.__dict__`` if there is no frame (usually when the interpreter is embedded).
+inline dict globals() {
+    PyObject *p = PyEval_GetGlobals();
+    return reinterpret_borrow<dict>(p ? p : module::import("__main__").attr("__dict__").ptr());
+}
+
+NAMESPACE_BEGIN(detail)
+/// Generic support for creating new Python heap types
+class generic_type : public object {
+    template <typename...> friend class class_;
+public:
+    PYBIND11_OBJECT_DEFAULT(generic_type, object, PyType_Check)
+protected:
+    void initialize(const type_record &rec) {
+        if (rec.scope && hasattr(rec.scope, rec.name))
+            pybind11_fail("generic_type: cannot initialize type \"" + std::string(rec.name) +
+                          "\": an object with that name is already defined");
+
+        if (rec.module_local ? get_local_type_info(*rec.type) : get_global_type_info(*rec.type))
+            pybind11_fail("generic_type: type \"" + std::string(rec.name) +
+                          "\" is already registered!");
+
+        m_ptr = make_new_python_type(rec);
+
+        /* Register supplemental type information in C++ dict */
+        auto *tinfo = new detail::type_info();
+        tinfo->type = (PyTypeObject *) m_ptr;
+        tinfo->cpptype = rec.type;
+        tinfo->type_size = rec.type_size;
+        tinfo->operator_new = rec.operator_new;
+        tinfo->holder_size_in_ptrs = size_in_ptrs(rec.holder_size);
+        tinfo->init_instance = rec.init_instance;
+        tinfo->dealloc = rec.dealloc;
+        tinfo->simple_type = true;
+        tinfo->simple_ancestors = true;
+        tinfo->default_holder = rec.default_holder;
+        tinfo->module_local = rec.module_local;
+
+        auto &internals = get_internals();
+        auto tindex = std::type_index(*rec.type);
+        tinfo->direct_conversions = &internals.direct_conversions[tindex];
+        if (rec.module_local)
+            registered_local_types_cpp()[tindex] = tinfo;
+        else
+            internals.registered_types_cpp[tindex] = tinfo;
+        internals.registered_types_py[(PyTypeObject *) m_ptr] = { tinfo };
+
+        if (rec.bases.size() > 1 || rec.multiple_inheritance) {
+            mark_parents_nonsimple(tinfo->type);
+            tinfo->simple_ancestors = false;
+        }
+        else if (rec.bases.size() == 1) {
+            auto parent_tinfo = get_type_info((PyTypeObject *) rec.bases[0].ptr());
+            tinfo->simple_ancestors = parent_tinfo->simple_ancestors;
+        }
+
+        if (rec.module_local) {
+            // Stash the local typeinfo and loader so that external modules can access it.
+            tinfo->module_local_load = &type_caster_generic::local_load;
+            setattr(m_ptr, PYBIND11_MODULE_LOCAL_ID, capsule(tinfo));
+        }
+    }
+
+    /// Helper function which tags all parents of a type using mult. inheritance
+    void mark_parents_nonsimple(PyTypeObject *value) {
+        auto t = reinterpret_borrow<tuple>(value->tp_bases);
+        for (handle h : t) {
+            auto tinfo2 = get_type_info((PyTypeObject *) h.ptr());
+            if (tinfo2)
+                tinfo2->simple_type = false;
+            mark_parents_nonsimple((PyTypeObject *) h.ptr());
+        }
+    }
+
+    void install_buffer_funcs(
+            buffer_info *(*get_buffer)(PyObject *, void *),
+            void *get_buffer_data) {
+        PyHeapTypeObject *type = (PyHeapTypeObject*) m_ptr;
+        auto tinfo = detail::get_type_info(&type->ht_type);
+
+        if (!type->ht_type.tp_as_buffer)
+            pybind11_fail(
+                "To be able to register buffer protocol support for the type '" +
+                std::string(tinfo->type->tp_name) +
+                "' the associated class<>(..) invocation must "
+                "include the pybind11::buffer_protocol() annotation!");
+
+        tinfo->get_buffer = get_buffer;
+        tinfo->get_buffer_data = get_buffer_data;
+    }
+
+    void def_property_static_impl(const char *name,
+                                  handle fget, handle fset,
+                                  detail::function_record *rec_fget) {
+        const auto is_static = !(rec_fget->is_method && rec_fget->scope);
+        const auto has_doc = rec_fget->doc && pybind11::options::show_user_defined_docstrings();
+
+        auto property = handle((PyObject *) (is_static ? get_internals().static_property_type
+                                                       : &PyProperty_Type));
+        attr(name) = property(fget.ptr() ? fget : none(),
+                              fset.ptr() ? fset : none(),
+                              /*deleter*/none(),
+                              pybind11::str(has_doc ? rec_fget->doc : ""));
+    }
+};
+
+/// Set the pointer to operator new if it exists. The cast is needed because it can be overloaded.
+template <typename T, typename = void_t<decltype(static_cast<void *(*)(size_t)>(T::operator new))>>
+void set_operator_new(type_record *r) { r->operator_new = &T::operator new; }
+
+template <typename> void set_operator_new(...) { }
+
+template <typename T, typename SFINAE = void> struct has_operator_delete : std::false_type { };
+template <typename T> struct has_operator_delete<T, void_t<decltype(static_cast<void (*)(void *)>(T::operator delete))>>
+    : std::true_type { };
+template <typename T, typename SFINAE = void> struct has_operator_delete_size : std::false_type { };
+template <typename T> struct has_operator_delete_size<T, void_t<decltype(static_cast<void (*)(void *, size_t)>(T::operator delete))>>
+    : std::true_type { };
+/// Call class-specific delete if it exists or global otherwise. Can also be an overload set.
+template <typename T, enable_if_t<has_operator_delete<T>::value, int> = 0>
+void call_operator_delete(T *p, size_t) { T::operator delete(p); }
+template <typename T, enable_if_t<!has_operator_delete<T>::value && has_operator_delete_size<T>::value, int> = 0>
+void call_operator_delete(T *p, size_t s) { T::operator delete(p, s); }
+
+inline void call_operator_delete(void *p, size_t) { ::operator delete(p); }
+
+NAMESPACE_END(detail)
+
+/// Given a pointer to a member function, cast it to its `Derived` version.
+/// Forward everything else unchanged.
+template <typename /*Derived*/, typename F>
+auto method_adaptor(F &&f) -> decltype(std::forward<F>(f)) { return std::forward<F>(f); }
+
+template <typename Derived, typename Return, typename Class, typename... Args>
+auto method_adaptor(Return (Class::*pmf)(Args...)) -> Return (Derived::*)(Args...) { return pmf; }
+
+template <typename Derived, typename Return, typename Class, typename... Args>
+auto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)(Args...) const { return pmf; }
+
+template <typename type_, typename... options>
+class class_ : public detail::generic_type {
+    template <typename T> using is_holder = detail::is_holder_type<type_, T>;
+    template <typename T> using is_subtype = detail::is_strict_base_of<type_, T>;
+    template <typename T> using is_base = detail::is_strict_base_of<T, type_>;
+    // struct instead of using here to help MSVC:
+    template <typename T> struct is_valid_class_option :
+        detail::any_of<is_holder<T>, is_subtype<T>, is_base<T>> {};
+
+public:
+    using type = type_;
+    using type_alias = detail::exactly_one_t<is_subtype, void, options...>;
+    constexpr static bool has_alias = !std::is_void<type_alias>::value;
+    using holder_type = detail::exactly_one_t<is_holder, std::unique_ptr<type>, options...>;
+
+    static_assert(detail::all_of<is_valid_class_option<options>...>::value,
+            "Unknown/invalid class_ template parameters provided");
+
+    static_assert(!has_alias || std::is_polymorphic<type>::value,
+            "Cannot use an alias class with a non-polymorphic type");
+
+    PYBIND11_OBJECT(class_, generic_type, PyType_Check)
+
+    template <typename... Extra>
+    class_(handle scope, const char *name, const Extra &... extra) {
+        using namespace detail;
+
+        // MI can only be specified via class_ template options, not constructor parameters
+        static_assert(
+            none_of<is_pyobject<Extra>...>::value || // no base class arguments, or:
+            (   constexpr_sum(is_pyobject<Extra>::value...) == 1 && // Exactly one base
+                constexpr_sum(is_base<options>::value...)   == 0 && // no template option bases
+                none_of<std::is_same<multiple_inheritance, Extra>...>::value), // no multiple_inheritance attr
+            "Error: multiple inheritance bases must be specified via class_ template options");
+
+        type_record record;
+        record.scope = scope;
+        record.name = name;
+        record.type = &typeid(type);
+        record.type_size = sizeof(conditional_t<has_alias, type_alias, type>);
+        record.holder_size = sizeof(holder_type);
+        record.init_instance = init_instance;
+        record.dealloc = dealloc;
+        record.default_holder = std::is_same<holder_type, std::unique_ptr<type>>::value;
+
+        set_operator_new<type>(&record);
+
+        /* Register base classes specified via template arguments to class_, if any */
+        PYBIND11_EXPAND_SIDE_EFFECTS(add_base<options>(record));
+
+        /* Process optional arguments, if any */
+        process_attributes<Extra...>::init(extra..., &record);
+
+        generic_type::initialize(record);
+
+        if (has_alias) {
+            auto &instances = record.module_local ? registered_local_types_cpp() : get_internals().registered_types_cpp;
+            instances[std::type_index(typeid(type_alias))] = instances[std::type_index(typeid(type))];
+        }
+    }
+
+    template <typename Base, detail::enable_if_t<is_base<Base>::value, int> = 0>
+    static void add_base(detail::type_record &rec) {
+        rec.add_base(typeid(Base), [](void *src) -> void * {
+            return static_cast<Base *>(reinterpret_cast<type *>(src));
+        });
+    }
+
+    template <typename Base, detail::enable_if_t<!is_base<Base>::value, int> = 0>
+    static void add_base(detail::type_record &) { }
+
+    template <typename Func, typename... Extra>
+    class_ &def(const char *name_, Func&& f, const Extra&... extra) {
+        cpp_function cf(method_adaptor<type>(std::forward<Func>(f)), name(name_), is_method(*this),
+                        sibling(getattr(*this, name_, none())), extra...);
+        attr(cf.name()) = cf;
+        return *this;
+    }
+
+    template <typename Func, typename... Extra> class_ &
+    def_static(const char *name_, Func &&f, const Extra&... extra) {
+        static_assert(!std::is_member_function_pointer<Func>::value,
+                "def_static(...) called with a non-static member function pointer");
+        cpp_function cf(std::forward<Func>(f), name(name_), scope(*this),
+                        sibling(getattr(*this, name_, none())), extra...);
+        attr(cf.name()) = cf;
+        return *this;
+    }
+
+    template <detail::op_id id, detail::op_type ot, typename L, typename R, typename... Extra>
+    class_ &def(const detail::op_<id, ot, L, R> &op, const Extra&... extra) {
+        op.execute(*this, extra...);
+        return *this;
+    }
+
+    template <detail::op_id id, detail::op_type ot, typename L, typename R, typename... Extra>
+    class_ & def_cast(const detail::op_<id, ot, L, R> &op, const Extra&... extra) {
+        op.execute_cast(*this, extra...);
+        return *this;
+    }
+
+    template <typename... Args, typename... Extra>
+    class_ &def(const detail::initimpl::constructor<Args...> &init, const Extra&... extra) {
+        init.execute(*this, extra...);
+        return *this;
+    }
+
+    template <typename... Args, typename... Extra>
+    class_ &def(const detail::initimpl::alias_constructor<Args...> &init, const Extra&... extra) {
+        init.execute(*this, extra...);
+        return *this;
+    }
+
+    template <typename... Args, typename... Extra>
+    class_ &def(detail::initimpl::factory<Args...> &&init, const Extra&... extra) {
+        std::move(init).execute(*this, extra...);
+        return *this;
+    }
+
+    template <typename... Args, typename... Extra>
+    class_ &def(detail::initimpl::pickle_factory<Args...> &&pf, const Extra &...extra) {
+        std::move(pf).execute(*this, extra...);
+        return *this;
+    }
+
+    template <typename Func> class_& def_buffer(Func &&func) {
+        struct capture { Func func; };
+        capture *ptr = new capture { std::forward<Func>(func) };
+        install_buffer_funcs([](PyObject *obj, void *ptr) -> buffer_info* {
+            detail::make_caster<type> caster;
+            if (!caster.load(obj, false))
+                return nullptr;
+            return new buffer_info(((capture *) ptr)->func(caster));
+        }, ptr);
+        return *this;
+    }
+
+    template <typename Return, typename Class, typename... Args>
+    class_ &def_buffer(Return (Class::*func)(Args...)) {
+        return def_buffer([func] (type &obj) { return (obj.*func)(); });
+    }
+
+    template <typename Return, typename Class, typename... Args>
+    class_ &def_buffer(Return (Class::*func)(Args...) const) {
+        return def_buffer([func] (const type &obj) { return (obj.*func)(); });
+    }
+
+    template <typename C, typename D, typename... Extra>
+    class_ &def_readwrite(const char *name, D C::*pm, const Extra&... extra) {
+        static_assert(std::is_base_of<C, type>::value, "def_readwrite() requires a class member (or base class member)");
+        cpp_function fget([pm](const type &c) -> const D &{ return c.*pm; }, is_method(*this)),
+                     fset([pm](type &c, const D &value) { c.*pm = value; }, is_method(*this));
+        def_property(name, fget, fset, return_value_policy::reference_internal, extra...);
+        return *this;
+    }
+
+    template <typename C, typename D, typename... Extra>
+    class_ &def_readonly(const char *name, const D C::*pm, const Extra& ...extra) {
+        static_assert(std::is_base_of<C, type>::value, "def_readonly() requires a class member (or base class member)");
+        cpp_function fget([pm](const type &c) -> const D &{ return c.*pm; }, is_method(*this));
+        def_property_readonly(name, fget, return_value_policy::reference_internal, extra...);
+        return *this;
+    }
+
+    template <typename D, typename... Extra>
+    class_ &def_readwrite_static(const char *name, D *pm, const Extra& ...extra) {
+        cpp_function fget([pm](object) -> const D &{ return *pm; }, scope(*this)),
+                     fset([pm](object, const D &value) { *pm = value; }, scope(*this));
+        def_property_static(name, fget, fset, return_value_policy::reference, extra...);
+        return *this;
+    }
+
+    template <typename D, typename... Extra>
+    class_ &def_readonly_static(const char *name, const D *pm, const Extra& ...extra) {
+        cpp_function fget([pm](object) -> const D &{ return *pm; }, scope(*this));
+        def_property_readonly_static(name, fget, return_value_policy::reference, extra...);
+        return *this;
+    }
+
+    /// Uses return_value_policy::reference_internal by default
+    template <typename Getter, typename... Extra>
+    class_ &def_property_readonly(const char *name, const Getter &fget, const Extra& ...extra) {
+        return def_property_readonly(name, cpp_function(method_adaptor<type>(fget)),
+                                     return_value_policy::reference_internal, extra...);
+    }
+
+    /// Uses cpp_function's return_value_policy by default
+    template <typename... Extra>
+    class_ &def_property_readonly(const char *name, const cpp_function &fget, const Extra& ...extra) {
+        return def_property(name, fget, cpp_function(), extra...);
+    }
+
+    /// Uses return_value_policy::reference by default
+    template <typename Getter, typename... Extra>
+    class_ &def_property_readonly_static(const char *name, const Getter &fget, const Extra& ...extra) {
+        return def_property_readonly_static(name, cpp_function(fget), return_value_policy::reference, extra...);
+    }
+
+    /// Uses cpp_function's return_value_policy by default
+    template <typename... Extra>
+    class_ &def_property_readonly_static(const char *name, const cpp_function &fget, const Extra& ...extra) {
+        return def_property_static(name, fget, cpp_function(), extra...);
+    }
+
+    /// Uses return_value_policy::reference_internal by default
+    template <typename Getter, typename Setter, typename... Extra>
+    class_ &def_property(const char *name, const Getter &fget, const Setter &fset, const Extra& ...extra) {
+        return def_property(name, fget, cpp_function(method_adaptor<type>(fset)), extra...);
+    }
+    template <typename Getter, typename... Extra>
+    class_ &def_property(const char *name, const Getter &fget, const cpp_function &fset, const Extra& ...extra) {
+        return def_property(name, cpp_function(method_adaptor<type>(fget)), fset,
+                            return_value_policy::reference_internal, extra...);
+    }
+
+    /// Uses cpp_function's return_value_policy by default
+    template <typename... Extra>
+    class_ &def_property(const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) {
+        return def_property_static(name, fget, fset, is_method(*this), extra...);
+    }
+
+    /// Uses return_value_policy::reference by default
+    template <typename Getter, typename... Extra>
+    class_ &def_property_static(const char *name, const Getter &fget, const cpp_function &fset, const Extra& ...extra) {
+        return def_property_static(name, cpp_function(fget), fset, return_value_policy::reference, extra...);
+    }
+
+    /// Uses cpp_function's return_value_policy by default
+    template <typename... Extra>
+    class_ &def_property_static(const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) {
+        auto rec_fget = get_function_record(fget), rec_fset = get_function_record(fset);
+        char *doc_prev = rec_fget->doc; /* 'extra' field may include a property-specific documentation string */
+        detail::process_attributes<Extra...>::init(extra..., rec_fget);
+        if (rec_fget->doc && rec_fget->doc != doc_prev) {
+            free(doc_prev);
+            rec_fget->doc = strdup(rec_fget->doc);
+        }
+        if (rec_fset) {
+            doc_prev = rec_fset->doc;
+            detail::process_attributes<Extra...>::init(extra..., rec_fset);
+            if (rec_fset->doc && rec_fset->doc != doc_prev) {
+                free(doc_prev);
+                rec_fset->doc = strdup(rec_fset->doc);
+            }
+        }
+        def_property_static_impl(name, fget, fset, rec_fget);
+        return *this;
+    }
+
+private:
+    /// Initialize holder object, variant 1: object derives from enable_shared_from_this
+    template <typename T>
+    static void init_holder(detail::instance *inst, detail::value_and_holder &v_h,
+            const holder_type * /* unused */, const std::enable_shared_from_this<T> * /* dummy */) {
+        try {
+            auto sh = std::dynamic_pointer_cast<typename holder_type::element_type>(
+                    v_h.value_ptr<type>()->shared_from_this());
+            if (sh) {
+                new (std::addressof(v_h.holder<holder_type>())) holder_type(std::move(sh));
+                v_h.set_holder_constructed();
+            }
+        } catch (const std::bad_weak_ptr &) {}
+
+        if (!v_h.holder_constructed() && inst->owned) {
+            new (std::addressof(v_h.holder<holder_type>())) holder_type(v_h.value_ptr<type>());
+            v_h.set_holder_constructed();
+        }
+    }
+
+    static void init_holder_from_existing(const detail::value_and_holder &v_h,
+            const holder_type *holder_ptr, std::true_type /*is_copy_constructible*/) {
+        new (std::addressof(v_h.holder<holder_type>())) holder_type(*reinterpret_cast<const holder_type *>(holder_ptr));
+    }
+
+    static void init_holder_from_existing(const detail::value_and_holder &v_h,
+            const holder_type *holder_ptr, std::false_type /*is_copy_constructible*/) {
+        new (std::addressof(v_h.holder<holder_type>())) holder_type(std::move(*const_cast<holder_type *>(holder_ptr)));
+    }
+
+    /// Initialize holder object, variant 2: try to construct from existing holder object, if possible
+    static void init_holder(detail::instance *inst, detail::value_and_holder &v_h,
+            const holder_type *holder_ptr, const void * /* dummy -- not enable_shared_from_this<T>) */) {
+        if (holder_ptr) {
+            init_holder_from_existing(v_h, holder_ptr, std::is_copy_constructible<holder_type>());
+            v_h.set_holder_constructed();
+        } else if (inst->owned || detail::always_construct_holder<holder_type>::value) {
+            new (std::addressof(v_h.holder<holder_type>())) holder_type(v_h.value_ptr<type>());
+            v_h.set_holder_constructed();
+        }
+    }
+
+    /// Performs instance initialization including constructing a holder and registering the known
+    /// instance.  Should be called as soon as the `type` value_ptr is set for an instance.  Takes an
+    /// optional pointer to an existing holder to use; if not specified and the instance is
+    /// `.owned`, a new holder will be constructed to manage the value pointer.
+    static void init_instance(detail::instance *inst, const void *holder_ptr) {
+        auto v_h = inst->get_value_and_holder(detail::get_type_info(typeid(type)));
+        if (!v_h.instance_registered()) {
+            register_instance(inst, v_h.value_ptr(), v_h.type);
+            v_h.set_instance_registered();
+        }
+        init_holder(inst, v_h, (const holder_type *) holder_ptr, v_h.value_ptr<type>());
+    }
+
+    /// Deallocates an instance; via holder, if constructed; otherwise via operator delete.
+    static void dealloc(detail::value_and_holder &v_h) {
+        if (v_h.holder_constructed()) {
+            v_h.holder<holder_type>().~holder_type();
+            v_h.set_holder_constructed(false);
+        }
+        else {
+            detail::call_operator_delete(v_h.value_ptr<type>(), v_h.type->type_size);
+        }
+        v_h.value_ptr() = nullptr;
+    }
+
+    static detail::function_record *get_function_record(handle h) {
+        h = detail::get_function(h);
+        return h ? (detail::function_record *) reinterpret_borrow<capsule>(PyCFunction_GET_SELF(h.ptr()))
+                 : nullptr;
+    }
+};
+
+/// Binds an existing constructor taking arguments Args...
+template <typename... Args> detail::initimpl::constructor<Args...> init() { return {}; }
+/// Like `init<Args...>()`, but the instance is always constructed through the alias class (even
+/// when not inheriting on the Python side).
+template <typename... Args> detail::initimpl::alias_constructor<Args...> init_alias() { return {}; }
+
+/// Binds a factory function as a constructor
+template <typename Func, typename Ret = detail::initimpl::factory<Func>>
+Ret init(Func &&f) { return {std::forward<Func>(f)}; }
+
+/// Dual-argument factory function: the first function is called when no alias is needed, the second
+/// when an alias is needed (i.e. due to python-side inheritance).  Arguments must be identical.
+template <typename CFunc, typename AFunc, typename Ret = detail::initimpl::factory<CFunc, AFunc>>
+Ret init(CFunc &&c, AFunc &&a) {
+    return {std::forward<CFunc>(c), std::forward<AFunc>(a)};
+}
+
+/// Binds pickling functions `__getstate__` and `__setstate__` and ensures that the type
+/// returned by `__getstate__` is the same as the argument accepted by `__setstate__`.
+template <typename GetState, typename SetState>
+detail::initimpl::pickle_factory<GetState, SetState> pickle(GetState &&g, SetState &&s) {
+    return {std::forward<GetState>(g), std::forward<SetState>(s)};
+}
+
+/// Binds C++ enumerations and enumeration classes to Python
+template <typename Type> class enum_ : public class_<Type> {
+public:
+    using class_<Type>::def;
+    using class_<Type>::def_property_readonly_static;
+    using Scalar = typename std::underlying_type<Type>::type;
+
+    template <typename... Extra>
+    enum_(const handle &scope, const char *name, const Extra&... extra)
+      : class_<Type>(scope, name, extra...), m_entries(), m_parent(scope) {
+
+        constexpr bool is_arithmetic = detail::any_of<std::is_same<arithmetic, Extra>...>::value;
+
+        auto m_entries_ptr = m_entries.inc_ref().ptr();
+        def("__repr__", [name, m_entries_ptr](Type value) -> pybind11::str {
+            for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr)) {
+                if (pybind11::cast<Type>(kv.second) == value)
+                    return pybind11::str("{}.{}").format(name, kv.first);
+            }
+            return pybind11::str("{}.???").format(name);
+        });
+        def_property_readonly_static("__members__", [m_entries_ptr](object /* self */) {
+            dict m;
+            for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr))
+                m[kv.first] = kv.second;
+            return m;
+        }, return_value_policy::copy);
+        def(init([](Scalar i) { return static_cast<Type>(i); }));
+        def("__int__", [](Type value) { return (Scalar) value; });
+        #if PY_MAJOR_VERSION < 3
+            def("__long__", [](Type value) { return (Scalar) value; });
+        #endif
+        def("__eq__", [](const Type &value, Type *value2) { return value2 && value == *value2; });
+        def("__ne__", [](const Type &value, Type *value2) { return !value2 || value != *value2; });
+        if (is_arithmetic) {
+            def("__lt__", [](const Type &value, Type *value2) { return value2 && value < *value2; });
+            def("__gt__", [](const Type &value, Type *value2) { return value2 && value > *value2; });
+            def("__le__", [](const Type &value, Type *value2) { return value2 && value <= *value2; });
+            def("__ge__", [](const Type &value, Type *value2) { return value2 && value >= *value2; });
+        }
+        if (std::is_convertible<Type, Scalar>::value) {
+            // Don't provide comparison with the underlying type if the enum isn't convertible,
+            // i.e. if Type is a scoped enum, mirroring the C++ behaviour.  (NB: we explicitly
+            // convert Type to Scalar below anyway because this needs to compile).
+            def("__eq__", [](const Type &value, Scalar value2) { return (Scalar) value == value2; });
+            def("__ne__", [](const Type &value, Scalar value2) { return (Scalar) value != value2; });
+            if (is_arithmetic) {
+                def("__lt__", [](const Type &value, Scalar value2) { return (Scalar) value < value2; });
+                def("__gt__", [](const Type &value, Scalar value2) { return (Scalar) value > value2; });
+                def("__le__", [](const Type &value, Scalar value2) { return (Scalar) value <= value2; });
+                def("__ge__", [](const Type &value, Scalar value2) { return (Scalar) value >= value2; });
+                def("__invert__", [](const Type &value) { return ~((Scalar) value); });
+                def("__and__", [](const Type &value, Scalar value2) { return (Scalar) value & value2; });
+                def("__or__", [](const Type &value, Scalar value2) { return (Scalar) value | value2; });
+                def("__xor__", [](const Type &value, Scalar value2) { return (Scalar) value ^ value2; });
+                def("__rand__", [](const Type &value, Scalar value2) { return (Scalar) value & value2; });
+                def("__ror__", [](const Type &value, Scalar value2) { return (Scalar) value | value2; });
+                def("__rxor__", [](const Type &value, Scalar value2) { return (Scalar) value ^ value2; });
+                def("__and__", [](const Type &value, const Type &value2) { return (Scalar) value & (Scalar) value2; });
+                def("__or__", [](const Type &value, const Type &value2) { return (Scalar) value | (Scalar) value2; });
+                def("__xor__", [](const Type &value, const Type &value2) { return (Scalar) value ^ (Scalar) value2; });
+            }
+        }
+        def("__hash__", [](const Type &value) { return (Scalar) value; });
+        // Pickling and unpickling -- needed for use with the 'multiprocessing' module
+        def(pickle([](const Type &value) { return pybind11::make_tuple((Scalar) value); },
+                   [](tuple t) { return static_cast<Type>(t[0].cast<Scalar>()); }));
+    }
+
+    /// Export enumeration entries into the parent scope
+    enum_& export_values() {
+        for (const auto &kv : m_entries)
+            m_parent.attr(kv.first) = kv.second;
+        return *this;
+    }
+
+    /// Add an enumeration entry
+    enum_& value(char const* name, Type value) {
+        auto v = pybind11::cast(value, return_value_policy::copy);
+        this->attr(name) = v;
+        m_entries[pybind11::str(name)] = v;
+        return *this;
+    }
+
+private:
+    dict m_entries;
+    handle m_parent;
+};
+
+NAMESPACE_BEGIN(detail)
+
+
+inline void keep_alive_impl(handle nurse, handle patient) {
+    if (!nurse || !patient)
+        pybind11_fail("Could not activate keep_alive!");
+
+    if (patient.is_none() || nurse.is_none())
+        return; /* Nothing to keep alive or nothing to be kept alive by */
+
+    auto tinfo = all_type_info(Py_TYPE(nurse.ptr()));
+    if (!tinfo.empty()) {
+        /* It's a pybind-registered type, so we can store the patient in the
+         * internal list. */
+        add_patient(nurse.ptr(), patient.ptr());
+    }
+    else {
+        /* Fall back to clever approach based on weak references taken from
+         * Boost.Python. This is not used for pybind-registered types because
+         * the objects can be destroyed out-of-order in a GC pass. */
+        cpp_function disable_lifesupport(
+            [patient](handle weakref) { patient.dec_ref(); weakref.dec_ref(); });
+
+        weakref wr(nurse, disable_lifesupport);
+
+        patient.inc_ref(); /* reference patient and leak the weak reference */
+        (void) wr.release();
+    }
+}
+
+PYBIND11_NOINLINE inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret) {
+    auto get_arg = [&](size_t n) {
+        if (n == 0)
+            return ret;
+        else if (n == 1 && call.init_self)
+            return call.init_self;
+        else if (n <= call.args.size())
+            return call.args[n - 1];
+        return handle();
+    };
+
+    keep_alive_impl(get_arg(Nurse), get_arg(Patient));
+}
+
+inline std::pair<decltype(internals::registered_types_py)::iterator, bool> all_type_info_get_cache(PyTypeObject *type) {
+    auto res = get_internals().registered_types_py
+#ifdef __cpp_lib_unordered_map_try_emplace
+        .try_emplace(type);
+#else
+        .emplace(type, std::vector<detail::type_info *>());
+#endif
+    if (res.second) {
+        // New cache entry created; set up a weak reference to automatically remove it if the type
+        // gets destroyed:
+        weakref((PyObject *) type, cpp_function([type](handle wr) {
+            get_internals().registered_types_py.erase(type);
+            wr.dec_ref();
+        })).release();
+    }
+
+    return res;
+}
+
+template <typename Iterator, typename Sentinel, bool KeyIterator, return_value_policy Policy>
+struct iterator_state {
+    Iterator it;
+    Sentinel end;
+    bool first_or_done;
+};
+
+NAMESPACE_END(detail)
+
+/// Makes a python iterator from a first and past-the-end C++ InputIterator.
+template <return_value_policy Policy = return_value_policy::reference_internal,
+          typename Iterator,
+          typename Sentinel,
+          typename ValueType = decltype(*std::declval<Iterator>()),
+          typename... Extra>
+iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) {
+    typedef detail::iterator_state<Iterator, Sentinel, false, Policy> state;
+
+    if (!detail::get_type_info(typeid(state), false)) {
+        class_<state>(handle(), "iterator", pybind11::module_local())
+            .def("__iter__", [](state &s) -> state& { return s; })
+            .def("__next__", [](state &s) -> ValueType {
+                if (!s.first_or_done)
+                    ++s.it;
+                else
+                    s.first_or_done = false;
+                if (s.it == s.end) {
+                    s.first_or_done = true;
+                    throw stop_iteration();
+                }
+                return *s.it;
+            }, std::forward<Extra>(extra)..., Policy);
+    }
+
+    return cast(state{first, last, true});
+}
+
+/// Makes an python iterator over the keys (`.first`) of a iterator over pairs from a
+/// first and past-the-end InputIterator.
+template <return_value_policy Policy = return_value_policy::reference_internal,
+          typename Iterator,
+          typename Sentinel,
+          typename KeyType = decltype((*std::declval<Iterator>()).first),
+          typename... Extra>
+iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) {
+    typedef detail::iterator_state<Iterator, Sentinel, true, Policy> state;
+
+    if (!detail::get_type_info(typeid(state), false)) {
+        class_<state>(handle(), "iterator", pybind11::module_local())
+            .def("__iter__", [](state &s) -> state& { return s; })
+            .def("__next__", [](state &s) -> KeyType {
+                if (!s.first_or_done)
+                    ++s.it;
+                else
+                    s.first_or_done = false;
+                if (s.it == s.end) {
+                    s.first_or_done = true;
+                    throw stop_iteration();
+                }
+                return (*s.it).first;
+            }, std::forward<Extra>(extra)..., Policy);
+    }
+
+    return cast(state{first, last, true});
+}
+
+/// Makes an iterator over values of an stl container or other container supporting
+/// `std::begin()`/`std::end()`
+template <return_value_policy Policy = return_value_policy::reference_internal,
+          typename Type, typename... Extra> iterator make_iterator(Type &value, Extra&&... extra) {
+    return make_iterator<Policy>(std::begin(value), std::end(value), extra...);
+}
+
+/// Makes an iterator over the keys (`.first`) of a stl map-like container supporting
+/// `std::begin()`/`std::end()`
+template <return_value_policy Policy = return_value_policy::reference_internal,
+          typename Type, typename... Extra> iterator make_key_iterator(Type &value, Extra&&... extra) {
+    return make_key_iterator<Policy>(std::begin(value), std::end(value), extra...);
+}
+
+template <typename InputType, typename OutputType> void implicitly_convertible() {
+    struct set_flag {
+        bool &flag;
+        set_flag(bool &flag) : flag(flag) { flag = true; }
+        ~set_flag() { flag = false; }
+    };
+    auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * {
+        static bool currently_used = false;
+        if (currently_used) // implicit conversions are non-reentrant
+            return nullptr;
+        set_flag flag_helper(currently_used);
+        if (!detail::make_caster<InputType>().load(obj, false))
+            return nullptr;
+        tuple args(1);
+        args[0] = obj;
+        PyObject *result = PyObject_Call((PyObject *) type, args.ptr(), nullptr);
+        if (result == nullptr)
+            PyErr_Clear();
+        return result;
+    };
+
+    if (auto tinfo = detail::get_type_info(typeid(OutputType)))
+        tinfo->implicit_conversions.push_back(implicit_caster);
+    else
+        pybind11_fail("implicitly_convertible: Unable to find type " + type_id<OutputType>());
+}
+
+template <typename ExceptionTranslator>
+void register_exception_translator(ExceptionTranslator&& translator) {
+    detail::get_internals().registered_exception_translators.push_front(
+        std::forward<ExceptionTranslator>(translator));
+}
+
+/**
+ * Wrapper to generate a new Python exception type.
+ *
+ * This should only be used with PyErr_SetString for now.
+ * It is not (yet) possible to use as a py::base.
+ * Template type argument is reserved for future use.
+ */
+template <typename type>
+class exception : public object {
+public:
+    exception() = default;
+    exception(handle scope, const char *name, PyObject *base = PyExc_Exception) {
+        std::string full_name = scope.attr("__name__").cast<std::string>() +
+                                std::string(".") + name;
+        m_ptr = PyErr_NewException(const_cast<char *>(full_name.c_str()), base, NULL);
+        if (hasattr(scope, name))
+            pybind11_fail("Error during initialization: multiple incompatible "
+                          "definitions with name \"" + std::string(name) + "\"");
+        scope.attr(name) = *this;
+    }
+
+    // Sets the current python exception to this exception object with the given message
+    void operator()(const char *message) {
+        PyErr_SetString(m_ptr, message);
+    }
+};
+
+NAMESPACE_BEGIN(detail)
+// Returns a reference to a function-local static exception object used in the simple
+// register_exception approach below.  (It would be simpler to have the static local variable
+// directly in register_exception, but that makes clang <3.5 segfault - issue #1349).
+template <typename CppException>
+exception<CppException> &get_exception_object() { static exception<CppException> ex; return ex; }
+NAMESPACE_END(detail)
+
+/**
+ * Registers a Python exception in `m` of the given `name` and installs an exception translator to
+ * translate the C++ exception to the created Python exception using the exceptions what() method.
+ * This is intended for simple exception translations; for more complex translation, register the
+ * exception object and translator directly.
+ */
+template <typename CppException>
+exception<CppException> &register_exception(handle scope,
+                                            const char *name,
+                                            PyObject *base = PyExc_Exception) {
+    auto &ex = detail::get_exception_object<CppException>();
+    if (!ex) ex = exception<CppException>(scope, name, base);
+
+    register_exception_translator([](std::exception_ptr p) {
+        if (!p) return;
+        try {
+            std::rethrow_exception(p);
+        } catch (const CppException &e) {
+            detail::get_exception_object<CppException>()(e.what());
+        }
+    });
+    return ex;
+}
+
+NAMESPACE_BEGIN(detail)
+PYBIND11_NOINLINE inline void print(tuple args, dict kwargs) {
+    auto strings = tuple(args.size());
+    for (size_t i = 0; i < args.size(); ++i) {
+        strings[i] = str(args[i]);
+    }
+    auto sep = kwargs.contains("sep") ? kwargs["sep"] : cast(" ");
+    auto line = sep.attr("join")(strings);
+
+    object file;
+    if (kwargs.contains("file")) {
+        file = kwargs["file"].cast<object>();
+    } else {
+        try {
+            file = module::import("sys").attr("stdout");
+        } catch (const error_already_set &) {
+            /* If print() is called from code that is executed as
+               part of garbage collection during interpreter shutdown,
+               importing 'sys' can fail. Give up rather than crashing the
+               interpreter in this case. */
+            return;
+        }
+    }
+
+    auto write = file.attr("write");
+    write(line);
+    write(kwargs.contains("end") ? kwargs["end"] : cast("\n"));
+
+    if (kwargs.contains("flush") && kwargs["flush"].cast<bool>())
+        file.attr("flush")();
+}
+NAMESPACE_END(detail)
+
+template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args>
+void print(Args &&...args) {
+    auto c = detail::collect_arguments<policy>(std::forward<Args>(args)...);
+    detail::print(c.args(), c.kwargs());
+}
+
+#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
+
+/* The functions below essentially reproduce the PyGILState_* API using a RAII
+ * pattern, but there are a few important differences:
+ *
+ * 1. When acquiring the GIL from an non-main thread during the finalization
+ *    phase, the GILState API blindly terminates the calling thread, which
+ *    is often not what is wanted. This API does not do this.
+ *
+ * 2. The gil_scoped_release function can optionally cut the relationship
+ *    of a PyThreadState and its associated thread, which allows moving it to
+ *    another thread (this is a fairly rare/advanced use case).
+ *
+ * 3. The reference count of an acquired thread state can be controlled. This
+ *    can be handy to prevent cases where callbacks issued from an external
+ *    thread would otherwise constantly construct and destroy thread state data
+ *    structures.
+ *
+ * See the Python bindings of NanoGUI (http://github.com/wjakob/nanogui) for an
+ * example which uses features 2 and 3 to migrate the Python thread of
+ * execution to another thread (to run the event loop on the original thread,
+ * in this case).
+ */
+
+class gil_scoped_acquire {
+public:
+    PYBIND11_NOINLINE gil_scoped_acquire() {
+        auto const &internals = detail::get_internals();
+        tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate);
+
+        if (!tstate) {
+            tstate = PyThreadState_New(internals.istate);
+            #if !defined(NDEBUG)
+                if (!tstate)
+                    pybind11_fail("scoped_acquire: could not create thread state!");
+            #endif
+            tstate->gilstate_counter = 0;
+            PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);
+        } else {
+            release = detail::get_thread_state_unchecked() != tstate;
+        }
+
+        if (release) {
+            /* Work around an annoying assertion in PyThreadState_Swap */
+            #if defined(Py_DEBUG)
+                PyInterpreterState *interp = tstate->interp;
+                tstate->interp = nullptr;
+            #endif
+            PyEval_AcquireThread(tstate);
+            #if defined(Py_DEBUG)
+                tstate->interp = interp;
+            #endif
+        }
+
+        inc_ref();
+    }
+
+    void inc_ref() {
+        ++tstate->gilstate_counter;
+    }
+
+    PYBIND11_NOINLINE void dec_ref() {
+        --tstate->gilstate_counter;
+        #if !defined(NDEBUG)
+            if (detail::get_thread_state_unchecked() != tstate)
+                pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!");
+            if (tstate->gilstate_counter < 0)
+                pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!");
+        #endif
+        if (tstate->gilstate_counter == 0) {
+            #if !defined(NDEBUG)
+                if (!release)
+                    pybind11_fail("scoped_acquire::dec_ref(): internal error!");
+            #endif
+            PyThreadState_Clear(tstate);
+            PyThreadState_DeleteCurrent();
+            PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate);
+            release = false;
+        }
+    }
+
+    PYBIND11_NOINLINE ~gil_scoped_acquire() {
+        dec_ref();
+        if (release)
+           PyEval_SaveThread();
+    }
+private:
+    PyThreadState *tstate = nullptr;
+    bool release = true;
+};
+
+class gil_scoped_release {
+public:
+    explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) {
+        // `get_internals()` must be called here unconditionally in order to initialize
+        // `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an
+        // initialization race could occur as multiple threads try `gil_scoped_acquire`.
+        const auto &internals = detail::get_internals();
+        tstate = PyEval_SaveThread();
+        if (disassoc) {
+            auto key = internals.tstate;
+            PYBIND11_TLS_DELETE_VALUE(key);
+        }
+    }
+    ~gil_scoped_release() {
+        if (!tstate)
+            return;
+        PyEval_RestoreThread(tstate);
+        if (disassoc) {
+            auto key = detail::get_internals().tstate;
+            PYBIND11_TLS_REPLACE_VALUE(key, tstate);
+        }
+    }
+private:
+    PyThreadState *tstate;
+    bool disassoc;
+};
+#elif defined(PYPY_VERSION)
+class gil_scoped_acquire {
+    PyGILState_STATE state;
+public:
+    gil_scoped_acquire() { state = PyGILState_Ensure(); }
+    ~gil_scoped_acquire() { PyGILState_Release(state); }
+};
+
+class gil_scoped_release {
+    PyThreadState *state;
+public:
+    gil_scoped_release() { state = PyEval_SaveThread(); }
+    ~gil_scoped_release() { PyEval_RestoreThread(state); }
+};
+#else
+class gil_scoped_acquire { };
+class gil_scoped_release { };
+#endif
+
+error_already_set::~error_already_set() {
+    if (type) {
+        error_scope scope;
+        gil_scoped_acquire gil;
+        type.release().dec_ref();
+        value.release().dec_ref();
+        trace.release().dec_ref();
+    }
+}
+
+inline function get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name)  {
+    handle self = detail::get_object_handle(this_ptr, this_type);
+    if (!self)
+        return function();
+    handle type = self.get_type();
+    auto key = std::make_pair(type.ptr(), name);
+
+    /* Cache functions that aren't overloaded in Python to avoid
+       many costly Python dictionary lookups below */
+    auto &cache = detail::get_internals().inactive_overload_cache;
+    if (cache.find(key) != cache.end())
+        return function();
+
+    function overload = getattr(self, name, function());
+    if (overload.is_cpp_function()) {
+        cache.insert(key);
+        return function();
+    }
+
+    /* Don't call dispatch code if invoked from overridden function.
+       Unfortunately this doesn't work on PyPy. */
+#if !defined(PYPY_VERSION)
+    PyFrameObject *frame = PyThreadState_Get()->frame;
+    if (frame && (std::string) str(frame->f_code->co_name) == name &&
+        frame->f_code->co_argcount > 0) {
+        PyFrame_FastToLocals(frame);
+        PyObject *self_caller = PyDict_GetItem(
+            frame->f_locals, PyTuple_GET_ITEM(frame->f_code->co_varnames, 0));
+        if (self_caller == self.ptr())
+            return function();
+    }
+#else
+    /* PyPy currently doesn't provide a detailed cpyext emulation of
+       frame objects, so we have to emulate this using Python. This
+       is going to be slow..*/
+    dict d; d["self"] = self; d["name"] = pybind11::str(name);
+    PyObject *result = PyRun_String(
+        "import inspect\n"
+        "frame = inspect.currentframe()\n"
+        "if frame is not None:\n"
+        "    frame = frame.f_back\n"
+        "    if frame is not None and str(frame.f_code.co_name) == name and "
+        "frame.f_code.co_argcount > 0:\n"
+        "        self_caller = frame.f_locals[frame.f_code.co_varnames[0]]\n"
+        "        if self_caller == self:\n"
+        "            self = None\n",
+        Py_file_input, d.ptr(), d.ptr());
+    if (result == nullptr)
+        throw error_already_set();
+    if (d["self"].is_none())
+        return function();
+    Py_DECREF(result);
+#endif
+
+    return overload;
+}
+
+template <class T> function get_overload(const T *this_ptr, const char *name) {
+    auto tinfo = detail::get_type_info(typeid(T));
+    return tinfo ? get_type_overload(this_ptr, tinfo, name) : function();
+}
+
+#define PYBIND11_OVERLOAD_INT(ret_type, cname, name, ...) { \
+        pybind11::gil_scoped_acquire gil; \
+        pybind11::function overload = pybind11::get_overload(static_cast<const cname *>(this), name); \
+        if (overload) { \
+            auto o = overload(__VA_ARGS__); \
+            if (pybind11::detail::cast_is_temporary_value_reference<ret_type>::value) { \
+                static pybind11::detail::overload_caster_t<ret_type> caster; \
+                return pybind11::detail::cast_ref<ret_type>(std::move(o), caster); \
+            } \
+            else return pybind11::detail::cast_safe<ret_type>(std::move(o)); \
+        } \
+    }
+
+#define PYBIND11_OVERLOAD_NAME(ret_type, cname, name, fn, ...) \
+    PYBIND11_OVERLOAD_INT(ret_type, cname, name, __VA_ARGS__) \
+    return cname::fn(__VA_ARGS__)
+
+#define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...) \
+    PYBIND11_OVERLOAD_INT(ret_type, cname, name, __VA_ARGS__) \
+    pybind11::pybind11_fail("Tried to call pure virtual function \"" #cname "::" name "\"");
+
+#define PYBIND11_OVERLOAD(ret_type, cname, fn, ...) \
+    PYBIND11_OVERLOAD_NAME(ret_type, cname, #fn, fn, __VA_ARGS__)
+
+#define PYBIND11_OVERLOAD_PURE(ret_type, cname, fn, ...) \
+    PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, #fn, fn, __VA_ARGS__)
+
+NAMESPACE_END(PYBIND11_NAMESPACE)
+
+#if defined(_MSC_VER)
+#  pragma warning(pop)
+#elif defined(__INTEL_COMPILER)
+/* Leave ignored warnings on */
+#elif defined(__GNUG__) && !defined(__clang__)
+#  pragma GCC diagnostic pop
+#endif
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/pybind11/__init__.py b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/pybind11/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..5782ffea22ec8200cb3da8fc6d2761a7deecfc2f
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/pybind11/__init__.py
@@ -0,0 +1,28 @@
+from ._version import version_info, __version__  # noqa: F401 imported but unused
+
+
+def get_include(user=False):
+    from distutils.dist import Distribution
+    import os
+    import sys
+
+    # Are we running in a virtual environment?
+    virtualenv = hasattr(sys, 'real_prefix') or \
+        sys.prefix != getattr(sys, "base_prefix", sys.prefix)
+
+    if virtualenv:
+        return os.path.join(sys.prefix, 'include', 'site',
+                            'python' + sys.version[:3])
+    else:
+        dist = Distribution({'name': 'pybind11'})
+        dist.parse_config_files()
+
+        dist_cobj = dist.get_command_obj('install', create=True)
+
+        # Search for packages in user's home directory?
+        if user:
+            dist_cobj.user = user
+            dist_cobj.prefix = ""
+        dist_cobj.finalize_options()
+
+        return os.path.dirname(dist_cobj.install_headers)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/pybind11/__main__.py b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/pybind11/__main__.py
new file mode 100644
index 0000000000000000000000000000000000000000..9ef8378029b435d7660a793a73f7ff53754d9f7a
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/pybind11/__main__.py
@@ -0,0 +1,37 @@
+from __future__ import print_function
+
+import argparse
+import sys
+import sysconfig
+
+from . import get_include
+
+
+def print_includes():
+    dirs = [sysconfig.get_path('include'),
+            sysconfig.get_path('platinclude'),
+            get_include(),
+            get_include(True)]
+
+    # Make unique but preserve order
+    unique_dirs = []
+    for d in dirs:
+        if d not in unique_dirs:
+            unique_dirs.append(d)
+
+    print(' '.join('-I' + d for d in unique_dirs))
+
+
+def main():
+    parser = argparse.ArgumentParser(prog='python -m pybind11')
+    parser.add_argument('--includes', action='store_true',
+                        help='Include flags for both pybind11 and Python headers.')
+    args = parser.parse_args()
+    if not sys.argv[1:]:
+        parser.print_help()
+    if args.includes:
+        print_includes()
+
+
+if __name__ == '__main__':
+    main()
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/pybind11/_version.py b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/pybind11/_version.py
new file mode 100644
index 0000000000000000000000000000000000000000..54ebfb13bc579eb6114b5f573fe1b7352d42f351
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/pybind11/_version.py
@@ -0,0 +1,2 @@
+version_info = (2, 2, 4)
+__version__ = '.'.join(map(str, version_info))
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/pytypes.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/pytypes.h
new file mode 100644
index 0000000000000000000000000000000000000000..d7fa17775c3bb9ab48b861f21555f5128ea3465b
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/pytypes.h
@@ -0,0 +1,1332 @@
+/*
+    pybind11/pytypes.h: Convenience wrapper classes for basic Python types
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "detail/common.h"
+#include "buffer_info.h"
+#include <utility>
+#include <type_traits>
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+
+/* A few forward declarations */
+class handle; class object;
+class str; class iterator;
+struct arg; struct arg_v;
+
+NAMESPACE_BEGIN(detail)
+class args_proxy;
+inline bool isinstance_generic(handle obj, const std::type_info &tp);
+
+// Accessor forward declarations
+template <typename Policy> class accessor;
+namespace accessor_policies {
+    struct obj_attr;
+    struct str_attr;
+    struct generic_item;
+    struct sequence_item;
+    struct list_item;
+    struct tuple_item;
+}
+using obj_attr_accessor = accessor<accessor_policies::obj_attr>;
+using str_attr_accessor = accessor<accessor_policies::str_attr>;
+using item_accessor = accessor<accessor_policies::generic_item>;
+using sequence_accessor = accessor<accessor_policies::sequence_item>;
+using list_accessor = accessor<accessor_policies::list_item>;
+using tuple_accessor = accessor<accessor_policies::tuple_item>;
+
+/// Tag and check to identify a class which implements the Python object API
+class pyobject_tag { };
+template <typename T> using is_pyobject = std::is_base_of<pyobject_tag, remove_reference_t<T>>;
+
+/** \rst
+    A mixin class which adds common functions to `handle`, `object` and various accessors.
+    The only requirement for `Derived` is to implement ``PyObject *Derived::ptr() const``.
+\endrst */
+template <typename Derived>
+class object_api : public pyobject_tag {
+    const Derived &derived() const { return static_cast<const Derived &>(*this); }
+
+public:
+    /** \rst
+        Return an iterator equivalent to calling ``iter()`` in Python. The object
+        must be a collection which supports the iteration protocol.
+    \endrst */
+    iterator begin() const;
+    /// Return a sentinel which ends iteration.
+    iterator end() const;
+
+    /** \rst
+        Return an internal functor to invoke the object's sequence protocol. Casting
+        the returned ``detail::item_accessor`` instance to a `handle` or `object`
+        subclass causes a corresponding call to ``__getitem__``. Assigning a `handle`
+        or `object` subclass causes a call to ``__setitem__``.
+    \endrst */
+    item_accessor operator[](handle key) const;
+    /// See above (the only difference is that they key is provided as a string literal)
+    item_accessor operator[](const char *key) const;
+
+    /** \rst
+        Return an internal functor to access the object's attributes. Casting the
+        returned ``detail::obj_attr_accessor`` instance to a `handle` or `object`
+        subclass causes a corresponding call to ``getattr``. Assigning a `handle`
+        or `object` subclass causes a call to ``setattr``.
+    \endrst */
+    obj_attr_accessor attr(handle key) const;
+    /// See above (the only difference is that they key is provided as a string literal)
+    str_attr_accessor attr(const char *key) const;
+
+    /** \rst
+        Matches * unpacking in Python, e.g. to unpack arguments out of a ``tuple``
+        or ``list`` for a function call. Applying another * to the result yields
+        ** unpacking, e.g. to unpack a dict as function keyword arguments.
+        See :ref:`calling_python_functions`.
+    \endrst */
+    args_proxy operator*() const;
+
+    /// Check if the given item is contained within this object, i.e. ``item in obj``.
+    template <typename T> bool contains(T &&item) const;
+
+    /** \rst
+        Assuming the Python object is a function or implements the ``__call__``
+        protocol, ``operator()`` invokes the underlying function, passing an
+        arbitrary set of parameters. The result is returned as a `object` and
+        may need to be converted back into a Python object using `handle::cast()`.
+
+        When some of the arguments cannot be converted to Python objects, the
+        function will throw a `cast_error` exception. When the Python function
+        call fails, a `error_already_set` exception is thrown.
+    \endrst */
+    template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args>
+    object operator()(Args &&...args) const;
+    template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args>
+    PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)")
+        object call(Args&&... args) const;
+
+    /// Equivalent to ``obj is other`` in Python.
+    bool is(object_api const& other) const { return derived().ptr() == other.derived().ptr(); }
+    /// Equivalent to ``obj is None`` in Python.
+    bool is_none() const { return derived().ptr() == Py_None; }
+    PYBIND11_DEPRECATED("Use py::str(obj) instead")
+    pybind11::str str() const;
+
+    /// Get or set the object's docstring, i.e. ``obj.__doc__``.
+    str_attr_accessor doc() const;
+
+    /// Return the object's current reference count
+    int ref_count() const { return static_cast<int>(Py_REFCNT(derived().ptr())); }
+    /// Return a handle to the Python type object underlying the instance
+    handle get_type() const;
+};
+
+NAMESPACE_END(detail)
+
+/** \rst
+    Holds a reference to a Python object (no reference counting)
+
+    The `handle` class is a thin wrapper around an arbitrary Python object (i.e. a
+    ``PyObject *`` in Python's C API). It does not perform any automatic reference
+    counting and merely provides a basic C++ interface to various Python API functions.
+
+    .. seealso::
+        The `object` class inherits from `handle` and adds automatic reference
+        counting features.
+\endrst */
+class handle : public detail::object_api<handle> {
+public:
+    /// The default constructor creates a handle with a ``nullptr``-valued pointer
+    handle() = default;
+    /// Creates a ``handle`` from the given raw Python object pointer
+    handle(PyObject *ptr) : m_ptr(ptr) { } // Allow implicit conversion from PyObject*
+
+    /// Return the underlying ``PyObject *`` pointer
+    PyObject *ptr() const { return m_ptr; }
+    PyObject *&ptr() { return m_ptr; }
+
+    /** \rst
+        Manually increase the reference count of the Python object. Usually, it is
+        preferable to use the `object` class which derives from `handle` and calls
+        this function automatically. Returns a reference to itself.
+    \endrst */
+    const handle& inc_ref() const & { Py_XINCREF(m_ptr); return *this; }
+
+    /** \rst
+        Manually decrease the reference count of the Python object. Usually, it is
+        preferable to use the `object` class which derives from `handle` and calls
+        this function automatically. Returns a reference to itself.
+    \endrst */
+    const handle& dec_ref() const & { Py_XDECREF(m_ptr); return *this; }
+
+    /** \rst
+        Attempt to cast the Python object into the given C++ type. A `cast_error`
+        will be throw upon failure.
+    \endrst */
+    template <typename T> T cast() const;
+    /// Return ``true`` when the `handle` wraps a valid Python object
+    explicit operator bool() const { return m_ptr != nullptr; }
+    /** \rst
+        Deprecated: Check that the underlying pointers are the same.
+        Equivalent to ``obj1 is obj2`` in Python.
+    \endrst */
+    PYBIND11_DEPRECATED("Use obj1.is(obj2) instead")
+    bool operator==(const handle &h) const { return m_ptr == h.m_ptr; }
+    PYBIND11_DEPRECATED("Use !obj1.is(obj2) instead")
+    bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; }
+    PYBIND11_DEPRECATED("Use handle::operator bool() instead")
+    bool check() const { return m_ptr != nullptr; }
+protected:
+    PyObject *m_ptr = nullptr;
+};
+
+/** \rst
+    Holds a reference to a Python object (with reference counting)
+
+    Like `handle`, the `object` class is a thin wrapper around an arbitrary Python
+    object (i.e. a ``PyObject *`` in Python's C API). In contrast to `handle`, it
+    optionally increases the object's reference count upon construction, and it
+    *always* decreases the reference count when the `object` instance goes out of
+    scope and is destructed. When using `object` instances consistently, it is much
+    easier to get reference counting right at the first attempt.
+\endrst */
+class object : public handle {
+public:
+    object() = default;
+    PYBIND11_DEPRECATED("Use reinterpret_borrow<object>() or reinterpret_steal<object>()")
+    object(handle h, bool is_borrowed) : handle(h) { if (is_borrowed) inc_ref(); }
+    /// Copy constructor; always increases the reference count
+    object(const object &o) : handle(o) { inc_ref(); }
+    /// Move constructor; steals the object from ``other`` and preserves its reference count
+    object(object &&other) noexcept { m_ptr = other.m_ptr; other.m_ptr = nullptr; }
+    /// Destructor; automatically calls `handle::dec_ref()`
+    ~object() { dec_ref(); }
+
+    /** \rst
+        Resets the internal pointer to ``nullptr`` without without decreasing the
+        object's reference count. The function returns a raw handle to the original
+        Python object.
+    \endrst */
+    handle release() {
+      PyObject *tmp = m_ptr;
+      m_ptr = nullptr;
+      return handle(tmp);
+    }
+
+    object& operator=(const object &other) {
+        other.inc_ref();
+        dec_ref();
+        m_ptr = other.m_ptr;
+        return *this;
+    }
+
+    object& operator=(object &&other) noexcept {
+        if (this != &other) {
+            handle temp(m_ptr);
+            m_ptr = other.m_ptr;
+            other.m_ptr = nullptr;
+            temp.dec_ref();
+        }
+        return *this;
+    }
+
+    // Calling cast() on an object lvalue just copies (via handle::cast)
+    template <typename T> T cast() const &;
+    // Calling on an object rvalue does a move, if needed and/or possible
+    template <typename T> T cast() &&;
+
+protected:
+    // Tags for choosing constructors from raw PyObject *
+    struct borrowed_t { };
+    struct stolen_t { };
+
+    template <typename T> friend T reinterpret_borrow(handle);
+    template <typename T> friend T reinterpret_steal(handle);
+
+public:
+    // Only accessible from derived classes and the reinterpret_* functions
+    object(handle h, borrowed_t) : handle(h) { inc_ref(); }
+    object(handle h, stolen_t) : handle(h) { }
+};
+
+/** \rst
+    Declare that a `handle` or ``PyObject *`` is a certain type and borrow the reference.
+    The target type ``T`` must be `object` or one of its derived classes. The function
+    doesn't do any conversions or checks. It's up to the user to make sure that the
+    target type is correct.
+
+    .. code-block:: cpp
+
+        PyObject *p = PyList_GetItem(obj, index);
+        py::object o = reinterpret_borrow<py::object>(p);
+        // or
+        py::tuple t = reinterpret_borrow<py::tuple>(p); // <-- `p` must be already be a `tuple`
+\endrst */
+template <typename T> T reinterpret_borrow(handle h) { return {h, object::borrowed_t{}}; }
+
+/** \rst
+    Like `reinterpret_borrow`, but steals the reference.
+
+     .. code-block:: cpp
+
+        PyObject *p = PyObject_Str(obj);
+        py::str s = reinterpret_steal<py::str>(p); // <-- `p` must be already be a `str`
+\endrst */
+template <typename T> T reinterpret_steal(handle h) { return {h, object::stolen_t{}}; }
+
+NAMESPACE_BEGIN(detail)
+inline std::string error_string();
+NAMESPACE_END(detail)
+
+/// Fetch and hold an error which was already set in Python.  An instance of this is typically
+/// thrown to propagate python-side errors back through C++ which can either be caught manually or
+/// else falls back to the function dispatcher (which then raises the captured error back to
+/// python).
+class error_already_set : public std::runtime_error {
+public:
+    /// Constructs a new exception from the current Python error indicator, if any.  The current
+    /// Python error indicator will be cleared.
+    error_already_set() : std::runtime_error(detail::error_string()) {
+        PyErr_Fetch(&type.ptr(), &value.ptr(), &trace.ptr());
+    }
+
+    inline ~error_already_set();
+
+    /// Give the currently-held error back to Python, if any.  If there is currently a Python error
+    /// already set it is cleared first.  After this call, the current object no longer stores the
+    /// error variables (but the `.what()` string is still available).
+    void restore() { PyErr_Restore(type.release().ptr(), value.release().ptr(), trace.release().ptr()); }
+
+    // Does nothing; provided for backwards compatibility.
+    PYBIND11_DEPRECATED("Use of error_already_set.clear() is deprecated")
+    void clear() {}
+
+    /// Check if the currently trapped error type matches the given Python exception class (or a
+    /// subclass thereof).  May also be passed a tuple to search for any exception class matches in
+    /// the given tuple.
+    bool matches(handle ex) const { return PyErr_GivenExceptionMatches(ex.ptr(), type.ptr()); }
+
+private:
+    object type, value, trace;
+};
+
+/** \defgroup python_builtins _
+    Unless stated otherwise, the following C++ functions behave the same
+    as their Python counterparts.
+ */
+
+/** \ingroup python_builtins
+    \rst
+    Return true if ``obj`` is an instance of ``T``. Type ``T`` must be a subclass of
+    `object` or a class which was exposed to Python as ``py::class_<T>``.
+\endrst */
+template <typename T, detail::enable_if_t<std::is_base_of<object, T>::value, int> = 0>
+bool isinstance(handle obj) { return T::check_(obj); }
+
+template <typename T, detail::enable_if_t<!std::is_base_of<object, T>::value, int> = 0>
+bool isinstance(handle obj) { return detail::isinstance_generic(obj, typeid(T)); }
+
+template <> inline bool isinstance<handle>(handle obj) = delete;
+template <> inline bool isinstance<object>(handle obj) { return obj.ptr() != nullptr; }
+
+/// \ingroup python_builtins
+/// Return true if ``obj`` is an instance of the ``type``.
+inline bool isinstance(handle obj, handle type) {
+    const auto result = PyObject_IsInstance(obj.ptr(), type.ptr());
+    if (result == -1)
+        throw error_already_set();
+    return result != 0;
+}
+
+/// \addtogroup python_builtins
+/// @{
+inline bool hasattr(handle obj, handle name) {
+    return PyObject_HasAttr(obj.ptr(), name.ptr()) == 1;
+}
+
+inline bool hasattr(handle obj, const char *name) {
+    return PyObject_HasAttrString(obj.ptr(), name) == 1;
+}
+
+inline object getattr(handle obj, handle name) {
+    PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr());
+    if (!result) { throw error_already_set(); }
+    return reinterpret_steal<object>(result);
+}
+
+inline object getattr(handle obj, const char *name) {
+    PyObject *result = PyObject_GetAttrString(obj.ptr(), name);
+    if (!result) { throw error_already_set(); }
+    return reinterpret_steal<object>(result);
+}
+
+inline object getattr(handle obj, handle name, handle default_) {
+    if (PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr())) {
+        return reinterpret_steal<object>(result);
+    } else {
+        PyErr_Clear();
+        return reinterpret_borrow<object>(default_);
+    }
+}
+
+inline object getattr(handle obj, const char *name, handle default_) {
+    if (PyObject *result = PyObject_GetAttrString(obj.ptr(), name)) {
+        return reinterpret_steal<object>(result);
+    } else {
+        PyErr_Clear();
+        return reinterpret_borrow<object>(default_);
+    }
+}
+
+inline void setattr(handle obj, handle name, handle value) {
+    if (PyObject_SetAttr(obj.ptr(), name.ptr(), value.ptr()) != 0) { throw error_already_set(); }
+}
+
+inline void setattr(handle obj, const char *name, handle value) {
+    if (PyObject_SetAttrString(obj.ptr(), name, value.ptr()) != 0) { throw error_already_set(); }
+}
+
+inline ssize_t hash(handle obj) {
+    auto h = PyObject_Hash(obj.ptr());
+    if (h == -1) { throw error_already_set(); }
+    return h;
+}
+
+/// @} python_builtins
+
+NAMESPACE_BEGIN(detail)
+inline handle get_function(handle value) {
+    if (value) {
+#if PY_MAJOR_VERSION >= 3
+        if (PyInstanceMethod_Check(value.ptr()))
+            value = PyInstanceMethod_GET_FUNCTION(value.ptr());
+        else
+#endif
+        if (PyMethod_Check(value.ptr()))
+            value = PyMethod_GET_FUNCTION(value.ptr());
+    }
+    return value;
+}
+
+// Helper aliases/functions to support implicit casting of values given to python accessors/methods.
+// When given a pyobject, this simply returns the pyobject as-is; for other C++ type, the value goes
+// through pybind11::cast(obj) to convert it to an `object`.
+template <typename T, enable_if_t<is_pyobject<T>::value, int> = 0>
+auto object_or_cast(T &&o) -> decltype(std::forward<T>(o)) { return std::forward<T>(o); }
+// The following casting version is implemented in cast.h:
+template <typename T, enable_if_t<!is_pyobject<T>::value, int> = 0>
+object object_or_cast(T &&o);
+// Match a PyObject*, which we want to convert directly to handle via its converting constructor
+inline handle object_or_cast(PyObject *ptr) { return ptr; }
+
+
+template <typename Policy>
+class accessor : public object_api<accessor<Policy>> {
+    using key_type = typename Policy::key_type;
+
+public:
+    accessor(handle obj, key_type key) : obj(obj), key(std::move(key)) { }
+    accessor(const accessor &) = default;
+    accessor(accessor &&) = default;
+
+    // accessor overload required to override default assignment operator (templates are not allowed
+    // to replace default compiler-generated assignments).
+    void operator=(const accessor &a) && { std::move(*this).operator=(handle(a)); }
+    void operator=(const accessor &a) & { operator=(handle(a)); }
+
+    template <typename T> void operator=(T &&value) && {
+        Policy::set(obj, key, object_or_cast(std::forward<T>(value)));
+    }
+    template <typename T> void operator=(T &&value) & {
+        get_cache() = reinterpret_borrow<object>(object_or_cast(std::forward<T>(value)));
+    }
+
+    template <typename T = Policy>
+    PYBIND11_DEPRECATED("Use of obj.attr(...) as bool is deprecated in favor of pybind11::hasattr(obj, ...)")
+    explicit operator enable_if_t<std::is_same<T, accessor_policies::str_attr>::value ||
+            std::is_same<T, accessor_policies::obj_attr>::value, bool>() const {
+        return hasattr(obj, key);
+    }
+    template <typename T = Policy>
+    PYBIND11_DEPRECATED("Use of obj[key] as bool is deprecated in favor of obj.contains(key)")
+    explicit operator enable_if_t<std::is_same<T, accessor_policies::generic_item>::value, bool>() const {
+        return obj.contains(key);
+    }
+
+    operator object() const { return get_cache(); }
+    PyObject *ptr() const { return get_cache().ptr(); }
+    template <typename T> T cast() const { return get_cache().template cast<T>(); }
+
+private:
+    object &get_cache() const {
+        if (!cache) { cache = Policy::get(obj, key); }
+        return cache;
+    }
+
+private:
+    handle obj;
+    key_type key;
+    mutable object cache;
+};
+
+NAMESPACE_BEGIN(accessor_policies)
+struct obj_attr {
+    using key_type = object;
+    static object get(handle obj, handle key) { return getattr(obj, key); }
+    static void set(handle obj, handle key, handle val) { setattr(obj, key, val); }
+};
+
+struct str_attr {
+    using key_type = const char *;
+    static object get(handle obj, const char *key) { return getattr(obj, key); }
+    static void set(handle obj, const char *key, handle val) { setattr(obj, key, val); }
+};
+
+struct generic_item {
+    using key_type = object;
+
+    static object get(handle obj, handle key) {
+        PyObject *result = PyObject_GetItem(obj.ptr(), key.ptr());
+        if (!result) { throw error_already_set(); }
+        return reinterpret_steal<object>(result);
+    }
+
+    static void set(handle obj, handle key, handle val) {
+        if (PyObject_SetItem(obj.ptr(), key.ptr(), val.ptr()) != 0) { throw error_already_set(); }
+    }
+};
+
+struct sequence_item {
+    using key_type = size_t;
+
+    static object get(handle obj, size_t index) {
+        PyObject *result = PySequence_GetItem(obj.ptr(), static_cast<ssize_t>(index));
+        if (!result) { throw error_already_set(); }
+        return reinterpret_steal<object>(result);
+    }
+
+    static void set(handle obj, size_t index, handle val) {
+        // PySequence_SetItem does not steal a reference to 'val'
+        if (PySequence_SetItem(obj.ptr(), static_cast<ssize_t>(index), val.ptr()) != 0) {
+            throw error_already_set();
+        }
+    }
+};
+
+struct list_item {
+    using key_type = size_t;
+
+    static object get(handle obj, size_t index) {
+        PyObject *result = PyList_GetItem(obj.ptr(), static_cast<ssize_t>(index));
+        if (!result) { throw error_already_set(); }
+        return reinterpret_borrow<object>(result);
+    }
+
+    static void set(handle obj, size_t index, handle val) {
+        // PyList_SetItem steals a reference to 'val'
+        if (PyList_SetItem(obj.ptr(), static_cast<ssize_t>(index), val.inc_ref().ptr()) != 0) {
+            throw error_already_set();
+        }
+    }
+};
+
+struct tuple_item {
+    using key_type = size_t;
+
+    static object get(handle obj, size_t index) {
+        PyObject *result = PyTuple_GetItem(obj.ptr(), static_cast<ssize_t>(index));
+        if (!result) { throw error_already_set(); }
+        return reinterpret_borrow<object>(result);
+    }
+
+    static void set(handle obj, size_t index, handle val) {
+        // PyTuple_SetItem steals a reference to 'val'
+        if (PyTuple_SetItem(obj.ptr(), static_cast<ssize_t>(index), val.inc_ref().ptr()) != 0) {
+            throw error_already_set();
+        }
+    }
+};
+NAMESPACE_END(accessor_policies)
+
+/// STL iterator template used for tuple, list, sequence and dict
+template <typename Policy>
+class generic_iterator : public Policy {
+    using It = generic_iterator;
+
+public:
+    using difference_type = ssize_t;
+    using iterator_category = typename Policy::iterator_category;
+    using value_type = typename Policy::value_type;
+    using reference = typename Policy::reference;
+    using pointer = typename Policy::pointer;
+
+    generic_iterator() = default;
+    generic_iterator(handle seq, ssize_t index) : Policy(seq, index) { }
+
+    reference operator*() const { return Policy::dereference(); }
+    reference operator[](difference_type n) const { return *(*this + n); }
+    pointer operator->() const { return **this; }
+
+    It &operator++() { Policy::increment(); return *this; }
+    It operator++(int) { auto copy = *this; Policy::increment(); return copy; }
+    It &operator--() { Policy::decrement(); return *this; }
+    It operator--(int) { auto copy = *this; Policy::decrement(); return copy; }
+    It &operator+=(difference_type n) { Policy::advance(n); return *this; }
+    It &operator-=(difference_type n) { Policy::advance(-n); return *this; }
+
+    friend It operator+(const It &a, difference_type n) { auto copy = a; return copy += n; }
+    friend It operator+(difference_type n, const It &b) { return b + n; }
+    friend It operator-(const It &a, difference_type n) { auto copy = a; return copy -= n; }
+    friend difference_type operator-(const It &a, const It &b) { return a.distance_to(b); }
+
+    friend bool operator==(const It &a, const It &b) { return a.equal(b); }
+    friend bool operator!=(const It &a, const It &b) { return !(a == b); }
+    friend bool operator< (const It &a, const It &b) { return b - a > 0; }
+    friend bool operator> (const It &a, const It &b) { return b < a; }
+    friend bool operator>=(const It &a, const It &b) { return !(a < b); }
+    friend bool operator<=(const It &a, const It &b) { return !(a > b); }
+};
+
+NAMESPACE_BEGIN(iterator_policies)
+/// Quick proxy class needed to implement ``operator->`` for iterators which can't return pointers
+template <typename T>
+struct arrow_proxy {
+    T value;
+
+    arrow_proxy(T &&value) : value(std::move(value)) { }
+    T *operator->() const { return &value; }
+};
+
+/// Lightweight iterator policy using just a simple pointer: see ``PySequence_Fast_ITEMS``
+class sequence_fast_readonly {
+protected:
+    using iterator_category = std::random_access_iterator_tag;
+    using value_type = handle;
+    using reference = const handle;
+    using pointer = arrow_proxy<const handle>;
+
+    sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) { }
+
+    reference dereference() const { return *ptr; }
+    void increment() { ++ptr; }
+    void decrement() { --ptr; }
+    void advance(ssize_t n) { ptr += n; }
+    bool equal(const sequence_fast_readonly &b) const { return ptr == b.ptr; }
+    ssize_t distance_to(const sequence_fast_readonly &b) const { return ptr - b.ptr; }
+
+private:
+    PyObject **ptr;
+};
+
+/// Full read and write access using the sequence protocol: see ``detail::sequence_accessor``
+class sequence_slow_readwrite {
+protected:
+    using iterator_category = std::random_access_iterator_tag;
+    using value_type = object;
+    using reference = sequence_accessor;
+    using pointer = arrow_proxy<const sequence_accessor>;
+
+    sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) { }
+
+    reference dereference() const { return {obj, static_cast<size_t>(index)}; }
+    void increment() { ++index; }
+    void decrement() { --index; }
+    void advance(ssize_t n) { index += n; }
+    bool equal(const sequence_slow_readwrite &b) const { return index == b.index; }
+    ssize_t distance_to(const sequence_slow_readwrite &b) const { return index - b.index; }
+
+private:
+    handle obj;
+    ssize_t index;
+};
+
+/// Python's dictionary protocol permits this to be a forward iterator
+class dict_readonly {
+protected:
+    using iterator_category = std::forward_iterator_tag;
+    using value_type = std::pair<handle, handle>;
+    using reference = const value_type;
+    using pointer = arrow_proxy<const value_type>;
+
+    dict_readonly() = default;
+    dict_readonly(handle obj, ssize_t pos) : obj(obj), pos(pos) { increment(); }
+
+    reference dereference() const { return {key, value}; }
+    void increment() { if (!PyDict_Next(obj.ptr(), &pos, &key, &value)) { pos = -1; } }
+    bool equal(const dict_readonly &b) const { return pos == b.pos; }
+
+private:
+    handle obj;
+    PyObject *key, *value;
+    ssize_t pos = -1;
+};
+NAMESPACE_END(iterator_policies)
+
+#if !defined(PYPY_VERSION)
+using tuple_iterator = generic_iterator<iterator_policies::sequence_fast_readonly>;
+using list_iterator = generic_iterator<iterator_policies::sequence_fast_readonly>;
+#else
+using tuple_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>;
+using list_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>;
+#endif
+
+using sequence_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>;
+using dict_iterator = generic_iterator<iterator_policies::dict_readonly>;
+
+inline bool PyIterable_Check(PyObject *obj) {
+    PyObject *iter = PyObject_GetIter(obj);
+    if (iter) {
+        Py_DECREF(iter);
+        return true;
+    } else {
+        PyErr_Clear();
+        return false;
+    }
+}
+
+inline bool PyNone_Check(PyObject *o) { return o == Py_None; }
+
+inline bool PyUnicode_Check_Permissive(PyObject *o) { return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o); }
+
+class kwargs_proxy : public handle {
+public:
+    explicit kwargs_proxy(handle h) : handle(h) { }
+};
+
+class args_proxy : public handle {
+public:
+    explicit args_proxy(handle h) : handle(h) { }
+    kwargs_proxy operator*() const { return kwargs_proxy(*this); }
+};
+
+/// Python argument categories (using PEP 448 terms)
+template <typename T> using is_keyword = std::is_base_of<arg, T>;
+template <typename T> using is_s_unpacking = std::is_same<args_proxy, T>; // * unpacking
+template <typename T> using is_ds_unpacking = std::is_same<kwargs_proxy, T>; // ** unpacking
+template <typename T> using is_positional = satisfies_none_of<T,
+    is_keyword, is_s_unpacking, is_ds_unpacking
+>;
+template <typename T> using is_keyword_or_ds = satisfies_any_of<T, is_keyword, is_ds_unpacking>;
+
+// Call argument collector forward declarations
+template <return_value_policy policy = return_value_policy::automatic_reference>
+class simple_collector;
+template <return_value_policy policy = return_value_policy::automatic_reference>
+class unpacking_collector;
+
+NAMESPACE_END(detail)
+
+// TODO: After the deprecated constructors are removed, this macro can be simplified by
+//       inheriting ctors: `using Parent::Parent`. It's not an option right now because
+//       the `using` statement triggers the parent deprecation warning even if the ctor
+//       isn't even used.
+#define PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
+    public: \
+        PYBIND11_DEPRECATED("Use reinterpret_borrow<"#Name">() or reinterpret_steal<"#Name">()") \
+        Name(handle h, bool is_borrowed) : Parent(is_borrowed ? Parent(h, borrowed_t{}) : Parent(h, stolen_t{})) { } \
+        Name(handle h, borrowed_t) : Parent(h, borrowed_t{}) { } \
+        Name(handle h, stolen_t) : Parent(h, stolen_t{}) { } \
+        PYBIND11_DEPRECATED("Use py::isinstance<py::python_type>(obj) instead") \
+        bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); } \
+        static bool check_(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); }
+
+#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \
+    PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
+    /* This is deliberately not 'explicit' to allow implicit conversion from object: */ \
+    Name(const object &o) \
+    : Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) \
+    { if (!m_ptr) throw error_already_set(); } \
+    Name(object &&o) \
+    : Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) \
+    { if (!m_ptr) throw error_already_set(); } \
+    template <typename Policy_> \
+    Name(const ::pybind11::detail::accessor<Policy_> &a) : Name(object(a)) { }
+
+#define PYBIND11_OBJECT(Name, Parent, CheckFun) \
+    PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
+    /* This is deliberately not 'explicit' to allow implicit conversion from object: */ \
+    Name(const object &o) : Parent(o) { } \
+    Name(object &&o) : Parent(std::move(o)) { }
+
+#define PYBIND11_OBJECT_DEFAULT(Name, Parent, CheckFun) \
+    PYBIND11_OBJECT(Name, Parent, CheckFun) \
+    Name() : Parent() { }
+
+/// \addtogroup pytypes
+/// @{
+
+/** \rst
+    Wraps a Python iterator so that it can also be used as a C++ input iterator
+
+    Caveat: copying an iterator does not (and cannot) clone the internal
+    state of the Python iterable. This also applies to the post-increment
+    operator. This iterator should only be used to retrieve the current
+    value using ``operator*()``.
+\endrst */
+class iterator : public object {
+public:
+    using iterator_category = std::input_iterator_tag;
+    using difference_type = ssize_t;
+    using value_type = handle;
+    using reference = const handle;
+    using pointer = const handle *;
+
+    PYBIND11_OBJECT_DEFAULT(iterator, object, PyIter_Check)
+
+    iterator& operator++() {
+        advance();
+        return *this;
+    }
+
+    iterator operator++(int) {
+        auto rv = *this;
+        advance();
+        return rv;
+    }
+
+    reference operator*() const {
+        if (m_ptr && !value.ptr()) {
+            auto& self = const_cast<iterator &>(*this);
+            self.advance();
+        }
+        return value;
+    }
+
+    pointer operator->() const { operator*(); return &value; }
+
+    /** \rst
+         The value which marks the end of the iteration. ``it == iterator::sentinel()``
+         is equivalent to catching ``StopIteration`` in Python.
+
+         .. code-block:: cpp
+
+             void foo(py::iterator it) {
+                 while (it != py::iterator::sentinel()) {
+                    // use `*it`
+                    ++it;
+                 }
+             }
+    \endrst */
+    static iterator sentinel() { return {}; }
+
+    friend bool operator==(const iterator &a, const iterator &b) { return a->ptr() == b->ptr(); }
+    friend bool operator!=(const iterator &a, const iterator &b) { return a->ptr() != b->ptr(); }
+
+private:
+    void advance() {
+        value = reinterpret_steal<object>(PyIter_Next(m_ptr));
+        if (PyErr_Occurred()) { throw error_already_set(); }
+    }
+
+private:
+    object value = {};
+};
+
+class iterable : public object {
+public:
+    PYBIND11_OBJECT_DEFAULT(iterable, object, detail::PyIterable_Check)
+};
+
+class bytes;
+
+class str : public object {
+public:
+    PYBIND11_OBJECT_CVT(str, object, detail::PyUnicode_Check_Permissive, raw_str)
+
+    str(const char *c, size_t n)
+        : object(PyUnicode_FromStringAndSize(c, (ssize_t) n), stolen_t{}) {
+        if (!m_ptr) pybind11_fail("Could not allocate string object!");
+    }
+
+    // 'explicit' is explicitly omitted from the following constructors to allow implicit conversion to py::str from C++ string-like objects
+    str(const char *c = "")
+        : object(PyUnicode_FromString(c), stolen_t{}) {
+        if (!m_ptr) pybind11_fail("Could not allocate string object!");
+    }
+
+    str(const std::string &s) : str(s.data(), s.size()) { }
+
+    explicit str(const bytes &b);
+
+    /** \rst
+        Return a string representation of the object. This is analogous to
+        the ``str()`` function in Python.
+    \endrst */
+    explicit str(handle h) : object(raw_str(h.ptr()), stolen_t{}) { }
+
+    operator std::string() const {
+        object temp = *this;
+        if (PyUnicode_Check(m_ptr)) {
+            temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(m_ptr));
+            if (!temp)
+                pybind11_fail("Unable to extract string contents! (encoding issue)");
+        }
+        char *buffer;
+        ssize_t length;
+        if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length))
+            pybind11_fail("Unable to extract string contents! (invalid type)");
+        return std::string(buffer, (size_t) length);
+    }
+
+    template <typename... Args>
+    str format(Args &&...args) const {
+        return attr("format")(std::forward<Args>(args)...);
+    }
+
+private:
+    /// Return string representation -- always returns a new reference, even if already a str
+    static PyObject *raw_str(PyObject *op) {
+        PyObject *str_value = PyObject_Str(op);
+#if PY_MAJOR_VERSION < 3
+        if (!str_value) throw error_already_set();
+        PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr);
+        Py_XDECREF(str_value); str_value = unicode;
+#endif
+        return str_value;
+    }
+};
+/// @} pytypes
+
+inline namespace literals {
+/** \rst
+    String literal version of `str`
+ \endrst */
+inline str operator"" _s(const char *s, size_t size) { return {s, size}; }
+}
+
+/// \addtogroup pytypes
+/// @{
+class bytes : public object {
+public:
+    PYBIND11_OBJECT(bytes, object, PYBIND11_BYTES_CHECK)
+
+    // Allow implicit conversion:
+    bytes(const char *c = "")
+        : object(PYBIND11_BYTES_FROM_STRING(c), stolen_t{}) {
+        if (!m_ptr) pybind11_fail("Could not allocate bytes object!");
+    }
+
+    bytes(const char *c, size_t n)
+        : object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(c, (ssize_t) n), stolen_t{}) {
+        if (!m_ptr) pybind11_fail("Could not allocate bytes object!");
+    }
+
+    // Allow implicit conversion:
+    bytes(const std::string &s) : bytes(s.data(), s.size()) { }
+
+    explicit bytes(const pybind11::str &s);
+
+    operator std::string() const {
+        char *buffer;
+        ssize_t length;
+        if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length))
+            pybind11_fail("Unable to extract bytes contents!");
+        return std::string(buffer, (size_t) length);
+    }
+};
+
+inline bytes::bytes(const pybind11::str &s) {
+    object temp = s;
+    if (PyUnicode_Check(s.ptr())) {
+        temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(s.ptr()));
+        if (!temp)
+            pybind11_fail("Unable to extract string contents! (encoding issue)");
+    }
+    char *buffer;
+    ssize_t length;
+    if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length))
+        pybind11_fail("Unable to extract string contents! (invalid type)");
+    auto obj = reinterpret_steal<object>(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length));
+    if (!obj)
+        pybind11_fail("Could not allocate bytes object!");
+    m_ptr = obj.release().ptr();
+}
+
+inline str::str(const bytes& b) {
+    char *buffer;
+    ssize_t length;
+    if (PYBIND11_BYTES_AS_STRING_AND_SIZE(b.ptr(), &buffer, &length))
+        pybind11_fail("Unable to extract bytes contents!");
+    auto obj = reinterpret_steal<object>(PyUnicode_FromStringAndSize(buffer, (ssize_t) length));
+    if (!obj)
+        pybind11_fail("Could not allocate string object!");
+    m_ptr = obj.release().ptr();
+}
+
+class none : public object {
+public:
+    PYBIND11_OBJECT(none, object, detail::PyNone_Check)
+    none() : object(Py_None, borrowed_t{}) { }
+};
+
+class bool_ : public object {
+public:
+    PYBIND11_OBJECT_CVT(bool_, object, PyBool_Check, raw_bool)
+    bool_() : object(Py_False, borrowed_t{}) { }
+    // Allow implicit conversion from and to `bool`:
+    bool_(bool value) : object(value ? Py_True : Py_False, borrowed_t{}) { }
+    operator bool() const { return m_ptr && PyLong_AsLong(m_ptr) != 0; }
+
+private:
+    /// Return the truth value of an object -- always returns a new reference
+    static PyObject *raw_bool(PyObject *op) {
+        const auto value = PyObject_IsTrue(op);
+        if (value == -1) return nullptr;
+        return handle(value ? Py_True : Py_False).inc_ref().ptr();
+    }
+};
+
+NAMESPACE_BEGIN(detail)
+// Converts a value to the given unsigned type.  If an error occurs, you get back (Unsigned) -1;
+// otherwise you get back the unsigned long or unsigned long long value cast to (Unsigned).
+// (The distinction is critically important when casting a returned -1 error value to some other
+// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes).
+template <typename Unsigned>
+Unsigned as_unsigned(PyObject *o) {
+    if (sizeof(Unsigned) <= sizeof(unsigned long)
+#if PY_VERSION_HEX < 0x03000000
+            || PyInt_Check(o)
+#endif
+    ) {
+        unsigned long v = PyLong_AsUnsignedLong(o);
+        return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
+    }
+    else {
+        unsigned long long v = PyLong_AsUnsignedLongLong(o);
+        return v == (unsigned long long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
+    }
+}
+NAMESPACE_END(detail)
+
+class int_ : public object {
+public:
+    PYBIND11_OBJECT_CVT(int_, object, PYBIND11_LONG_CHECK, PyNumber_Long)
+    int_() : object(PyLong_FromLong(0), stolen_t{}) { }
+    // Allow implicit conversion from C++ integral types:
+    template <typename T,
+              detail::enable_if_t<std::is_integral<T>::value, int> = 0>
+    int_(T value) {
+        if (sizeof(T) <= sizeof(long)) {
+            if (std::is_signed<T>::value)
+                m_ptr = PyLong_FromLong((long) value);
+            else
+                m_ptr = PyLong_FromUnsignedLong((unsigned long) value);
+        } else {
+            if (std::is_signed<T>::value)
+                m_ptr = PyLong_FromLongLong((long long) value);
+            else
+                m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value);
+        }
+        if (!m_ptr) pybind11_fail("Could not allocate int object!");
+    }
+
+    template <typename T,
+              detail::enable_if_t<std::is_integral<T>::value, int> = 0>
+    operator T() const {
+        return std::is_unsigned<T>::value
+            ? detail::as_unsigned<T>(m_ptr)
+            : sizeof(T) <= sizeof(long)
+              ? (T) PyLong_AsLong(m_ptr)
+              : (T) PYBIND11_LONG_AS_LONGLONG(m_ptr);
+    }
+};
+
+class float_ : public object {
+public:
+    PYBIND11_OBJECT_CVT(float_, object, PyFloat_Check, PyNumber_Float)
+    // Allow implicit conversion from float/double:
+    float_(float value) : object(PyFloat_FromDouble((double) value), stolen_t{}) {
+        if (!m_ptr) pybind11_fail("Could not allocate float object!");
+    }
+    float_(double value = .0) : object(PyFloat_FromDouble((double) value), stolen_t{}) {
+        if (!m_ptr) pybind11_fail("Could not allocate float object!");
+    }
+    operator float() const { return (float) PyFloat_AsDouble(m_ptr); }
+    operator double() const { return (double) PyFloat_AsDouble(m_ptr); }
+};
+
+class weakref : public object {
+public:
+    PYBIND11_OBJECT_DEFAULT(weakref, object, PyWeakref_Check)
+    explicit weakref(handle obj, handle callback = {})
+        : object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), stolen_t{}) {
+        if (!m_ptr) pybind11_fail("Could not allocate weak reference!");
+    }
+};
+
+class slice : public object {
+public:
+    PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check)
+    slice(ssize_t start_, ssize_t stop_, ssize_t step_) {
+        int_ start(start_), stop(stop_), step(step_);
+        m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr());
+        if (!m_ptr) pybind11_fail("Could not allocate slice object!");
+    }
+    bool compute(size_t length, size_t *start, size_t *stop, size_t *step,
+                 size_t *slicelength) const {
+        return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr,
+                                    (ssize_t) length, (ssize_t *) start,
+                                    (ssize_t *) stop, (ssize_t *) step,
+                                    (ssize_t *) slicelength) == 0;
+    }
+};
+
+class capsule : public object {
+public:
+    PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact)
+    PYBIND11_DEPRECATED("Use reinterpret_borrow<capsule>() or reinterpret_steal<capsule>()")
+    capsule(PyObject *ptr, bool is_borrowed) : object(is_borrowed ? object(ptr, borrowed_t{}) : object(ptr, stolen_t{})) { }
+
+    explicit capsule(const void *value, const char *name = nullptr, void (*destructor)(PyObject *) = nullptr)
+        : object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) {
+        if (!m_ptr)
+            pybind11_fail("Could not allocate capsule object!");
+    }
+
+    PYBIND11_DEPRECATED("Please pass a destructor that takes a void pointer as input")
+    capsule(const void *value, void (*destruct)(PyObject *))
+        : object(PyCapsule_New(const_cast<void*>(value), nullptr, destruct), stolen_t{}) {
+        if (!m_ptr)
+            pybind11_fail("Could not allocate capsule object!");
+    }
+
+    capsule(const void *value, void (*destructor)(void *)) {
+        m_ptr = PyCapsule_New(const_cast<void *>(value), nullptr, [](PyObject *o) {
+            auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o));
+            void *ptr = PyCapsule_GetPointer(o, nullptr);
+            destructor(ptr);
+        });
+
+        if (!m_ptr)
+            pybind11_fail("Could not allocate capsule object!");
+
+        if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0)
+            pybind11_fail("Could not set capsule context!");
+    }
+
+    capsule(void (*destructor)()) {
+        m_ptr = PyCapsule_New(reinterpret_cast<void *>(destructor), nullptr, [](PyObject *o) {
+            auto destructor = reinterpret_cast<void (*)()>(PyCapsule_GetPointer(o, nullptr));
+            destructor();
+        });
+
+        if (!m_ptr)
+            pybind11_fail("Could not allocate capsule object!");
+    }
+
+    template <typename T> operator T *() const {
+        auto name = this->name();
+        T * result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, name));
+        if (!result) pybind11_fail("Unable to extract capsule contents!");
+        return result;
+    }
+
+    const char *name() const { return PyCapsule_GetName(m_ptr); }
+};
+
+class tuple : public object {
+public:
+    PYBIND11_OBJECT_CVT(tuple, object, PyTuple_Check, PySequence_Tuple)
+    explicit tuple(size_t size = 0) : object(PyTuple_New((ssize_t) size), stolen_t{}) {
+        if (!m_ptr) pybind11_fail("Could not allocate tuple object!");
+    }
+    size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
+    detail::tuple_accessor operator[](size_t index) const { return {*this, index}; }
+    detail::tuple_iterator begin() const { return {*this, 0}; }
+    detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; }
+};
+
+class dict : public object {
+public:
+    PYBIND11_OBJECT_CVT(dict, object, PyDict_Check, raw_dict)
+    dict() : object(PyDict_New(), stolen_t{}) {
+        if (!m_ptr) pybind11_fail("Could not allocate dict object!");
+    }
+    template <typename... Args,
+              typename = detail::enable_if_t<detail::all_of<detail::is_keyword_or_ds<Args>...>::value>,
+              // MSVC workaround: it can't compile an out-of-line definition, so defer the collector
+              typename collector = detail::deferred_t<detail::unpacking_collector<>, Args...>>
+    explicit dict(Args &&...args) : dict(collector(std::forward<Args>(args)...).kwargs()) { }
+
+    size_t size() const { return (size_t) PyDict_Size(m_ptr); }
+    detail::dict_iterator begin() const { return {*this, 0}; }
+    detail::dict_iterator end() const { return {}; }
+    void clear() const { PyDict_Clear(ptr()); }
+    bool contains(handle key) const { return PyDict_Contains(ptr(), key.ptr()) == 1; }
+    bool contains(const char *key) const { return PyDict_Contains(ptr(), pybind11::str(key).ptr()) == 1; }
+
+private:
+    /// Call the `dict` Python type -- always returns a new reference
+    static PyObject *raw_dict(PyObject *op) {
+        if (PyDict_Check(op))
+            return handle(op).inc_ref().ptr();
+        return PyObject_CallFunctionObjArgs((PyObject *) &PyDict_Type, op, nullptr);
+    }
+};
+
+class sequence : public object {
+public:
+    PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check)
+    size_t size() const { return (size_t) PySequence_Size(m_ptr); }
+    detail::sequence_accessor operator[](size_t index) const { return {*this, index}; }
+    detail::sequence_iterator begin() const { return {*this, 0}; }
+    detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; }
+};
+
+class list : public object {
+public:
+    PYBIND11_OBJECT_CVT(list, object, PyList_Check, PySequence_List)
+    explicit list(size_t size = 0) : object(PyList_New((ssize_t) size), stolen_t{}) {
+        if (!m_ptr) pybind11_fail("Could not allocate list object!");
+    }
+    size_t size() const { return (size_t) PyList_Size(m_ptr); }
+    detail::list_accessor operator[](size_t index) const { return {*this, index}; }
+    detail::list_iterator begin() const { return {*this, 0}; }
+    detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; }
+    template <typename T> void append(T &&val) const {
+        PyList_Append(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr());
+    }
+};
+
+class args : public tuple { PYBIND11_OBJECT_DEFAULT(args, tuple, PyTuple_Check) };
+class kwargs : public dict { PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check)  };
+
+class set : public object {
+public:
+    PYBIND11_OBJECT_CVT(set, object, PySet_Check, PySet_New)
+    set() : object(PySet_New(nullptr), stolen_t{}) {
+        if (!m_ptr) pybind11_fail("Could not allocate set object!");
+    }
+    size_t size() const { return (size_t) PySet_Size(m_ptr); }
+    template <typename T> bool add(T &&val) const {
+        return PySet_Add(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 0;
+    }
+    void clear() const { PySet_Clear(m_ptr); }
+};
+
+class function : public object {
+public:
+    PYBIND11_OBJECT_DEFAULT(function, object, PyCallable_Check)
+    handle cpp_function() const {
+        handle fun = detail::get_function(m_ptr);
+        if (fun && PyCFunction_Check(fun.ptr()))
+            return fun;
+        return handle();
+    }
+    bool is_cpp_function() const { return (bool) cpp_function(); }
+};
+
+class buffer : public object {
+public:
+    PYBIND11_OBJECT_DEFAULT(buffer, object, PyObject_CheckBuffer)
+
+    buffer_info request(bool writable = false) {
+        int flags = PyBUF_STRIDES | PyBUF_FORMAT;
+        if (writable) flags |= PyBUF_WRITABLE;
+        Py_buffer *view = new Py_buffer();
+        if (PyObject_GetBuffer(m_ptr, view, flags) != 0) {
+            delete view;
+            throw error_already_set();
+        }
+        return buffer_info(view);
+    }
+};
+
+class memoryview : public object {
+public:
+    explicit memoryview(const buffer_info& info) {
+        static Py_buffer buf { };
+        // Py_buffer uses signed sizes, strides and shape!..
+        static std::vector<Py_ssize_t> py_strides { };
+        static std::vector<Py_ssize_t> py_shape { };
+        buf.buf = info.ptr;
+        buf.itemsize = info.itemsize;
+        buf.format = const_cast<char *>(info.format.c_str());
+        buf.ndim = (int) info.ndim;
+        buf.len = info.size;
+        py_strides.clear();
+        py_shape.clear();
+        for (size_t i = 0; i < (size_t) info.ndim; ++i) {
+            py_strides.push_back(info.strides[i]);
+            py_shape.push_back(info.shape[i]);
+        }
+        buf.strides = py_strides.data();
+        buf.shape = py_shape.data();
+        buf.suboffsets = nullptr;
+        buf.readonly = false;
+        buf.internal = nullptr;
+
+        m_ptr = PyMemoryView_FromBuffer(&buf);
+        if (!m_ptr)
+            pybind11_fail("Unable to create memoryview from buffer descriptor");
+    }
+
+    PYBIND11_OBJECT_CVT(memoryview, object, PyMemoryView_Check, PyMemoryView_FromObject)
+};
+/// @} pytypes
+
+/// \addtogroup python_builtins
+/// @{
+inline size_t len(handle h) {
+    ssize_t result = PyObject_Length(h.ptr());
+    if (result < 0)
+        pybind11_fail("Unable to compute length of object");
+    return (size_t) result;
+}
+
+inline str repr(handle h) {
+    PyObject *str_value = PyObject_Repr(h.ptr());
+    if (!str_value) throw error_already_set();
+#if PY_MAJOR_VERSION < 3
+    PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr);
+    Py_XDECREF(str_value); str_value = unicode;
+    if (!str_value) throw error_already_set();
+#endif
+    return reinterpret_steal<str>(str_value);
+}
+
+inline iterator iter(handle obj) {
+    PyObject *result = PyObject_GetIter(obj.ptr());
+    if (!result) { throw error_already_set(); }
+    return reinterpret_steal<iterator>(result);
+}
+/// @} python_builtins
+
+NAMESPACE_BEGIN(detail)
+template <typename D> iterator object_api<D>::begin() const { return iter(derived()); }
+template <typename D> iterator object_api<D>::end() const { return iterator::sentinel(); }
+template <typename D> item_accessor object_api<D>::operator[](handle key) const {
+    return {derived(), reinterpret_borrow<object>(key)};
+}
+template <typename D> item_accessor object_api<D>::operator[](const char *key) const {
+    return {derived(), pybind11::str(key)};
+}
+template <typename D> obj_attr_accessor object_api<D>::attr(handle key) const {
+    return {derived(), reinterpret_borrow<object>(key)};
+}
+template <typename D> str_attr_accessor object_api<D>::attr(const char *key) const {
+    return {derived(), key};
+}
+template <typename D> args_proxy object_api<D>::operator*() const {
+    return args_proxy(derived().ptr());
+}
+template <typename D> template <typename T> bool object_api<D>::contains(T &&item) const {
+    return attr("__contains__")(std::forward<T>(item)).template cast<bool>();
+}
+
+template <typename D>
+pybind11::str object_api<D>::str() const { return pybind11::str(derived()); }
+
+template <typename D>
+str_attr_accessor object_api<D>::doc() const { return attr("__doc__"); }
+
+template <typename D>
+handle object_api<D>::get_type() const { return (PyObject *) Py_TYPE(derived().ptr()); }
+
+NAMESPACE_END(detail)
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/stl.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/stl.h
new file mode 100644
index 0000000000000000000000000000000000000000..1a4bbf0db13249abfa8e9fd872b3b0d8d8476bdc
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/stl.h
@@ -0,0 +1,376 @@
+/*
+    pybind11/stl.h: Transparent conversion for STL data types
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "pybind11.h"
+#include <set>
+#include <unordered_set>
+#include <map>
+#include <unordered_map>
+#include <iostream>
+#include <list>
+#include <valarray>
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
+#endif
+
+#ifdef __has_include
+// std::optional (but including it in c++14 mode isn't allowed)
+#  if defined(PYBIND11_CPP17) && __has_include(<optional>)
+#    include <optional>
+#    define PYBIND11_HAS_OPTIONAL 1
+#  endif
+// std::experimental::optional (but not allowed in c++11 mode)
+#  if defined(PYBIND11_CPP14) && (__has_include(<experimental/optional>) && \
+                                 !__has_include(<optional>))
+#    include <experimental/optional>
+#    define PYBIND11_HAS_EXP_OPTIONAL 1
+#  endif
+// std::variant
+#  if defined(PYBIND11_CPP17) && __has_include(<variant>)
+#    include <variant>
+#    define PYBIND11_HAS_VARIANT 1
+#  endif
+#elif defined(_MSC_VER) && defined(PYBIND11_CPP17)
+#  include <optional>
+#  include <variant>
+#  define PYBIND11_HAS_OPTIONAL 1
+#  define PYBIND11_HAS_VARIANT 1
+#endif
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+NAMESPACE_BEGIN(detail)
+
+/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for
+/// forwarding a container element).  Typically used indirect via forwarded_type(), below.
+template <typename T, typename U>
+using forwarded_type = conditional_t<
+    std::is_lvalue_reference<T>::value, remove_reference_t<U> &, remove_reference_t<U> &&>;
+
+/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically
+/// used for forwarding a container's elements.
+template <typename T, typename U>
+forwarded_type<T, U> forward_like(U &&u) {
+    return std::forward<detail::forwarded_type<T, U>>(std::forward<U>(u));
+}
+
+template <typename Type, typename Key> struct set_caster {
+    using type = Type;
+    using key_conv = make_caster<Key>;
+
+    bool load(handle src, bool convert) {
+        if (!isinstance<pybind11::set>(src))
+            return false;
+        auto s = reinterpret_borrow<pybind11::set>(src);
+        value.clear();
+        for (auto entry : s) {
+            key_conv conv;
+            if (!conv.load(entry, convert))
+                return false;
+            value.insert(cast_op<Key &&>(std::move(conv)));
+        }
+        return true;
+    }
+
+    template <typename T>
+    static handle cast(T &&src, return_value_policy policy, handle parent) {
+        policy = return_value_policy_override<Key>::policy(policy);
+        pybind11::set s;
+        for (auto &&value : src) {
+            auto value_ = reinterpret_steal<object>(key_conv::cast(forward_like<T>(value), policy, parent));
+            if (!value_ || !s.add(value_))
+                return handle();
+        }
+        return s.release();
+    }
+
+    PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name() + _("]"));
+};
+
+template <typename Type, typename Key, typename Value> struct map_caster {
+    using key_conv   = make_caster<Key>;
+    using value_conv = make_caster<Value>;
+
+    bool load(handle src, bool convert) {
+        if (!isinstance<dict>(src))
+            return false;
+        auto d = reinterpret_borrow<dict>(src);
+        value.clear();
+        for (auto it : d) {
+            key_conv kconv;
+            value_conv vconv;
+            if (!kconv.load(it.first.ptr(), convert) ||
+                !vconv.load(it.second.ptr(), convert))
+                return false;
+            value.emplace(cast_op<Key &&>(std::move(kconv)), cast_op<Value &&>(std::move(vconv)));
+        }
+        return true;
+    }
+
+    template <typename T>
+    static handle cast(T &&src, return_value_policy policy, handle parent) {
+        dict d;
+        return_value_policy policy_key = return_value_policy_override<Key>::policy(policy);
+        return_value_policy policy_value = return_value_policy_override<Value>::policy(policy);
+        for (auto &&kv : src) {
+            auto key = reinterpret_steal<object>(key_conv::cast(forward_like<T>(kv.first), policy_key, parent));
+            auto value = reinterpret_steal<object>(value_conv::cast(forward_like<T>(kv.second), policy_value, parent));
+            if (!key || !value)
+                return handle();
+            d[key] = value;
+        }
+        return d.release();
+    }
+
+    PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name() + _(", ") + value_conv::name() + _("]"));
+};
+
+template <typename Type, typename Value> struct list_caster {
+    using value_conv = make_caster<Value>;
+
+    bool load(handle src, bool convert) {
+        if (!isinstance<sequence>(src))
+            return false;
+        auto s = reinterpret_borrow<sequence>(src);
+        value.clear();
+        reserve_maybe(s, &value);
+        for (auto it : s) {
+            value_conv conv;
+            if (!conv.load(it, convert))
+                return false;
+            value.push_back(cast_op<Value &&>(std::move(conv)));
+        }
+        return true;
+    }
+
+private:
+    template <typename T = Type,
+              enable_if_t<std::is_same<decltype(std::declval<T>().reserve(0)), void>::value, int> = 0>
+    void reserve_maybe(sequence s, Type *) { value.reserve(s.size()); }
+    void reserve_maybe(sequence, void *) { }
+
+public:
+    template <typename T>
+    static handle cast(T &&src, return_value_policy policy, handle parent) {
+        policy = return_value_policy_override<Value>::policy(policy);
+        list l(src.size());
+        size_t index = 0;
+        for (auto &&value : src) {
+            auto value_ = reinterpret_steal<object>(value_conv::cast(forward_like<T>(value), policy, parent));
+            if (!value_)
+                return handle();
+            PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference
+        }
+        return l.release();
+    }
+
+    PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name() + _("]"));
+};
+
+template <typename Type, typename Alloc> struct type_caster<std::vector<Type, Alloc>>
+ : list_caster<std::vector<Type, Alloc>, Type> { };
+
+template <typename Type, typename Alloc> struct type_caster<std::list<Type, Alloc>>
+ : list_caster<std::list<Type, Alloc>, Type> { };
+
+template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0> struct array_caster {
+    using value_conv = make_caster<Value>;
+
+private:
+    template <bool R = Resizable>
+    bool require_size(enable_if_t<R, size_t> size) {
+        if (value.size() != size)
+            value.resize(size);
+        return true;
+    }
+    template <bool R = Resizable>
+    bool require_size(enable_if_t<!R, size_t> size) {
+        return size == Size;
+    }
+
+public:
+    bool load(handle src, bool convert) {
+        if (!isinstance<list>(src))
+            return false;
+        auto l = reinterpret_borrow<list>(src);
+        if (!require_size(l.size()))
+            return false;
+        size_t ctr = 0;
+        for (auto it : l) {
+            value_conv conv;
+            if (!conv.load(it, convert))
+                return false;
+            value[ctr++] = cast_op<Value &&>(std::move(conv));
+        }
+        return true;
+    }
+
+    template <typename T>
+    static handle cast(T &&src, return_value_policy policy, handle parent) {
+        list l(src.size());
+        size_t index = 0;
+        for (auto &&value : src) {
+            auto value_ = reinterpret_steal<object>(value_conv::cast(forward_like<T>(value), policy, parent));
+            if (!value_)
+                return handle();
+            PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference
+        }
+        return l.release();
+    }
+
+    PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name() + _<Resizable>(_(""), _("[") + _<Size>() + _("]")) + _("]"));
+};
+
+template <typename Type, size_t Size> struct type_caster<std::array<Type, Size>>
+ : array_caster<std::array<Type, Size>, Type, false, Size> { };
+
+template <typename Type> struct type_caster<std::valarray<Type>>
+ : array_caster<std::valarray<Type>, Type, true> { };
+
+template <typename Key, typename Compare, typename Alloc> struct type_caster<std::set<Key, Compare, Alloc>>
+  : set_caster<std::set<Key, Compare, Alloc>, Key> { };
+
+template <typename Key, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_set<Key, Hash, Equal, Alloc>>
+  : set_caster<std::unordered_set<Key, Hash, Equal, Alloc>, Key> { };
+
+template <typename Key, typename Value, typename Compare, typename Alloc> struct type_caster<std::map<Key, Value, Compare, Alloc>>
+  : map_caster<std::map<Key, Value, Compare, Alloc>, Key, Value> { };
+
+template <typename Key, typename Value, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>>
+  : map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key, Value> { };
+
+// This type caster is intended to be used for std::optional and std::experimental::optional
+template<typename T> struct optional_caster {
+    using value_conv = make_caster<typename T::value_type>;
+
+    template <typename T_>
+    static handle cast(T_ &&src, return_value_policy policy, handle parent) {
+        if (!src)
+            return none().inc_ref();
+        policy = return_value_policy_override<typename T::value_type>::policy(policy);
+        return value_conv::cast(*std::forward<T_>(src), policy, parent);
+    }
+
+    bool load(handle src, bool convert) {
+        if (!src) {
+            return false;
+        } else if (src.is_none()) {
+            return true;  // default-constructed value is already empty
+        }
+        value_conv inner_caster;
+        if (!inner_caster.load(src, convert))
+            return false;
+
+        value.emplace(cast_op<typename T::value_type &&>(std::move(inner_caster)));
+        return true;
+    }
+
+    PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name() + _("]"));
+};
+
+#if PYBIND11_HAS_OPTIONAL
+template<typename T> struct type_caster<std::optional<T>>
+    : public optional_caster<std::optional<T>> {};
+
+template<> struct type_caster<std::nullopt_t>
+    : public void_caster<std::nullopt_t> {};
+#endif
+
+#if PYBIND11_HAS_EXP_OPTIONAL
+template<typename T> struct type_caster<std::experimental::optional<T>>
+    : public optional_caster<std::experimental::optional<T>> {};
+
+template<> struct type_caster<std::experimental::nullopt_t>
+    : public void_caster<std::experimental::nullopt_t> {};
+#endif
+
+/// Visit a variant and cast any found type to Python
+struct variant_caster_visitor {
+    return_value_policy policy;
+    handle parent;
+
+    using result_type = handle; // required by boost::variant in C++11
+
+    template <typename T>
+    result_type operator()(T &&src) const {
+        return make_caster<T>::cast(std::forward<T>(src), policy, parent);
+    }
+};
+
+/// Helper class which abstracts away variant's `visit` function. `std::variant` and similar
+/// `namespace::variant` types which provide a `namespace::visit()` function are handled here
+/// automatically using argument-dependent lookup. Users can provide specializations for other
+/// variant-like classes, e.g. `boost::variant` and `boost::apply_visitor`.
+template <template<typename...> class Variant>
+struct visit_helper {
+    template <typename... Args>
+    static auto call(Args &&...args) -> decltype(visit(std::forward<Args>(args)...)) {
+        return visit(std::forward<Args>(args)...);
+    }
+};
+
+/// Generic variant caster
+template <typename Variant> struct variant_caster;
+
+template <template<typename...> class V, typename... Ts>
+struct variant_caster<V<Ts...>> {
+    static_assert(sizeof...(Ts) > 0, "Variant must consist of at least one alternative.");
+
+    template <typename U, typename... Us>
+    bool load_alternative(handle src, bool convert, type_list<U, Us...>) {
+        auto caster = make_caster<U>();
+        if (caster.load(src, convert)) {
+            value = cast_op<U>(caster);
+            return true;
+        }
+        return load_alternative(src, convert, type_list<Us...>{});
+    }
+
+    bool load_alternative(handle, bool, type_list<>) { return false; }
+
+    bool load(handle src, bool convert) {
+        // Do a first pass without conversions to improve constructor resolution.
+        // E.g. `py::int_(1).cast<variant<double, int>>()` needs to fill the `int`
+        // slot of the variant. Without two-pass loading `double` would be filled
+        // because it appears first and a conversion is possible.
+        if (convert && load_alternative(src, false, type_list<Ts...>{}))
+            return true;
+        return load_alternative(src, convert, type_list<Ts...>{});
+    }
+
+    template <typename Variant>
+    static handle cast(Variant &&src, return_value_policy policy, handle parent) {
+        return visit_helper<V>::call(variant_caster_visitor{policy, parent},
+                                     std::forward<Variant>(src));
+    }
+
+    using Type = V<Ts...>;
+    PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster<Ts>::name()...) + _("]"));
+};
+
+#if PYBIND11_HAS_VARIANT
+template <typename... Ts>
+struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> { };
+#endif
+
+NAMESPACE_END(detail)
+
+inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
+    os << (std::string) str(obj);
+    return os;
+}
+
+NAMESPACE_END(PYBIND11_NAMESPACE)
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
diff --git a/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/stl_bind.h b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/stl_bind.h
new file mode 100644
index 0000000000000000000000000000000000000000..38dd68f6950e322e928f3d82810ed59c702b18e1
--- /dev/null
+++ b/meshpy/.eggs/pybind11-2.2.4-py3.7.egg/stl_bind.h
@@ -0,0 +1,599 @@
+/*
+    pybind11/std_bind.h: Binding generators for STL data types
+
+    Copyright (c) 2016 Sergey Lyskov and Wenzel Jakob
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "detail/common.h"
+#include "operators.h"
+
+#include <algorithm>
+#include <sstream>
+
+NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
+NAMESPACE_BEGIN(detail)
+
+/* SFINAE helper class used by 'is_comparable */
+template <typename T>  struct container_traits {
+    template <typename T2> static std::true_type test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>())*);
+    template <typename T2> static std::false_type test_comparable(...);
+    template <typename T2> static std::true_type test_value(typename T2::value_type *);
+    template <typename T2> static std::false_type test_value(...);
+    template <typename T2> static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *);
+    template <typename T2> static std::false_type test_pair(...);
+
+    static constexpr const bool is_comparable = std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value;
+    static constexpr const bool is_pair = std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value;
+    static constexpr const bool is_vector = std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value;
+    static constexpr const bool is_element = !is_pair && !is_vector;
+};
+
+/* Default: is_comparable -> std::false_type */
+template <typename T, typename SFINAE = void>
+struct is_comparable : std::false_type { };
+
+/* For non-map data structures, check whether operator== can be instantiated */
+template <typename T>
+struct is_comparable<
+    T, enable_if_t<container_traits<T>::is_element &&
+                   container_traits<T>::is_comparable>>
+    : std::true_type { };
+
+/* For a vector/map data structure, recursively check the value type (which is std::pair for maps) */
+template <typename T>
+struct is_comparable<T, enable_if_t<container_traits<T>::is_vector>> {
+    static constexpr const bool value =
+        is_comparable<typename T::value_type>::value;
+};
+
+/* For pairs, recursively check the two data types */
+template <typename T>
+struct is_comparable<T, enable_if_t<container_traits<T>::is_pair>> {
+    static constexpr const bool value =
+        is_comparable<typename T::first_type>::value &&
+        is_comparable<typename T::second_type>::value;
+};
+
+/* Fallback functions */
+template <typename, typename, typename... Args> void vector_if_copy_constructible(const Args &...) { }
+template <typename, typename, typename... Args> void vector_if_equal_operator(const Args &...) { }
+template <typename, typename, typename... Args> void vector_if_insertion_operator(const Args &...) { }
+template <typename, typename, typename... Args> void vector_modifiers(const Args &...) { }
+
+template<typename Vector, typename Class_>
+void vector_if_copy_constructible(enable_if_t<is_copy_constructible<Vector>::value, Class_> &cl) {
+    cl.def(init<const Vector &>(), "Copy constructor");
+}
+
+template<typename Vector, typename Class_>
+void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> &cl) {
+    using T = typename Vector::value_type;
+
+    cl.def(self == self);
+    cl.def(self != self);
+
+    cl.def("count",
+        [](const Vector &v, const T &x) {
+            return std::count(v.begin(), v.end(), x);
+        },
+        arg("x"),
+        "Return the number of times ``x`` appears in the list"
+    );
+
+    cl.def("remove", [](Vector &v, const T &x) {
+            auto p = std::find(v.begin(), v.end(), x);
+            if (p != v.end())
+                v.erase(p);
+            else
+                throw value_error();
+        },
+        arg("x"),
+        "Remove the first item from the list whose value is x. "
+        "It is an error if there is no such item."
+    );
+
+    cl.def("__contains__",
+        [](const Vector &v, const T &x) {
+            return std::find(v.begin(), v.end(), x) != v.end();
+        },
+        arg("x"),
+        "Return true the container contains ``x``"
+    );
+}
+
+// Vector modifiers -- requires a copyable vector_type:
+// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it seems
+// silly to allow deletion but not insertion, so include them here too.)
+template <typename Vector, typename Class_>
+void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) {
+    using T = typename Vector::value_type;
+    using SizeType = typename Vector::size_type;
+    using DiffType = typename Vector::difference_type;
+
+    cl.def("append",
+           [](Vector &v, const T &value) { v.push_back(value); },
+           arg("x"),
+           "Add an item to the end of the list");
+
+    cl.def(init([](iterable it) {
+        auto v = std::unique_ptr<Vector>(new Vector());
+        v->reserve(len(it));
+        for (handle h : it)
+           v->push_back(h.cast<T>());
+        return v.release();
+    }));
+
+    cl.def("extend",
+       [](Vector &v, const Vector &src) {
+           v.insert(v.end(), src.begin(), src.end());
+       },
+       arg("L"),
+       "Extend the list by appending all the items in the given list"
+    );
+
+    cl.def("insert",
+        [](Vector &v, SizeType i, const T &x) {
+            if (i > v.size())
+                throw index_error();
+            v.insert(v.begin() + (DiffType) i, x);
+        },
+        arg("i") , arg("x"),
+        "Insert an item at a given position."
+    );
+
+    cl.def("pop",
+        [](Vector &v) {
+            if (v.empty())
+                throw index_error();
+            T t = v.back();
+            v.pop_back();
+            return t;
+        },
+        "Remove and return the last item"
+    );
+
+    cl.def("pop",
+        [](Vector &v, SizeType i) {
+            if (i >= v.size())
+                throw index_error();
+            T t = v[i];
+            v.erase(v.begin() + (DiffType) i);
+            return t;
+        },
+        arg("i"),
+        "Remove and return the item at index ``i``"
+    );
+
+    cl.def("__setitem__",
+        [](Vector &v, SizeType i, const T &t) {
+            if (i >= v.size())
+                throw index_error();
+            v[i] = t;
+        }
+    );
+
+    /// Slicing protocol
+    cl.def("__getitem__",
+        [](const Vector &v, slice slice) -> Vector * {
+            size_t start, stop, step, slicelength;
+
+            if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
+                throw error_already_set();
+
+            Vector *seq = new Vector();
+            seq->reserve((size_t) slicelength);
+
+            for (size_t i=0; i<slicelength; ++i) {
+                seq->push_back(v[start]);
+                start += step;
+            }
+            return seq;
+        },
+        arg("s"),
+        "Retrieve list elements using a slice object"
+    );
+
+    cl.def("__setitem__",
+        [](Vector &v, slice slice,  const Vector &value) {
+            size_t start, stop, step, slicelength;
+            if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
+                throw error_already_set();
+
+            if (slicelength != value.size())
+                throw std::runtime_error("Left and right hand size of slice assignment have different sizes!");
+
+            for (size_t i=0; i<slicelength; ++i) {
+                v[start] = value[i];
+                start += step;
+            }
+        },
+        "Assign list elements using a slice object"
+    );
+
+    cl.def("__delitem__",
+        [](Vector &v, SizeType i) {
+            if (i >= v.size())
+                throw index_error();
+            v.erase(v.begin() + DiffType(i));
+        },
+        "Delete the list elements at index ``i``"
+    );
+
+    cl.def("__delitem__",
+        [](Vector &v, slice slice) {
+            size_t start, stop, step, slicelength;
+
+            if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
+                throw error_already_set();
+
+            if (step == 1 && false) {
+                v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength));
+            } else {
+                for (size_t i = 0; i < slicelength; ++i) {
+                    v.erase(v.begin() + DiffType(start));
+                    start += step - 1;
+                }
+            }
+        },
+        "Delete list elements using a slice object"
+    );
+
+}
+
+// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>),
+// we have to access by copying; otherwise we return by reference.
+template <typename Vector> using vector_needs_copy = negation<
+    std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>>;
+
+// The usual case: access and iterate by reference
+template <typename Vector, typename Class_>
+void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl) {
+    using T = typename Vector::value_type;
+    using SizeType = typename Vector::size_type;
+    using ItType   = typename Vector::iterator;
+
+    cl.def("__getitem__",
+        [](Vector &v, SizeType i) -> T & {
+            if (i >= v.size())
+                throw index_error();
+            return v[i];
+        },
+        return_value_policy::reference_internal // ref + keepalive
+    );
+
+    cl.def("__iter__",
+           [](Vector &v) {
+               return make_iterator<
+                   return_value_policy::reference_internal, ItType, ItType, T&>(
+                   v.begin(), v.end());
+           },
+           keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
+    );
+}
+
+// The case for special objects, like std::vector<bool>, that have to be returned-by-copy:
+template <typename Vector, typename Class_>
+void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl) {
+    using T = typename Vector::value_type;
+    using SizeType = typename Vector::size_type;
+    using ItType   = typename Vector::iterator;
+    cl.def("__getitem__",
+        [](const Vector &v, SizeType i) -> T {
+            if (i >= v.size())
+                throw index_error();
+            return v[i];
+        }
+    );
+
+    cl.def("__iter__",
+           [](Vector &v) {
+               return make_iterator<
+                   return_value_policy::copy, ItType, ItType, T>(
+                   v.begin(), v.end());
+           },
+           keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
+    );
+}
+
+template <typename Vector, typename Class_> auto vector_if_insertion_operator(Class_ &cl, std::string const &name)
+    -> decltype(std::declval<std::ostream&>() << std::declval<typename Vector::value_type>(), void()) {
+    using size_type = typename Vector::size_type;
+
+    cl.def("__repr__",
+           [name](Vector &v) {
+            std::ostringstream s;
+            s << name << '[';
+            for (size_type i=0; i < v.size(); ++i) {
+                s << v[i];
+                if (i != v.size() - 1)
+                    s << ", ";
+            }
+            s << ']';
+            return s.str();
+        },
+        "Return the canonical string representation of this list."
+    );
+}
+
+// Provide the buffer interface for vectors if we have data() and we have a format for it
+// GCC seems to have "void std::vector<bool>::data()" - doing SFINAE on the existence of data() is insufficient, we need to check it returns an appropriate pointer
+template <typename Vector, typename = void>
+struct vector_has_data_and_format : std::false_type {};
+template <typename Vector>
+struct vector_has_data_and_format<Vector, enable_if_t<std::is_same<decltype(format_descriptor<typename Vector::value_type>::format(), std::declval<Vector>().data()), typename Vector::value_type*>::value>> : std::true_type {};
+
+// Add the buffer interface to a vector
+template <typename Vector, typename Class_, typename... Args>
+enable_if_t<detail::any_of<std::is_same<Args, buffer_protocol>...>::value>
+vector_buffer(Class_& cl) {
+    using T = typename Vector::value_type;
+
+    static_assert(vector_has_data_and_format<Vector>::value, "There is not an appropriate format descriptor for this vector");
+
+    // numpy.h declares this for arbitrary types, but it may raise an exception and crash hard at runtime if PYBIND11_NUMPY_DTYPE hasn't been called, so check here
+    format_descriptor<T>::format();
+
+    cl.def_buffer([](Vector& v) -> buffer_info {
+        return buffer_info(v.data(), static_cast<ssize_t>(sizeof(T)), format_descriptor<T>::format(), 1, {v.size()}, {sizeof(T)});
+    });
+
+    cl.def(init([](buffer buf) {
+        auto info = buf.request();
+        if (info.ndim != 1 || info.strides[0] % static_cast<ssize_t>(sizeof(T)))
+            throw type_error("Only valid 1D buffers can be copied to a vector");
+        if (!detail::compare_buffer_info<T>::compare(info) || (ssize_t) sizeof(T) != info.itemsize)
+            throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor<T>::format() + ")");
+
+        auto vec = std::unique_ptr<Vector>(new Vector());
+        vec->reserve((size_t) info.shape[0]);
+        T *p = static_cast<T*>(info.ptr);
+        ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T));
+        T *end = p + info.shape[0] * step;
+        for (; p != end; p += step)
+            vec->push_back(*p);
+        return vec.release();
+    }));
+
+    return;
+}
+
+template <typename Vector, typename Class_, typename... Args>
+enable_if_t<!detail::any_of<std::is_same<Args, buffer_protocol>...>::value> vector_buffer(Class_&) {}
+
+NAMESPACE_END(detail)
+
+//
+// std::vector
+//
+template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args>
+class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args&&... args) {
+    using Class_ = class_<Vector, holder_type>;
+
+    // If the value_type is unregistered (e.g. a converting type) or is itself registered
+    // module-local then make the vector binding module-local as well:
+    using vtype = typename Vector::value_type;
+    auto vtype_info = detail::get_type_info(typeid(vtype));
+    bool local = !vtype_info || vtype_info->module_local;
+
+    Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
+
+    // Declare the buffer interface if a buffer_protocol() is passed in
+    detail::vector_buffer<Vector, Class_, Args...>(cl);
+
+    cl.def(init<>());
+
+    // Register copy constructor (if possible)
+    detail::vector_if_copy_constructible<Vector, Class_>(cl);
+
+    // Register comparison-related operators and functions (if possible)
+    detail::vector_if_equal_operator<Vector, Class_>(cl);
+
+    // Register stream insertion operator (if possible)
+    detail::vector_if_insertion_operator<Vector, Class_>(cl, name);
+
+    // Modifiers require copyable vector value type
+    detail::vector_modifiers<Vector, Class_>(cl);
+
+    // Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive
+    detail::vector_accessor<Vector, Class_>(cl);
+
+    cl.def("__bool__",
+        [](const Vector &v) -> bool {
+            return !v.empty();
+        },
+        "Check whether the list is nonempty"
+    );
+
+    cl.def("__len__", &Vector::size);
+
+
+
+
+#if 0
+    // C++ style functions deprecated, leaving it here as an example
+    cl.def(init<size_type>());
+
+    cl.def("resize",
+         (void (Vector::*) (size_type count)) & Vector::resize,
+         "changes the number of elements stored");
+
+    cl.def("erase",
+        [](Vector &v, SizeType i) {
+        if (i >= v.size())
+            throw index_error();
+        v.erase(v.begin() + i);
+    }, "erases element at index ``i``");
+
+    cl.def("empty",         &Vector::empty,         "checks whether the container is empty");
+    cl.def("size",          &Vector::size,          "returns the number of elements");
+    cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end");
+    cl.def("pop_back",                               &Vector::pop_back, "removes the last element");
+
+    cl.def("max_size",      &Vector::max_size,      "returns the maximum possible number of elements");
+    cl.def("reserve",       &Vector::reserve,       "reserves storage");
+    cl.def("capacity",      &Vector::capacity,      "returns the number of elements that can be held in currently allocated storage");
+    cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory");
+
+    cl.def("clear", &Vector::clear, "clears the contents");
+    cl.def("swap",   &Vector::swap, "swaps the contents");
+
+    cl.def("front", [](Vector &v) {
+        if (v.size()) return v.front();
+        else throw index_error();
+    }, "access the first element");
+
+    cl.def("back", [](Vector &v) {
+        if (v.size()) return v.back();
+        else throw index_error();
+    }, "access the last element ");
+
+#endif
+
+    return cl;
+}
+
+
+
+//
+// std::map, std::unordered_map
+//
+
+NAMESPACE_BEGIN(detail)
+
+/* Fallback functions */
+template <typename, typename, typename... Args> void map_if_insertion_operator(const Args &...) { }
+template <typename, typename, typename... Args> void map_assignment(const Args &...) { }
+
+// Map assignment when copy-assignable: just copy the value
+template <typename Map, typename Class_>
+void map_assignment(enable_if_t<std::is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) {
+    using KeyType = typename Map::key_type;
+    using MappedType = typename Map::mapped_type;
+
+    cl.def("__setitem__",
+           [](Map &m, const KeyType &k, const MappedType &v) {
+               auto it = m.find(k);
+               if (it != m.end()) it->second = v;
+               else m.emplace(k, v);
+           }
+    );
+}
+
+// Not copy-assignable, but still copy-constructible: we can update the value by erasing and reinserting
+template<typename Map, typename Class_>
+void map_assignment(enable_if_t<
+        !std::is_copy_assignable<typename Map::mapped_type>::value &&
+        is_copy_constructible<typename Map::mapped_type>::value,
+        Class_> &cl) {
+    using KeyType = typename Map::key_type;
+    using MappedType = typename Map::mapped_type;
+
+    cl.def("__setitem__",
+           [](Map &m, const KeyType &k, const MappedType &v) {
+               // We can't use m[k] = v; because value type might not be default constructable
+               auto r = m.emplace(k, v);
+               if (!r.second) {
+                   // value type is not copy assignable so the only way to insert it is to erase it first...
+                   m.erase(r.first);
+                   m.emplace(k, v);
+               }
+           }
+    );
+}
+
+
+template <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &cl, std::string const &name)
+-> decltype(std::declval<std::ostream&>() << std::declval<typename Map::key_type>() << std::declval<typename Map::mapped_type>(), void()) {
+
+    cl.def("__repr__",
+           [name](Map &m) {
+            std::ostringstream s;
+            s << name << '{';
+            bool f = false;
+            for (auto const &kv : m) {
+                if (f)
+                    s << ", ";
+                s << kv.first << ": " << kv.second;
+                f = true;
+            }
+            s << '}';
+            return s.str();
+        },
+        "Return the canonical string representation of this map."
+    );
+}
+
+
+NAMESPACE_END(detail)
+
+template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args>
+class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&... args) {
+    using KeyType = typename Map::key_type;
+    using MappedType = typename Map::mapped_type;
+    using Class_ = class_<Map, holder_type>;
+
+    // If either type is a non-module-local bound type then make the map binding non-local as well;
+    // otherwise (e.g. both types are either module-local or converting) the map will be
+    // module-local.
+    auto tinfo = detail::get_type_info(typeid(MappedType));
+    bool local = !tinfo || tinfo->module_local;
+    if (local) {
+        tinfo = detail::get_type_info(typeid(KeyType));
+        local = !tinfo || tinfo->module_local;
+    }
+
+    Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
+
+    cl.def(init<>());
+
+    // Register stream insertion operator (if possible)
+    detail::map_if_insertion_operator<Map, Class_>(cl, name);
+
+    cl.def("__bool__",
+        [](const Map &m) -> bool { return !m.empty(); },
+        "Check whether the map is nonempty"
+    );
+
+    cl.def("__iter__",
+           [](Map &m) { return make_key_iterator(m.begin(), m.end()); },
+           keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
+    );
+
+    cl.def("items",
+           [](Map &m) { return make_iterator(m.begin(), m.end()); },
+           keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
+    );
+
+    cl.def("__getitem__",
+        [](Map &m, const KeyType &k) -> MappedType & {
+            auto it = m.find(k);
+            if (it == m.end())
+              throw key_error();
+           return it->second;
+        },
+        return_value_policy::reference_internal // ref + keepalive
+    );
+
+    // Assignment provided only if the type is copyable
+    detail::map_assignment<Map, Class_>(cl);
+
+    cl.def("__delitem__",
+           [](Map &m, const KeyType &k) {
+               auto it = m.find(k);
+               if (it == m.end())
+                   throw key_error();
+               m.erase(it);
+           }
+    );
+
+    cl.def("__len__", &Map::size);
+
+    return cl;
+}
+
+NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/meshpy/.gitignore b/meshpy/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..127123bd48f887e5d370de9463c5f3aef036d2f5
--- /dev/null
+++ b/meshpy/.gitignore
@@ -0,0 +1,35 @@
+build
+*.dat
+test/*.lua
+MANIFEST
+*.vtk
+*.ele
+*.face
+*.neu
+*.poly
+*.node
+.*.swp
+test/ParaViewTrace*.pvs
+dist
+*~
+Makefile
+siteconf.py
+tags
+doc/html
+*.orig
+*.egg-info
+*.pyc
+*.pyo
+doc/.build
+*.pyd
+*.so
+setuptools*egg
+setuptools*pth
+setuptools*tar.gz
+setuptools*pth
+.sw[op]
+
+.cache
+CMakeCache*
+CMakeFiles
+cmake_install.cmake
diff --git a/meshpy/.gitlab-ci.yml b/meshpy/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..dcb58f13a83f9b01578123fb3fdd3640ef3d229c
--- /dev/null
+++ b/meshpy/.gitlab-ci.yml
@@ -0,0 +1,42 @@
+Python 2.7:
+  script:
+  - py_version=2.7
+  - EXTRA_INSTALL="numpy pybind11"
+  - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/build-and-test-py-project.sh
+  - ". ./build-and-test-py-project.sh"
+  tags:
+  - python2.7
+  except:
+  - tags
+
+Python 3.5:
+  script:
+  - py_version=3.5
+  - EXTRA_INSTALL="numpy pybind11"
+  - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/build-and-test-py-project.sh
+  - ". ./build-and-test-py-project.sh"
+  tags:
+  - python3.5
+  except:
+  - tags
+
+Python 3.7:
+  script:
+  - py_version=3.7
+  - EXTRA_INSTALL="numpy pybind11"
+  - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/build-and-test-py-project.sh
+  - ". ./build-and-test-py-project.sh"
+  tags:
+  - python3.7
+  except:
+  - tags
+
+Documentation:
+  script:
+  - EXTRA_INSTALL="numpy pybind11"
+  - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/build-docs.sh
+  - ". ./build-docs.sh"
+  tags:
+  - python3.5
+  only:
+  - master
diff --git a/meshpy/CMakeLists.txt b/meshpy/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ea504f5ee8ccde959cb5d4336c6339d45201de36
--- /dev/null
+++ b/meshpy/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.5)
+# by default use python3
+# for python2 use -Dpy_version=2
+
+if (NOT py_version LESS 3)
+    find_package( Boost COMPONENTS "python3")
+else()
+    find_package( Boost COMPONENTS "python")
+endif()
+
+if(Boost_FOUND)
+    include_directories(${Boost_INCLUDE_DIRS})
+    MESSAGE(STATUS "VERSION: " ${Boost_LIB_VERSION})
+    MESSAGE(STATUS "INCLUDE_DIRS: " ${Boost_INCLUDE_DIRS})
+    MESSAGE(STATUS "LIB_DIRS: " ${Boost_LIBRARY_DIRS})
+    MESSAGE(STATUS "LIBRARIES: " ${Boost_LIBRARIES})
+endif()
diff --git a/meshpy/LICENSE b/meshpy/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..8ab78373893d1363ce39d7d0b88c1c44ff876710
--- /dev/null
+++ b/meshpy/LICENSE
@@ -0,0 +1,137 @@
+-------------------------------------------------------------------------------
+Triangle License
+-------------------------------------------------------------------------------
+
+
+Copyright 1993, 1995, 1997, 1998, 2002, 2005 Jonathan Richard Shewchuk
+2360 Woolsey #H
+Berkeley, California  94705-1927
+Please send bugs and comments to jrs@cs.berkeley.edu
+
+Created as part of the Quake project (tools for earthquake simulation).
+Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.
+There is no warranty whatsoever.  Use at your own risk.
+
+
+Triangle generates exact Delaunay triangulations, constrained Delaunay
+triangulations, conforming Delaunay triangulations, Voronoi diagrams, and
+high-quality triangular meshes.  The latter can be generated with no small
+or large angles, and are thus suitable for finite element analysis.
+Show Me graphically displays the contents of the geometric files used by
+Triangle.  Show Me can also write images in PostScript form.
+
+Information on the algorithms used by Triangle, including complete
+references, can be found in the comments at the beginning of the triangle.c
+source file.  Another listing of these references, with PostScript copies
+of some of the papers, is available from the Web page
+
+    http://www.cs.cmu.edu/~quake/triangle.research.html
+
+------------------------------------------------------------------------------
+
+These programs may be freely redistributed under the condition that the
+copyright notices (including the copy of this notice in the code comments
+and the copyright notice printed when the `-h' switch is selected) are
+not removed, and no compensation is received.  Private, research, and
+institutional use is free.  You may distribute modified versions of this
+code UNDER THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT
+IN THE SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH
+SOURCE AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND
+CLEAR NOTICE IS GIVEN OF THE MODIFICATIONS.  Distribution of this code as
+part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT
+WITH THE AUTHOR.  (If you are not directly supplying this code to a
+customer, and you are instead telling them how they can obtain it for
+free, then you are not required to make any arrangement with me.)
+
+-------------------------------------------------------------------------------
+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.
+
+-------------------------------------------------------------------------------
+Wrapper license
+-------------------------------------------------------------------------------
+The wrapper is licensed to you under the following terms:
+
+Copyright (c) 2004-2008 Andreas Kloeckner
+
+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:
+
+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.
diff --git a/meshpy/MANIFEST.in b/meshpy/MANIFEST.in
new file mode 100644
index 0000000000000000000000000000000000000000..d8736d1a9593ebe7389e2d48e9689bb4bc8c8dc2
--- /dev/null
+++ b/meshpy/MANIFEST.in
@@ -0,0 +1,19 @@
+include src/cpp/*.h
+include src/cpp/*.hpp
+include src/cpp/*LICENSE
+include README.rst
+include LICENSE
+include test/*.py
+include examples/clean.sh
+include examples/clean.sh
+
+include doc/*.rst
+include doc/conf.py
+include doc/Makefile
+include doc/_static/*.css
+include doc/_templates/*.html
+
+include configure.py
+include Makefile.in
+include aksetup_helper.py
+include README_SETUP.txt
diff --git a/meshpy/Makefile.in b/meshpy/Makefile.in
new file mode 100644
index 0000000000000000000000000000000000000000..693cbb4807b204525c4a221d6a71557fb54a1d02
--- /dev/null
+++ b/meshpy/Makefile.in
@@ -0,0 +1,24 @@
+.PHONY	: all install clean tags dist doc
+
+all: tags
+	${PYTHON_EXE} setup.py build
+
+dist:
+	${PYTHON_EXE} setup.py sdist
+
+install: tags
+	${PYTHON_EXE} setup.py install
+
+clean:
+	rm -Rf build
+	rm -f tags
+
+tags:
+	ctags -R src || true
+
+doc:
+	rm -Rf doc/html
+	mkdir doc/html
+	${PYTHON_EXE} `which epydoc` \
+	  -o doc/html -v --html \
+	  meshpy
diff --git a/meshpy/README b/meshpy/README
new file mode 100644
index 0000000000000000000000000000000000000000..85e6668c41fd36c131a2bd038b10f9ae712b3420
--- /dev/null
+++ b/meshpy/README
@@ -0,0 +1,92 @@
+Thanks for downloading MeshPy!
+
+WHAT IS THIS?
+-------------
+
+MeshPy enables you to generate quality triangular and tetrahedral meshes for
+arbitrary geometric regions, all from within Python. Meshes of this type are
+chiefly used in finite-element simulation codes, but also have many other 
+applications ranging from computer graphics to robotics.
+
+In order to generate these 2D and 3D meshes, MeshPy provides Python interfaces 
+to two well-regarded mesh generators, Triangle [1] by J. Shewchuk and TetGen [2]
+by Hang Si.
+
+[1] http://www.cs.cmu.edu/~quake/triangle.html
+[2] http://tetgen.berlios.de/
+
+MeshPy is based on TetGen 1.4.2 and Triangle 1.6.
+
+GETTING STARTED
+---------------
+
+To get started, you need the Boost.Python [1] wrapper generator library 
+installed. See below for installation instructions.
+
+After you have installed MeshPy, take a look at the examples in the test/
+subdirectory to see what you can do with MeshPy and how. There is no user
+documentation currently, but if you would like to contribute some, 
+please feel free. In general, you might want to study how Triangle's and
+TetGen's C interfaces work--then MeshPy's interface should not be a 
+surprise. MeshPy makes an attempt to make the two meshing interfaces even
+more similar than they already are, by renaming fields called "triangle..." 
+and "tetrahedron..." into "element...".
+
+I hope you enjoy using MeshPy. If you use it for your work, I'd be delighted
+to hear from you.
+
+Andreas Kloeckner <kloeckner@dam.brown.edu>
+
+[1] http://www.boost.org/libs/python/doc/
+
+INSTALLING BOOST.PYTHON
+-----------------------
+
+(You may skip all this if your distribution ships Boost.Python, which is the case
+for Debian and Ubuntu. For the latter two, you just need to install the package
+libboost-python-dev, it will pull in all the other dependencies.)
+
+If you figure you need to build manually, proceed as follows:
+
+* Download a Boost release from http://www.boost.org/.
+
+* Download and install Boost.Jam, a build tool, from
+
+* Build Boost, such as by typing
+
+    bjam -sPYTHON_ROOT=/usr -sPYTHON_VERSION=2.4 \
+      -sBUILD="release <runtime-link>dynamic <threading>multi"
+
+  (You may have to adapt PYTHON_ROOT and PYTHON_VERSION depending on your system.)
+
+* Check the directory 
+
+    boost/bin/boost/libs/python/build/libboost_python.so...
+      .../gcc/release/shared-linkable-true/threading-multi
+
+  and find libboost_python*.so. (Don't copy the dots from the command
+  line--they are only there to make the line fit on this page.) Copy these
+  files to somewhere on your dynamic linker path, for example:
+  
+  - /usr/lib
+  - a directory on LD_LIBRARY_PATH
+  - or something mentioned in /etc/ld.so.conf.
+
+  You should also create a symbolic link called libboost_python.so
+  to the main .so file.
+
+* Run ldconfig.
+  
+INSTALLING MESHPY
+-----------------
+
+Simply run
+
+    su -c "python setup.py install"
+
+To cut down on compile time in this step, you may edit the variable OPT in the file
+
+    /usr/lib/python2.N/config/Makefile
+
+and remove the "-g" flag from it. This will cut compile time and memory requirements
+for the compile in about half.
diff --git a/meshpy/README.rst b/meshpy/README.rst
new file mode 100644
index 0000000000000000000000000000000000000000..b0b67b162a05465bed35857c1a38c605935a0e40
--- /dev/null
+++ b/meshpy/README.rst
@@ -0,0 +1,36 @@
+MeshPy: Simplicial Mesh Generation from Python
+==============================================
+
+.. image:: https://gitlab.tiker.net/inducer/meshpy/badges/master/pipeline.svg
+   :target: https://gitlab.tiker.net/inducer/meshpy/commits/master
+.. image:: https://badge.fury.io/py/meshpy.png
+    :target: http://pypi.python.org/pypi/meshpy
+
+MeshPy offers quality triangular and tetrahedral mesh generation for Python.
+Meshes of this type are chiefly used in finite-element simulation codes, but
+also have many other applications ranging from computer graphics to robotics.
+
+In order to generate 2D and 3D meshes, MeshPy provides Python interfaces to
+three well-regarded mesh generators, `Triangle
+<http://www.cs.cmu.edu/~quake/triangle.html>`_ by J.  Shewchuk, `TetGen
+<http://tetgen.berlios.de/>`_ by Hang Si
+The former two are included in the package in slightly modified versions. A
+generic mesh reader for the latter is included, as is an easy way to run `gmsh`
+from a Python script.
+
+For an interface to `gmsh
+<http://www.geuz.org/gmsh/>`_ by Christophe Geuzaine and Jean-Francois Remacle,
+see `gmsh_interop <https://github.com/inducer/gmsh_interop>`.
+
+MeshPy has no dependencies other than a C++ compiler and a working Python installation.
+
+As of Version 0.91.2, MeshPy also works with Python 3.
+
+Online resources
+================
+
+* `Home page <https://mathema.tician.de/software/meshpy>`_
+* `Documentation <http://documen.tician.de/meshpy>`_
+* `Source <https://github.com/inducer/meshpy>`_
+* `Package index <https://pypi.python.org/pypi/MeshPy>`_
+* `Mailing list <http://lists.tiker.net/listinfo/meshpy>`_
diff --git a/meshpy/README_SETUP.txt b/meshpy/README_SETUP.txt
new file mode 100644
index 0000000000000000000000000000000000000000..07cbb551e0ad7e116d865ee80ebbd43c5be65563
--- /dev/null
+++ b/meshpy/README_SETUP.txt
@@ -0,0 +1,34 @@
+Hi, welcome.
+
+This Python package uses aksetup for installation, which means that
+installation should be easy and quick.
+
+If you don't want to continue reading, just try the regular
+
+  ./configure.py --help
+  ./configure.py --some-options
+  make
+  sudo make install
+
+That should do the trick. (By the way: If a config option says "several ok",
+then you may specify several values, separated by commas.)
+
+aksetup also supports regular distutils installation, without using 
+configure:
+
+  python setup.py build
+  sudo python setup.py install
+
+In this case, configuration is obtained from files in this order:
+
+/etc/aksetup-defaults.py
+$HOME/.aksetup-defaults.py
+$PACKAGEDIR/siteconf.py
+
+Once you've run configure, you can copy options from your siteconf.py file to
+one of these files, and you won't ever have to configure them again manually.
+In fact, you may pass the options "--update-user" and "--update-global" to
+configure, and it will automatically update these files for you.
+
+This is particularly handy if you want to perform an unattended or automatic
+installation via easy_install.
diff --git a/meshpy/aksetup_helper.py b/meshpy/aksetup_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..50507afca8e8af736d51ef154316b6badef69b42
--- /dev/null
+++ b/meshpy/aksetup_helper.py
@@ -0,0 +1,825 @@
+import setuptools  # noqa
+from setuptools import Extension
+import sys
+
+
+def count_down_delay(delay):
+    from time import sleep
+    while delay:
+        sys.stdout.write("Continuing in %d seconds...   \r" % delay)
+        sys.stdout.flush()
+        delay -= 1
+        sleep(1)
+    print("")
+
+DASH_SEPARATOR = 75 * "-"
+
+
+def setup(*args, **kwargs):
+    from setuptools import setup
+    try:
+        setup(*args, **kwargs)
+    except KeyboardInterrupt:
+        raise
+    except SystemExit:
+        raise
+    except:
+        print(DASH_SEPARATOR)
+        print("Sorry, your build failed. Try rerunning configure.py with "
+                "different options.")
+        print(DASH_SEPARATOR)
+        raise
+
+
+class NumpyExtension(Extension):
+    # nicked from
+    # http://mail.python.org/pipermail/distutils-sig/2007-September/008253.html
+    # solution by Michael Hoffmann
+    def __init__(self, *args, **kwargs):
+        Extension.__init__(self, *args, **kwargs)
+        self._include_dirs = self.include_dirs
+        del self.include_dirs  # restore overwritten property
+
+    def get_numpy_incpath(self):
+        from imp import find_module
+        # avoid actually importing numpy, it screws up distutils
+        file, pathname, descr = find_module("numpy")
+        from os.path import join
+        return join(pathname, "core", "include")
+
+    def get_additional_include_dirs(self):
+        return [self.get_numpy_incpath()]
+
+    def get_include_dirs(self):
+        return self._include_dirs + self.get_additional_include_dirs()
+
+    def set_include_dirs(self, value):
+        self._include_dirs = value
+
+    def del_include_dirs(self):
+        pass
+
+    include_dirs = property(get_include_dirs, set_include_dirs, del_include_dirs)
+
+
+class PyUblasExtension(NumpyExtension):
+    def get_module_include_path(self, name):
+        from pkg_resources import Requirement, resource_filename
+        return resource_filename(Requirement.parse(name), "%s/include" % name)
+
+    def get_additional_include_dirs(self):
+        return (NumpyExtension.get_additional_include_dirs(self)
+                + [self.get_module_include_path("pyublas")])
+
+
+class HedgeExtension(PyUblasExtension):
+    @property
+    def include_dirs(self):
+        return self._include_dirs + [
+                self.get_numpy_incpath(),
+                self.get_module_include_path("pyublas"),
+                self.get_module_include_path("hedge"),
+                ]
+
+
+# {{{ tools
+
+def flatten(list):
+    """For an iterable of sub-iterables, generate each member of each
+    sub-iterable in turn, i.e. a flattened version of that super-iterable.
+
+    Example: Turn [[a,b,c],[d,e,f]] into [a,b,c,d,e,f].
+    """
+    for sublist in list:
+        for j in sublist:
+            yield j
+
+
+def humanize(sym_str):
+    words = sym_str.lower().replace("_", " ").split(" ")
+    return " ".join([word.capitalize() for word in words])
+
+# }}}
+
+
+# {{{ siteconf handling
+
+def get_config(schema=None, warn_about_no_config=True):
+    if schema is None:
+        from setup import get_config_schema
+        schema = get_config_schema()
+
+    if (not schema.have_config() and not schema.have_global_config()
+            and warn_about_no_config):
+        print("*************************************************************")
+        print("*** I have detected that you have not run configure.py.")
+        print("*************************************************************")
+        print("*** Additionally, no global config files were found.")
+        print("*** I will go ahead with the default configuration.")
+        print("*** In all likelihood, this will not work out.")
+        print("*** ")
+        print("*** See README_SETUP.txt for more information.")
+        print("*** ")
+        print("*** If the build does fail, just re-run configure.py with the")
+        print("*** correct arguments, and then retry. Good luck!")
+        print("*************************************************************")
+        print("*** HIT Ctrl-C NOW IF THIS IS NOT WHAT YOU WANT")
+        print("*************************************************************")
+
+        count_down_delay(delay=10)
+
+    config = expand_options(schema.read_config())
+    schema.update_config_from_and_modify_command_line(config, sys.argv)
+    return config
+
+
+def hack_distutils(debug=False, fast_link=True, what_opt=3):
+    # hack distutils.sysconfig to eliminate debug flags
+    # stolen from mpi4py
+
+    def remove_prefixes(optlist, bad_prefixes):
+        for bad_prefix in bad_prefixes:
+            for i, flag in enumerate(optlist):
+                if flag.startswith(bad_prefix):
+                    optlist.pop(i)
+                    break
+        return optlist
+
+    if not sys.platform.lower().startswith("win"):
+        from distutils import sysconfig
+
+        cvars = sysconfig.get_config_vars()
+        cflags = cvars.get('OPT')
+        if cflags:
+            cflags = remove_prefixes(cflags.split(),
+                    ['-g', '-O', '-Wstrict-prototypes', '-DNDEBUG'])
+            if debug:
+                cflags.append("-g")
+            else:
+                if what_opt is None:
+                    pass
+                else:
+                    cflags.append("-O%s" % what_opt)
+                    cflags.append("-DNDEBUG")
+
+            cvars['OPT'] = str.join(' ', cflags)
+            if "BASECFLAGS" in cvars:
+                cvars["CFLAGS"] = cvars["BASECFLAGS"] + " " + cvars["OPT"]
+            else:
+                assert "CFLAGS" in cvars
+
+        if fast_link:
+            for varname in ["LDSHARED", "BLDSHARED"]:
+                ldsharedflags = cvars.get(varname)
+                if ldsharedflags:
+                    ldsharedflags = remove_prefixes(ldsharedflags.split(),
+                            ['-Wl,-O'])
+                    cvars[varname] = str.join(' ', ldsharedflags)
+
+# }}}
+
+
+# {{{ configure guts
+
+def default_or(a, b):
+    if a is None:
+        return b
+    else:
+        return a
+
+
+def expand_str(s, options):
+    import re
+
+    def my_repl(match):
+        sym = match.group(1)
+        try:
+            repl = options[sym]
+        except KeyError:
+            from os import environ
+            repl = environ[sym]
+
+        return expand_str(repl, options)
+
+    return re.subn(r"\$\{([a-zA-Z0-9_]+)\}", my_repl, s)[0]
+
+
+def expand_value(v, options):
+    if isinstance(v, str):
+        return expand_str(v, options)
+    elif isinstance(v, list):
+        result = []
+        for i in v:
+            try:
+                exp_i = expand_value(i, options)
+            except:
+                pass
+            else:
+                result.append(exp_i)
+
+        return result
+    else:
+        return v
+
+
+def expand_options(options):
+    return dict(
+            (k, expand_value(v, options)) for k, v in options.items())
+
+
+class ConfigSchema:
+    def __init__(self, options, conf_file="siteconf.py", conf_dir="."):
+        self.optdict = dict((opt.name, opt) for opt in options)
+        self.options = options
+        self.conf_dir = conf_dir
+        self.conf_file = conf_file
+
+        from os.path import expanduser
+        self.user_conf_file = expanduser("~/.aksetup-defaults.py")
+
+        if not sys.platform.lower().startswith("win"):
+            self.global_conf_file = "/etc/aksetup-defaults.py"
+        else:
+            self.global_conf_file = None
+
+    def get_conf_file(self):
+        import os
+        return os.path.join(self.conf_dir, self.conf_file)
+
+    def set_conf_dir(self, conf_dir):
+        self.conf_dir = conf_dir
+
+    def get_default_config(self):
+        return dict((opt.name, opt.default) for opt in self.options)
+
+    def read_config_from_pyfile(self, filename):
+        result = {}
+        filevars = {}
+        infile = open(filename, "r")
+        try:
+            contents = infile.read()
+        finally:
+            infile.close()
+
+        exec(compile(contents, filename, "exec"), filevars)
+
+        for key, value in filevars.items():
+            if key in self.optdict:
+                result[key] = value
+
+        return result
+
+    def update_conf_file(self, filename, config):
+        result = {}
+        filevars = {}
+
+        try:
+            exec(compile(open(filename, "r").read(), filename, "exec"), filevars)
+        except IOError:
+            pass
+
+        if "__builtins__" in filevars:
+            del filevars["__builtins__"]
+
+        for key, value in config.items():
+            if value is not None:
+                filevars[key] = value
+
+        keys = list(filevars.keys())
+        keys.sort()
+
+        outf = open(filename, "w")
+        for key in keys:
+            outf.write("%s = %s\n" % (key, repr(filevars[key])))
+        outf.close()
+
+        return result
+
+    def update_user_config(self, config):
+        self.update_conf_file(self.user_conf_file, config)
+
+    def update_global_config(self, config):
+        if self.global_conf_file is not None:
+            self.update_conf_file(self.global_conf_file, config)
+
+    def get_default_config_with_files(self):
+        result = self.get_default_config()
+
+        import os
+
+        confignames = []
+        if self.global_conf_file is not None:
+            confignames.append(self.global_conf_file)
+        confignames.append(self.user_conf_file)
+
+        for fn in confignames:
+            if os.access(fn, os.R_OK):
+                result.update(self.read_config_from_pyfile(fn))
+
+        return result
+
+    def have_global_config(self):
+        import os
+        result = os.access(self.user_conf_file, os.R_OK)
+
+        if self.global_conf_file is not None:
+            result = result or os.access(self.global_conf_file, os.R_OK)
+
+        return result
+
+    def have_config(self):
+        import os
+        return os.access(self.get_conf_file(), os.R_OK)
+
+    def update_from_python_snippet(self, config, py_snippet, filename):
+        filevars = {}
+        exec(compile(py_snippet, filename, "exec"), filevars)
+
+        for key, value in filevars.items():
+            if key in self.optdict:
+                config[key] = value
+            elif key == "__builtins__":
+                pass
+            else:
+                raise KeyError("invalid config key in %s: %s" % (
+                        filename, key))
+
+    def update_config_from_and_modify_command_line(self, config, argv):
+        cfg_prefix = "--conf:"
+
+        i = 0
+        while i < len(argv):
+            arg = argv[i]
+
+            if arg.startswith(cfg_prefix):
+                del argv[i]
+                self.update_from_python_snippet(
+                        config, arg[len(cfg_prefix):], "<command line>")
+            else:
+                i += 1
+
+        return config
+
+    def read_config(self):
+        import os
+        cfile = self.get_conf_file()
+
+        result = self.get_default_config_with_files()
+        if os.access(cfile, os.R_OK):
+            with open(cfile, "r") as inf:
+                py_snippet = inf.read()
+            self.update_from_python_snippet(result, py_snippet, cfile)
+
+        return result
+
+    def add_to_configparser(self, parser, def_config=None):
+        if def_config is None:
+            def_config = self.get_default_config_with_files()
+
+        for opt in self.options:
+            default = default_or(def_config.get(opt.name), opt.default)
+            opt.add_to_configparser(parser, default)
+
+    def get_from_configparser(self, options):
+        result = {}
+        for opt in self.options:
+            result[opt.name] = opt.take_from_configparser(options)
+        return result
+
+    def write_config(self, config):
+        outf = open(self.get_conf_file(), "w")
+        for opt in self.options:
+            value = config[opt.name]
+            if value is not None:
+                outf.write("%s = %s\n" % (opt.name, repr(config[opt.name])))
+        outf.close()
+
+    def make_substitutions(self, config):
+        return dict((opt.name, opt.value_to_str(config[opt.name]))
+                for opt in self.options)
+
+
+class Option(object):
+    def __init__(self, name, default=None, help=None):
+        self.name = name
+        self.default = default
+        self.help = help
+
+    def as_option(self):
+        return self.name.lower().replace("_", "-")
+
+    def metavar(self):
+        last_underscore = self.name.rfind("_")
+        return self.name[last_underscore+1:]
+
+    def get_help(self, default):
+        result = self.help
+        if self.default:
+            result += " (default: %s)" % self.value_to_str(
+                    default_or(default, self.default))
+        return result
+
+    def value_to_str(self, default):
+        return default
+
+    def add_to_configparser(self, parser, default=None):
+        default = default_or(default, self.default)
+        default_str = self.value_to_str(default)
+        parser.add_option(
+            "--" + self.as_option(), dest=self.name,
+            default=default_str,
+            metavar=self.metavar(), help=self.get_help(default))
+
+    def take_from_configparser(self, options):
+        return getattr(options, self.name)
+
+
+class Switch(Option):
+    def add_to_configparser(self, parser, default=None):
+        if not isinstance(self.default, bool):
+            raise ValueError("Switch options must have a default")
+
+        if default is None:
+            default = self.default
+
+        option_name = self.as_option()
+
+        if default:
+            option_name = "no-" + option_name
+            action = "store_false"
+        else:
+            action = "store_true"
+
+        parser.add_option(
+            "--" + option_name,
+            dest=self.name,
+            help=self.get_help(default),
+            default=default,
+            action=action)
+
+
+class StringListOption(Option):
+    def value_to_str(self, default):
+        if default is None:
+            return None
+
+        return ",".join([str(el).replace(",", r"\,") for el in default])
+
+    def get_help(self, default):
+        return Option.get_help(self, default) + " (several ok)"
+
+    def take_from_configparser(self, options):
+        opt = getattr(options, self.name)
+        if opt is None:
+            return None
+        else:
+            if opt:
+                import re
+                sep = re.compile(r"(?<!\\),")
+                result = sep.split(opt)
+                result = [i.replace(r"\,", ",") for i in result]
+                return result
+            else:
+                return []
+
+
+class IncludeDir(StringListOption):
+    def __init__(self, lib_name, default=None, human_name=None, help=None):
+        StringListOption.__init__(self, "%s_INC_DIR" % lib_name, default,
+                help=help or ("Include directories for %s"
+                % (human_name or humanize(lib_name))))
+
+
+class LibraryDir(StringListOption):
+    def __init__(self, lib_name, default=None, human_name=None, help=None):
+        StringListOption.__init__(self, "%s_LIB_DIR" % lib_name, default,
+                help=help or ("Library directories for %s"
+                % (human_name or humanize(lib_name))))
+
+
+class Libraries(StringListOption):
+    def __init__(self, lib_name, default=None, human_name=None, help=None):
+        StringListOption.__init__(self, "%s_LIBNAME" % lib_name, default,
+                help=help or ("Library names for %s (without lib or .so)"
+                % (human_name or humanize(lib_name))))
+
+
+class BoostLibraries(Libraries):
+    def __init__(self, lib_base_name, default_lib_name=None):
+        if default_lib_name is None:
+            if lib_base_name == "python":
+                default_lib_name = "boost_python-py%d%d" % sys.version_info[:2]
+            else:
+                default_lib_name = "boost_%s" % lib_base_name
+
+        Libraries.__init__(self, "BOOST_%s" % lib_base_name.upper(),
+                [default_lib_name],
+                help="Library names for Boost C++ %s library (without lib or .so)"
+                % humanize(lib_base_name))
+
+
+def set_up_shipped_boost_if_requested(project_name, conf, source_path=None,
+        boost_chrono=False):
+    """Set up the package to use a shipped version of Boost.
+
+    Return a tuple of a list of extra C files to build and extra
+    defines to be used.
+
+    :arg boost_chrono: one of *False* and ``"header_only"``
+        (only relevant in shipped mode)
+    """
+    from os.path import exists
+
+    if source_path is None:
+        source_path = "bpl-subset/bpl_subset"
+
+    if conf["USE_SHIPPED_BOOST"]:
+        if not exists("%s/boost/version.hpp" % source_path):
+            print(DASH_SEPARATOR)
+            print("The shipped Boost library was not found, but "
+                    "USE_SHIPPED_BOOST is True.")
+            print("(The files should be under %s/.)" % source_path)
+            print(DASH_SEPARATOR)
+            print("If you got this package from git, you probably want to do")
+            print("")
+            print(" $ git submodule update --init")
+            print("")
+            print("to fetch what you are presently missing. If you got this from")
+            print("a distributed package on the net, that package is broken and")
+            print("should be fixed. For now, I will turn off 'USE_SHIPPED_BOOST'")
+            print("to try and see if the build succeeds that way, but in the long")
+            print("run you might want to either get the missing bits or turn")
+            print("'USE_SHIPPED_BOOST' off.")
+            print(DASH_SEPARATOR)
+            conf["USE_SHIPPED_BOOST"] = False
+
+            count_down_delay(delay=10)
+
+    if conf["USE_SHIPPED_BOOST"]:
+        conf["BOOST_INC_DIR"] = [source_path]
+        conf["BOOST_LIB_DIR"] = []
+        conf["BOOST_PYTHON_LIBNAME"] = []
+        conf["BOOST_THREAD_LIBNAME"] = []
+
+        from glob import glob
+        source_files = (glob(source_path + "/libs/*/*/*/*.cpp")
+                + glob(source_path + "/libs/*/*/*.cpp")
+                + glob(source_path + "/libs/*/*.cpp"))
+
+        # make sure next line succeeds even on Windows
+        source_files = [f.replace("\\", "/") for f in source_files]
+
+        source_files = [f for f in source_files
+                if not f.startswith(source_path + "/libs/thread/src")]
+
+        if sys.platform == "win32":
+            source_files += glob(
+                    source_path + "/libs/thread/src/win32/*.cpp")
+            source_files += glob(
+                    source_path + "/libs/thread/src/tss_null.cpp")
+        else:
+            source_files += glob(
+                    source_path + "/libs/thread/src/pthread/*.cpp")
+
+        source_files = [f for f in source_files
+                if not f.endswith("once_atomic.cpp")]
+
+        from os.path import isdir
+        main_boost_inc = source_path + "/boost"
+        bpl_project_boost_inc = source_path + "/%sboost" % project_name
+
+        if not isdir(bpl_project_boost_inc):
+            try:
+                from os import symlink
+                symlink("boost", bpl_project_boost_inc)
+            except (ImportError, OSError):
+                from shutil import copytree
+                print("Copying files, hang on... (do not interrupt)")
+                copytree(main_boost_inc, bpl_project_boost_inc)
+
+        defines = {
+                # do not pick up libboost link dependency on windows
+                "BOOST_ALL_NO_LIB": 1,
+                "BOOST_THREAD_BUILD_DLL": 1,
+
+                "BOOST_MULTI_INDEX_DISABLE_SERIALIZATION": 1,
+                "BOOST_PYTHON_SOURCE": 1,
+                "boost": '%sboost' % project_name,
+                }
+
+        if boost_chrono is False:
+            defines["BOOST_THREAD_DONT_USE_CHRONO"] = 1
+        elif boost_chrono == "header_only":
+            defines["BOOST_CHRONO_HEADER_ONLY"] = 1
+        else:
+            raise ValueError("invalid value of 'boost_chrono'")
+
+        return (source_files, defines)
+    else:
+        return [], {}
+
+
+def make_boost_base_options():
+    return [
+        IncludeDir("BOOST", []),
+        LibraryDir("BOOST", []),
+        Option("BOOST_COMPILER", default="gcc43",
+            help="The compiler with which Boost C++ was compiled, e.g. gcc43"),
+        ]
+
+
+def configure_frontend():
+    from optparse import OptionParser
+
+    from setup import get_config_schema
+    schema = get_config_schema()
+    if schema.have_config():
+        print("************************************************************")
+        print("*** I have detected that you have already run configure.")
+        print("*** I'm taking the configured values as defaults for this")
+        print("*** configure run. If you don't want this, delete the file")
+        print("*** %s." % schema.get_conf_file())
+        print("************************************************************")
+
+    description = "generate a configuration file for this software package"
+    parser = OptionParser(description=description)
+    parser.add_option(
+            "--python-exe", dest="python_exe", default=sys.executable,
+            help="Which Python interpreter to use", metavar="PATH")
+
+    parser.add_option("--prefix", default=None,
+            help="Ignored")
+    parser.add_option("--enable-shared", help="Ignored", action="store_false")
+    parser.add_option("--disable-static", help="Ignored", action="store_false")
+    parser.add_option("--update-user",
+            help="Update user config file (%s)" % schema.user_conf_file,
+            action="store_true")
+    parser.add_option("--update-global",
+            help="Update global config file (%s)" % schema.global_conf_file,
+            action="store_true")
+
+    schema.add_to_configparser(parser, schema.read_config())
+
+    options, args = parser.parse_args()
+
+    config = schema.get_from_configparser(options)
+    schema.write_config(config)
+
+    if options.update_user:
+        schema.update_user_config(config)
+
+    if options.update_global:
+        schema.update_global_config(config)
+
+    import os
+    if os.access("Makefile.in", os.F_OK):
+        substs = schema.make_substitutions(config)
+        substs["PYTHON_EXE"] = options.python_exe
+
+        substitute(substs, "Makefile")
+
+
+def substitute(substitutions, fname):
+    import re
+    var_re = re.compile(r"\$\{([A-Za-z_0-9]+)\}")
+    string_var_re = re.compile(r"\$str\{([A-Za-z_0-9]+)\}")
+
+    fname_in = fname+".in"
+    lines = open(fname_in, "r").readlines()
+    new_lines = []
+    for l in lines:
+        made_change = True
+        while made_change:
+            made_change = False
+            match = var_re.search(l)
+            if match:
+                varname = match.group(1)
+                l = l[:match.start()] + str(substitutions[varname]) + l[match.end():]
+                made_change = True
+
+            match = string_var_re.search(l)
+            if match:
+                varname = match.group(1)
+                subst = substitutions[varname]
+                if subst is None:
+                    subst = ""
+                else:
+                    subst = '"%s"' % subst
+
+                l = l[:match.start()] + subst + l[match.end():]
+                made_change = True
+        new_lines.append(l)
+    new_lines.insert(1, "# DO NOT EDIT THIS FILE -- "
+            "it was generated by configure.py\n")
+    new_lines.insert(2, "# %s\n" % (" ".join(sys.argv)))
+    open(fname, "w").write("".join(new_lines))
+
+    from os import stat, chmod
+    infile_stat_res = stat(fname_in)
+    chmod(fname, infile_stat_res.st_mode)
+
+
+def _run_git_command(cmd):
+    git_error = None
+    from subprocess import Popen, PIPE
+    stdout = None
+    try:
+        popen = Popen(["git"] + cmd, stdout=PIPE)
+        stdout, stderr = popen.communicate()
+        if popen.returncode != 0:
+            git_error = "git returned error code %d: %s" % (popen.returncode, stderr)
+    except OSError:
+        git_error = "(OS error, likely git not found)"
+
+    if git_error is not None:
+        print(DASH_SEPARATOR)
+        print("Trouble invoking git")
+        print(DASH_SEPARATOR)
+        print("The package directory appears to be a git repository, but I could")
+        print("not invoke git to check whether my submodules are up to date.")
+        print("")
+        print("The error was:")
+        print(git_error)
+        print("Hit Ctrl-C now if you'd like to think about the situation.")
+        print(DASH_SEPARATOR)
+        count_down_delay(delay=0)
+    if stdout:
+        return stdout.decode("utf-8"), git_error
+    else:
+        return '', "(subprocess call to git did not succeed)"
+
+
+def check_git_submodules():
+    from os.path import isdir
+    if not isdir(".git"):
+        # not a git repository
+        return
+    if isdir("../.repo"):
+        # assume repo is in charge and bail
+        return
+
+    stdout, git_error = _run_git_command(["submodule", "status"])
+    if git_error is not None:
+        return
+
+    pkg_warnings = []
+
+    lines = stdout.split("\n")
+    for l in lines:
+        if not l.strip():
+            continue
+
+        status = l[0]
+        sha, package = l[1:].split(" ", 1)
+
+        if package == "bpl-subset" or (
+                package.startswith("boost") and package.endswith("subset")):
+            # treated separately
+            continue
+
+        if status == "+":
+            pkg_warnings.append("version of '%s' is not what this "
+                    "outer package wants" % package)
+        elif status == "-":
+            pkg_warnings.append("subpackage '%s' is not initialized"
+                    % package)
+        elif status == " ":
+            pass
+        else:
+            pkg_warnings.append("subpackage '%s' has unrecognized status '%s'"
+                    % package)
+
+    if pkg_warnings:
+            print(DASH_SEPARATOR)
+            print("git submodules are not up-to-date or in odd state")
+            print(DASH_SEPARATOR)
+            print("If this makes no sense, you probably want to say")
+            print("")
+            print(" $ git submodule update --init")
+            print("")
+            print("to fetch what you are presently missing and "
+                    "move on with your life.")
+            print("If you got this from a distributed package on the "
+                    "net, that package is")
+            print("broken and should be fixed. Please inform whoever "
+                    "gave you this package.")
+            print("")
+            print("These issues were found:")
+            for w in pkg_warnings:
+                print("  %s" % w)
+            print("")
+            print("I will try to initialize the submodules for you "
+                    "after a short wait.")
+            print(DASH_SEPARATOR)
+            print("Hit Ctrl-C now if you'd like to think about the situation.")
+            print(DASH_SEPARATOR)
+
+            from os.path import exists
+            if not exists(".dirty-git-ok"):
+                count_down_delay(delay=10)
+                stdout, git_error = _run_git_command(
+                        ["submodule", "update", "--init"])
+                if git_error is None:
+                    print(DASH_SEPARATOR)
+                    print("git submodules initialized successfully")
+                    print(DASH_SEPARATOR)
diff --git a/meshpy/configure.py b/meshpy/configure.py
new file mode 100755
index 0000000000000000000000000000000000000000..63edd4b997e7a83f6d182359cbafe5078b126a60
--- /dev/null
+++ b/meshpy/configure.py
@@ -0,0 +1,6 @@
+#! /usr/bin/env python
+
+from __future__ import absolute_import
+
+from aksetup_helper import configure_frontend
+configure_frontend()
diff --git a/meshpy/contrib/extract-gmsh-node-order/cube.geo b/meshpy/contrib/extract-gmsh-node-order/cube.geo
new file mode 100644
index 0000000000000000000000000000000000000000..71553022dffeaaf609e81c2138048d41c3dd41f6
--- /dev/null
+++ b/meshpy/contrib/extract-gmsh-node-order/cube.geo
@@ -0,0 +1,19 @@
+Mesh.RecombineAll=1;
+Mesh.Recombine3DAll=1;
+Mesh.Algorithm = 8;
+Mesh.Algorithm3D = 9;
+Mesh.Smoothing = 0;
+
+Mesh.ElementOrder = 4;
+
+Point(1) = {0, 0, 0, 3};
+
+line_out[] = Extrude {1,0,0} {
+  Point{1}; Recombine;
+};
+surf_out[] = Extrude {0,1,0} {
+  Line{line_out[1]}; Recombine;
+};
+vol_out[] = Extrude {0,0,1} {
+  Surface{surf_out[1]}; Recombine;
+};
diff --git a/meshpy/contrib/extract-gmsh-node-order/extract-node-order.py b/meshpy/contrib/extract-gmsh-node-order/extract-node-order.py
new file mode 100644
index 0000000000000000000000000000000000000000..ab9828e706ff77662e17fb7226db0ce60f895512
--- /dev/null
+++ b/meshpy/contrib/extract-gmsh-node-order/extract-node-order.py
@@ -0,0 +1,757 @@
+import numpy as np
+import io
+
+element = "72 191 387 142 6 44 338 37 197 196 195 146 147 148 76 77 78 393 392 391 207 208 209 390 389 388 451 452 453 158 159 160 45 46 47 43 42 41 339 340 341 342 343 344 398 397 400 399 401 404 403 402 405 210 211 212 213 214 215 216 217 218 161 164 163 162 168 167 166 165 169 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 345 346 347 348 349 350 351 352 353 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498"
+
+nodes = """
+1 0 0 0
+2 1 0 0
+3 0 1 0
+4 1 1 0
+5 0 0 1
+6 1 0 1
+7 1 1 1
+8 0 1 1
+9 0.4999999999986938 0 0
+10 0.124999999999778 0 0
+11 0.2499999999994166 0 0
+12 0.3749999999990552 0 0
+13 0.6249999999990203 0 0
+14 0.7499999999993469 0 0
+15 0.8749999999996734 0 0
+16 0.4999999999986938 1 0
+17 0.124999999999778 1 0
+18 0.2499999999994166 1 0
+19 0.3749999999990552 1 0
+20 0.6249999999990203 1 0
+21 0.7499999999993469 1 0
+22 0.8749999999996734 1 0
+23 0 0.4999999999986938 0
+24 0 0.124999999999778 0
+25 0 0.2499999999994166 0
+26 0 0.3749999999990552 0
+27 0 0.6249999999990203 0
+28 0 0.7499999999993469 0
+29 0 0.8749999999996734 0
+30 1 0.4999999999986938 0
+31 1 0.124999999999778 0
+32 1 0.2499999999994166 0
+33 1 0.3749999999990552 0
+34 1 0.6249999999990203 0
+35 1 0.7499999999993469 0
+36 1 0.8749999999996734 0
+37 0.4999999999986938 0 1
+38 0.124999999999778 0 1
+39 0.2499999999994166 0 1
+40 0.3749999999990552 0 1
+41 0.6249999999990203 0 1
+42 0.7499999999993469 0 1
+43 0.8749999999996734 0 1
+44 1 0.4999999999986938 1
+45 1 0.124999999999778 1
+46 1 0.2499999999994166 1
+47 1 0.3749999999990552 1
+48 1 0.6249999999990203 1
+49 1 0.7499999999993469 1
+50 1 0.8749999999996734 1
+51 0.5000000000020601 1 1
+52 0.8750000000001986 1 1
+53 0.7500000000007291 1 1
+54 0.6250000000013878 1 1
+55 0.3750000000015452 1 1
+56 0.2500000000010302 1 1
+57 0.1250000000005151 1 1
+58 0 0.5000000000020601 1
+59 0 0.8750000000001986 1
+60 0 0.7500000000007291 1
+61 0 0.6250000000013878 1
+62 0 0.3750000000015452 1
+63 0 0.2500000000010302 1
+64 0 0.1250000000005151 1
+65 0 0 0.4999999999986938
+66 0 0 0.124999999999778
+67 0 0 0.2499999999994166
+68 0 0 0.3749999999990552
+69 0 0 0.6249999999990203
+70 0 0 0.7499999999993469
+71 0 0 0.8749999999996734
+72 1 0 0.4999999999986938
+73 1 0 0.124999999999778
+74 1 0 0.2499999999994166
+75 1 0 0.3749999999990552
+76 1 0 0.6249999999990203
+77 1 0 0.7499999999993469
+78 1 0 0.8749999999996734
+79 1 1 0.4999999999986938
+80 1 1 0.124999999999778
+81 1 1 0.2499999999994166
+82 1 1 0.3749999999990552
+83 1 1 0.6249999999990203
+84 1 1 0.7499999999993469
+85 1 1 0.8749999999996734
+86 0 1 0.4999999999986938
+87 0 1 0.124999999999778
+88 0 1 0.2499999999994166
+89 0 1 0.3749999999990552
+90 0 1 0.6249999999990203
+91 0 1 0.7499999999993469
+92 0 1 0.8749999999996734
+93 0.499999998874093 0.500000001125907 0
+94 0.8749999997185233 0.5000000002804972 0
+95 0.7499999994370465 0.5000000005623004 0
+96 0.6249999991555698 0.5000000008441037 0
+97 0.4999999991552432 0.3750000008444303 0
+98 0.4999999994363934 0.2500000005629535 0
+99 0.4999999997175436 0.1250000002814767 0
+100 0.6249999997881583 0.1250000002110518 0
+101 0.8749999999293866 0.1250000000702025 0
+102 0.8749999997888104 0.3750000002103984 0
+103 0.6249999993664328 0.375000000633086 0
+104 0.7499999998587721 0.1250000001406271 0
+105 0.8749999998590984 0.2500000001403005 0
+106 0.7499999995776221 0.3750000004217424 0
+107 0.6249999995772957 0.2500000004220689 0
+108 0.7499999997181972 0.2500000002811847 0
+109 0.3749999991555698 0.5000000008441037 0
+110 0.2499999994370465 0.5000000005623004 0
+111 0.1249999997185233 0.5000000002804972 0
+112 0.1249999997888367 0.3750000002103984 0
+113 0.1249999999294641 0.1250000000702019 0
+114 0.3749999997881833 0.1250000002110512 0
+115 0.3749999993664407 0.3750000006330858 0
+116 0.1249999998591504 0.2500000001403002 0
+117 0.2499999998588238 0.1250000001406266 0
+118 0.3749999995773122 0.2500000004220685 0
+119 0.2499999995776387 0.3750000004217422 0
+120 0.2499999997182313 0.2500000002811844 0
+121 0.4999999991552432 0.6250000008444303 0
+122 0.4999999994363934 0.7500000005629535 0
+123 0.4999999997175436 0.8750000002814767 0
+124 0.6249999997881583 0.8750000002110261 0
+125 0.8749999999293866 0.8750000000701244 0
+126 0.8749999997888104 0.6250000002103722 0
+127 0.6249999993664328 0.6250000006330778 0
+128 0.7499999998587721 0.8750000001405749 0
+129 0.8749999998590984 0.7500000001402483 0
+130 0.7499999995776221 0.6250000004217252 0
+131 0.6249999995772957 0.7500000004220519 0
+132 0.7499999997181972 0.7500000002811502 0
+133 0.3749999997881832 0.8750000002110261 0
+134 0.1249999999294635 0.8750000000701244 0
+135 0.1249999997888361 0.6250000002103722 0
+136 0.3749999993664406 0.6250000006330778 0
+137 0.2499999998588234 0.8750000001405749 0
+138 0.1249999998591499 0.7500000001402483 0
+139 0.2499999995776384 0.6250000004217252 0
+140 0.3749999995773119 0.7500000004220519 0
+141 0.2499999997182309 0.7500000002811502 0
+142 0.499999998874093 0 0.500000001125907
+143 0.4999999991552432 0 0.3750000008444303
+144 0.4999999994363934 0 0.2500000005629535
+145 0.4999999997175436 0 0.1250000002814767
+146 0.8749999997185233 0 0.5000000002804972
+147 0.7499999994370465 0 0.5000000005623004
+148 0.6249999991555698 0 0.5000000008441037
+149 0.6249999993664321 0 0.3750000006330859
+150 0.6249999997881575 0 0.1250000002110513
+151 0.874999999929385 0 0.1250000000702018
+152 0.87499999978881 0 0.3750000002103984
+153 0.6249999995772946 0 0.2500000004220685
+154 0.749999999858771 0 0.1250000001406266
+155 0.8749999998590977 0 0.2500000001403003
+156 0.7499999995776214 0 0.3750000004217422
+157 0.7499999997181963 0 0.2500000002811844
+158 0.4999999991552432 0 0.6250000008444303
+159 0.4999999994363934 0 0.7500000005629535
+160 0.4999999997175436 0 0.8750000002814767
+161 0.87499999978881 0 0.6250000002103727
+162 0.6249999993664316 0 0.6250000006330776
+163 0.6249999997881563 0 0.8750000002110248
+164 0.8749999999293853 0 0.8750000000701237
+165 0.7499999995776208 0 0.6250000004217251
+166 0.6249999995772939 0 0.7500000004220511
+167 0.7499999998587709 0 0.8750000001405743
+168 0.8749999998590977 0 0.7500000001402483
+169 0.7499999997181959 0 0.7500000002811498
+170 0.1249999997185233 0 0.5000000002804972
+171 0.2499999994370465 0 0.5000000005623004
+172 0.3749999991555698 0 0.5000000008441037
+173 0.1249999997888375 0 0.3750000002103993
+174 0.3749999993664418 0 0.3750000006330866
+175 0.374999999788184 0 0.125000000211052
+176 0.1249999999294649 0 0.125000000070203
+177 0.2499999995776395 0 0.3750000004217429
+178 0.3749999995773129 0 0.2500000004220693
+179 0.2499999998588245 0 0.1250000001406275
+180 0.1249999998591512 0 0.2500000001403011
+181 0.2499999997182321 0 0.2500000002811852
+182 0.1249999999294641 0 0.8750000000701235
+183 0.1249999997888368 0 0.6250000002103722
+184 0.3749999993664406 0 0.6250000006330765
+185 0.3749999997881835 0 0.8750000002110253
+186 0.1249999998591503 0 0.7500000001402476
+187 0.2499999995776387 0 0.6250000004217243
+188 0.3749999995773122 0 0.7500000004220508
+189 0.2499999998588238 0 0.8750000001405743
+190 0.2499999997182312 0 0.7500000002811493
+191 1 0.5000000025136858 0.5000000025136859
+192 1 0.5000000006274419 0.1250000006284215
+193 1 0.5000000012561898 0.250000001256843
+194 1 0.5000000018849378 0.3750000018852644
+195 1 0.3750000018852644 0.5000000018849379
+196 1 0.2500000012568429 0.5000000012561898
+197 1 0.1250000006284214 0.5000000006274419
+198 1 0.1250000004712603 0.3750000004706069
+199 1 0.1250000001569387 0.1250000001569381
+200 1 0.3750000004706069 0.1250000004712598
+201 1 0.3750000014137116 0.3750000014137115
+202 1 0.1250000003140995 0.2500000003137725
+203 1 0.2500000003137729 0.125000000314099
+204 1 0.3750000009421595 0.2500000009424857
+205 1 0.250000000942486 0.3750000009421592
+206 1 0.2500000006281294 0.2500000006281291
+207 1 0.5000000018849378 0.6250000018852644
+208 1 0.5000000012561898 0.750000001256843
+209 1 0.5000000006274419 0.8750000006284215
+210 1 0.1250000004712611 0.6250000004705811
+211 1 0.3750000014137127 0.6250000014137033
+212 1 0.3750000004706078 0.8750000004712335
+213 1 0.1250000001569394 0.8750000001568599
+214 1 0.2500000009424868 0.6250000009421419
+215 1 0.3750000009421603 0.7500000009424683
+216 1 0.2500000003137737 0.8750000003140468
+217 1 0.1250000003141002 0.7500000003137206
+218 1 0.2500000006281303 0.7500000006280944
+219 1 0.6250000018852644 0.5000000018849379
+220 1 0.7500000012568429 0.5000000012561898
+221 1 0.8750000006284214 0.5000000006274419
+222 1 0.8750000004712346 0.3750000004706069
+223 1 0.8750000001568605 0.1250000001569381
+224 1 0.6250000004705807 0.1250000004712598
+225 1 0.6250000014137034 0.3750000014137115
+226 1 0.8750000003140472 0.2500000003137726
+227 1 0.7500000003137206 0.125000000314099
+228 1 0.6250000009421423 0.2500000009424857
+229 1 0.750000000942469 0.3750000009421592
+230 1 0.7500000006280949 0.2500000006281291
+231 1 0.8750000001568606 0.8750000001568596
+232 1 0.8750000004712345 0.6250000004705807
+233 1 0.6250000014137027 0.625000001413702
+234 1 0.6250000004705816 0.8750000004712338
+235 1 0.8750000003140473 0.7500000003137199
+236 1 0.7500000009424685 0.6250000009421413
+237 1 0.6250000009421423 0.750000000942468
+238 1 0.750000000313721 0.8750000003140468
+239 1 0.7500000006280949 0.7500000006280941
+240 0.3943375672963764 1 0.3943375672963763
+241 0.5457531754722823 1 0.4207531754719557
+242 0.6971687836481881 1 0.447168783647535
+243 0.8485843918240941 1 0.4735843918231144
+244 0.4735843918231144 1 0.09858439182409406
+245 0.4471687836475351 1 0.1971687836481881
+246 0.4207531754719558 1 0.2957531754722822
+247 0.5655648816039676 1 0.3155648816039757
+248 0.8551882938679898 1 0.3551882938673622
+249 0.8683960979557794 1 0.118396097955857
+250 0.6051882938673364 1 0.1051882938680154
+251 0.7103765877359787 1 0.3353765877356688
+252 0.8617921959118846 1 0.2367921959116096
+253 0.736792195911558 1 0.1117921959119362
+254 0.5853765877356519 1 0.2103765877359955
+255 0.7235843918237682 1 0.2235843918238026
+256 0.4207531754727973 1 0.5457531754722822
+257 0.4471687836492182 1 0.6971687836481881
+258 0.4735843918256392 1 0.8485843918240941
+259 0.8683960979561727 1 0.8683960979557778
+260 0.8551882938681203 1 0.6051882938673351
+261 0.5655648816045593 1 0.5655648816039655
+262 0.6051882938691119 1 0.8551882938679883
+263 0.8617921959121465 1 0.7367921959115562
+264 0.7103765877363237 1 0.5853765877356503
+265 0.5853765877368353 1 0.7103765877359769
+266 0.736792195912594 1 0.8617921959118831
+267 0.7235843918244589 1 0.7235843918237668
+268 0.2957531754722823 1 0.4207531754719557
+269 0.1971687836481881 1 0.447168783647535
+270 0.09858439182409406 1 0.4735843918231144
+271 0.3551882938692296 1 0.8551882938679881
+272 0.3155648816045981 1 0.5655648816039659
+273 0.1051882938682003 1 0.6051882938673343
+274 0.1183960979564103 1 0.868396097955778
+275 0.3353765877369141 1 0.7103765877359769
+276 0.2103765877363992 1 0.5853765877356503
+277 0.1117921959123052 1 0.7367921959115562
+278 0.2367921959128199 1 0.8617921959118831
+279 0.2235843918246095 1 0.7235843918237668
+280 0.3551882938673615 1 0.1051882938680149
+281 0.1183960979558564 1 0.1183960979558569
+282 0.1051882938680154 1 0.3551882938673614
+283 0.3155648816039751 1 0.3155648816039752
+284 0.2367921959116093 1 0.1117921959119359
+285 0.1117921959119359 1 0.2367921959116093
+286 0.210376587735995 1 0.3353765877356684
+287 0.3353765877356683 1 0.210376587735995
+288 0.2235843918238021 1 0.2235843918238022
+289 0 0.6056624327015634 0.3943375672984366
+290 0 0.579246824525846 0.2957531754738275
+291 0 0.5528312163501286 0.1971687836492183
+292 0 0.5264156081744112 0.09858439182460915
+293 0 0.1514156081753908 0.4735843918236295
+294 0 0.3028312163507817 0.4471687836485652
+295 0 0.4542468245261726 0.4207531754735009
+296 0 0.4344351183943934 0.3155648816051338
+297 0 0.3948117061308349 0.1051882938684007
+298 0 0.1316039020436821 0.118396097955985
+299 0 0.1448117061314881 0.3551882938677476
+300 0 0.4146234122626143 0.2103765877367672
+301 0 0.2632078040872585 0.1117921959121929
+302 0 0.1382078040875848 0.2367921959118665
+303 0 0.2896234122629409 0.3353765877364407
+304 0 0.2764156081750995 0.2235843918243169
+305 0 0.5792468245266875 0.5457531754738274
+306 0 0.5528312163518118 0.6971687836492183
+307 0 0.526415608176936 0.8485843918246092
+308 0 0.131603902044234 0.8683960979559066
+309 0 0.1448117061316717 0.6051882938677213
+310 0 0.4344351183950163 0.5655648816051242
+311 0 0.3948117061327019 0.8551882938683747
+312 0 0.1382078040879531 0.7367921959118139
+313 0 0.2896234122633441 0.5853765877364228
+314 0 0.4146234122638589 0.7103765877367495
+315 0 0.2632078040884678 0.8617921959121406
+316 0 0.2764156081759059 0.7235843918242818
+317 0 0.9014156081753908 0.4735843918236295
+318 0 0.8028312163507817 0.4471687836485652
+319 0 0.7042468245261726 0.4207531754735009
+320 0 0.6448117061325844 0.8551882938683755
+321 0 0.8816039020439973 0.8683960979559074
+322 0 0.8948117061315936 0.6051882938677215
+323 0 0.6844351183949768 0.5655648816051259
+324 0 0.7632078040882428 0.8617921959121413
+325 0 0.8882078040877954 0.7367921959118144
+326 0 0.789623412263269 0.5853765877364239
+327 0 0.6646234122637806 0.7103765877367507
+328 0 0.7764156081757559 0.7235843918242828
+329 0 0.8816039020436022 0.1183960979559855
+330 0 0.6448117061308078 0.1051882938684011
+331 0 0.6844351183943842 0.3155648816051339
+332 0 0.8948117061314609 0.3551882938677479
+333 0 0.7632078040872051 0.1117921959121933
+334 0 0.664623412262596 0.2103765877367675
+335 0 0.7896234122629225 0.335376587736441
+336 0 0.8882078040875316 0.2367921959118667
+337 0 0.7764156081750637 0.2235843918243172
+338 0.5000000002611179 0.4999999997388821 1
+339 0.8750000000652794 0.4999999999337409 1
+340 0.7500000001305589 0.499999999868788 1
+341 0.6250000001958385 0.499999999803835 1
+342 0.5000000001955118 0.3749999998041615 1
+343 0.5000000001299059 0.249999999869441 1
+344 0.5000000000642999 0.1249999999347206 1
+345 0.8750000000160754 0.1249999999835142 1
+346 0.875000000048878 0.3749999999503324 1
+347 0.6250000001466334 0.3749999998528852 1
+348 0.6250000000482252 0.1249999999509854 1
+349 0.8750000000324762 0.2499999999669232 1
+350 0.7500000000977556 0.3749999999016088 1
+351 0.6250000000974291 0.2499999999019355 1
+352 0.7500000000321503 0.1249999999672498 1
+353 0.7500000000649529 0.2499999999344293 1
+354 0.3750000001958385 0.4999999998046766 1
+355 0.250000000130559 0.4999999998704712 1
+356 0.1250000000652794 0.4999999999362656 1
+357 0.125000000016154 0.1249999999840663 1
+358 0.3750000000482518 0.124999999951169 1
+359 0.3750000001466429 0.374999999853507 1
+360 0.1250000000489046 0.374999999952199 1
+361 0.2500000000322027 0.1249999999676176 1
+362 0.3750000000974473 0.249999999902338 1
+363 0.2500000000977738 0.374999999902853 1
+364 0.1250000000325292 0.2499999999681326 1
+365 0.2500000000649883 0.2499999999352354 1
+366 0.5000000001963535 0.6249999998041615 1
+367 0.500000000131589 0.7499999998694411 1
+368 0.5000000000668245 0.8749999999347206 1
+369 0.875000000016469 0.8749999999834345 1
+370 0.8750000000490094 0.6249999999503049 1
+371 0.6250000001472252 0.6249999998528748 1
+372 0.6250000000500004 0.8749999999509582 1
+373 0.8750000000327389 0.7499999999668695 1
+374 0.7500000000981012 0.6249999999015898 1
+375 0.625000000098613 0.7499999999019166 1
+376 0.7500000000331868 0.8749999999671962 1
+377 0.7500000000656439 0.7499999999343931 1
+378 0.3750000001472645 0.6249999998534679 1
+379 0.1250000000490876 0.6249999999520811 1
+380 0.1250000000167054 0.8749999999838282 1
+381 0.3750000000501178 0.8749999999510895 1
+382 0.250000000098176 0.6249999999027742 1
+383 0.1250000000328966 0.7499999999679064 1
+384 0.2500000000334118 0.8749999999674589 1
+385 0.3750000000986912 0.7499999999022626 1
+386 0.2500000000657939 0.7499999999350848 1
+387 0.499999998874093 0.500000001125907 0.4999999999998944
+388 0.499999998874093 0.1250000002814768 0.5000000008444039
+389 0.499999998874093 0.2500000005629535 0.5000000005629007
+390 0.499999998874093 0.3750000008444303 0.5000000002813976
+391 0.6249999991555697 0.5000000014728517 0.5000000006283423
+392 0.7499999994370465 0.5000000018197964 0.5000000012567901
+393 0.8749999997185233 0.5000000021667411 0.5000000018852381
+394 0.499999998874093 0.500000001125907 0.3749999999999208
+395 0.499999998874093 0.500000001125907 0.2499999999999472
+396 0.499999998874093 0.500000001125907 0.1249999999999736
+397 0.6249999991555697 0.1250000003682129 0.5000000007901634
+398 0.8749999997185233 0.1250000005416853 0.5000000006816824
+399 0.8749999997185233 0.3750000016250559 0.5000000014840529
+400 0.6249999991555697 0.3750000011046388 0.5000000006822827
+401 0.7499999994370464 0.1250000004549491 0.5000000007359229
+402 0.8749999997185233 0.2500000010833706 0.5000000010828676
+403 0.7499999994370465 0.3750000013648473 0.5000000010831677
+404 0.6249999991555697 0.2500000007364259 0.500000000736223
+405 0.7499999994370465 0.2500000009098982 0.5000000009095453
+406 0.4999999990849556 0.1250000002814768 0.3750000006333029
+407 0.4999999989443805 0.3750000008444303 0.3750000002110482
+408 0.4999999990849557 0.3750000008444303 0.1250000000703494
+409 0.4999999995066809 0.1250000002814768 0.125000000211101
+410 0.4999999990146681 0.2500000005629535 0.3750000004221755
+411 0.4999999990146681 0.3750000008444303 0.2500000001406988
+412 0.4999999992958183 0.2500000005629535 0.1250000001407252
+413 0.4999999992958183 0.1250000002814768 0.2500000004222019
+414 0.4999999991552432 0.2500000005629535 0.2500000002814504
+415 0.6249999991555697 0.5000000013156647 0.3750000004712567
+416 0.8749999997185233 0.5000000016951801 0.3750000014139285
+417 0.8749999997185233 0.5000000007520581 0.1250000004713095
+418 0.6249999991555697 0.5000000010012907 0.1250000001570856
+419 0.7499999994370464 0.5000000015054225 0.3750000009425926
+420 0.8749999997185233 0.5000000012236191 0.250000000942619
+421 0.7499999994370465 0.5000000008766744 0.1250000003141975
+422 0.6249999991555697 0.5000000011584778 0.2500000003141711
+423 0.7499999994370465 0.5000000011910484 0.2500000006283951
+424 0.6249999993137308 0.1250000003289326 0.3750000005926322
+425 0.8749999997712471 0.1250000004238157 0.3750000005112815
+426 0.8749999998766644 0.1250000001880734 0.1250000001704734
+427 0.6249999996300275 0.1250000002503553 0.125000000197568
+428 0.6249999992082922 0.375000000986755 0.3750000005117155
+429 0.8749999997361178 0.375000001271394 0.3750000011130505
+430 0.8749999997712339 0.3750000005640707 0.1250000003710316
+431 0.6249999993137062 0.3750000007509804 0.1250000001705768
+432 0.7499999995424935 0.1250000003763763 0.3750000005519594
+433 0.6249999994718725 0.1250000002896434 0.2500000003950982
+434 0.6249999992610163 0.2500000006578457 0.375000000552175
+435 0.8749999998239582 0.1250000003059454 0.250000000340879
+436 0.8749999997536918 0.2500000008476077 0.3750000008121686
+437 0.7499999997533525 0.1250000002192199 0.1250000001840248
+438 0.8749999998239592 0.2500000003760758 0.1250000002707549
+439 0.6249999994718716 0.2500000005006723 0.1250000001840764
+440 0.7499999994722067 0.3750000011290756 0.3750000008123838
+441 0.6249999992609914 0.3750000008688647 0.2500000003411424
+442 0.8749999997536816 0.3750000009177321 0.2500000007420408
+443 0.7499999995424647 0.3750000006575266 0.1250000002708
+444 0.7499999996479201 0.125000000297798 0.2500000003679916
+445 0.7499999995073583 0.2500000007527278 0.3750000006821752
+446 0.6249999993664361 0.2500000005792576 0.2500000003681237
+447 0.8749999997888229 0.2500000006118416 0.2500000005414613
+448 0.7499999996479192 0.2500000004383763 0.1250000002274181
+449 0.7499999995073339 0.3750000008932995 0.2500000005415889
+450 0.7499999995776333 0.2500000005955513 0.2500000004547944
+451 0.4999999992208493 0.5000000007791509 0.6249999999999207
+452 0.4999999995676054 0.5000000004323946 0.7499999999999472
+453 0.4999999999143617 0.5000000000856383 0.8749999999999736
+454 0.8749999998052123 0.5000000016084911 0.6250000014139285
+455 0.624999999415637 0.5000000010555976 0.6250000004712567
+456 0.6249999999357713 0.5000000002210891 0.8750000001570856
+457 0.8749999999785905 0.5000000004919909 0.8750000004713095
+458 0.7499999996104246 0.5000000013320444 0.6250000009425927
+459 0.6249999996757041 0.5000000006383434 0.7500000003141711
+460 0.7499999999571809 0.50000000035654 0.8750000003141976
+461 0.8749999998919014 0.500000001050241 0.7500000009426191
+462 0.7499999997838027 0.5000000008442922 0.7500000006283951
+463 0.4999999992044477 0.3750000005843631 0.6250000002110482
+464 0.4999999991716447 0.1250000001947877 0.625000000633303
+465 0.4999999997667481 0.1250000000214096 0.8750000002111009
+466 0.4999999998651572 0.3750000000642287 0.8750000000703494
+467 0.4999999991880462 0.2500000003895754 0.6250000004221755
+468 0.4999999994691964 0.1250000001080986 0.7500000004222019
+469 0.4999999998159527 0.2500000000428191 0.8750000001407252
+470 0.4999999995348025 0.3750000003242959 0.7500000001406988
+471 0.4999999995019995 0.2500000002161973 0.7500000002814504
+472 0.8749999997929233 0.1250000004021479 0.6250000005112808
+473 0.8749999998011183 0.3750000012063794 0.6250000011130464
+474 0.6249999994033272 0.3750000007916983 0.6250000005117089
+475 0.6249999993787542 0.1250000002639102 0.6250000005926483
+476 0.8749999999416932 0.12500000012306 0.8750000001704286
+477 0.8749999999663061 0.3750000003690245 0.8750000003710272
+478 0.6249999998988636 0.3750000001658217 0.8750000001705759
+479 0.6249999998250568 0.1250000000552856 0.8750000001975418
+480 0.8749999997970254 0.2500000008042647 0.6250000008121679
+481 0.749999999585833 0.1250000003330269 0.6250000005519594
+482 0.8749999998673121 0.1250000002626061 0.750000000340859
+483 0.7499999996022247 0.3750000009990393 0.6250000008123792
+484 0.8749999998837211 0.3750000007877042 0.750000000742047
+485 0.6249999993910498 0.2500000005278059 0.6250000005521897
+486 0.6249999996511059 0.3750000004787618 0.7500000003411533
+487 0.6249999996019113 0.1250000001596002 0.7500000003951004
+488 0.8749999999540006 0.2500000002460432 0.8750000002707303
+489 0.7499999998833661 0.1250000000891698 0.8750000001839766
+490 0.749999999932589 0.3750000002674255 0.8750000002708052
+491 0.6249999998619524 0.250000000110552 0.8750000001840567
+492 0.7499999995940344 0.2500000006660346 0.6250000006821768
+493 0.8749999998755233 0.2500000005251561 0.7500000005414567
+494 0.7499999997346043 0.125000000211101 0.7500000003679745
+495 0.7499999997674098 0.3750000006332341 0.7500000005415969
+496 0.6249999996265153 0.2500000003191813 0.750000000368134
+497 0.7499999999079705 0.2500000001782982 0.875000000227389
+498 0.7499999997510109 0.2500000004221687 0.7500000004547891
+499 0.1249999997185233 0.5792468248076493 0.420753175473801
+500 0.2499999994370465 0.5528312169137353 0.4471687836491655
+501 0.3749999991555698 0.5264156090198211 0.4735843918245299
+502 0.1249999997185233 0.434435118605737 0.4405648816754751
+503 0.1249999997185233 0.1448117062019123 0.4801882940788231
+504 0.3749999991555698 0.1316039022549553 0.4933960985892103
+505 0.3749999991555698 0.3948117067648659 0.4801882940794234
+506 0.1249999997185233 0.2896234124038247 0.460376587877149
+507 0.2499999994370465 0.1382078042284338 0.4867921963340167
+508 0.3749999991555698 0.2632078045099105 0.4867921963343168
+509 0.2499999994370465 0.4146234126853015 0.4603765878774492
+510 0.2499999994370465 0.2764156084568676 0.4735843921057329
+511 0.1249999997185233 0.5594351186758613 0.3155648816053508
+512 0.3749999991555698 0.5198117069758919 0.3551882938683975
+513 0.3749999991555698 0.5066039028880331 0.1183960979561325
+514 0.1249999997185233 0.5198117064122851 0.1051882938684503
+515 0.2499999994370465 0.5396234128258766 0.3353765877368741
+516 0.3749999991555698 0.5132078049319624 0.236792195912265
+517 0.2499999994370465 0.5132078046501591 0.1117921959122914
+518 0.1249999997185233 0.5396234125440732 0.2103765877369005
+519 0.2499999994370465 0.5264156087380178 0.2235843918245827
+520 0.1249999997361066 0.4195763390069061 0.3304236612566116
+521 0.3749999992082915 0.3898587802319221 0.3601412205595738
+522 0.3749999993137214 0.1299529267439741 0.3700470739419112
+523 0.1249999997712628 0.1398587796689935 0.3601412205591361
+524 0.1249999997712611 0.3898587798092351 0.1101412204188884
+525 0.374999999313734 0.3799529271660355 0.1200470735198712
+526 0.3749999996300281 0.1266509757220266 0.1233490246473116
+527 0.1249999998767224 0.1299529266031298 0.1200470735197548
+528 0.2499999994722002 0.4047175596194167 0.345282440908093
+529 0.1249999997536827 0.2797175593379478 0.3452824409078702
+530 0.1249999997536861 0.4047175594080718 0.2202824408377507
+531 0.3749999992610069 0.2599058534879497 0.3650941472507425
+532 0.3749999992610151 0.3849058536989817 0.2400941470397263
+533 0.2499999995424936 0.1349058532064879 0.3650941472505233
+534 0.3749999994718767 0.1283019512330027 0.246698049294615
+535 0.1249999998239949 0.1349058531360653 0.240094147039443
+536 0.2499999995424988 0.3849058534876362 0.1150941469693791
+537 0.1249999998239888 0.2599058532061784 0.1150941469693198
+538 0.3749999994718836 0.2533019514440306 0.1216980490835956
+539 0.2499999997533738 0.1283019511625738 0.1216980490835288
+540 0.2499999995073462 0.2698117064129519 0.3551882940793059
+541 0.2499999995073517 0.3948117065535303 0.2301882939387398
+542 0.1249999997888383 0.269811706272066 0.2301882939385931
+543 0.3749999993664467 0.2566039024659912 0.2433960981671682
+544 0.2499999996479361 0.1316039021845369 0.2433960981670306
+545 0.2499999996479365 0.2566039023251014 0.1183960980264532
+546 0.2499999995776437 0.2632078043690307 0.2367921960528808
+547 0.4207531751908056 0.8750000002814767 0.4207531754722558
+548 0.4471687830852347 0.7500000005629535 0.4471687836481353
+549 0.4735843909796639 0.6250000008444303 0.4735843918240148
+550 0.44056488132249 0.8750000002814767 0.3155648816041918
+551 0.4801882935858591 0.8750000002814767 0.1051882938680639
+552 0.4933960971113484 0.6250000008444303 0.1183960979560037
+553 0.4801882930235587 0.6250000008444303 0.3551882938680112
+554 0.4603765874541746 0.8750000002814768 0.2103765877361279
+555 0.4867921953486037 0.7500000005629536 0.1117921959120338
+556 0.4867921950674535 0.6250000008444303 0.2367921959120074
+557 0.4603765871730244 0.7500000005629536 0.3353765877361015
+558 0.4735843912608141 0.7500000005629535 0.2235843918240676
+559 0.5655648813931041 0.8750000003682129 0.4405648817610523
+560 0.6051882932347479 0.6250000011046388 0.4801882943392456
+561 0.868396097744916 0.6250000016250559 0.4933960993697071
+562 0.8551882937977013 0.8750000005416853 0.4801882943386453
+563 0.5853765873139261 0.7500000007364259 0.460376588050149
+564 0.736792195489832 0.6250000013648473 0.4867921968544764
+565 0.8617921957713086 0.7500000010833705 0.4867921968541762
+566 0.7103765875954028 0.8750000004549491 0.4603765880498488
+567 0.7235843915426173 0.7500000009098982 0.4735843924521626
+568 0.5804236609918825 0.8750000003289237 0.3304236613207999
+569 0.6101412201894046 0.8750000002503315 0.1101412204402843
+570 0.8700470733964648 0.8750000001880077 0.1200470735847191
+571 0.8601412203306407 0.8750000004238078 0.360141220754012
+572 0.6101412197676769 0.6250000009867535 0.360141220754439
+573 0.620047072833531 0.625000000750988 0.1200470735848187
+574 0.8733490242778331 0.6250000005640284 0.1233490248424457
+575 0.8700470732558825 0.6250000012713717 0.3700470745272904
+576 0.5952824405906465 0.8750000002896308 0.2202824408805432
+577 0.720282440661255 0.8750000003763572 0.3452824410374039
+578 0.5952824403797832 0.7500000006578418 0.3452824410376194
+579 0.7400941467929361 0.8750000002191718 0.1150941470125027
+580 0.6150941465114781 0.7500000005006707 0.1150941470125558
+581 0.8650941468635595 0.8750000003059132 0.2400941471693691
+582 0.871698048837161 0.75000000037603 0.1216980492135879
+583 0.8650941467932609 0.7500000008475891 0.3650941476406505
+584 0.615094146300604 0.625000000868872 0.2400941471696282
+585 0.7400941465117741 0.6250000011290558 0.3650941476408624
+586 0.7466980485556904 0.6250000006575174 0.1216980492136338
+587 0.8716980487668555 0.625000000917692 0.2466980496848663
+588 0.7301882937270989 0.8750000002977674 0.230188294024955
+589 0.6051882934456341 0.7500000005792611 0.2301882940250892
+590 0.7301882935865145 0.7500000007527065 0.355188294339132
+591 0.7433960976743154 0.7500000004383455 0.1183960981130685
+592 0.8683960978152175 0.7500000006118152 0.2433960984271229
+593 0.7433960975337276 0.6250000008932776 0.2433960984272446
+594 0.7367921956304162 0.7500000005955283 0.236792196226101
+595 0.1249999998052123 0.5594351185898034 0.5655648816053508
+596 0.1249999999785904 0.5198117061541115 0.8551882938684503
+597 0.3749999999357713 0.5066039021084627 0.8683960979561325
+598 0.3749999994156369 0.519811706716035 0.6051882938683975
+599 0.1249999998919014 0.5396234123719574 0.7103765877369005
+600 0.2499999999571809 0.5132078041312872 0.8617921959122914
+601 0.3749999996757041 0.5132078044122489 0.736792195912265
+602 0.2499999996104246 0.5396234126529191 0.5853765877368741
+603 0.2499999997838027 0.5264156083921031 0.7235843918245828
+604 0.1249999999417561 0.1299529265385327 0.870047073519718
+605 0.1249999997929321 0.1398587796474549 0.6101412205591229
+606 0.124999999801119 0.4195763389423539 0.5804236612566018
+607 0.1249999999663225 0.3898587796155873 0.8601412204188907
+608 0.3749999998250856 0.1266509755271186 0.8733490246473089
+609 0.3749999993787428 0.1299529266790162 0.6200470739419188
+610 0.3749999994033467 0.389858780037023 0.6101412205595648
+611 0.3749999998988808 0.379952926581342 0.8700470735198567
+612 0.1249999998673462 0.134905853092994 0.7400941470394244
+613 0.1249999999540387 0.2599058530770569 0.8650941469692979
+614 0.2499999998834222 0.1283019510328266 0.8716980490835161
+615 0.1249999997970263 0.2797175592949044 0.595282440907865
+616 0.2499999995858402 0.1349058531632399 0.6150941472505316
+617 0.1249999998837262 0.4047175592789711 0.7202824408377552
+618 0.2499999996022362 0.4047175594896937 0.5952824409080955
+619 0.2499999999326061 0.3849058530984619 0.8650941469693743
+620 0.3749999996019152 0.1283019511030671 0.7466980492946146
+621 0.37499999986198 0.2533019510542288 0.8716980490835761
+622 0.3749999993910442 0.2599058533580242 0.6150941472507461
+623 0.3749999996511144 0.384905853309183 0.7400941470397054
+624 0.1249999998755361 0.2698117061859809 0.7301882939385858
+625 0.2499999997346325 0.1316039020980335 0.7433960981670286
+626 0.2499999999080131 0.2566039020656411 0.8683960980264371
+627 0.2499999995940382 0.2698117063264645 0.6051882940793069
+628 0.2499999997674235 0.3948117062940794 0.7301882939387432
+629 0.374999999626513 0.2566039022061252 0.7433960981671537
+630 0.2499999997510271 0.2632078041960531 0.7367921960528756
+631 0.4801882938478199 0.8750000000214095 0.8551882938680641
+632 0.4405648814098103 0.8750000001947877 0.5655648816041918
+633 0.4801882932838363 0.6250000005843631 0.6051882938680111
+634 0.4933960978921811 0.6250000000642287 0.8683960979560037
+635 0.4603765876288151 0.8750000001080986 0.7103765877361279
+636 0.4603765873468232 0.7500000003895754 0.5853765877361015
+637 0.4867921955880087 0.6250000003242959 0.7367921959120074
+638 0.4867921958700004 0.7500000000428192 0.8617921959120338
+639 0.4735843916084118 0.7500000002161973 0.7235843918240676
+640 0.8700470734617908 0.8750000001230049 0.8700470735846731
+641 0.6101412203857833 0.8750000000552807 0.860141220440269
+642 0.5804236610573255 0.8750000002638925 0.5804236613207805
+643 0.8601412203524155 0.8750000004021357 0.6101412207540049
+644 0.8733490244729931 0.6250000003689976 0.8733490248424325
+645 0.6200470734191179 0.6250000001658361 0.8700470735848274
+646 0.6101412199628652 0.6250000007916835 0.6101412207544312
+647 0.8700470733209404 0.6250000012063545 0.6200470745272761
+648 0.7400941469237554 0.875000000089146 0.8650941470124757
+649 0.8650941469070964 0.8750000002625618 0.7400941471693325
+650 0.871698048967394 0.7500000002460039 0.8716980492135566
+651 0.5952824407215566 0.8750000001595886 0.720282440880527
+652 0.6150941469024617 0.7500000001105694 0.8650941470125567
+653 0.7202824407048672 0.8750000003330195 0.595282441037402
+654 0.5952824405101077 0.7500000005277998 0.5952824410376162
+655 0.865094146836679 0.7500000008042441 0.6150941476406468
+656 0.7466980489460445 0.6250000002674178 0.8716980492136315
+657 0.8716980488969602 0.6250000007876694 0.746698049684846
+658 0.6150941466909963 0.6250000004787686 0.7400941471696328
+659 0.7400941466418935 0.6250000009990108 0.6150941476408465
+660 0.7301882938143073 0.8750000002110788 0.7301882940249367
+661 0.7433960979349091 0.7500000001782916 0.8683960981130632
+662 0.8683960979020284 0.7500000005251146 0.7433960984270944
+663 0.6051882937062781 0.7500000003191795 0.7301882940250828
+664 0.7301882936733936 0.7500000006660278 0.6051882943391382
+665 0.7433960977939623 0.6250000006332099 0.7433960984272334
+666 0.7367921958041408 0.7500000004221508 0.7367921962260929
+667 0.3155648813931041 0.8816039022549553 0.4339609795600992
+668 0.3551882932347479 0.6448117067648659 0.4603765877363863
+669 0.118396097744916 0.6844351186057369 0.4339609795611294
+670 0.1051882937977014 0.8948117062019123 0.460376587735786
+671 0.3353765873139261 0.7632078045099105 0.4471687836482428
+672 0.2367921954898319 0.6646234126853015 0.4471687836487579
+673 0.1117921957713087 0.7896234124038246 0.4471687836484577
+674 0.2103765875954028 0.8882078042284338 0.4471687836479427
+675 0.2235843915426173 0.7764156084568676 0.4471687836483502
+676 0.3700470734191346 0.6299529265813321 0.8650941469341086
+677 0.3601412203858684 0.8766509755270654 0.8584902448900302
+678 0.3304236610573543 0.8799529266789846 0.5754707346700665
+679 0.3601412199628772 0.6398587800370337 0.5952824408023107
+680 0.1233490244730454 0.6398587796155023 0.858490244890289
+681 0.1200470734619633 0.8799529265383723 0.8650941469339627
+682 0.1101412203524432 0.8898587796473871 0.5952824408018353
+683 0.1200470733209504 0.6695763389423135 0.5754707346708434
+684 0.3650941469025019 0.75330195105419 0.8617921959120741
+685 0.3650941466910025 0.6349058533091767 0.7301882938682039
+686 0.2466980489460905 0.6349058530984218 0.8617921959122028
+687 0.3452824407216123 0.8783019511030269 0.716980489780051
+688 0.2400941469239199 0.8783019510327276 0.8617921959120055
+689 0.3452824405101159 0.7599058533580121 0.5853765877361975
+690 0.2202824407049027 0.8849058531631959 0.5853765877359606
+691 0.2400941466419115 0.6547175594896784 0.5853765877365832
+692 0.1216980489675039 0.7599058530769033 0.8617921959121272
+693 0.121698048896996 0.6547175592788995 0.7169804897805577
+694 0.1150941469072068 0.8849058530928858 0.7301882938679021
+695 0.1150941468366924 0.7797175592948333 0.5853765877363315
+696 0.3551882937063068 0.7566039022060981 0.7235843918241335
+697 0.2433960979350069 0.7566039020655549 0.8617921959121103
+698 0.2433960977939973 0.6448117062940423 0.7235843918243859
+699 0.2301882938144087 0.8816039020979599 0.7235843918239793
+700 0.230188293673409 0.7698117063264333 0.5853765877362779
+701 0.1183960979020966 0.7698117061858658 0.723584391824224
+702 0.2367921958042033 0.7632078041959884 0.7235843918241869
+703 0.360141220189417 0.876650975722017 0.1084902448900484
+704 0.3304236609918741 0.8799529267439823 0.3254707346700836
+705 0.1101412203306375 0.8898587796689581 0.3452824408018561
+706 0.1200470733965307 0.879952926603084 0.1150941469340083
+707 0.3700470728335194 0.6299529271660304 0.1150941469341053
+708 0.3601412197676748 0.6398587802319401 0.3452824408023012
+709 0.1200470732558962 0.6695763390068826 0.3254707346708509
+710 0.1233490242778563 0.6398587798091996 0.1084902448902956
+711 0.3452824405906478 0.8783019512330029 0.2169804897800671
+712 0.2400941467929722 0.8783019511625415 0.1117921959120265
+713 0.3650941465114694 0.7533019514440266 0.1117921959120788
+714 0.2202824406612572 0.8849058532064716 0.3353765877359707
+715 0.3452824403797773 0.7599058534879728 0.3353765877361945
+716 0.1150941468635882 0.8849058531360267 0.2301882938679338
+717 0.1150941467932691 0.7797175593379322 0.3353765877363553
+718 0.1216980488371975 0.7599058532061412 0.1117921959121539
+719 0.3650941463005976 0.6349058536989861 0.2301882938682041
+720 0.2466980485556843 0.6349058534876081 0.1117921959121979
+721 0.2400941465117851 0.6547175596194192 0.3353765877365785
+722 0.1216980487668725 0.6547175594080327 0.2169804897805718
+723 0.2301882937271177 0.8816039021845105 0.2235843918239998
+724 0.3551882934456259 0.7566039024660044 0.2235843918241377
+725 0.2433960976743315 0.7566039023250746 0.1117921959121145
+726 0.2301882935865223 0.7698117064129467 0.3353765877362759
+727 0.1183960978152357 0.7698117062720422 0.2235843918242547
+728 0.2433960975337323 0.6448117065535048 0.2235843918243884
+729 0.2367921956304287 0.7632078043690131 0.223584391824196
+"""
+
+element = (np.loadtxt(io.StringIO(element)) - 1).astype(np.int32)
+nodes = np.loadtxt(io.StringIO(nodes))
+
+assert nodes.shape[1] == 4
+assert np.array_equal(nodes[:, 0], np.arange(len(nodes))+1)
+
+order = 4
+nodes = 2*order*nodes
+rnodes = np.round(nodes[:, 1:]).astype(np.int32)
+
+offset = (-4, 0, -4)
+
+s = [tuple(ni + oi for ni, oi in zip(node, offset))
+        for node in rnodes[element]]
+
+for t in s:
+    print(str(t) + ",")
+
+print(len(set(s)), len(s))
+assert len(set(s)) == len(element)
diff --git a/meshpy/doc/conf.py b/meshpy/doc/conf.py
new file mode 100644
index 0000000000000000000000000000000000000000..58ab16e751f1dde0704936b707fc77b4918e4a24
--- /dev/null
+++ b/meshpy/doc/conf.py
@@ -0,0 +1,194 @@
+# -*- coding: utf-8 -*-
+#
+# MeshPy documentation build configuration file, created by
+# sphinx-quickstart on Tue Jul  1 12:35:03 2008.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# The contents of this file are pickled, so don't put values in the namespace
+# that aren't pickleable (module imports are okay, they're removed automatically).
+#
+# All configuration values have a default value; values that are commented out
+# serve to show the default value.
+
+#import sys, os
+
+# If your extensions are in another directory, add it here. If the directory
+# is relative to the documentation root, use os.path.abspath to make it
+# absolute, like shown here.
+#sys.path.append(os.path.abspath('some/directory'))
+
+# General configuration
+# ---------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = [
+        'sphinx.ext.autodoc',
+        'sphinx.ext.viewcode',
+        'sphinx.ext.intersphinx',
+        ]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General substitutions.
+project = "MeshPy"
+copyright = u"2008, Andreas Klöckner"
+
+# The default replacements for |version| and |release|, also used in various
+# other places throughout the built documents.
+#
+# The short X.Y version.
+def get_version():
+    conf = {}
+    exec(compile(open("../meshpy/__init__.py").read(), "../meshpy/__init__.py", 'exec'), conf)
+    return conf["version"]
+
+version = get_version()
+
+# The full version, including alpha/beta/rc tags.
+release = version
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directories, that shouldn't be searched
+# for source files.
+#exclude_dirs = []
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+
+# Options for HTML output
+# -----------------------
+
+html_theme = "alabaster"
+
+html_theme_options = {
+        "extra_nav_links": {
+            "🚀 Github": "https://github.com/inducer/meshpy",
+            "💾 Download Releases": "https://pypi.python.org/pypi/meshpy",
+            }
+        }
+
+html_sidebars = {
+    '**': [
+        'about.html',
+        'navigation.html',
+        'relations.html',
+        'searchbox.html',
+    ]
+}
+
+# The style sheet to use for HTML and HTML Help pages. A file of that name
+# must exist either in Sphinx' static/ path, or in one of the custom paths
+# given in html_static_path.
+#html_style = 'default.css'
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# The name of an image file (within the static path) to place at the top of
+# the sidebar.
+#html_logo = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_use_modindex = True
+
+# If true, the reST sources are included in the HTML build as _sources/<name>.
+#html_copy_source = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'MeshPydoc'
+
+
+# Options for LaTeX output
+# ------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, document class [howto/manual]).
+latex_documents = [
+  ('index', 'MeshPy.tex', 'MeshPy Documentation', 'Andreas Klöckner', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
diff --git a/meshpy/doc/faq.rst b/meshpy/doc/faq.rst
new file mode 100644
index 0000000000000000000000000000000000000000..11e71b8fb2e2026a0b74e9d14be6d413fd93c30e
--- /dev/null
+++ b/meshpy/doc/faq.rst
@@ -0,0 +1,94 @@
+Licensing Information
+=====================
+
+Wrapper License
+---------------
+
+MeshPy (the wrapper) is licensed to you under the MIT/X Consortium license:
+
+Copyright (c) 2008 Andreas Klöckner
+
+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:
+
+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.
+
+
+Triangle License
+----------------
+
+Copyright 1993, 1995, 1997, 1998, 2002, 2005 Jonathan Richard Shewchuk
+2360 Woolsey #H
+Berkeley, California  94705-1927
+Please send bugs and comments to jrs@cs.berkeley.edu
+
+Created as part of the Quake project (tools for earthquake simulation).
+Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.
+There is no warranty whatsoever.  Use at your own risk.
+
+
+Triangle generates exact Delaunay triangulations, constrained Delaunay
+triangulations, conforming Delaunay triangulations, Voronoi diagrams, and
+high-quality triangular meshes.  The latter can be generated with no small
+or large angles, and are thus suitable for finite element analysis.
+Show Me graphically displays the contents of the geometric files used by
+Triangle.  Show Me can also write images in PostScript form.
+
+Information on the algorithms used by Triangle, including complete
+references, can be found in the comments at the beginning of the triangle.c
+source file.  Another listing of these references, with PostScript copies
+of some of the papers, is available from the Web page
+
+http://www.cs.cmu.edu/~quake/triangle.research.html
+
+These programs may be freely redistributed under the condition that the
+copyright notices (including the copy of this notice in the code comments
+and the copyright notice printed when the '-h' switch is selected) are
+not removed, and no compensation is received.  Private, research, and
+institutional use is free.  You may distribute modified versions of this
+code UNDER THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT
+IN THE SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH
+SOURCE AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND
+CLEAR NOTICE IS GIVEN OF THE MODIFICATIONS.  Distribution of this code as
+part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT
+WITH THE AUTHOR.  (If you are not directly supplying this code to a
+customer, and you are instead telling them how they can obtain it for
+free, then you are not required to make any arrangement with me.)
+
+TetGen License
+--------------
+
+TetGen is distributed under a dual licensing scheme. You can
+redistribute it and/or modify it under the terms of the GNU Affero
+General Public License as published by the Free Software Foundation,
+either version 3 of the License, or (at your option) any later
+version. A copy of the GNU Affero General Public License is reproduced
+below.
+
+If the terms and conditions of the AGPL v.3. would prevent you from
+using TetGen, please consider the option to obtain a commercial
+license for a fee. These licenses are offered by the Weierstrass
+Institute for Applied Analysis and Stochastics (WIAS). As a rule,
+licenses are provided "as-is", unlimited in time for a one time
+fee. Please send corresponding requests to:
+tetgen@wias-berlin.de. Please do not forget to include some
+description of your company and the realm of its activities.
+
+For details, see the `TetGen web page <http://tetgen.org>`_
+
diff --git a/meshpy/doc/geometry.rst b/meshpy/doc/geometry.rst
new file mode 100644
index 0000000000000000000000000000000000000000..8a59d3188b0f37553ee920cd51613b02b41bf861
--- /dev/null
+++ b/meshpy/doc/geometry.rst
@@ -0,0 +1,4 @@
+Geometry Generation
+===================
+
+.. automodule:: meshpy.geometry
diff --git a/meshpy/doc/gmsh.rst b/meshpy/doc/gmsh.rst
new file mode 100644
index 0000000000000000000000000000000000000000..07b04d6e017a92caf7037e4665300c379042c583
--- /dev/null
+++ b/meshpy/doc/gmsh.rst
@@ -0,0 +1,6 @@
+Gmsh interface
+==============
+
+This is deprecated. See the `gmsh_interop
+<https://github.com/inducer/gmsh_interop>`_ packages instead.
+
diff --git a/meshpy/doc/index.rst b/meshpy/doc/index.rst
new file mode 100644
index 0000000000000000000000000000000000000000..df227fb544f4482bb4c91a539491765f3ae9349d
--- /dev/null
+++ b/meshpy/doc/index.rst
@@ -0,0 +1,94 @@
+Welcome to MeshPy's documentation!
+==================================
+
+MeshPy offers quality triangular and tetrahedral mesh generation for Python.
+Meshes of this type are chiefly used in finite-element simulation codes, but
+also have many other applications ranging from computer graphics to robotics.
+
+In order to generate these 2D and 3D meshes, MeshPy provides Python interfaces
+to a few well-regarded mesh generators: 
+
+* `Triangle <http://www.cs.cmu.edu/~quake/triangle.html>`_ by J. Shewchuk.
+* `TetGen <http://tetgen.berlios.de/>`_ by Hang Si.
+* `Gmsh <http://geuz.org/gmsh/>`_ by Christophe Geuzaine and Jean-François Remacle.
+
+Triangle and TetGen are included in the package in slightly modified versions. Gmsh
+is called as a subprocess.
+
+Show me! I need examples!
+-------------------------
+This simple code generates a mesh of a "brick"::
+
+    from meshpy.tet import MeshInfo, build
+
+    mesh_info = MeshInfo()
+    mesh_info.set_points([
+        (0,0,0), (2,0,0), (2,2,0), (0,2,0),
+        (0,0,12), (2,0,12), (2,2,12), (0,2,12),
+        ])
+    mesh_info.set_facets([
+        [0,1,2,3],
+        [4,5,6,7],
+        [0,4,5,1],
+        [1,5,6,2],
+        [2,6,7,3],
+        [3,7,4,0],
+        ])
+    mesh = build(mesh_info)
+    print "Mesh Points:"
+    for i, p in enumerate(mesh.points):
+        print i, p
+    print "Point numbers in tetrahedra:"
+    for i, t in enumerate(mesh.elements):
+        print i, t
+    mesh.write_vtk("test.vtk")
+
+As a result of this, you will get::
+
+    Mesh Points:
+    0 [0.0, 0.0, 0.0]
+    1 [2.0, 0.0, 0.0]
+    2 [2.0, 2.0, 0.0]
+    3 [0.0, 2.0, 0.0]
+    4 [0.0, 0.0, 12.0]
+    5 [2.0, 0.0, 12.0]
+    6 [2.0, 2.0, 12.0]
+    7 [0.0, 2.0, 12.0]
+    8 [1.000116, 0.0, 0.0]
+    9 [0.0, 0.99960499999999997, 0.0]
+    10 [0.0, 0.99934199999999995, 12.0]
+    11 [1.0006170000000001, 0.0, 12.0]
+    ...
+    Point numbers in tetrahedra:
+    0 [21, 39, 38, 52]
+    1 [9, 50, 2, 3]
+    2 [12, 45, 15, 54]
+    3 [39, 43, 20, 52]
+    4 [41, 45, 24, 54]
+    ...
+
+and a file :file:`test.vtk` that you can view with `Paraview <http://paraview.org>`_ or
+`Visit <http://www.llnl.gov/VisIt/>`_.
+
+Contents
+========
+
+.. toctree::
+    :maxdepth: 2
+
+    installation
+    tri-tet
+    gmsh
+    geometry
+    faq
+
+MeshPy has its own `web page <http://mathema.tician.de/software/meshpy>`_, where you
+can find updated software, news, a forum, and documentation.
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/meshpy/doc/installation.rst b/meshpy/doc/installation.rst
new file mode 100644
index 0000000000000000000000000000000000000000..f7f587f7a36d91e994b1a440891f635cc3c752ff
--- /dev/null
+++ b/meshpy/doc/installation.rst
@@ -0,0 +1,50 @@
+.. highlight:: sh
+
+Installation
+============
+
+This tutorial will walk you through the process of building MeshPy. To follow,
+you really only need three basic things:
+
+* A UNIX-like machine with web access.
+* A C++ compiler, preferably a Version 4.x gcc.
+* A working `Python <http://www.python.org>`_ installation, Version 2.4 or newer.
+
+Step 1: Download and unpack MeshPy
+-----------------------------------
+
+`Download MeshPy <http://pypi.python.org/pypi/MeshPy>`_ and unpack it::
+
+    $ tar xfz MeshPy-VERSION.tar.gz
+
+If you're downloading from git, say::
+
+    $ git clone --recursive http://git.tiker.net/trees/meshpy.git
+
+If your version of git doesn't support `--recursive`, then say::
+
+    $ git clone http://git.tiker.net/trees/meshpy.git
+    $ cd meshpy
+    $ git submodule init
+    $ git submodule update
+
+The setup script will remind you about this if you forget.
+
+Step 2: Build MeshPy
+--------------------
+
+Just type::
+
+    $ cd MeshPy-VERSION # if you're not there already
+    $ ./configure
+    $ python setup.py install
+
+Once that works, congratulations! You've successfully built MeshPy.
+
+Step 3: Test MeshPy
+-------------------
+
+Just type::
+
+    $ cd test
+    $ py.test
diff --git a/meshpy/doc/tri-tet.rst b/meshpy/doc/tri-tet.rst
new file mode 100644
index 0000000000000000000000000000000000000000..9e7f004435f028c328eab4001b8745613cc5041e
--- /dev/null
+++ b/meshpy/doc/tri-tet.rst
@@ -0,0 +1,368 @@
+Triangle/TetGen interface
+=========================
+
+Some common notions
+-------------------
+
+.. class:: ForeignArray
+
+    Note that :class:`ForeignArray` instances are not usually created by users,
+    and :class:`ForeignArray`  is not a class name available in MeshPy. It is
+    just used to explain the interface provided.
+
+    Almost all input and output data in MeshPy can be accessed using the
+    :class:`ForeignArray` interface.  It is called "foreign" because it
+    provides access to an area of memory accessible by a pointer managed by an
+    outside piece of software, such as a mesh generator.
+
+    Note that :class:`ForeignArray` has no *append* method. Instead, use
+    :meth:`ForeignArray.resize` and then set the consecutive entries of the
+    array.
+
+    .. method:: __len__()
+
+        Return the number of entries in the array. If the array is 2D (i.e. has
+        non-1 :attr:`unit`), :meth:`ForeignArray.__len__` only returns the
+        length of the leading dimension.  For example, for an array of points
+        in *n*-dimensional space, :meth:`__len__` returns the number of points.
+
+    .. attribute:: unit
+
+        If this :class:`ForeignArray` represents a two-dimensional array, such
+        as an array of point coordinates, :meth:`ForeignArray.unit` gives the
+        size of the subordinate dimension.
+
+        For example, for an array of points in 3-dimensional space,
+        :meth:`ForeignArray.__len__` returns the number of dimensions (3).
+
+    .. attribute:: allocated
+
+        Return a :class:`bool` indicating whether storage has
+        been allocated for this array. This is only meaningful if the size
+        of this array is tied to that of another, see :meth:`ForeignArray.setup`.
+
+    .. method:: resize(new_size)
+
+        Change the length of the array as returned by :meth:`ForeignArray.__len__`.
+
+    .. method:: setup()
+
+        Set up (i.e. allocate) storage for the array. This only works on arrays
+        whose size is tied to that of other arrays, such as an array of point
+        markers, which necessarily has the same size as the associated array of
+        points, if it is allocated.
+
+    .. method:: deallocate()
+
+        Release any storage associated with the array.
+
+    .. method:: __getitem__(index)
+                __setitem__(index, value)
+
+        Get and set entries in the array. If this foreign array is 2D
+        (see :attr:`ForeignArray.unit`), index may be a 2-tuple of integers, as in::
+
+            points[2,1] = 17
+
+
+
+
+:mod:`meshpy.triangle` -- Triangular Meshing
+--------------------------------------------
+.. module:: meshpy.triangle
+    :synopsis: Generate triangular meshes
+.. moduleauthor:: Andreas Klöckner <inform@tiker.net>
+
+
+.. class:: MeshInfo
+
+    :class:`MeshInfo` objects are picklable.
+
+    .. attribute:: points
+
+        A 2D :class:`ForeignArray` of :class:`float` with dimension *(N,2)*,
+        providing a list of points that are referred to by index from other
+        entries of this structure.
+
+    .. attribute:: point_attributes
+
+        If :attr:`MeshInfo.number_of_point_attributes` is non-zero, this is a
+        :class:`ForeignArray` of :class:`floats` of point attributes.
+
+        This element's size is tied to that of :attr:`MeshInfo.points`.
+
+    .. attribute:: point_markers
+
+        :class:`ForeignArray` of :class:`floats` of point attributes.
+
+        This element's size is tied to that of :attr:`MeshInfo.points`.
+
+    .. attribute:: elements
+
+    .. attribute:: element_attributes
+
+        This element's size is tied to that of :attr:`MeshInfo.elements`.
+
+    .. attribute:: element_volumes
+
+        This element's size is tied to that of :attr:`MeshInfo.elements`.
+
+    .. attribute:: neighbors
+
+    .. attribute:: facets
+
+    .. attribute:: facet_markers
+
+    .. attribute:: holes
+
+    .. attribute:: regions
+
+    .. attribute:: faces
+    .. attribute:: face_markers
+
+    .. attribute:: normals
+
+    .. attribute:: number_of_point_attributes
+    .. attribute:: number_of_element_vertices
+
+        Defautls to 4 for linear tetrahedra. Change to 10 for second-order
+        tetrahedra.
+
+    .. attribute:: number_of_element_attributes
+
+    Convenient setters:
+
+    .. method:: set_points(points, point_markers=None)
+    .. method:: set_holes(points, hole_starts)
+    .. method:: set_facets(facets, facet_markers=None)
+
+    Other functionality:
+
+    .. method:: copy()
+
+        Return a duplicate copy of this object.
+
+.. function:: subdivide_facets(subdivisions, points, facets, facet_markers)
+
+    Subdivide facets into *subdivisions* subfacets.
+
+    This routine is useful if you have to prohibit the insertion of Steiner
+    points on the boundary  of your triangulation to allow the mesh to conform
+    either to itself periodically or another given mesh. In this case, you may
+    use this routine to create the necessary resolution along the boundary
+    in a predefined way.
+
+    *subdivisions* is either an :class:`int`, indicating a uniform number of
+    subdivisions throughout, or a list of the same length as *facets*,
+    specifying a subdivision count for each individual facet.
+
+    *points*
+        a list of points referred to from the facets list.
+    *facets*
+        a list of old facets, in the form *[(p1, p2), (p3,p4), ...]*.
+    *facet_markers*
+        either *None* or a list of facet markers of the same length
+        as *facets*.
+
+    Returns a tuple *(new_points, new_facets)*,
+    or *(new_points, new_facets, new_facet_markers)* if *facet_markers* is not
+    *None*.
+
+.. function:: build(mesh_info, verbose=False, refinement_func=None, attributes=False, volume_constraints=True, max_volume=None, allow_boundary_steiner=True, allow_volume_steiner=True, quality_meshing=True, generate_edges=None, generate_faces=False, min_angle=None)
+
+.. function:: refine(input_p, verbose=False, refinement_func=None,  quality_meshing=True, min_angle=None)
+
+.. function:: write_gnuplot_mesh(filename, out_p, facets=False)
+
+:mod:`meshpy.tet` -- Tetrahedral Meshing
+----------------------------------------
+
+.. module:: meshpy.tet
+   :synopsis: Generate triangular meshes
+.. moduleauthor:: Andreas Klöckner <inform@tiker.net>
+
+.. class:: Options(switches='pq', **kwargs)
+
+    Run time switches for TetGen. See the TetGen documentation for the meaning of each
+    switch.
+
+    Using the *kwargs* constructor argument, all the attributes defined
+    below can be set. This setting will occur after
+    :meth:`Options.parse_switches` is called with the *switches* parameter.
+
+    .. attribute:: plc
+    .. attribute:: quality
+    .. attribute:: refine
+    .. attribute:: coarse
+    .. attribute:: metric
+    .. attribute:: varvolume
+    .. attribute:: fixedvolume
+    .. attribute:: insertaddpoints
+    .. attribute:: regionattrib
+    .. attribute:: offcenter
+    .. attribute:: conformdel
+    .. attribute:: diagnose
+    .. attribute:: zeroindex
+    .. attribute:: optlevel
+    .. attribute:: optpasses
+    .. attribute:: order
+    .. attribute:: facesout
+    .. attribute:: edgesout
+    .. attribute:: neighout
+    .. attribute:: voroout
+    .. attribute:: meditview
+    .. attribute:: gidview
+    .. attribute:: geomview
+    .. attribute:: nobound
+    .. attribute:: nonodewritten
+    .. attribute:: noelewritten
+    .. attribute:: nofacewritten
+    .. attribute:: noiterationnum
+    .. attribute:: nomerge
+    .. attribute:: nobisect
+    .. attribute:: noflip
+    .. attribute:: nojettison
+    .. attribute:: steiner
+    .. attribute:: fliprepair
+    .. attribute:: offcenter
+    .. attribute:: docheck
+    .. attribute:: quiet
+    .. attribute:: verbose
+    .. attribute:: useshelles
+    .. attribute:: minratio
+    .. attribute:: goodratio
+    .. attribute:: minangle
+    .. attribute:: goodangle
+    .. attribute:: maxvolume
+    .. attribute:: maxdihedral
+    .. attribute:: alpha1
+    .. attribute:: alpha2
+    .. attribute:: alpha3
+    .. attribute:: epsilon
+    .. attribute:: epsilon2
+
+    .. method:: parse_switches(switches)
+
+.. class:: Polygon
+
+    .. attribute:: vertices
+
+.. class:: Facet
+
+    .. attribute:: polygons
+    .. attribute:: holes
+
+.. class:: PBCGroup
+
+    .. attribute:: facet_marker_1
+    .. attribute:: facet_marker_2
+    .. attribute:: point_pairs
+    .. attribute:: matrix
+
+
+.. class:: MeshInfo
+
+    .. attribute:: points
+    .. attribute:: point_attributes
+    .. attribute:: point_metric_tensors
+    .. attribute:: point_markers
+    .. attribute:: elements
+    .. attribute:: element_attributes
+    .. attribute:: element_volumes
+    .. attribute:: neighbors
+    .. attribute:: facets
+    .. attribute:: facet_markers
+    .. attribute:: holes
+    .. attribute:: regions
+    .. attribute:: facet_constraints
+    .. attribute:: segment_constraints
+    .. attribute:: pbc_groups
+    .. attribute:: faces
+    .. attribute:: adjacent_elements
+    .. attribute:: face_markers
+    .. attribute:: edges
+    .. attribute:: edge_markers
+    .. attribute:: edge_adjacent_elements
+
+        .. versionadded:: 2016.1
+    .. attribute:: number_of_point_attributes
+    .. attribute:: number_of_element_attributes
+
+    Convenient setters:
+
+    .. method:: set_points(points, point_markers=None)
+    .. method:: set_holes(points, hole_starts)
+    .. method:: set_facets(facets, markers=None)
+
+        Set a list of simple, single-polygon factes. Unlike
+        :meth:`MeshInfo.set_facets_ex`, this method does not allow holes and
+        only lets you use a single polygon per facet.
+
+        *facets*
+            a list of facets, where each facet is a single
+            polygons, represented by a list of point indices.
+        *markers*
+            Either None or a list of integers of the same
+            length as facets. Each integer is the facet marker assigned
+            to its corresponding facet.
+
+        .. note::
+
+            When the above says "list", any repeatable iterable
+            also accepted instead.
+
+    .. method:: set_facets_ex(facets, facet_holestarts=None, markers=None)
+
+        Set a list of complicated facets. Unlike :meth:`MeshInfo.set_facets`,
+        this method allows holes and multiple polygons per facet.
+
+        *facets*
+            a list of facets, where each facet is a list
+            of polygons, and each polygon is represented by a list
+            of point indices.
+        *facet_holestarts*
+            Either None or a list of hole starting points
+            for each facet. Each facet may have several hole starting points.
+            The mesh generator starts "eating" a hole into the facet at each
+            starting point and continues until it hits a polygon specified
+            in this facet's record in *facets*.
+        *markers*
+            Either None or a list of integers of the same
+            length as *facets*. Each integer is the facet marker assigned
+            to its corresponding facet.
+
+        .. note::
+
+            When the above says "list", any repeatable iterable
+            also accepted instead.
+
+    Other functionality:
+
+    .. attribute:: face_vertex_indices_to_face_marker
+
+    .. method:: dump()
+    .. method:: write_vtk(filename)
+
+    TetGen-provided loading and saving:
+
+    .. method:: save_nodes(filename)
+    .. method:: save_elements(filename)
+    .. method:: save_faces(filename)
+    .. method:: save_edges(filename)
+    .. method:: save_neighbors(filename)
+    .. method:: save_poly(filename)
+    .. method:: load_node(filename)
+    .. method:: load_pbc(filename)
+    .. method:: load_var(filename)
+    .. method:: load_mtr(filename)
+    .. method:: load_poly(filename)
+    .. method:: load_ply(filename)
+    .. method:: load_stl(filename)
+    .. method:: load_medit(filename)
+    .. method:: load_plc(filename)
+    .. method:: load_tetmesh(filename)
+
+.. function:: build(mesh_info, options=Options("pq"), verbose=False, attributes=False, volume_constraints=False, max_volume=None, diagnose=False, insert_points=None, mesh_order=None)
+
+    :param insert_points: a :class:`MeshInfo` object specifying additional points to be inserted
+
diff --git a/meshpy/doc/upload-docs.sh b/meshpy/doc/upload-docs.sh
new file mode 100755
index 0000000000000000000000000000000000000000..fe69b720e72a579be934f331e5c105b508a5563d
--- /dev/null
+++ b/meshpy/doc/upload-docs.sh
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+rsync --verbose --archive --delete .build/html/* doc-upload:doc/meshpy
diff --git a/meshpy/examples/.gitignore b/meshpy/examples/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..a1363379944a5745ceb49c0e493d80eb9335c79a
--- /dev/null
+++ b/meshpy/examples/.gitignore
@@ -0,0 +1 @@
+*.pdf
diff --git a/meshpy/examples/MESH_README.txt b/meshpy/examples/MESH_README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8d12a86c117e275824044388eecd9d539f6c5893
--- /dev/null
+++ b/meshpy/examples/MESH_README.txt
@@ -0,0 +1,14 @@
+-------------------------------------------------------------------------------
+Mesh licensing 
+-------------------------------------------------------------------------------
+This file summarizes the licenses surrounding data files in this directory.
+When using them for research or demonstration purposes, please be mindful of
+proper attribution.
+-------------------------------------------------------------------------------
+ka-6d.ply:
+The mesh 'ka-6d.ply' is a derivative work of a mesh in FlightGear and is thus
+licensed under the GNU GPL.
+
+(C) Flightgear Developers & Contributors
+(C) Andreas Kloeckner
+-------------------------------------------------------------------------------
diff --git a/meshpy/examples/airfoil3d.py b/meshpy/examples/airfoil3d.py
new file mode 100644
index 0000000000000000000000000000000000000000..d1307184359efe9176dc7fca1f91514651909966
--- /dev/null
+++ b/meshpy/examples/airfoil3d.py
@@ -0,0 +1,70 @@
+from __future__ import absolute_import
+from __future__ import print_function
+from six.moves import zip
+def main():
+    import numpy
+    #from math import pi, cos, sin
+    from meshpy.tet import MeshInfo, build
+    from meshpy.geometry import GeometryBuilder, Marker, \
+            generate_extrusion, make_box
+
+    from meshpy.naca import get_naca_points
+
+    geob = GeometryBuilder()
+
+    box_marker = Marker.FIRST_USER_MARKER
+
+    wing_length = 2
+    wing_subdiv = 5
+
+    rz_points = [
+            (0, -wing_length*1.05),
+            (0.7, -wing_length*1.05),
+            ] + [
+                (r, x) for x, r in zip(
+                    numpy.linspace(-wing_length, 0, wing_subdiv, endpoint=False),
+                    numpy.linspace(0.8, 1, wing_subdiv, endpoint=False))
+            ] + [(1, 0)] + [
+                (r, x) for x, r in zip(
+                    numpy.linspace(wing_length, 0, wing_subdiv, endpoint=False),
+                    numpy.linspace(0.8, 1, wing_subdiv, endpoint=False))
+            ][::-1] + [
+            (0.7, wing_length*1.05),
+            (0, wing_length*1.05)
+            ]
+
+    geob.add_geometry(*generate_extrusion(
+        rz_points=rz_points,
+        base_shape=get_naca_points("0012", verbose=False, number_of_points=20),
+        ring_markers=(wing_subdiv*2+4)*[box_marker]))
+
+    from meshpy.tools import make_swizzle_matrix
+    swizzle_matrix = make_swizzle_matrix("z:x,y:y,x:z")
+    geob.apply_transform(lambda p: numpy.dot(swizzle_matrix, p))
+
+    def deform_wing(p):
+        x, y, z = p
+        return numpy.array([
+            x,
+            y + 0.1*abs(x/wing_length)**2,
+            z + 0.8*abs(x/wing_length) ** 1.2])
+
+    geob.apply_transform(deform_wing)
+
+    points, facets, _, facet_markers = make_box(
+            numpy.array([-wing_length-1, -1, -1.5]),
+            numpy.array([wing_length+1, 1, 3]))
+
+    geob.add_geometry(points, facets, facet_markers=facet_markers)
+
+    mesh_info = MeshInfo()
+    geob.set(mesh_info)
+    mesh_info.set_holes([(0, 0, 0.5)])
+
+    mesh = build(mesh_info)
+    print("%d elements" % len(mesh.elements))
+    mesh.write_vtk("airfoil3d.vtk")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/meshpy/examples/box-in-box.py b/meshpy/examples/box-in-box.py
new file mode 100644
index 0000000000000000000000000000000000000000..028fe18860ad0a982e65b999b454933121b521fc
--- /dev/null
+++ b/meshpy/examples/box-in-box.py
@@ -0,0 +1,43 @@
+from __future__ import absolute_import
+from __future__ import print_function
+def main():
+    import numpy
+    from meshpy.tet import MeshInfo, build
+    from meshpy.geometry import GeometryBuilder, Marker, make_box
+
+    geob = GeometryBuilder()
+
+    box_marker = Marker.FIRST_USER_MARKER
+    extent_small = 0.3*numpy.ones(3, dtype=numpy.float64)
+    points, facets, _, _ = \
+            make_box(-extent_small, extent_small)
+
+    geob.add_geometry(points, facets, facet_markers=box_marker)
+
+    points, facets, _, facet_markers = \
+            make_box(numpy.array([-1, -1, -1]), numpy.array([1, 1, 5]))
+
+    geob.add_geometry(points, facets, facet_markers=facet_markers)
+
+    mesh_info = MeshInfo()
+    geob.set(mesh_info)
+    #mesh_info.set_holes([(0, 0, 0)])
+
+    # region attributes
+    mesh_info.regions.resize(1)
+    mesh_info.regions[0] = (
+            # point in region
+            [0, 0, 0] + [
+                # region number
+                1,
+                # max volume in region
+                0.001])
+
+    mesh = build(mesh_info, max_volume=0.06,
+            volume_constraints=True, attributes=True)
+    print(("%d elements" % len(mesh.elements)))
+    mesh.write_vtk("box-in-box.vtk")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/meshpy/examples/clean.sh b/meshpy/examples/clean.sh
new file mode 100755
index 0000000000000000000000000000000000000000..cabaac457bbb8d57586bef3f62005b9e0845b298
--- /dev/null
+++ b/meshpy/examples/clean.sh
@@ -0,0 +1,2 @@
+#! /bin/sh
+rm -f *.{vtk,ele,poly,node,lua}
diff --git a/meshpy/examples/demo.py b/meshpy/examples/demo.py
new file mode 100644
index 0000000000000000000000000000000000000000..d4271c6514bdf976ed30977ef8d4ed2ec53d588e
--- /dev/null
+++ b/meshpy/examples/demo.py
@@ -0,0 +1,26 @@
+from __future__ import absolute_import
+from __future__ import print_function
+from meshpy.tet import MeshInfo, build
+
+mesh_info = MeshInfo()
+mesh_info.set_points([
+    (0,0,0), (2,0,0), (2,2,0), (0,2,0),
+    (0,0,12), (2,0,12), (2,2,12), (0,2,12),
+    ])
+mesh_info.set_facets([
+    [0,1,2,3],
+    [4,5,6,7],
+    [0,4,5,1],
+    [1,5,6,2],
+    [2,6,7,3],
+    [3,7,4,0],
+    ])
+mesh = build(mesh_info)
+print("Mesh Points:")
+for i, p in enumerate(mesh.points):
+    print(i, p)
+print("Point numbers in tetrahedra:")
+for i, t in enumerate(mesh.elements):
+    print(i, t)
+mesh.write_vtk("test.vtk")
+
diff --git a/meshpy/examples/jw_mesh_examples.py b/meshpy/examples/jw_mesh_examples.py
new file mode 100644
index 0000000000000000000000000000000000000000..a3b8f9da0e7d466a4bf22e94c56f9a5bbe117532
--- /dev/null
+++ b/meshpy/examples/jw_mesh_examples.py
@@ -0,0 +1,220 @@
+# -*- coding: utf-8 -*-
+"""
+Short Gallery of examples
+for meshpy
+
+written by Juergen Weizenecker
+
+"""
+
+import numpy as np
+import jw_meshtools as mt
+import meshpy.triangle as triangle
+import numpy.linalg as la
+
+
+length=0.3
+
+
+
+
+# Simple mesh rectangle
+p,v=mt.RectangleSegments([-1,-1],[2.5,3],edge_length=length)
+mt.DoTriMesh(p,v,edge_length=length)
+
+
+
+
+# simple mesh circle
+p,v=mt.CircleSegments([1,2],2,edge_length=length)
+mt.DoTriMesh(p,v,edge_length=length)
+
+
+
+#
+# simple mesh triangle
+#
+p1,v1=mt.LineSegments([2,2],[-1,-3],edge_length=length)
+p2,v2=mt.LineSegments([-1,-3],[3,-1],num_points=10)
+p,v=mt.AddSegments(p1,p2,closed=True)
+mt.DoTriMesh(p,v,edge_length=length)
+
+
+# 
+# two semicircles
+#
+p1,v1=mt.CircleSegments([1.,0],1,a_min=-np.pi/2,a_max=np.pi/2,num_points=20)
+p2,v2=mt.CircleSegments([1,0],3,a_min=np.pi/2.,a_max=3.*np.pi/2,num_points=20)
+p,v=mt.AddSegments(p1,p2,closed=True)
+# plot mesh 
+mt.DoTriMesh(p,v,edge_length=length)
+
+
+#
+# rectangle and inner circle
+#
+p1,v1=mt.RectangleSegments([-2,-2],[2.5,3],edge_length=length)
+p2,v2=mt.CircleSegments([1,1],1,edge_length=length/5)
+p,v=mt.AddCurves(p1,v1,p2,v2)
+mt.DoTriMesh(p,v,edge_length=length)
+
+
+#
+# rectangle and inner line
+#
+p1,v1=mt.RectangleSegments([-2,-2],[2.5,3],edge_length=length)
+p2,v2=mt.LineSegments([0,0],[1,1],edge_length=length/5)
+p,v=mt.AddCurves(p1,v1,p2,v2)
+p3,v3=mt.LineSegments([-1,1],[0,-1],edge_length=length/5)
+p,v=mt.AddCurves(p,v,p3,v3)
+mt.DoTriMesh(p,v,edge_length=length)
+
+
+
+#
+# rectangle with holes
+p1,v1=mt.LineSegments([-2,-3],[2,-3],num_points=12)
+p2,v2=mt.LineSegments([2,3],[-2,3],num_points=12)
+p,v=mt.AddSegments(p1,p2,closed=True)
+p3,v3=mt.CircleSegments([-0.5,0.5],0.5,edge_length=length)
+p,v=mt.AddCurves(p,v,p3,v3)
+p4,v4=mt.CircleSegments([1,-1],0.5,edge_length=length)
+p,v=mt.AddCurves(p,v,p4,v4)
+mt.DoTriMesh(p,v,edge_length=length,holes=[(-0.4,0.4),(0.95,-0.8)])
+
+
+
+
+#
+# 2D curve
+#
+t=np.linspace(0,2*np.pi,120)
+r=3+np.sin(8*t)
+x=r*np.cos(t)
+y=r*np.sin(t)
+p=[(x[j],y[j]) for j in range(len(t))]
+p1,v1=mt.PointSegments(p)
+mt.DoTriMesh(p1,v1,edge_length=length)
+
+
+
+#
+# rectangle and local refinement 
+#
+p1,v1=mt.RectangleSegments([0,0],[1,1],num_points=100)
+p2,v2=mt.RectangleSegments([0.05,0.05],[0.95,0.95],num_points=40)
+p,v=mt.AddCurves(p1,v1,p2,v2)
+p3,v3=mt.RectangleSegments([0.1,0.1],[0.9,0.9],num_points=20)
+p,v=mt.AddCurves(p,v,p3,v3)
+mt.DoTriMesh(p,v,edge_length=length)
+
+
+
+
+#
+# 2D curve with local mesh refinement I
+#
+# 
+t=np.linspace(0,2*np.pi,120)
+r=3+np.sin(8*t)
+x=r*np.cos(t)
+y=r*np.sin(t)
+p=[(x[j],y[j]) for j in range(len(t))]
+p1,v1=mt.PointSegments(p)
+# function for refinement
+def myrefine1(tri_points, area):
+  center_tri = np.sum(np.array(tri_points), axis=0)/3.
+  x=center_tri[0]
+  y=center_tri[1]
+  if x>0:
+    max_area=0.05*(1+3*x)
+  else:
+    max_area=0.05
+  return bool(area>max_area);
+mt.DoTriMesh(p1,v1,tri_refine=myrefine1)
+
+
+
+
+
+#
+# 2D curve with local refinement II
+# !! 2 plots
+#
+# take p1 from above
+p2,v2=mt.CircleSegments([0,0],1,edge_length=0.1)
+p,v=mt.AddCurves(p1,v1,p2,v2)
+# function for refinement
+def myrefine2(tri_points, area):
+  center_tri = np.sum(np.array(tri_points), axis=0)/3.
+  r=np.sqrt(center_tri[0]**2+center_tri[1]**2) 
+  max_area=0.3+(0.01-0.3)/(1+0.5*(r-1)**2)
+  return bool(area>max_area);
+mt.DoTriMesh(p1,v1,tri_refine=myrefine2)  
+mt.DoTriMesh(p,v,tri_refine=myrefine2)
+
+
+
+
+#
+# 2D curve with local refinement III
+# 
+#
+# take p1 from above
+nodes=range(len(p1))
+# define tree to speed up node search
+from scipy.spatial import cKDTree
+p1tree=cKDTree(np.array(p1))
+# function for refinement
+def myrefine3(tri_points, area):
+  center_tri = np.sum(np.array(tri_points), axis=0)/3.
+  p0=[(center_tri[0],center_tri[1])]
+  node,r=mt.FindClosestNode(nodes,[],p0,tree=p1tree)
+  r=r[0]
+  max_area=0.3+(0.01-0.3)/(1+r**2) 
+  return bool(area>max_area);
+mt.DoTriMesh(p1,v1,tri_refine=myrefine3) 
+
+
+
+#
+# Example for using directly triangle
+#
+
+def round_trip_connect(start, end):
+  return [(i, i+1) for i in range(start, end)] + [(end, start)]
+
+points = [(1,0),(1,1),(-1,1),(-1,-1),(1,-1),(1,0)]
+facets = round_trip_connect(0, len(points)-1)
+
+circ_start = len(points)
+points.extend(
+        (3 * np.cos(angle), 3 * np.sin(angle))
+        for angle in np.linspace(0, 2*np.pi, 29, endpoint=False))
+
+facets.extend(round_trip_connect(circ_start, len(points)-1))
+
+def needs_refinement(vertices, area):
+    bary = np.sum(np.array(vertices), axis=0)/3
+    max_area = 0.01 + abs((la.norm(bary, np.inf)-1))*0.1
+    return bool(area > max_area)
+
+info = triangle.MeshInfo()
+info.set_points(points)
+info.set_holes([(0,0)])
+info.set_facets(facets)
+
+mesh = triangle.build(info, refinement_func=needs_refinement)
+#mesh = triangle.build(info) 
+
+mesh_points = np.array(mesh.points)
+mesh_tris = np.array(mesh.elements)
+
+import matplotlib.pyplot as pt
+print(mesh_points)
+print(mesh_tris)
+pt.triplot(mesh_points[:, 0], mesh_points[:, 1], mesh_tris)
+pt.show()
+
+
+  
diff --git a/meshpy/examples/jw_meshtools.py b/meshpy/examples/jw_meshtools.py
new file mode 100644
index 0000000000000000000000000000000000000000..f2a8e36321890990005161e81c310d2e52f69a73
--- /dev/null
+++ b/meshpy/examples/jw_meshtools.py
@@ -0,0 +1,311 @@
+# -*- coding: utf-8 -*-
+"""
+Toolbox for generating a mesh
+
+"""
+import numpy as np
+import scipy as sp
+from scipy.spatial import cKDTree
+import matplotlib.pyplot as plt
+import meshpy.triangle as triangle
+
+
+# Extract the edges
+# ouput, edges and boundary edges 
+def FindEdges(t):
+  #pdb.set_trace();  
+  NE=t.shape[0]
+  # generate an array of all edges
+  tt=np.array([t[:,0],t[:,1],t[:,1],t[:,2],t[:,2],t[:,0]]).T.reshape(3*NE,2)
+  ttt=np.sort(tt,1)
+  
+  # find all boundary edges
+  all_edges=[ tuple(x) for x in ttt ]
+  boundary_edges=[x for x in all_edges if all_edges.count(x)==1]
+  
+  # find all unique edges
+  all_edges=list(set(all_edges))
+  return all_edges,boundary_edges;
+
+
+
+
+
+##################
+#
+#  Boundary Tools
+#
+##################
+
+# given one segment 
+# e.g.  (X,2) find segment (2,Y) and delete (2,Y) from list 
+def FindNextSegment(all_segments,node):
+  # find next connecting segment  
+  help=[x for x in all_segments if x[0]==node]   
+  
+  new_bound=False
+  if len(help)==0: #if connecting segment does not exist (=>new boundary) 
+    ret=all_segments[0]
+    new_bound=True    
+  else:
+    ret=help[0]
+  
+  del all_segments[all_segments.index(ret)]
+  return ret,new_bound;  
+  
+  
+# sort segments:  (3,6),(6,1),(1,12),(12,5),...
+# on output: sorted segments and indices of the different boundaries
+def SortSegments(all_segments):  
+  count=len(all_segments)
+
+  node=-1
+  sorted_segments=[]
+  boundaries=[]
+  for j in range(len(all_segments)):
+    seg,new_bound=FindNextSegment(all_segments,node)
+    node=seg[1]
+    sorted_segments.append(seg)    
+    if new_bound==True:
+      boundaries.append(j)
+    
+  if len(sorted_segments)!=count:
+    print("Something is wrong, number of segments not the same")   
+  return sorted_segments,boundaries;
+
+# connect segments in a defined way
+# (see SortSegments), but start sorting with a defined point p
+# multiple p'2 for different closed boundaries are possible
+def ConnectBoundary(boundary_segments,Pall,p=[]):
+  
+  # sort the boundary segments  
+  allseg=boundary_segments[:]  
+  allseg,boundaries=SortSegments(allseg)
+  if p==[]:
+    return allseg,boundaries;
+    
+  max_boundaries=len(boundaries)
+   
+  # find all nodes on the given boundary
+  nodes=[x[0] for x in allseg]
+  # find closest nodes to desired point list p  
+  indices,distances=FindClosestNode(nodes,Pall,p)
+  
+  #change order within each closed boundary
+  flag_sorted=[]
+  for j in range(len(boundaries)):
+   flag_sorted.append(False) 
+   
+  for j in range(len(indices)):
+    # find position of node in the boundary list
+    # indj gives the position of the segment in allseg
+    indj=nodes.index(indices[j])
+    # find the number of boundary the node belongs to
+    this_boundary=(np.where((np.array(boundaries)<=indj))[0])[-1]
+    
+    if flag_sorted[this_boundary]==False:
+      # define the indices for slicing      
+      ind_1=boundaries[this_boundary]
+      if this_boundary+1==max_boundaries:
+        ind_2=len(allseg)
+      else:
+        ind_2=boundaries[this_boundary+1]  
+      
+      # rearange the segments in the corresponding boundary     
+      allseg=allseg[:ind_1]+allseg[indj:ind_2]+allseg[ind_1:indj]+allseg[ind_2:]
+      # resort only once      
+      flag_sorted[this_boundary]=True
+  
+  return allseg,boundaries;
+
+
+#
+# find closest node to point p0 in a list of N nodes
+# Pall coordinates of M nodes  M>=N
+# constraint defines constraints on distance
+def FindClosestNode(nodes,Pall,p0,constraint=-1,tree=None):
+  # take those points of the node list
+  
+  if tree==None:
+    p_nodes=np.array(Pall)
+    p_nodes=p_nodes[nodes] 
+    # look for minimum distance, define dist function
+    mytree = cKDTree(p_nodes)
+  else:
+    mytree=tree
+    
+  dist, index = mytree.query(np.array(p0))
+  
+  node_closest=[nodes[j] for j in index]
+   
+  # check constraints
+  num_p= len(p0)
+  if constraint<0:
+    return node_closest,dist;
+  elif np.isscalar(constraint)==True:
+    constraint=constraint*np.ones(num_p)
+  elif len(p0)!=len(constraint):
+    print('Error in constraint definition')
+    return [],[]
+  
+  # check constraint for each node
+  flags=[((dist[j]<=constraint[j]) | (constraint[j]<0)) for j in range(num_p)]
+  for j in range(num_p):
+    if flags[j]==False:
+      node_closest[j]=-1
+  return node_closest,dist;
+  
+   
+# check relative position of two points   
+def SamePoint(p1,p2,delta):
+  dp=(np.array(p1)-np.array(p2))
+  d=np.sqrt(dp[0]**2+dp[1]**2)
+  ret=False  
+  if d<delta:
+    ret=True
+  return ret;
+ 
+
+
+
+#####################
+#
+# Make simple curves
+#
+#####################
+#
+#
+# 
+# make a circle or part of it  
+#
+def CircleSegments(middle,radius,num_points=10,a_min=0.,a_max=2.*np.pi,edge_length=-1):  
+  # check for closed loop
+  number_points=num_points
+  if edge_length>0:
+    number_points=np.floor(abs(radius/edge_length*(a_max-a_min)))+1
+    
+  delta=(a_max-a_min)/number_points  
+  closed=False;  
+  if abs(a_max-a_min-2*np.pi)<0.1*delta:
+    closed=True
+    
+  t=np.linspace(a_min,a_max,number_points,not closed)
+  # define points
+  points=[(middle[0]+radius*np.cos(angle),middle[1]+radius*np.sin(angle)) for angle in t]
+  
+  # define vertices
+  vertices=[(j,j+1) for j in range(0,len(points)-1,1)]    
+  if closed==True:
+    vertices+=[(len(points)-1,0)]
+  return points,vertices;
+
+
+
+# Straight line
+def LineSegments(P1,P2,num_points=10,edge_length=-1):
+  
+  number_points=num_points
+  if edge_length>0:
+    p1=np.array(P1)
+    p2=np.array(P2)
+    number_points=np.floor(np.sqrt(np.sum((p2-p1)**2))/edge_length)+1
+  
+  t=np.linspace(0,1,number_points)
+  points=[(P1[0]+param*(P2[0]-P1[0]),P1[1]+param*(P2[1]-P1[1])) for param in t]
+  vertices=[(j,j+1) for j in range(0,len(points)-1,1)]
+  return points,vertices;
+
+
+
+# Rectangle
+def RectangleSegments(P1,P2,num_points=60,edge_length=-1):
+  P11=[P2[0],P1[1]]
+  P22=[P1[0],P2[1]]  
+  npoints=np.floor(num_points/4)
+  p_1,v_1=LineSegments(P1,P11,npoints,edge_length)
+  p_2,v_2=LineSegments(P11,P2,npoints,edge_length)  
+  p_3,v_3=LineSegments(P2,P22,npoints,edge_length)
+  p_4,v_4=LineSegments(P22,P1,npoints,edge_length)
+  p,v=AddSegments(p_1,p_2)
+  p,v=AddSegments(p,p_3)
+  p,v=AddSegments(p,p_4)
+  return p,v
+
+
+# List of points
+def PointSegments(p):
+  p1=np.array(p)
+  delta=np.min(np.sqrt(np.sum((p1[1:]-p1[:-1])**2,axis=1)))
+  Pall=[(x[0],x[1]) for x in p]  
+  closed=False  
+  if SamePoint(p1[0],p1[-1],delta)==True:
+    Pall=Pall[:-1]  
+    closed=True    
+    
+  vertices=[(j,j+1) for j in range(0,len(Pall)-1,1)]
+  if closed==True:
+    vertices+=[(len(Pall)-1,0)]  
+  
+  return Pall,vertices
+
+#Connect two different polygons  
+def AddSegments(P1,P2,closed=False):  
+  p1=np.array(P1)
+  p2=np.array(P2)
+  # find smallest distance within points p1 and p2
+  min1=np.min(np.sqrt(np.sum((p1[1:]-p1[:-1])**2,axis=1)))
+  min2=np.min(np.sqrt(np.sum((p2[1:]-p2[:-1])**2,axis=1)))
+  delta=np.min([min1,min2])
+  
+  # Add second curve to first curve 
+  del_first=SamePoint(p1[-1],p2[0],delta)
+  Pall=P1[:]  
+  if del_first==True:
+    Pall+=P2[1:]
+  else:
+    Pall+=P2
+  
+  # check if Pall is closed 
+  del_last=SamePoint(Pall[-1],p1[0],delta)
+  if del_last==True:
+    Pall=Pall[:-1]
+    
+  vertices=[(j,j+1) for j in range(0,len(Pall)-1,1)]
+  if (del_last==True) or (closed==True):
+    vertices+=[(len(Pall)-1,0)]
+  
+  return Pall,vertices;  
+
+
+# Append Curves
+def AddCurves(p1,v1,p2,v2):
+  # make one list  
+  p=p1+p2
+  v2n=[(v2[j][0]+len(p1),v2[j][1]+len(p1)) for j in range(len(v2))]
+  v=v1+v2n
+  return p,v;
+
+  
+# Generate mesh  
+def DoTriMesh(points,vertices,edge_length=-1,holes=[],tri_refine=None):
+  info = triangle.MeshInfo()
+  info.set_points(points)
+  if len(holes)>0:
+    info.set_holes(holes)
+  info.set_facets(vertices)
+
+
+  if tri_refine!=None:
+    mesh = triangle.build(info,refinement_func=tri_refine)
+  elif edge_length<=0:
+    mesh = triangle.build(info)   
+  else:
+    mesh = triangle.build(info,max_volume=0.5*edge_length**2)
+  
+  mesh_points = np.array(mesh.points)
+  mesh_elements = np.array(mesh.elements)
+  
+  
+  plt.triplot(mesh_points[:, 0], mesh_points[:, 1], mesh_elements,) 
+  plt.show()
+  return mesh_points,mesh_elements;  
diff --git a/meshpy/examples/ka-6d.ply b/meshpy/examples/ka-6d.ply
new file mode 100644
index 0000000000000000000000000000000000000000..cd479ed0c6a2849411f25f2aea3f25149813eeab
--- /dev/null
+++ b/meshpy/examples/ka-6d.ply
@@ -0,0 +1,2739 @@
+ply
+format ascii 1.0
+comment VCGLIB generated
+element vertex 911
+property float x
+property float y
+property float z
+element face 1818
+property list uchar int vertex_indices
+end_header
+-2.53779 -0.874807 0.361701 
+3.01063 -7.86294 0.395231 
+2.67315 8.00454 0.335959 
+2.29768 -7.86514 0.335959 
+2.46055 7.94854 0.335959 
+2.29768 7.86514 0.335959 
+2.17099 7.72964 0.335959 
+3.76896 -8.07564 0.335959 
+3.01063 7.86294 0.395231 
+3.76896 8.07564 0.335959 
+-0.56141 -1.93006 0.583304 
+-0.56141 1.93006 0.583304 
+-3.08403 0.942577 -0.26911 
+-3.08403 -0.867417 -0.236018 
+-3.08403 0.726857 -0.842377 
+-3.08403 0.818137 -0.239456 
+-3.08403 -0.726857 -0.842377 
+-3.08403 0.539307 -0.877237 
+-3.08403 -0.488497 -0.82562 
+-3.08403 -0.539307 -0.877237 
+-3.91989 0.426937 -0.785548 
+-3.93935 0.381326 -0.858948 
+-1.50178 -1.08824 -0.0181971 
+-1.23019 -1.12028 -0.168275 
+-1.2265 -1.09368 -0.0785382 
+-1.88591 1.03814 0.0786738 
+-2.44579 -1.04084 0.101075 
+9.28188 0 0.723383 
+9.25129 -0.133871 0.825321 
+9.25129 0.133871 0.825321 
+10.5133 0 0.97667 
+9.91637 0 0.850027 
+8.5531 0 3.48991 
+9.78764 0 3.5763 
+10.5194 0 1.16979 
+9.2433 -0.15548 0.91767 
+8.93949 0 3.55645 
+9.91273 -0.0934859 0.914697 
+9.91273 0.0934859 0.914697 
+8.87979 -3.05792 0.881246 
+8.75593 2.8863 0.923328 
+8.87979 3.05792 0.881246 
+9.79687 3.12625 0.881246 
+9.31763 -3.11498 0.881246 
+9.21955 -2.87834 0.918589 
+8.75593 -2.8863 0.923328 
+8.50119 2.8818 0.881246 
+8.66311 2.99346 0.881246 
+9.31763 3.11498 0.881246 
+8.66311 -2.99346 0.881246 
+9.51341 -2.88327 0.861804 
+9.51341 2.88327 0.861804 
+8.52379 -0.253479 0.952525 
+8.70712 0.225046 0.948112 
+8.92558 -0.197528 0.916288 
+8.92558 0.197528 0.916288 
+9.02651 0.186269 0.901245 
+8.53529 0.141349 1.18051 
+8.97217 0.14365 1.12042 
+7.30808 0.394589 0.929712 
+5.97209 0 1.33584 
+8.14849 -0.142818 1.19945 
+8.14849 0.142818 1.19945 
+9.15904 0.163526 0.881246 
+9.02651 -0.186269 0.901245 
+8.30491 0 3.34438 
+8.65189 0.141963 1.16447 
+8.53529 -0.248313 0.800641 
+8.68454 -0.226757 0.805984 
+9.21955 2.87834 0.85561 
+8.09098 0.305153 0.784654 
+7.53821 0.375496 0.80012 
+7.37388 -0.155224 1.19576 
+8.07831 0 3.09795 
+7.37388 0.155224 1.19576 
+9.51341 -2.88069 0.904149 
+9.51341 2.88069 0.904149 
+9.15904 -0.163526 0.881246 
+9.2433 0.15548 0.91767 
+-4.49171 -0.253801 0.647911 
+-6.11797 -0.111917 -0.391649 
+-6.11797 0.111917 -0.391649 
+-6.11797 0.0906809 -0.450887 
+-6.11797 -0.0494573 -0.511803 
+-6.11797 -0.0906809 -0.450887 
+-6.11797 0.0494573 -0.511803 
+-6.15074 0 -0.391649 
+-6.11797 -0.0904068 -0.291292 
+-6.11797 0.0904068 -0.291292 
+-6.11797 0.115235 -0.336436 
+-6.11797 -0.0452043 -0.248868 
+-4.03504 0.817169 0.14235 
+-2.42461 -0.906714 0.249255 
+-2.35673 0.868388 0.193357 
+-3.0811 -0.860457 0.0367379 
+-2.27809 -0.898125 0.147157 
+-2.42461 0.906714 0.249255 
+-4.03504 -0.817169 0.14235 
+-4.03512 0 -1.10113 
+-3.32169 -0.851618 0.348456 
+-3.32169 0.851618 0.348456 
+-2.6396 0.888605 0.316609 
+2.9631 -1.20617 -0.277182 
+2.6455 -1.30984 -0.16392 
+2.96423 -1.30258 -0.217357 
+2.9631 1.20617 -0.277182 
+2.96379 -1.34661 0.0301485 
+2.96379 1.34661 0.0301485 
+-2.27809 0.898125 0.147157 
+-2.19381 0.96254 0.158235 
+-2.53779 0.874807 0.361701 
+-2.49604 -0.895698 0.31593 
+-2.49604 0.895698 0.31593 
+-2.43952 0.916785 0.313112 
+1.95934 -0.874617 0.301705 
+-2.19381 -0.988717 0.297674 
+-2.19239 0.909893 0.109426 
+-1.88591 -1.03814 0.0786738 
+-1.88591 -1.05611 0.108779 
+-1.88591 1.05611 0.108779 
+0.963972 -0.957314 -0.274434 
+1.87193 0.953306 -0.272165 
+2.96382 -1.31049 0.0302124 
+2.96388 1.31313 -0.0368536 
+2.96382 1.31049 0.0302124 
+2.96374 1.28788 0.097497 
+2.96433 -1.29998 -0.100741 
+2.96433 1.29998 -0.100741 
+2.96404 1.24583 0.157554 
+2.96416 -1.24882 -0.191441 
+2.96324 -1.18716 -0.238559 
+2.96404 -1.24583 0.157554 
+2.96402 1.19128 0.203991 
+2.96324 1.18716 -0.238559 
+2.96402 -1.19128 0.203991 
+2.96483 -1.12241 0.226673 
+2.96323 -1.06586 -0.270446 
+2.96455 0.98315 0.2112 
+2.96455 -0.98315 0.2112 
+2.96442 0.90263 0.178142 
+2.96417 -0.857458 -0.174201 
+2.96421 -0.849759 0.125371 
+2.96394 0.817621 0.0490788 
+2.96364 -0.804482 -0.0351429 
+2.96364 0.804482 -0.0351429 
+2.96331 0.822326 -0.126532 
+-3.91414 -0.369186 1.16736 
+-3.91414 0 1.20677 
+-4.49712 0 0.685333 
+-3.91414 -0.591165 0.963749 
+-3.91414 0.591165 0.963749 
+-4.49171 0.253801 0.647911 
+-3.91414 -0.710333 0.668169 
+-3.91414 0.710333 0.668169 
+-3.57222 0.340054 1.30461 
+-3.91414 0.369186 1.16736 
+-2.68359 0 1.53871 
+-2.68359 0.554534 1.45808 
+-3.57222 -0.340054 1.30461 
+-3.57222 0 1.36881 
+-3.57222 -0.692627 1.00656 
+-2.68359 -0.80689 1.11743 
+-3.57222 -0.799024 0.724561 
+-3.57222 0.799024 0.724561 
+-3.57222 0.692627 1.00656 
+-1.98902 -0.722589 0.84449 
+-1.96102 -0.63848 1.13515 
+-1.96102 0.63848 1.13515 
+-1.96102 -0.466708 1.33675 
+-2.68359 0.916741 0.835233 
+-2.68359 0.80689 1.11743 
+-2.68359 -0.554534 1.45808 
+-1.96102 -0.329322 1.46632 
+-1.96102 0.329322 1.46632 
+-1.47446 0 1.51316 
+-1.96102 0 1.5499 
+-1.96102 0.466708 1.33675 
+-1.47446 0.565639 1.19455 
+-1.47446 -0.565639 1.19455 
+0.100958 -0.381001 1.16778 
+0.100958 0.381001 1.16778 
+0.0879 -0.250115 1.29799 
+0.0879 -0.360093 1.26479 
+0.0879 0.360093 1.26479 
+-1.47446 -0.447615 1.36681 
+-1.47446 0.447615 1.36681 
+0.0879 0.250115 1.29799 
+0.0879 -0.10998 1.3312 
+0.0879 0 1.34291 
+-1.47446 -0.246112 1.47606 
+-1.47446 0.246112 1.47606 
+0.63233 0 1.27673 
+0.0879 0.10998 1.3312 
+-4.78307 0.300902 0.583626 
+-4.78307 0 0.607631 
+-1.50363 -0.615787 1.04211 
+-1.98902 0.722589 0.84449 
+-2.29344 -0.783536 0.738058 
+-2.68359 -0.916741 0.835233 
+-4.4938 -0.451681 0.543677 
+-2.29344 0.783536 0.738058 
+-2.51432 -0.81237 0.67786 
+-2.69988 -0.844339 0.612684 
+-2.91595 0.825475 0.56758 
+-3.12388 -0.823567 0.511745 
+-2.91595 -0.825475 0.56758 
+-3.12388 0.823567 0.511745 
+-2.69988 0.844339 0.612684 
+-3.604 -0.76899 0.455014 
+-3.604 0.76899 0.455014 
+-3.34282 -0.800442 0.493194 
+-3.34282 0.800442 0.493194 
+5.18718 0.629555 0.24098 
+3.01955 0.764104 0.18742 
+5.18718 0.658397 0.64044 
+2.66615 -0.816364 0.333075 
+3.01955 -0.81037 0.5101 
+2.66615 -0.839496 0.494415 
+1.81272 -0.768054 0.78098 
+3.01955 0.728122 0.86486 
+2.66615 0.839496 0.494415 
+-3.93935 -0.381326 -0.858948 
+-4.03504 0.269547 -1.01235 
+-3.67274 -0.821997 -0.0548832 
+-3.32169 -0.898629 0.193905 
+-3.67274 0.821997 -0.0548832 
+-3.48098 -0.834463 -0.0251865 
+-3.32169 0.898629 0.193905 
+-3.28576 -0.335787 -1.00295 
+-3.49041 0.424467 -1.10943 
+-3.28576 0.335787 -1.00295 
+-3.49041 0.337427 -0.999098 
+-3.0811 0.424987 -1.12463 
+-2.39848 0.191842 -1.00067 
+1.60594 -0.172251 -0.568153 
+1.60594 0 -0.56656 
+-1.50574 -0.335548 -0.948802 
+-1.23019 -0.419587 -1.05115 
+-2.44579 -0.425677 -1.07659 
+-1.51335 -0.198093 -0.923457 
+-1.95655 -0.337729 -0.974066 
+-1.51335 0.198093 -0.923457 
+1.36581 0.635897 -0.653076 
+3.01955 0.594801 -0.24516 
+3.01955 -0.594801 -0.24516 
+5.18718 -0.45832 0.0210003 
+5.18718 0.45832 0.0210003 
+3.01955 0.471764 -0.35506 
+-0.473587 -0.189479 -0.805022 
+-1.50574 0.335548 -0.948802 
+-0.446537 0.333487 -0.848283 
+-0.446537 -0.333487 -0.848283 
+0.121885 -0.410137 -0.875948 
+0.121885 0.333247 -0.781573 
+0.566176 -0.180865 -0.686588 
+-0.473587 0.189479 -0.805022 
+0.121885 -0.333247 -0.781573 
+1.60594 0.344503 -0.569746 
+-3.91989 -0.426937 -0.785548 
+-3.07266 0.34084 -1.00068 
+-3.07266 -0.34084 -1.00068 
+-3.49041 -0.337427 -0.999098 
+-3.67274 -0.337117 -0.973128 
+-3.32169 0 -1.068 
+-3.67274 0.337117 -0.973128 
+-2.19239 -0.909893 0.109426 
+-2.12693 0.932102 0.0886456 
+-2.43421 -0.90903 0.0719294 
+-2.12693 -0.932102 0.0886456 
+-1.00616 -1.09437 -0.119192 
+-1.23019 1.12028 -0.168275 
+-1.2265 1.09368 -0.0785382 
+-1.00616 1.09437 -0.119192 
+-1.00755 -1.17122 -0.107995 
+-0.813925 -1.09135 -0.150126 
+-0.813925 1.09135 -0.150126 
+1.35571 1.1255 -0.311557 
+0.823181 -1.03949 -0.268335 
+1.35571 -1.1255 -0.311557 
+0.823181 1.03949 -0.268335 
+0.29065 -1.11805 -0.264808 
+0.822889 -1.00331 -0.257668 
+0.29065 1.11805 -0.264808 
+0.822889 1.00331 -0.257668 
+3.01955 -0.717839 -0.13526 
+3.01955 0.717839 -0.13526 
+1.35924 -0.901274 -0.29769 
+1.36581 0.823317 -0.523635 
+1.35924 0.901274 -0.29769 
+2.33557 -0.793406 -0.202174 
+1.88678 -0.84299 -0.24608 
+1.36581 -0.823317 -0.523635 
+1.88678 0.84299 -0.24608 
+2.29902 0.945676 0.290251 
+2.31274 -0.84549 0.31739 
+2.31274 -0.868623 0.47873 
+2.31274 0.868623 0.47873 
+1.60594 0.926876 0.44736 
+1.95934 -0.897749 0.463045 
+1.60594 -0.926876 0.44736 
+1.95934 -0.889281 0.403982 
+2.31274 0.84549 0.31739 
+1.95934 0.889281 0.403982 
+1.95934 0.897749 0.463045 
+-1.03494 -2.0487 0.396483 
+-1.03494 2.0487 0.396483 
+-2.41752 -0.865714 0.3971 
+-2.41752 0.865714 0.3971 
+-2.51432 0.81237 0.67786 
+-0.542631 1.93637 0.205763 
+-0.50905 1.29113 0.162409 
+1.34258 -1.35746 0.216253 
+1.34258 1.35746 0.216253 
+2.433 -0.951711 0.299235 
+2.433 0.951711 0.299235 
+2.41459 -0.837096 0.321911 
+2.41459 0.837096 0.321911 
+2.6455 -0.93418 0.280565 
+2.64128 1.13568 0.267791 
+-1.51335 -0.81079 0.836 
+-1.51335 0.858696 0.629739 
+-1.51335 -0.858696 0.629739 
+2.29902 -0.945676 0.290251 
+2.64183 1.40401 0.254034 
+1.95934 0.874617 0.301705 
+0.885366 0.911126 0.489491 
+2.6455 0.81442 -0.19224 
+1.60594 0.172251 -0.568153 
+-0.473587 0 -0.793893 
+0.566177 0 -0.680226 
+0.566176 0.180865 -0.686588 
+-1.51335 0 -0.90756 
+3.01955 -0.471764 -0.35506 
+2.96423 1.30258 -0.217357 
+2.96416 1.24882 -0.191441 
+2.96338 1.31525 -0.199665 
+2.96338 -1.31525 -0.199665 
+2.96444 1.34581 -0.126228 
+2.96444 -1.34581 -0.126228 
+2.9635 -1.2679 -0.159422 
+2.9635 1.2679 -0.159422 
+2.96388 -1.31313 -0.0368536 
+2.96371 -1.31679 0.104152 
+2.96374 -1.28788 0.097497 
+2.96371 1.31679 0.104152 
+2.96403 1.20379 0.215485 
+2.96499 -1.13168 0.245838 
+2.96483 1.12241 0.226673 
+2.96403 -1.20379 0.215485 
+3.01955 -0.787237 0.34876 
+2.96442 -0.90263 0.178142 
+3.01955 0.787237 0.34876 
+3.01955 -0.740972 0.0260804 
+2.96421 0.849759 0.125371 
+3.01955 -0.729405 -0.0545896 
+2.96394 -0.817621 0.0490788 
+2.96331 -0.822326 -0.126532 
+2.96426 0.802753 -0.217263 
+2.96426 -0.802753 -0.217263 
+2.9631 -0.929855 -0.277182 
+2.96323 0.942954 -0.241584 
+2.96417 0.857458 -0.174201 
+2.9631 0.929855 -0.277182 
+2.96323 -0.942954 -0.241584 
+2.96323 1.06586 -0.270446 
+1.87193 -0.953306 -0.272165 
+-2.19381 0.977533 0.227955 
+-1.88591 1.07823 0.194296 
+-2.19381 -0.96254 0.158235 
+-1.45061 1.21842 0.248379 
+-1.88591 1.09472 0.279813 
+-1.45061 1.19572 0.144175 
+-1.88591 -1.07823 0.194296 
+-1.11537 1.26941 0.144778 
+-1.00755 1.29082 0.100248 
+-1.45061 -1.19572 0.144175 
+-1.45061 -1.1653 0.0399715 
+-1.50178 1.08824 -0.0181971 
+-1.45061 1.1653 0.0399715 
+-1.00755 -1.29082 0.100248 
+-1.11537 -1.26941 0.144778 
+-0.44008 -1.36911 0.0597318 
+-0.44008 1.36911 0.0597318 
+-1.00755 -1.25367 -0.0199814 
+-0.44008 -1.23168 -0.174109 
+-1.00755 1.25367 -0.0199814 
+-0.44008 1.32642 -0.0752764 
+-1.00755 1.17122 -0.107995 
+-0.44008 1.23168 -0.174109 
+0.29065 -1.43061 0.0216282 
+-0.50905 -1.29113 0.162409 
+0.29065 -1.27917 -0.226433 
+0.29065 -1.38357 -0.12159 
+-0.44008 -1.32642 -0.0752764 
+0.29065 1.27917 -0.226433 
+-0.44008 -1.08547 -0.210284 
+1.35571 -1.48057 0.132876 
+0.29065 1.43061 0.0216282 
+0.29065 1.38357 -0.12159 
+1.35571 1.29006 -0.271862 
+1.87193 -1.26946 -0.272165 
+1.87193 1.11138 -0.311457 
+1.35571 -0.960936 -0.271862 
+1.35571 0.960936 -0.271862 
+1.35571 -1.39669 -0.163413 
+1.35571 -1.29006 -0.271862 
+1.87193 -1.37189 -0.164818 
+1.35571 -1.44474 -0.0152684 
+1.87193 1.41804 -0.0181797 
+1.35571 1.44474 -0.0152684 
+1.35571 1.39669 -0.163413 
+1.87193 -1.41804 -0.0181797 
+1.87193 -1.45247 0.128459 
+1.35571 1.48057 0.132876 
+1.87193 1.45247 0.128459 
+2.29902 -1.09727 -0.311357 
+1.87193 -1.11138 -0.311457 
+2.29902 -1.34709 -0.161763 
+1.87193 1.37189 -0.164818 
+1.87193 1.26946 -0.272165 
+2.29902 1.39135 -0.0121696 
+2.29902 -1.39135 -0.0121696 
+1.82982 1.37492 0.230421 
+2.29902 -1.24886 -0.271274 
+2.29902 1.24886 -0.271274 
+2.29902 -0.945676 -0.271274 
+2.29902 0.945676 -0.271274 
+2.29902 1.09727 -0.311357 
+2.6455 -1.07605 -0.311257 
+2.29902 1.34709 -0.161763 
+2.6455 1.30984 -0.16392 
+2.33557 0.793406 -0.202174 
+2.6455 1.35126 -0.0165825 
+2.2552 -1.39016 0.242791 
+2.29902 -1.42437 0.137425 
+2.29902 1.42437 0.137425 
+2.6455 -1.21792 -0.271779 
+2.6455 1.21792 -0.271779 
+2.9631 -1.06801 -0.311157 
+2.9631 1.06801 -0.311157 
+2.6455 -0.93418 -0.271779 
+2.6455 0.93418 -0.271779 
+2.6455 1.07605 -0.311257 
+2.6455 -0.81442 -0.19224 
+2.96478 0.954101 0.280222 
+2.66615 0.816364 0.333075 
+2.96478 -0.954101 0.280222 
+2.6455 0.93418 0.280565 
+2.96499 1.13168 0.245838 
+2.6455 -1.38216 0.130755 
+2.96406 1.26814 0.166919 
+2.6455 1.38216 0.130755 
+2.96406 -1.26814 0.166919 
+-2.35673 -0.868388 0.193357 
+-2.19381 -0.977533 0.227955 
+-2.43952 -0.916785 0.313112 
+-2.19381 0.988717 0.297674 
+2.64128 -1.13568 0.267791 
+2.96387 1.35662 -0.0478767 
+2.96387 -1.35662 -0.0478767 
+2.6455 -1.35126 -0.0165825 
+-2.6396 -0.888605 0.316609 
+-4.03504 -0.269547 -1.01235 
+-4.48334 0.674709 0.409919 
+-4.03504 -0.553424 -0.586608 
+-4.03504 0.553424 -0.586608 
+-4.03504 0.775563 -0.233459 
+-4.48334 0.770916 0.122363 
+-4.03504 -0.775563 -0.233459 
+-6.07414 -0.149952 -0.248702 
+-6.07414 0 -0.164319 
+-6.11797 0 -0.234529 
+-6.11797 0.0452043 -0.248868 
+-6.07414 0.0749767 -0.185635 
+-6.11797 -0.115235 -0.336436 
+-6.11797 0 -0.532746 
+-6.07414 0.150406 -0.485948 
+-6.07414 -0.150406 -0.485948 
+-6.07414 -0.191133 -0.31581 
+-6.07414 -0.185629 -0.397887 
+-6.07414 0.149952 -0.248702 
+-6.01159 0 -0.0660269 
+-6.07414 -0.0749767 -0.185635 
+-6.01159 0.10406 -0.0954448 
+-6.01159 -0.208118 -0.182482 
+-6.01159 -0.11385 -0.634879 
+-6.07414 0 -0.607636 
+-6.07414 -0.0820309 -0.576503 
+-6.01159 0.11385 -0.634879 
+-6.07414 0.0820309 -0.576503 
+-6.01159 -0.257635 -0.388372 
+-6.07414 0.185629 -0.397887 
+-6.01159 -0.208749 -0.509904 
+-6.01159 0.208749 -0.509904 
+-6.07414 0.191133 -0.31581 
+-6.01159 0.257635 -0.388372 
+-6.01159 -0.10406 -0.0954448 
+-5.91159 0.134745 0.00298204 
+-5.91159 -0.269489 -0.111356 
+-5.91159 0 0.0416271 
+-5.91159 -0.343498 -0.233021 
+-6.01159 0.208118 -0.182482 
+-6.01159 0 -0.677845 
+-5.91159 0.270306 -0.541478 
+-5.91159 -0.270306 -0.541478 
+-6.01159 0.265273 -0.275098 
+-6.01159 -0.265273 -0.275098 
+-4.48342 0 -1.10112 
+-4.78307 0 -1.09561 
+-4.48334 -0.254292 -1.01303 
+-4.78307 0.23337 -0.969202 
+-5.62946 -0.39091 0.0613448 
+-5.91159 0.269489 -0.111356 
+-5.34733 -0.57329 -0.027614 
+-5.62946 -0.189149 -0.833373 
+-5.62946 0 -0.918349 
+-5.91159 0 -0.762096 
+-5.34733 -0.207109 -0.895494 
+-5.34733 0.207109 -0.895494 
+-5.34733 0.415262 -0.594025 
+-5.62946 -0.364501 -0.586208 
+-5.91159 -0.147423 -0.705653 
+-5.91159 0.147423 -0.705653 
+-5.62946 0.364501 -0.586208 
+-5.62946 0.189149 -0.833373 
+-5.34733 -0.542854 -0.300859 
+-5.91159 0.333608 -0.381826 
+-5.91159 -0.333608 -0.381826 
+-5.62946 -0.485901 -0.121823 
+-5.62946 -0.464973 -0.345849 
+-5.62946 0.464973 -0.345849 
+-5.91159 0.343498 -0.233021 
+-5.62946 0.485901 -0.121823 
+-5.34733 0.542854 -0.300859 
+-5.34733 0.57329 -0.027614 
+-5.62946 0.195456 0.207999 
+-5.91159 -0.134745 0.00298204 
+-5.62946 0.39091 0.0613448 
+-5.34733 0 0.397423 
+-5.62946 -0.195456 0.207999 
+-5.62946 0 0.249735 
+-4.78307 0.601801 0.36173 
+-4.78307 -0.23337 -0.969202 
+-4.48334 0.254292 -1.01303 
+-4.48334 0.522097 -0.590555 
+-4.48334 -0.522097 -0.590555 
+-4.48334 0.731661 -0.218984 
+-4.48334 -0.770916 0.122363 
+-4.78307 -0.719087 0.089259 
+-4.48334 -0.731661 -0.218984 
+-5.34733 -0.46925 0.195797 
+-5.34733 0.46925 0.195797 
+-5.34733 0 -0.99914 
+-5.34733 -0.415262 -0.594025 
+-4.78307 -0.496539 -0.601533 
+-4.78307 0.671464 -0.243989 
+-4.78307 0.496539 -0.601533 
+-4.78307 -0.671464 -0.243989 
+-4.78307 0.719087 0.089259 
+-4.78307 -0.300902 0.583626 
+-4.78307 -0.601801 0.36173 
+-5.34733 0.234626 0.357559 
+-5.34733 -0.234626 0.357559 
+3.01955 -0.728122 0.86486 
+3.01955 0.391445 1.18532 
+1.60594 -0.47821 1.13988 
+1.60594 0.47821 1.13988 
+3.01955 -0.391445 1.18532 
+1.60594 0 1.26191 
+8.03896 0.309997 0.965108 
+8.03896 -0.309997 0.965108 
+8.53529 0.247516 1.06766 
+6.91733 0 1.60978 
+6.95017 -0.442124 0.86337 
+8.50119 -2.8818 0.881246 
+8.68454 0.226757 0.805984 
+8.53529 0.248313 0.800641 
+7.27895 -0.40552 0.811791 
+8.75593 -2.8863 0.858114 
+8.75593 2.8863 0.858114 
+7.27895 0.40552 0.811791 
+9.79687 -3.12625 0.881246 
+6.7843 0 1.48736 
+7.01477 0.100896 1.19651 
+6.59662 0 1.44692 
+6.28373 -0.0373285 1.19785 
+6.12561 0 1.4002 
+9.21955 -2.87834 0.85561 
+9.21955 2.87834 0.918589 
+8.97217 -0.14365 1.12042 
+8.65189 -0.141963 1.16447 
+8.70712 -0.225046 0.948112 
+8.52379 0.253479 0.952525 
+5.18718 0.595628 0.97187 
+5.18718 0 1.2063 
+3.01955 0 1.23766 
+5.18718 0 -0.0911597 
+3.01955 0 -0.40468 
+3.01955 0.81037 0.5101 
+8.53529 0 0.517751 
+8.53529 -0.237978 0.704231 
+8.53529 0.237978 0.704231 
+-3.08403 -0.881047 -0.670306 
+-3.08403 0.881047 -0.670306 
+-3.08403 -0.960727 -0.450042 
+-3.85508 0.961347 -0.450154 
+-3.85508 0.881677 -0.670397 
+-3.85508 -0.818777 -0.239589 
+-3.08403 -0.818137 -0.239456 
+-3.85508 0.818777 -0.239589 
+-3.85508 -0.774657 -0.260111 
+-3.08403 -0.475487 -0.74701 
+-3.08403 -0.774017 -0.25998 
+-3.08403 0.774017 -0.25998 
+-3.85508 0.476157 -0.747092 
+-3.85508 -0.476157 -0.747092 
+-3.08403 0.475487 -0.74701 
+-3.08403 0.488497 -0.82562 
+-3.85508 -0.489167 -0.825694 
+-3.85508 0.539977 -0.877307 
+-3.85508 -0.539977 -0.877307 
+-3.85508 0.727507 -0.84245 
+-3.85508 -0.600587 -0.904297 
+-3.08403 -0.599927 -0.904231 
+-3.08403 0.599927 -0.904231 
+-3.85508 0.600587 -0.904297 
+-1.23019 -1.13183 -0.353969 
+-2.44579 -1.14589 -0.396956 
+-2.44579 1.00206 -0.898507 
+-3.09459 -1.0016 -0.862829 
+-2.44579 1.14589 -0.396956 
+-2.44579 -1.14961 -0.186595 
+-3.90881 0.724167 -0.898314 
+-3.85508 -0.881677 -0.670397 
+-3.92412 0.906487 -0.69485 
+-3.92412 -0.906487 -0.69485 
+-3.85508 -0.961347 -0.450154 
+-3.9491 -1.00852 -0.315093 
+-3.9491 1.00852 -0.315093 
+-3.85508 0.943197 -0.26924 
+-3.95849 0.890367 -0.18133 
+-3.85508 -0.868047 -0.236151 
+-3.85508 0.868047 -0.236151 
+-3.95849 -0.832097 -0.185396 
+-3.95849 0.832097 -0.185396 
+-3.85508 0.774657 -0.260111 
+-3.95741 -0.776827 -0.213361 
+-3.95741 0.776827 -0.213361 
+-3.85508 0.489167 -0.825694 
+-3.9128 -0.442317 -0.8785 
+-3.90116 -0.574077 -0.971452 
+-3.85508 -0.727507 -0.84245 
+-3.85889 -0.969457 -0.343513 
+-3.85889 0.969457 -0.343513 
+-3.94279 1.0007 -0.434401 
+-3.85518 -1.03706 -0.15055 
+-3.95511 -0.979237 -0.22046 
+-3.95511 0.979237 -0.22046 
+-3.95849 -0.890367 -0.18133 
+-3.85518 0.920717 -0.0322682 
+-3.85518 -0.920717 -0.0322682 
+-3.85518 0.971987 -0.0510992 
+-3.85518 -0.802107 -0.101832 
+-3.85518 0.802107 -0.101832 
+-3.90428 -0.502407 -0.939534 
+-3.9128 0.442317 -0.8785 
+-3.85518 -0.555667 -1.0408 
+-3.85518 0.555667 -1.0408 
+-3.90428 0.502407 -0.939534 
+-3.85518 0.707167 -1.00036 
+-3.90116 0.574077 -0.971452 
+-3.90881 -0.724167 -0.898314 
+-3.85518 1.06134 -0.425472 
+-3.85518 -1.06134 -0.425472 
+-3.94279 -1.0007 -0.434401 
+-3.85518 1.03706 -0.15055 
+-3.67274 1.1045 -0.2514 
+-3.85518 -0.971987 -0.0510992 
+-3.67274 -0.945637 0.0227438 
+-3.85518 0.417187 -1.0176 
+-3.85518 -0.417187 -1.0176 
+-3.67274 -0.420797 -1.0768 
+-3.67274 0.565137 -1.10269 
+-3.85518 -0.707167 -1.00036 
+-3.67274 -0.723047 -1.05757 
+-3.67274 1.11345 -0.416037 
+-3.85518 0.933697 -0.772988 
+-3.85518 -0.933697 -0.772988 
+-3.85518 -1.07314 -0.277937 
+-3.85518 1.07314 -0.277937 
+-3.49041 1.13555 -0.231067 
+-3.67274 1.0669 -0.109248 
+-3.67274 -1.0669 -0.109248 
+-3.49041 -1.09644 -0.0797953 
+-3.67274 0.999067 0.00172983 
+-3.67274 -0.999067 0.00172983 
+-3.49041 -0.970327 0.0606648 
+-3.49041 0.970327 0.0606648 
+-3.48098 0.834463 -0.0251865 
+-3.67274 0.945637 0.0227438 
+-3.67274 0.420797 -1.0768 
+-3.67274 -0.565137 -1.10269 
+-3.49041 -0.424467 -1.10943 
+-3.49041 -0.574587 -1.13697 
+-3.49041 0.574587 -1.13697 
+-3.67274 -0.959167 -0.814027 
+-3.49041 -0.738827 -1.08895 
+-3.49041 0.984397 -0.836782 
+-3.67274 0.723047 -1.05757 
+-3.67274 0.959167 -0.814027 
+-3.67274 -1.11345 -0.416037 
+-3.67274 -1.1045 -0.2514 
+-3.0811 -1.1671 -0.186595 
+-3.49041 1.09644 -0.0797953 
+-3.0811 1.12628 -0.0250462 
+-3.0811 -1.12628 -0.0250462 
+-3.49041 -1.0259 0.0383028 
+-3.0811 -1.05266 0.101075 
+-3.49041 1.0259 0.0383028 
+-3.0811 -0.424987 -1.12463 
+-3.0811 0.581657 -1.15405 
+-3.49041 0.738827 -1.08895 
+-3.0811 0.753057 -1.10276 
+-3.0811 -0.753057 -1.10276 
+-3.49041 -1.14486 -0.406266 
+-3.49041 -0.984397 -0.836782 
+-3.09459 1.0016 -0.862829 
+-3.0811 1.16649 -0.399181 
+-3.49041 1.14486 -0.406266 
+-3.49041 -1.13555 -0.231067 
+-3.0811 -1.16649 -0.399181 
+-3.0811 1.1671 -0.186595 
+-2.44579 1.14961 -0.186595 
+-2.44579 -1.11081 -0.0250461 
+-2.44579 1.11081 -0.0250461 
+-3.0811 1.05266 0.101075 
+-3.0811 -0.994657 0.124957 
+-2.44579 0.985707 0.124957 
+-2.44579 1.04084 0.101075 
+-2.44579 -0.985707 0.124957 
+-3.0811 0.994657 0.124957 
+-3.0811 0.860457 0.0367379 
+-2.43421 0.90903 0.0719294 
+-3.0811 -0.581657 -1.15405 
+-2.44579 0.756067 -1.10276 
+-2.44579 0.583457 -1.15405 
+-1.23019 0.567517 -1.07884 
+-1.23019 0.419587 -1.05115 
+-2.44579 -0.583457 -1.15405 
+-1.23019 -0.567517 -1.07884 
+-2.44579 -0.756067 -1.10276 
+-1.23019 0.729347 -1.03057 
+-2.44579 -1.00206 -0.898507 
+-1.23019 0.973707 -0.838325 
+0.121885 -0.542747 -0.899513 
+0.121885 0.410137 -0.875948 
+-1.23019 -0.729347 -1.03057 
+-1.23019 -0.973707 -0.838325 
+0.121885 -0.906867 -0.694829 
+0.121885 0.687817 -0.858436 
+0.121885 0.542747 -0.899513 
+0.121885 -0.687817 -0.858436 
+1.36581 -0.511777 -0.685575 
+1.36581 0.511777 -0.685575 
+1.36581 -0.635897 -0.653076 
+1.60594 -0.344503 -0.569746 
+-3.08403 -0.967337 -0.349142 
+-3.08403 0.960727 -0.450042 
+-3.08403 0.967337 -0.349142 
+-3.08403 -0.942577 -0.26911 
+-3.08403 0.867417 -0.236018 
+-3.85508 -0.943197 -0.26924 
+0.963972 0.957314 -0.274434 
+-1.88591 -1.09472 0.279813 
+-1.45061 -1.21842 0.248379 
+-4.4938 0.451681 0.543677 
+-4.48334 -0.674709 0.409919 
+-3.97321 -0.700374 0.451518 
+-3.97321 0.700374 0.451518 
+-4.47329 -0.582013 0.479882 
+-4.47329 0.582013 0.479882 
+8.53529 -0.247516 1.06766 
+8.53529 -0.141349 1.18051 
+-0.861793 0.521872 1.09238 
+1.06526 -4.97046 0.270861 
+3.09835 -8.05894 0.335959 
+1.06526 4.97046 0.270861 
+2.67315 -8.00454 0.335959 
+3.09835 8.05894 0.335959 
+2.46055 -7.94854 0.335959 
+2.17099 -7.72964 0.335959 
+0.81418 -4.833 0.270861 
+0.81418 4.833 0.270861 
+-0.542631 -1.93637 0.205763 
+0.399974 -1.64691 0.211008 
+1.81272 0.768054 0.78098 
+0.887511 0.869861 0.576801 
+0.887511 -0.869861 0.576801 
+0.885366 -0.911126 0.489491 
+1.82982 -1.37492 0.230421 
+0.399974 1.64691 0.211008 
+2.2552 1.39016 0.242791 
+2.64183 -1.40401 0.254034 
+0.26164 -1.31874 0.18482 
+0.26164 1.31874 0.18482 
+-0.0713282 1.79164 0.208385 
+-0.0713282 -1.79164 0.208385 
+0.253484 1.80328 0.217831 
+0.253484 -1.80328 0.217831 
+1.0496 -1.67019 0.229899 
+1.0496 1.67019 0.229899 
+1.61316 -5.006 0.270861 
+1.61316 5.006 0.270861 
+-1.23019 1.13183 -0.353969 
+5.18718 -0.595628 0.97187 
+6.06868 -0.518876 0.91762 
+7.30808 -0.394589 0.929712 
+6.24013 -0.48615 1.00199 
+6.06868 0.518876 0.91762 
+6.24013 0.48615 1.00199 
+7.29308 0.376672 1.03212 
+7.29308 -0.376672 1.03212 
+5.18718 -0.658397 0.64044 
+6.23307 -0.531959 0.726115 
+7.53821 -0.375496 0.80012 
+6.75601 -0.468739 0.768953 
+6.23307 0.531959 0.726115 
+7.16202 0.418556 0.755385 
+6.95017 0.442124 0.86337 
+6.75601 0.468739 0.768953 
+6.63908 -0.467354 0.512817 
+6.86123 0.433766 0.472606 
+6.63908 0.467354 0.512817 
+8.53529 -0.127758 0.539191 
+6.86123 -0.378657 0.390086 
+8.53529 0.127758 0.539191 
+7.16202 -0.418556 0.755385 
+8.09098 -0.305153 0.784654 
+5.68089 -0.576805 0.369581 
+5.68089 0.576805 0.369581 
+6.02421 -0.504106 0.315533 
+6.02421 0.504106 0.315533 
+6.02421 0.531661 0.356793 
+6.02421 -0.531661 0.356793 
+6.86123 -0.433766 0.472606 
+6.86123 0.378657 0.390086 
+6.1746 -0.524055 0.498182 
+6.1746 0.524055 0.498182 
+4.10336 0.685264 0.13353 
+4.10336 -0.685264 0.13353 
+3.01955 -0.764104 0.18742 
+4.10336 -0.673697 0.05286 
+3.01955 0.729405 -0.0545896 
+3.01955 0.740972 0.0260804 
+5.18718 -0.629555 0.24098 
+4.10336 0.673697 0.05286 
+0.121885 -1.04862 -0.282625 
+0.350255 1.03029 -0.267193 
+0.120963 -1.04295 -0.240179 
+0.349793 -1.02745 -0.245971 
+0.349793 1.02745 -0.245971 
+0.464209 1.0197 -0.248866 
+-0.216134 1.06942 -0.300461 
+-0.554152 -1.09022 -0.318297 
+-0.44008 1.08547 -0.210284 
+-0.554152 1.09022 -0.318297 
+0.120963 1.04295 -0.240179 
+-0.216134 -1.06942 -0.300461 
+0.121885 1.04862 -0.282625 
+0.121885 0.906867 -0.694829 
+0.743847 0.935969 -0.40313 
+0.972217 0.917634 -0.387699 
+0.743847 -0.935969 -0.40313 
+0.464209 -1.0197 -0.248866 
+0.972217 -0.917634 -0.387699 
+0.578624 -1.01195 -0.251762 
+0.578624 1.01195 -0.251762 
+0.350255 -1.03029 -0.267193 
+-1.95655 0.337729 -0.974066 
+-2.39848 -0.191842 -1.00067 
+-2.90259 -0.339019 -0.99336 
+-2.90259 0.339019 -0.99336 
+-2.42213 -0.340666 -0.987647 
+-2.44579 0.425677 -1.07659 
+-2.42213 0.340666 -0.987647 
+6.64745 0.0799605 1.19695 
+5.86469 0.175109 1.19635 
+6.66784 0.227854 1.18756 
+6.66784 -0.227854 1.18756 
+7.01477 -0.100896 1.19651 
+5.86469 -0.175109 1.19635 
+6.64745 -0.0799605 1.19695 
+5.18718 0.312889 1.17567 
+5.91126 0 1.20755 
+6.28373 0.0373285 1.19785 
+6.66784 -0.369223 1.08566 
+6.66784 0.369223 1.08566 
+5.18718 -0.312889 1.17567 
+-0.861793 -0.521872 1.09238 
+0.149685 0.789422 0.80849 
+-1.51335 0.81079 0.836 
+0.149685 -0.789422 0.80849 
+0.169083 -0.812846 0.706241 
+0.154545 -0.691921 0.911545 
+-1.18271 -0.568829 1.06725 
+0.154545 0.691921 0.911545 
+-1.50363 0.615787 1.04211 
+-1.18271 0.568829 1.06725 
+0.169083 0.812846 0.706241 
+0.475464 -0.644963 0.93668 
+0.475464 0.644963 0.93668 
+3 0 304 10 
+3 11 305 110 
+3 10 802 321 
+3 320 323 11 
+3 10 304 790 
+3 6 305 11 
+3 785 7 1 
+3 8 9 788 
+3 787 785 1 
+3 8 788 2 
+3 789 787 1 
+3 8 2 4 
+3 3 789 1 
+3 8 4 5 
+3 790 3 1 
+3 8 5 6 
+3 10 790 1 
+3 8 6 11 
+3 7 802 1 
+3 8 323 9 
+3 802 10 1 
+3 8 11 323 
+3 604 766 769 
+3 12 768 767 
+3 602 604 769 
+3 12 767 603 
+3 602 769 13 
+3 770 12 603 
+3 16 602 13 
+3 770 603 14 
+3 16 13 608 
+3 15 770 14 
+3 16 608 612 
+3 613 15 14 
+3 16 612 611 
+3 616 613 14 
+3 623 16 611 
+3 616 14 624 
+3 19 623 611 
+3 616 624 17 
+3 18 19 611 
+3 616 17 617 
+3 221 649 258 
+3 20 665 21 
+3 733 24 22 
+3 377 271 734 
+3 631 24 733 
+3 734 271 732 
+3 631 23 24 
+3 271 270 732 
+3 26 22 117 
+3 25 377 738 
+3 733 22 26 
+3 738 377 734 
+3 27 37 28 
+3 29 38 27 
+3 30 37 31 
+3 31 38 30 
+3 31 37 27 
+3 27 38 31 
+3 37 35 28 
+3 29 78 38 
+3 35 32 65 
+3 65 32 78 
+3 37 34 33 
+3 33 34 38 
+3 34 37 30 
+3 30 38 34 
+3 32 35 36 
+3 36 78 32 
+3 36 37 33 
+3 33 38 36 
+3 35 37 36 
+3 36 38 78 
+3 45 49 39 
+3 41 47 40 
+3 45 39 43 
+3 48 41 40 
+3 43 581 75 
+3 76 42 48 
+3 43 44 45 
+3 40 588 48 
+3 43 75 44 
+3 588 76 48 
+3 49 45 574 
+3 46 40 47 
+3 578 43 39 
+3 41 48 579 
+3 39 49 578 
+3 579 47 41 
+3 578 49 574 
+3 46 47 579 
+3 43 50 581 
+3 42 51 48 
+3 43 587 50 
+3 51 69 48 
+3 43 578 587 
+3 69 579 48 
+3 591 52 75 
+3 76 592 53 
+3 64 54 581 
+3 42 55 56 
+3 782 590 65 
+3 65 66 57 
+3 589 35 65 
+3 65 78 58 
+3 816 573 45 
+3 40 828 59 
+3 893 585 60 
+3 60 894 893 
+3 61 782 73 
+3 73 57 62 
+3 577 824 578 
+3 579 71 580 
+3 28 35 77 
+3 63 78 29 
+3 77 35 64 
+3 56 78 63 
+3 77 64 581 
+3 42 56 63 
+3 589 65 590 
+3 66 65 58 
+3 67 68 587 
+3 69 575 576 
+3 67 587 837 
+3 70 69 576 
+3 824 837 578 
+3 579 70 71 
+3 816 570 781 
+3 571 569 59 
+3 816 44 570 
+3 569 588 59 
+3 72 61 73 
+3 73 62 74 
+3 570 75 52 
+3 592 76 569 
+3 77 68 600 
+3 601 575 63 
+3 50 68 77 
+3 63 575 51 
+3 573 577 574 
+3 46 580 828 
+3 35 54 64 
+3 56 55 78 
+3 35 591 54 
+3 55 53 78 
+3 560 79 559 
+3 193 151 541 
+3 86 80 474 
+3 89 81 86 
+3 86 84 80 
+3 81 82 86 
+3 86 83 84 
+3 82 85 86 
+3 86 475 83 
+3 85 475 86 
+3 86 474 87 
+3 88 89 86 
+3 90 471 86 
+3 86 471 472 
+3 86 87 90 
+3 472 88 86 
+3 646 97 468 
+3 466 91 647 
+3 97 99 777 
+3 778 100 91 
+3 97 224 99 
+3 100 227 91 
+3 94 92 224 
+3 227 96 741 
+3 92 94 453 
+3 93 741 96 
+3 453 94 95 
+3 108 741 93 
+3 94 265 95 
+3 108 116 741 
+3 111 461 92 
+3 96 101 112 
+3 97 223 224 
+3 227 225 91 
+3 97 662 223 
+3 225 663 91 
+3 646 662 97 
+3 91 663 647 
+3 98 263 462 
+3 222 263 98 
+3 99 306 210 
+3 211 307 100 
+3 99 0 306 
+3 307 110 100 
+3 461 0 99 
+3 100 110 101 
+3 0 461 111 
+3 112 101 110 
+3 102 103 436 
+3 437 430 105 
+3 103 102 336 
+3 335 105 430 
+3 336 102 104 
+3 333 105 335 
+3 103 336 338 
+3 337 335 430 
+3 106 342 449 
+3 451 344 107 
+3 348 346 457 
+3 318 448 345 
+3 95 368 453 
+3 93 109 108 
+3 368 95 265 
+3 116 108 109 
+3 0 111 455 
+3 113 112 110 
+3 92 455 111 
+3 112 113 96 
+3 114 322 294 
+3 301 293 324 
+3 115 0 455 
+3 113 110 456 
+3 265 118 368 
+3 109 119 116 
+3 268 118 265 
+3 116 119 266 
+3 268 117 118 
+3 119 25 266 
+3 117 376 118 
+3 119 378 25 
+3 22 376 117 
+3 25 378 377 
+3 273 395 384 
+3 388 864 387 
+3 286 402 120 
+3 772 403 288 
+3 290 425 365 
+3 121 426 292 
+3 290 289 425 
+3 426 431 292 
+3 122 341 126 
+3 127 123 124 
+3 343 122 126 
+3 127 124 125 
+3 343 126 339 
+3 340 127 125 
+3 131 343 339 
+3 340 125 128 
+3 131 339 129 
+3 334 340 128 
+3 129 130 131 
+3 128 133 334 
+3 131 130 134 
+3 132 133 128 
+3 134 130 135 
+3 347 133 132 
+3 135 130 136 
+3 364 133 347 
+3 138 135 136 
+3 364 347 137 
+3 138 136 363 
+3 360 364 137 
+3 350 138 363 
+3 360 137 139 
+3 350 363 140 
+3 361 360 139 
+3 141 350 140 
+3 361 139 353 
+3 141 140 356 
+3 145 361 353 
+3 355 141 356 
+3 145 353 142 
+3 355 356 143 
+3 144 145 142 
+3 148 146 147 
+3 147 155 148 
+3 148 79 146 
+3 155 151 148 
+3 79 149 146 
+3 155 150 151 
+3 79 152 149 
+3 150 153 151 
+3 79 199 152 
+3 153 775 151 
+3 208 152 777 
+3 778 153 209 
+3 208 162 152 
+3 153 163 209 
+3 160 152 162 
+3 163 153 164 
+3 160 149 152 
+3 153 150 164 
+3 160 146 149 
+3 150 155 164 
+3 160 158 146 
+3 155 154 164 
+3 159 146 158 
+3 154 155 159 
+3 159 147 146 
+3 155 147 159 
+3 159 171 156 
+3 156 157 159 
+3 159 158 171 
+3 157 154 159 
+3 160 171 158 
+3 154 157 164 
+3 160 161 171 
+3 157 170 164 
+3 160 198 161 
+3 170 169 164 
+3 160 162 198 
+3 169 163 164 
+3 208 198 162 
+3 163 169 209 
+3 165 166 198 
+3 169 167 196 
+3 168 198 166 
+3 167 169 176 
+3 168 161 198 
+3 169 170 176 
+3 168 171 161 
+3 170 157 176 
+3 168 172 171 
+3 157 173 176 
+3 175 171 172 
+3 173 157 175 
+3 175 156 171 
+3 157 156 175 
+3 175 189 174 
+3 174 190 175 
+3 175 172 189 
+3 190 173 175 
+3 168 189 172 
+3 173 190 176 
+3 168 184 189 
+3 190 185 176 
+3 168 178 184 
+3 185 177 176 
+3 168 166 178 
+3 177 167 176 
+3 165 178 166 
+3 167 177 196 
+3 165 195 178 
+3 177 906 196 
+3 179 182 178 
+3 177 183 180 
+3 181 178 182 
+3 183 177 186 
+3 181 184 178 
+3 177 185 186 
+3 181 189 184 
+3 185 190 186 
+3 181 187 189 
+3 190 192 186 
+3 188 189 187 
+3 192 190 188 
+3 188 174 189 
+3 190 174 188 
+3 188 187 191 
+3 191 192 188 
+3 181 191 187 
+3 192 191 186 
+3 181 182 191 
+3 191 183 186 
+3 179 191 182 
+3 183 191 180 
+3 79 194 559 
+3 193 194 151 
+3 79 148 194 
+3 194 148 151 
+3 195 165 319 
+3 900 196 906 
+3 197 165 198 
+3 169 196 200 
+3 199 79 560 
+3 541 151 775 
+3 776 779 560 
+3 541 780 463 
+3 165 197 319 
+3 900 200 196 
+3 197 201 319 
+3 900 308 200 
+3 202 201 198 
+3 169 308 207 
+3 201 197 198 
+3 169 200 308 
+3 201 202 306 
+3 307 207 308 
+3 202 205 306 
+3 307 203 207 
+3 205 204 306 
+3 307 206 203 
+3 204 210 306 
+3 307 211 206 
+3 204 205 198 
+3 169 203 206 
+3 205 202 198 
+3 169 207 203 
+3 210 208 99 
+3 100 209 211 
+3 208 777 99 
+3 100 778 209 
+3 208 210 198 
+3 169 211 209 
+3 210 204 198 
+3 169 206 211 
+3 179 565 568 
+3 568 566 180 
+3 191 179 568 
+3 568 180 191 
+3 179 898 565 
+3 566 783 180 
+3 195 904 178 
+3 177 907 906 
+3 904 898 178 
+3 177 783 907 
+3 850 854 822 
+3 214 212 213 
+3 216 349 822 
+3 214 351 598 
+3 349 850 822 
+3 214 213 351 
+3 217 295 215 
+3 445 296 220 
+3 215 349 217 
+3 220 351 445 
+3 216 217 349 
+3 351 220 598 
+3 295 563 218 
+3 795 219 296 
+3 299 298 218 
+3 795 303 297 
+3 217 216 563 
+3 219 598 220 
+3 298 295 218 
+3 795 296 303 
+3 295 217 563 
+3 219 220 296 
+3 462 221 464 
+3 465 21 222 
+3 223 226 224 
+3 227 698 225 
+3 226 94 224 
+3 227 741 698 
+3 228 719 702 
+3 229 232 230 
+3 261 228 702 
+3 229 230 231 
+3 228 260 719 
+3 232 259 230 
+3 879 263 331 
+3 331 263 233 
+3 240 879 331 
+3 331 233 878 
+3 879 880 263 
+3 263 881 233 
+3 234 235 597 
+3 597 235 327 
+3 236 237 238 
+3 883 747 249 
+3 236 239 248 
+3 255 241 249 
+3 331 239 240 
+3 878 241 331 
+3 239 236 240 
+3 878 249 241 
+3 244 764 762 
+3 763 242 243 
+3 332 244 762 
+3 763 243 247 
+3 244 284 764 
+3 242 285 243 
+3 244 245 854 
+3 212 246 243 
+3 244 332 245 
+3 246 247 243 
+3 240 236 238 
+3 883 249 878 
+3 251 236 248 
+3 255 249 250 
+3 251 252 237 
+3 747 755 250 
+3 236 251 237 
+3 747 250 249 
+3 251 256 252 
+3 755 253 250 
+3 256 248 254 
+3 330 255 253 
+3 256 251 248 
+3 255 250 253 
+3 256 765 252 
+3 755 257 253 
+3 765 254 234 
+3 327 330 257 
+3 765 256 254 
+3 330 253 257 
+3 262 221 462 
+3 222 21 264 
+3 464 646 468 
+3 466 647 465 
+3 221 646 464 
+3 465 647 21 
+3 258 646 221 
+3 21 647 20 
+3 880 260 263 
+3 263 259 881 
+3 260 228 263 
+3 263 230 259 
+3 880 238 719 
+3 232 883 881 
+3 260 880 719 
+3 232 881 259 
+3 261 263 228 
+3 230 263 231 
+3 262 462 263 
+3 263 222 264 
+3 262 263 261 
+3 231 263 264 
+3 94 267 265 
+3 116 742 741 
+3 267 268 265 
+3 116 266 742 
+3 267 739 268 
+3 266 737 742 
+3 22 24 273 
+3 387 271 377 
+3 24 269 273 
+3 387 272 271 
+3 274 269 23 
+3 270 272 275 
+3 269 24 23 
+3 270 271 272 
+3 269 274 273 
+3 387 275 272 
+3 274 395 273 
+3 387 864 275 
+3 395 274 626 
+3 813 275 864 
+3 274 23 626 
+3 813 270 275 
+3 858 280 395 
+3 864 282 866 
+3 280 277 278 
+3 276 279 282 
+3 277 402 278 
+3 276 403 279 
+3 281 277 280 
+3 282 279 283 
+3 277 281 402 
+3 403 283 279 
+3 875 281 280 
+3 282 283 876 
+3 286 120 291 
+3 287 772 288 
+3 284 291 764 
+3 242 287 285 
+3 284 289 291 
+3 287 431 285 
+3 290 286 291 
+3 287 288 292 
+3 289 290 291 
+3 287 292 431 
+3 215 315 317 
+3 447 316 445 
+3 315 294 322 
+3 293 301 316 
+3 315 215 295 
+3 296 445 316 
+3 294 295 298 
+3 303 296 301 
+3 295 294 315 
+3 316 301 296 
+3 114 300 299 
+3 297 302 324 
+3 300 298 299 
+3 297 303 302 
+3 298 300 294 
+3 301 302 303 
+3 300 114 294 
+3 301 324 302 
+3 321 319 201 
+3 308 900 320 
+3 321 306 10 
+3 11 307 320 
+3 306 0 10 
+3 11 110 307 
+3 0 115 304 
+3 305 456 110 
+3 321 201 306 
+3 307 308 320 
+3 774 380 304 
+3 305 373 369 
+3 380 793 304 
+3 305 309 373 
+3 380 390 793 
+3 309 310 373 
+3 390 803 793 
+3 309 804 310 
+3 396 311 803 
+3 804 312 413 
+3 457 313 802 
+3 323 314 318 
+3 322 313 315 
+3 316 314 293 
+3 313 317 315 
+3 316 447 314 
+3 317 313 457 
+3 318 314 447 
+3 321 902 319 
+3 900 908 320 
+3 321 798 902 
+3 908 325 320 
+3 802 798 321 
+3 320 325 323 
+3 802 313 322 
+3 293 314 323 
+3 802 322 798 
+3 325 293 323 
+3 114 798 322 
+3 293 325 324 
+3 299 798 114 
+3 324 325 297 
+3 443 289 284 
+3 285 431 326 
+3 443 284 358 
+3 357 285 326 
+3 234 254 329 
+3 329 330 327 
+3 234 329 235 
+3 235 329 327 
+3 254 248 328 
+3 328 255 330 
+3 254 328 329 
+3 329 328 330 
+3 248 239 331 
+3 331 241 255 
+3 248 331 328 
+3 328 331 255 
+3 765 234 332 
+3 247 327 257 
+3 234 597 332 
+3 247 597 327 
+3 130 102 438 
+3 439 105 133 
+3 130 438 136 
+3 364 439 133 
+3 102 130 129 
+3 334 133 105 
+3 102 129 104 
+3 333 334 105 
+3 339 336 129 
+3 334 335 340 
+3 336 104 129 
+3 334 333 335 
+3 126 338 339 
+3 340 337 127 
+3 338 336 339 
+3 340 335 337 
+3 341 459 126 
+3 127 458 123 
+3 459 338 126 
+3 127 337 458 
+3 122 106 341 
+3 123 107 124 
+3 106 459 341 
+3 123 458 107 
+3 343 342 122 
+3 124 344 125 
+3 342 106 122 
+3 124 107 344 
+3 131 452 343 
+3 125 450 128 
+3 452 342 343 
+3 125 344 450 
+3 134 348 131 
+3 128 345 132 
+3 348 452 131 
+3 128 450 345 
+3 135 346 134 
+3 132 448 347 
+3 346 348 134 
+3 132 345 448 
+3 138 446 346 
+3 448 444 137 
+3 138 346 135 
+3 347 448 137 
+3 350 349 446 
+3 444 351 139 
+3 350 446 138 
+3 137 444 139 
+3 141 850 350 
+3 139 213 353 
+3 850 349 350 
+3 139 351 213 
+3 355 352 141 
+3 353 853 142 
+3 352 850 141 
+3 353 213 853 
+3 143 354 352 
+3 853 852 144 
+3 143 352 355 
+3 142 853 144 
+3 356 284 354 
+3 852 285 145 
+3 356 354 143 
+3 144 852 145 
+3 140 358 356 
+3 145 357 361 
+3 358 284 356 
+3 145 285 357 
+3 363 359 140 
+3 361 362 360 
+3 359 358 140 
+3 361 357 362 
+3 136 438 359 
+3 362 439 364 
+3 136 359 363 
+3 360 362 364 
+3 290 365 286 
+3 288 121 292 
+3 365 402 286 
+3 288 403 121 
+3 372 773 454 
+3 366 370 367 
+3 773 115 454 
+3 366 456 370 
+3 118 372 368 
+3 109 367 119 
+3 372 454 368 
+3 109 366 367 
+3 375 774 372 
+3 367 369 371 
+3 774 773 372 
+3 367 370 369 
+3 376 375 118 
+3 119 371 378 
+3 375 372 118 
+3 119 367 371 
+3 774 375 380 
+3 373 371 369 
+3 375 379 380 
+3 373 374 371 
+3 383 379 376 
+3 378 374 385 
+3 379 375 376 
+3 378 371 374 
+3 273 383 376 
+3 378 385 387 
+3 273 376 22 
+3 377 378 387 
+3 381 390 379 
+3 374 310 382 
+3 390 380 379 
+3 374 373 310 
+3 393 381 383 
+3 385 382 386 
+3 381 379 383 
+3 385 374 382 
+3 384 393 383 
+3 385 386 388 
+3 384 383 273 
+3 387 385 388 
+3 389 803 381 
+3 382 804 397 
+3 803 390 381 
+3 382 310 804 
+3 392 389 393 
+3 386 397 398 
+3 389 381 393 
+3 386 382 397 
+3 391 392 393 
+3 386 398 394 
+3 391 393 384 
+3 388 386 394 
+3 280 391 384 
+3 388 394 282 
+3 280 384 395 
+3 864 388 282 
+3 407 396 389 
+3 397 413 409 
+3 396 803 389 
+3 397 804 413 
+3 404 407 392 
+3 398 409 410 
+3 407 389 392 
+3 398 397 409 
+3 405 404 391 
+3 394 410 399 
+3 404 392 391 
+3 394 398 410 
+3 278 405 280 
+3 282 399 276 
+3 405 391 280 
+3 282 394 399 
+3 405 278 400 
+3 419 276 399 
+3 278 416 400 
+3 419 401 276 
+3 278 402 416 
+3 401 403 276 
+3 402 365 416 
+3 401 121 403 
+3 404 405 406 
+3 418 399 410 
+3 405 400 406 
+3 418 419 399 
+3 407 404 411 
+3 408 410 409 
+3 404 406 411 
+3 408 418 410 
+3 396 407 412 
+3 414 409 413 
+3 407 411 412 
+3 414 408 409 
+3 311 396 799 
+3 422 413 312 
+3 396 412 799 
+3 422 414 413 
+3 400 416 423 
+3 424 401 419 
+3 416 415 423 
+3 424 427 401 
+3 416 365 415 
+3 427 121 401 
+3 365 425 415 
+3 427 426 121 
+3 406 400 417 
+3 429 419 418 
+3 400 423 417 
+3 429 424 419 
+3 411 406 421 
+3 420 418 408 
+3 406 417 421 
+3 420 429 418 
+3 412 411 421 
+3 420 408 414 
+3 412 421 434 
+3 435 420 414 
+3 799 412 434 
+3 435 414 422 
+3 799 434 433 
+3 801 435 422 
+3 423 415 436 
+3 437 427 424 
+3 415 428 436 
+3 437 442 427 
+3 415 425 428 
+3 442 426 427 
+3 425 440 428 
+3 442 441 426 
+3 417 423 103 
+3 430 424 429 
+3 423 436 103 
+3 430 437 424 
+3 425 289 440 
+3 441 431 426 
+3 289 443 440 
+3 441 326 431 
+3 421 417 460 
+3 432 429 420 
+3 417 103 460 
+3 432 430 429 
+3 434 421 449 
+3 451 420 435 
+3 421 460 449 
+3 451 432 420 
+3 433 434 802 
+3 323 435 801 
+3 434 449 802 
+3 323 451 435 
+3 436 428 102 
+3 105 442 437 
+3 428 438 102 
+3 105 439 442 
+3 428 440 438 
+3 439 441 442 
+3 440 359 438 
+3 439 362 441 
+3 440 443 359 
+3 362 326 441 
+3 443 358 359 
+3 362 357 326 
+3 215 317 446 
+3 444 447 445 
+3 215 446 349 
+3 351 444 445 
+3 317 457 446 
+3 444 318 447 
+3 457 346 446 
+3 444 448 318 
+3 802 449 452 
+3 450 451 323 
+3 449 342 452 
+3 450 344 451 
+3 453 368 454 
+3 366 109 93 
+3 453 454 92 
+3 96 366 93 
+3 92 454 115 
+3 456 366 96 
+3 92 115 455 
+3 113 456 96 
+3 457 802 452 
+3 450 323 318 
+3 457 452 348 
+3 345 450 318 
+3 449 460 106 
+3 107 432 451 
+3 460 459 106 
+3 107 458 432 
+3 338 459 460 
+3 432 458 337 
+3 338 460 103 
+3 430 432 337 
+3 99 224 461 
+3 101 227 100 
+3 224 92 461 
+3 101 96 227 
+3 509 507 98 
+3 98 507 543 
+3 509 98 462 
+3 222 98 543 
+3 776 547 97 
+3 91 467 463 
+3 776 97 777 
+3 778 91 463 
+3 545 509 462 
+3 222 543 544 
+3 545 462 464 
+3 465 222 544 
+3 549 545 464 
+3 465 544 546 
+3 549 464 468 
+3 466 465 546 
+3 547 549 468 
+3 466 546 467 
+3 547 468 97 
+3 91 466 467 
+3 469 482 90 
+3 472 473 480 
+3 469 90 87 
+3 88 472 480 
+3 482 470 471 
+3 471 470 473 
+3 482 471 90 
+3 472 471 473 
+3 478 469 474 
+3 89 480 494 
+3 469 87 474 
+3 89 88 480 
+3 486 487 475 
+3 475 489 486 
+3 487 83 475 
+3 475 85 489 
+3 487 477 83 
+3 85 476 489 
+3 477 84 83 
+3 85 82 476 
+3 477 479 80 
+3 81 491 476 
+3 477 80 84 
+3 82 81 476 
+3 479 478 474 
+3 89 494 491 
+3 479 474 80 
+3 81 89 491 
+3 484 496 482 
+3 473 483 501 
+3 484 482 469 
+3 480 473 501 
+3 496 481 470 
+3 470 481 483 
+3 496 470 482 
+3 473 470 483 
+3 506 484 469 
+3 480 501 505 
+3 506 469 478 
+3 494 480 505 
+3 502 485 486 
+3 486 488 502 
+3 485 487 486 
+3 486 489 488 
+3 485 492 487 
+3 489 493 488 
+3 492 477 487 
+3 489 476 493 
+3 492 490 479 
+3 491 495 493 
+3 492 479 477 
+3 476 491 493 
+3 490 506 478 
+3 494 505 495 
+3 490 478 479 
+3 491 494 495 
+3 498 536 496 
+3 483 497 512 
+3 498 496 484 
+3 501 483 512 
+3 536 499 481 
+3 481 499 497 
+3 536 481 496 
+3 483 481 497 
+3 500 498 484 
+3 501 512 531 
+3 500 484 506 
+3 505 501 531 
+3 516 521 502 
+3 502 522 516 
+3 521 485 502 
+3 502 488 522 
+3 521 504 485 
+3 488 503 522 
+3 504 492 485 
+3 488 493 503 
+3 504 527 490 
+3 495 526 503 
+3 504 490 492 
+3 493 495 503 
+3 527 500 506 
+3 505 531 526 
+3 527 506 490 
+3 495 505 526 
+3 507 509 508 
+3 508 543 507 
+3 509 542 508 
+3 508 510 543 
+3 511 498 528 
+3 532 512 537 
+3 498 500 528 
+3 532 531 512 
+3 528 513 511 
+3 537 534 532 
+3 513 550 511 
+3 537 551 534 
+3 514 521 516 
+3 516 522 524 
+3 514 516 515 
+3 515 516 524 
+3 515 552 517 
+3 518 552 515 
+3 515 517 514 
+3 524 518 515 
+3 514 517 553 
+3 519 518 524 
+3 514 553 520 
+3 523 519 524 
+3 520 504 521 
+3 522 503 523 
+3 520 521 514 
+3 524 522 523 
+3 520 553 529 
+3 530 519 523 
+3 553 525 529 
+3 530 533 519 
+3 529 527 520 
+3 523 526 530 
+3 527 504 520 
+3 523 503 526 
+3 528 500 529 
+3 530 531 532 
+3 500 527 529 
+3 530 526 531 
+3 529 525 528 
+3 532 533 530 
+3 525 513 528 
+3 532 534 533 
+3 511 550 539 
+3 535 551 537 
+3 550 562 539 
+3 535 561 551 
+3 539 536 511 
+3 537 497 535 
+3 536 498 511 
+3 537 512 497 
+3 539 562 540 
+3 540 561 535 
+3 562 538 540 
+3 540 538 561 
+3 540 499 539 
+3 535 499 540 
+3 499 536 539 
+3 535 497 499 
+3 776 560 547 
+3 467 541 463 
+3 560 548 547 
+3 467 558 541 
+3 545 554 542 
+3 510 556 544 
+3 545 542 509 
+3 543 510 544 
+3 549 557 545 
+3 544 555 546 
+3 557 554 545 
+3 544 556 555 
+3 547 548 549 
+3 546 558 467 
+3 548 557 549 
+3 546 555 558 
+3 513 548 550 
+3 551 558 534 
+3 548 560 550 
+3 551 541 558 
+3 552 508 542 
+3 510 508 552 
+3 552 542 517 
+3 518 510 552 
+3 517 542 554 
+3 556 510 518 
+3 517 554 553 
+3 519 556 518 
+3 553 554 525 
+3 533 556 519 
+3 554 557 525 
+3 533 555 556 
+3 525 557 513 
+3 534 555 533 
+3 557 548 513 
+3 534 558 555 
+3 559 194 562 
+3 561 194 193 
+3 194 538 562 
+3 561 538 194 
+3 562 550 560 
+3 541 551 561 
+3 562 560 559 
+3 193 541 561 
+3 563 567 218 
+3 795 564 219 
+3 567 565 218 
+3 795 566 564 
+3 567 595 568 
+3 568 595 564 
+3 567 568 565 
+3 566 568 564 
+3 570 44 75 
+3 76 588 569 
+3 570 52 781 
+3 571 592 569 
+3 782 65 73 
+3 73 65 57 
+3 889 72 572 
+3 572 74 583 
+3 72 73 572 
+3 572 73 74 
+3 889 572 582 
+3 582 572 583 
+3 573 574 45 
+3 40 46 828 
+3 68 50 587 
+3 69 51 575 
+3 67 600 68 
+3 575 601 576 
+3 577 578 574 
+3 46 579 580 
+3 54 591 581 
+3 42 53 55 
+3 591 75 581 
+3 42 76 53 
+3 889 582 584 
+3 584 582 583 
+3 891 889 584 
+3 584 583 885 
+3 891 584 586 
+3 586 584 885 
+3 585 891 586 
+3 586 885 894 
+3 585 586 60 
+3 60 586 894 
+3 837 587 578 
+3 579 69 70 
+3 837 600 67 
+3 576 601 70 
+3 45 44 816 
+3 59 588 40 
+3 589 590 781 
+3 571 66 58 
+3 589 781 35 
+3 78 571 58 
+3 782 781 590 
+3 66 571 57 
+3 77 581 50 
+3 51 42 63 
+3 77 600 28 
+3 29 601 63 
+3 591 35 781 
+3 571 78 53 
+3 591 781 52 
+3 592 571 53 
+3 897 567 814 
+3 593 564 892 
+3 567 563 814 
+3 593 219 564 
+3 594 595 897 
+3 892 595 594 
+3 595 567 897 
+3 892 564 595 
+3 245 332 596 
+3 596 247 246 
+3 332 597 596 
+3 596 597 247 
+3 814 563 822 
+3 214 219 593 
+3 563 216 822 
+3 214 598 219 
+3 596 599 833 
+3 835 599 596 
+3 596 833 245 
+3 246 835 596 
+3 599 27 833 
+3 835 27 599 
+3 833 27 600 
+3 601 27 835 
+3 27 28 600 
+3 601 29 27 
+3 268 739 26 
+3 738 737 266 
+3 268 26 117 
+3 25 738 266 
+3 602 16 651 
+3 621 14 603 
+3 602 651 633 
+3 606 621 603 
+3 604 602 633 
+3 606 603 767 
+3 604 633 636 
+3 605 606 767 
+3 641 607 13 
+3 770 609 642 
+3 607 608 13 
+3 770 15 609 
+3 607 610 608 
+3 15 645 609 
+3 610 612 608 
+3 15 613 645 
+3 610 615 612 
+3 613 614 645 
+3 615 611 612 
+3 613 616 614 
+3 615 618 18 
+3 617 648 614 
+3 615 18 611 
+3 616 617 614 
+3 618 620 19 
+3 17 619 648 
+3 618 19 18 
+3 617 17 648 
+3 620 622 623 
+3 624 625 619 
+3 620 623 19 
+3 17 624 619 
+3 622 651 16 
+3 14 621 625 
+3 622 16 623 
+3 624 14 625 
+3 626 627 757 
+3 753 630 813 
+3 627 752 757 
+3 753 628 630 
+3 752 627 629 
+3 726 630 628 
+3 627 730 629 
+3 726 727 630 
+3 631 627 626 
+3 813 630 732 
+3 631 626 23 
+3 270 813 732 
+3 712 730 627 
+3 630 727 731 
+3 712 627 631 
+3 732 630 731 
+3 651 671 635 
+3 634 632 621 
+3 651 635 633 
+3 606 634 621 
+3 633 635 636 
+3 605 634 606 
+3 635 674 636 
+3 605 654 634 
+3 652 637 771 
+3 639 638 653 
+3 637 656 771 
+3 639 657 638 
+3 771 656 658 
+3 640 657 639 
+3 771 658 641 
+3 642 640 639 
+3 641 658 643 
+3 644 640 642 
+3 641 643 607 
+3 609 644 642 
+3 607 643 646 
+3 647 644 609 
+3 607 646 610 
+3 645 647 609 
+3 610 646 615 
+3 614 647 645 
+3 646 258 615 
+3 614 20 647 
+3 615 258 618 
+3 648 20 614 
+3 258 649 618 
+3 648 665 20 
+3 618 649 620 
+3 619 665 648 
+3 649 664 620 
+3 619 668 665 
+3 620 664 650 
+3 670 668 619 
+3 620 650 622 
+3 625 670 619 
+3 622 650 671 
+3 632 670 625 
+3 622 671 651 
+3 621 632 625 
+3 636 674 652 
+3 653 654 605 
+3 674 637 652 
+3 653 638 654 
+3 655 656 688 
+3 689 657 675 
+3 656 637 688 
+3 689 638 657 
+3 677 658 655 
+3 675 640 661 
+3 658 656 655 
+3 675 657 640 
+3 660 643 658 
+3 640 644 659 
+3 660 658 677 
+3 661 640 659 
+3 662 646 643 
+3 644 647 663 
+3 662 643 660 
+3 659 644 663 
+3 680 664 221 
+3 21 668 679 
+3 664 649 221 
+3 21 665 668 
+3 666 650 664 
+3 668 670 667 
+3 666 664 680 
+3 679 668 667 
+3 683 671 650 
+3 670 632 669 
+3 683 650 666 
+3 667 670 669 
+3 687 635 671 
+3 632 634 686 
+3 687 671 683 
+3 669 632 686 
+3 673 674 635 
+3 634 654 672 
+3 673 635 687 
+3 686 634 672 
+3 688 637 673 
+3 672 638 689 
+3 637 674 673 
+3 672 654 638 
+3 655 688 711 
+3 676 689 675 
+3 655 711 692 
+3 691 676 675 
+3 677 655 692 
+3 691 675 661 
+3 677 692 695 
+3 694 691 661 
+3 660 677 678 
+3 699 661 659 
+3 677 695 678 
+3 699 694 661 
+3 662 660 223 
+3 225 659 663 
+3 660 678 223 
+3 225 699 659 
+3 680 221 262 
+3 264 21 679 
+3 680 262 681 
+3 700 264 679 
+3 666 680 681 
+3 700 679 667 
+3 666 681 701 
+3 682 700 667 
+3 683 666 684 
+3 708 667 669 
+3 666 701 684 
+3 708 682 667 
+3 687 683 705 
+3 709 669 686 
+3 683 684 705 
+3 709 708 669 
+3 673 687 710 
+3 685 686 672 
+3 687 705 710 
+3 685 709 686 
+3 688 673 710 
+3 685 672 689 
+3 688 710 711 
+3 676 685 689 
+3 692 711 729 
+3 690 676 691 
+3 692 729 693 
+3 713 690 691 
+3 695 692 693 
+3 713 691 694 
+3 695 693 716 
+3 718 713 694 
+3 678 695 696 
+3 697 694 699 
+3 695 716 696 
+3 697 718 694 
+3 223 678 226 
+3 698 699 225 
+3 678 696 226 
+3 698 697 699 
+3 681 262 261 
+3 231 264 700 
+3 681 261 702 
+3 229 231 700 
+3 701 681 702 
+3 229 700 682 
+3 701 702 703 
+3 704 229 682 
+3 684 701 703 
+3 704 682 708 
+3 684 703 706 
+3 721 704 708 
+3 705 684 725 
+3 707 708 709 
+3 684 706 725 
+3 707 721 708 
+3 710 705 725 
+3 707 709 685 
+3 710 725 724 
+3 728 707 685 
+3 711 710 724 
+3 728 685 676 
+3 711 724 729 
+3 690 728 676 
+3 693 729 712 
+3 731 690 713 
+3 693 712 715 
+3 714 731 713 
+3 716 693 715 
+3 714 713 718 
+3 716 715 717 
+3 735 714 718 
+3 696 716 717 
+3 735 718 697 
+3 696 717 736 
+3 740 735 697 
+3 226 696 94 
+3 741 697 698 
+3 696 736 94 
+3 741 740 697 
+3 703 702 719 
+3 232 229 704 
+3 703 719 743 
+3 720 232 704 
+3 706 703 743 
+3 720 704 721 
+3 706 743 723 
+3 722 720 721 
+3 725 706 629 
+3 726 721 707 
+3 706 723 629 
+3 726 722 721 
+3 724 725 629 
+3 726 707 728 
+3 724 629 730 
+3 727 726 728 
+3 729 724 730 
+3 727 728 690 
+3 729 730 712 
+3 731 727 690 
+3 715 712 631 
+3 732 731 714 
+3 715 631 733 
+3 734 732 714 
+3 717 715 733 
+3 734 714 735 
+3 717 733 26 
+3 738 734 735 
+3 736 717 26 
+3 738 735 740 
+3 736 26 739 
+3 737 738 740 
+3 94 736 739 
+3 737 740 741 
+3 94 739 267 
+3 742 737 741 
+3 743 719 238 
+3 883 232 720 
+3 743 238 748 
+3 745 883 720 
+3 723 743 748 
+3 745 720 722 
+3 723 748 750 
+3 744 745 722 
+3 629 723 752 
+3 628 722 726 
+3 723 750 752 
+3 628 744 722 
+3 748 238 749 
+3 746 883 745 
+3 238 237 749 
+3 746 747 883 
+3 750 748 749 
+3 746 745 744 
+3 750 749 756 
+3 751 746 744 
+3 752 750 756 
+3 751 744 628 
+3 752 756 757 
+3 753 751 628 
+3 749 237 754 
+3 760 747 746 
+3 237 252 754 
+3 760 755 747 
+3 756 749 754 
+3 760 746 751 
+3 756 754 761 
+3 759 760 751 
+3 757 756 761 
+3 759 751 753 
+3 757 761 758 
+3 869 759 753 
+3 626 757 758 
+3 869 753 813 
+3 754 252 765 
+3 257 755 760 
+3 754 765 762 
+3 763 257 760 
+3 761 754 762 
+3 763 760 759 
+3 761 762 764 
+3 242 763 759 
+3 758 761 764 
+3 242 759 869 
+3 758 764 291 
+3 287 242 869 
+3 762 765 332 
+3 247 257 763 
+3 636 652 766 
+3 768 653 605 
+3 636 766 604 
+3 767 768 605 
+3 771 641 769 
+3 12 642 639 
+3 641 13 769 
+3 12 770 642 
+3 652 771 766 
+3 768 639 653 
+3 771 769 766 
+3 768 12 639 
+3 120 281 875 
+3 876 283 772 
+3 402 281 120 
+3 772 283 403 
+3 115 773 304 
+3 305 370 456 
+3 773 774 304 
+3 305 369 370 
+3 152 199 779 
+3 780 775 153 
+3 560 779 199 
+3 775 780 541 
+3 776 777 779 
+3 780 778 463 
+3 777 152 779 
+3 780 153 778 
+3 781 821 816 
+3 59 820 571 
+3 821 781 782 
+3 57 571 820 
+3 179 178 898 
+3 783 177 180 
+3 7 811 802 
+3 323 812 9 
+3 785 784 811 
+3 785 811 7 
+3 812 786 788 
+3 812 788 9 
+3 787 784 785 
+3 788 786 2 
+3 789 791 784 
+3 789 784 787 
+3 786 792 4 
+3 786 4 2 
+3 3 791 789 
+3 4 792 5 
+3 790 791 3 
+3 5 792 6 
+3 793 791 304 
+3 305 792 309 
+3 791 790 304 
+3 305 6 792 
+3 811 784 793 
+3 309 786 812 
+3 784 791 793 
+3 309 792 786 
+3 311 794 803 
+3 804 800 312 
+3 797 299 218 
+3 795 297 796 
+3 299 797 798 
+3 325 796 297 
+3 797 902 798 
+3 325 908 796 
+3 799 809 794 
+3 799 794 311 
+3 800 810 422 
+3 800 422 312 
+3 433 809 799 
+3 422 810 801 
+3 802 809 433 
+3 801 810 323 
+3 809 802 811 
+3 812 323 810 
+3 794 806 803 
+3 804 805 800 
+3 806 793 803 
+3 804 309 805 
+3 808 793 806 
+3 805 309 807 
+3 809 808 806 
+3 809 806 794 
+3 805 807 810 
+3 805 810 800 
+3 793 808 811 
+3 812 807 309 
+3 808 809 811 
+3 812 810 807 
+3 626 863 395 
+3 864 865 813 
+3 863 626 758 
+3 869 813 865 
+3 814 895 897 
+3 892 896 593 
+3 61 895 782 
+3 57 896 62 
+3 817 814 815 
+3 818 593 819 
+3 816 817 815 
+3 816 815 573 
+3 818 819 59 
+3 818 59 828 
+3 573 815 822 
+3 214 818 828 
+3 815 814 822 
+3 214 593 818 
+3 821 817 816 
+3 59 819 820 
+3 895 814 817 
+3 819 593 896 
+3 782 895 817 
+3 782 817 821 
+3 819 896 57 
+3 819 57 820 
+3 822 823 573 
+3 828 826 214 
+3 823 822 854 
+3 212 214 826 
+3 577 825 824 
+3 71 829 580 
+3 825 823 836 
+3 827 826 829 
+3 824 825 836 
+3 824 836 837 
+3 827 829 71 
+3 827 71 70 
+3 823 825 573 
+3 828 829 826 
+3 825 577 573 
+3 828 580 829 
+3 837 830 844 
+3 837 844 600 
+3 831 832 70 
+3 831 70 601 
+3 833 834 245 
+3 246 845 835 
+3 600 844 834 
+3 600 834 833 
+3 845 831 601 
+3 845 601 835 
+3 836 846 830 
+3 836 830 837 
+3 832 847 827 
+3 832 827 70 
+3 846 836 823 
+3 826 827 847 
+3 838 854 843 
+3 842 212 839 
+3 830 838 843 
+3 830 843 844 
+3 842 839 832 
+3 842 832 831 
+3 834 840 245 
+3 246 841 845 
+3 840 854 245 
+3 246 212 841 
+3 843 854 840 
+3 841 212 842 
+3 844 843 840 
+3 844 840 834 
+3 841 842 831 
+3 841 831 845 
+3 846 838 830 
+3 832 839 847 
+3 854 838 823 
+3 826 839 212 
+3 838 846 823 
+3 826 847 839 
+3 352 849 850 
+3 213 848 853 
+3 849 854 850 
+3 213 212 848 
+3 851 854 849 
+3 848 212 855 
+3 354 851 849 
+3 354 849 352 
+3 848 855 852 
+3 848 852 853 
+3 284 851 354 
+3 852 855 285 
+3 854 851 244 
+3 243 855 212 
+3 851 284 244 
+3 243 285 855 
+3 856 877 859 
+3 856 859 858 
+3 860 857 868 
+3 860 868 866 
+3 858 859 280 
+3 282 860 866 
+3 877 873 859 
+3 860 861 857 
+3 859 873 280 
+3 282 861 860 
+3 873 875 280 
+3 282 876 861 
+3 858 867 856 
+3 868 862 866 
+3 863 867 395 
+3 864 862 865 
+3 867 858 395 
+3 864 866 862 
+3 856 867 758 
+3 869 862 868 
+3 867 863 758 
+3 869 865 862 
+3 291 872 758 
+3 869 870 287 
+3 872 856 758 
+3 869 868 870 
+3 875 874 120 
+3 772 871 876 
+3 874 291 120 
+3 772 287 871 
+3 856 872 877 
+3 857 870 868 
+3 873 874 875 
+3 876 871 861 
+3 872 291 874 
+3 871 287 870 
+3 877 872 874 
+3 877 874 873 
+3 871 870 857 
+3 871 857 861 
+3 238 882 240 
+3 878 884 883 
+3 882 879 240 
+3 878 233 884 
+3 879 882 880 
+3 881 884 233 
+3 882 238 880 
+3 881 883 884 
+3 585 890 891 
+3 885 886 894 
+3 890 897 888 
+3 887 892 886 
+3 72 890 888 
+3 72 888 61 
+3 887 886 74 
+3 887 74 62 
+3 889 890 72 
+3 74 886 583 
+3 891 890 889 
+3 583 886 885 
+3 897 890 594 
+3 594 886 892 
+3 890 893 594 
+3 594 893 886 
+3 893 890 585 
+3 894 886 893 
+3 61 888 895 
+3 896 887 62 
+3 888 897 895 
+3 896 892 887 
+3 898 909 565 
+3 566 910 783 
+3 319 901 903 
+3 319 903 195 
+3 905 899 900 
+3 905 900 906 
+3 901 319 902 
+3 908 900 899 
+3 904 909 898 
+3 783 910 907 
+3 195 903 909 
+3 195 909 904 
+3 910 905 906 
+3 910 906 907 
+3 218 902 797 
+3 796 908 795 
+3 909 218 565 
+3 566 795 910 
+3 901 218 903 
+3 905 795 899 
+3 902 218 901 
+3 899 795 908 
+3 903 218 909 
+3 910 795 905 
diff --git a/meshpy/examples/mesh_ply.py b/meshpy/examples/mesh_ply.py
new file mode 100644
index 0000000000000000000000000000000000000000..4c785385afd1af2527813aa78f3e1f93d90bd417
--- /dev/null
+++ b/meshpy/examples/mesh_ply.py
@@ -0,0 +1,26 @@
+from __future__ import absolute_import
+from __future__ import print_function
+def main():
+    from ply import parse_ply
+    import sys
+    data = parse_ply(sys.argv[1])
+
+    from meshpy.geometry import GeometryBuilder
+
+    builder = GeometryBuilder()
+    builder.add_geometry(
+            points=[pt[:3] for pt in data["vertex"].data],
+            facets=[fd[0] for fd in data["face"].data])
+    builder.wrap_in_box(1)
+
+    from meshpy.tet import MeshInfo, build
+    mi = MeshInfo()
+    builder.set(mi)
+    mi.set_holes([builder.center()])
+    mesh = build(mi)
+    print("%d elements" % len(mesh.elements))
+    mesh.write_vtk("out.vtk")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/meshpy/examples/nico_mesh.py b/meshpy/examples/nico_mesh.py
new file mode 100644
index 0000000000000000000000000000000000000000..72ade6ef4e0e001254ab77ef5d7b8dca6431a5d0
--- /dev/null
+++ b/meshpy/examples/nico_mesh.py
@@ -0,0 +1,35 @@
+from __future__ import absolute_import
+from six.moves import range
+def main():
+    import meshpy.triangle as triangle
+    import math
+
+    points = [ (1,1),(-1,1),(-1,-1),(1,-1) ]
+
+    def round_trip_connect(start, end):
+      result = []
+      for i in range(start, end):
+        result.append((i, i+1))
+      result.append((end, start))
+      return result
+
+    def needs_refinement(vertices, area ):
+        vert_origin, vert_destination, vert_apex = vertices
+        bary_x = (vert_origin.x + vert_destination.x + vert_apex.x) / 3
+        bary_y = (vert_origin.y + vert_destination.y + vert_apex.y) / 3
+
+        dist_center = math.sqrt( (bary_x-1)**2 + (bary_y-1)**2 )
+        max_area = math.fabs( 0.05 * (dist_center-0.5) ) + 0.01
+        return area > max_area
+
+    info = triangle.MeshInfo()
+    info.set_points(points)
+    info.set_facets(round_trip_connect(0, len(points)-1))
+
+    mesh = triangle.build(info, refinement_func=needs_refinement)
+
+    mesh.write_neu(open("nico.neu", "w"))
+    triangle.write_gnuplot_mesh("triangles.dat", mesh)
+
+if __name__ == "__main__":
+    main()
diff --git a/meshpy/examples/test_ball.py b/meshpy/examples/test_ball.py
new file mode 100644
index 0000000000000000000000000000000000000000..86f6466826a6a540b07a41d37a578d6f48c8eeb4
--- /dev/null
+++ b/meshpy/examples/test_ball.py
@@ -0,0 +1,40 @@
+from __future__ import absolute_import
+from six.moves import range
+def main():
+    from math import pi, cos, sin
+    from meshpy.tet import MeshInfo, build
+    from meshpy.geometry import \
+            generate_surface_of_revolution, EXT_OPEN, \
+            GeometryBuilder
+
+    r = 3
+
+    points = 10
+    dphi = pi/points
+
+    def truncate(r):
+        if abs(r) < 1e-10:
+            return 0
+        else:
+            return r
+
+    rz = [(truncate(r*sin(i*dphi)), r*cos(i*dphi)) for i in range(points+1)]
+
+    geob = GeometryBuilder()
+    geob.add_geometry(*generate_surface_of_revolution(rz,
+            closure=EXT_OPEN, radial_subdiv=10))
+
+    mesh_info = MeshInfo()
+    geob.set(mesh_info)
+
+    mesh = build(mesh_info)
+    mesh.write_vtk("ball.vtk")
+
+    #mesh.write_neu(file("torus.neu", "w"),
+            #{1: ("pec", 0)})
+
+
+
+
+if __name__ == "__main__":
+    main()
diff --git a/meshpy/examples/test_cylinder.py b/meshpy/examples/test_cylinder.py
new file mode 100644
index 0000000000000000000000000000000000000000..b3624dd63f5d708e27d8a4aaca88a9b403a36cb5
--- /dev/null
+++ b/meshpy/examples/test_cylinder.py
@@ -0,0 +1,29 @@
+def main():
+    from math import pi, cos, sin
+    from meshpy.tet import MeshInfo, build
+    from meshpy.geometry import \
+            generate_surface_of_revolution, EXT_OPEN, \
+            GeometryBuilder
+
+    r = 1
+    l = 1
+
+    rz = [(0,0), (r,0), (r,l), (0,l)]
+
+    geob = GeometryBuilder()
+    geob.add_geometry(*generate_surface_of_revolution(rz,
+            radial_subdiv=20, ring_markers=[1,2,3]))
+
+    mesh_info = MeshInfo()
+    geob.set(mesh_info)
+
+    mesh = build(mesh_info, max_volume=0.01)
+    mesh.write_vtk("cylinder.vtk")
+    mesh.write_neu(open("cylinder.neu", "w"), {
+        1: ("minus_z", 1),
+        2: ("outer", 2),
+        3: ("plus_z", 3),
+        })
+
+if __name__ == "__main__":
+    main()
diff --git a/meshpy/examples/test_gmsh_reader.py b/meshpy/examples/test_gmsh_reader.py
new file mode 100644
index 0000000000000000000000000000000000000000..665a1c840e88d227e76230ebbc80496f3e43bfb3
--- /dev/null
+++ b/meshpy/examples/test_gmsh_reader.py
@@ -0,0 +1,34 @@
+class GmshMeshReceiver:
+    def __init__(self):
+        pass
+
+    def add_node(self, node_nr, point):
+        pass
+
+    def finalize_nodes(self):
+        pass
+
+    def add_element(self, element_nr, element_type, vertex_nrs,
+            lexicographic_nodes, tag_numbers):
+        pass
+
+    def finalize_elements(self):
+        pass
+
+    def add_tag(self, name, index, dimension):
+        pass
+
+    def finalize_tags(self):
+        pass
+
+
+def main():
+    mr = GmshMeshReceiver()
+
+    import sys
+    from meshpy.gmsh_reader import read_gmsh
+    read_gmsh(mr, sys.argv[1])
+
+
+if __name__ == "__main__":
+    main()
diff --git a/meshpy/examples/test_tet_torus.py b/meshpy/examples/test_tet_torus.py
new file mode 100644
index 0000000000000000000000000000000000000000..51a0ccefb0cc607c9e980c93fe55bbb5f77bd264
--- /dev/null
+++ b/meshpy/examples/test_tet_torus.py
@@ -0,0 +1,40 @@
+from __future__ import absolute_import
+from six.moves import range
+def main():
+    from math import pi, cos, sin
+    from meshpy.tet import MeshInfo, build
+    from meshpy.geometry import generate_surface_of_revolution,\
+            EXT_CLOSED_IN_RZ, GeometryBuilder
+
+    big_r = 3
+    little_r = 2.9
+
+    points = 50
+    dphi = 2*pi/points
+
+    rz = [(big_r+little_r*cos(i*dphi), little_r*sin(i*dphi))
+            for i in range(points)]
+
+    geob = GeometryBuilder()
+    geob.add_geometry(*generate_surface_of_revolution(rz,
+            closure=EXT_CLOSED_IN_RZ, radial_subdiv=20))
+
+    mesh_info = MeshInfo()
+    geob.set(mesh_info)
+
+    mesh_info.save_nodes("torus")
+    mesh_info.save_poly("torus")
+    mesh = build(mesh_info)
+    mesh.write_vtk("torus.vtk")
+    mesh.save_elements("torus_mesh")
+    mesh.save_nodes("torus_mesh")
+
+    mesh.write_neu(open("torus.neu", "w"),
+            {1: ("pec", 0)})
+
+
+
+
+if __name__ == "__main__":
+    main()
+
diff --git a/meshpy/examples/test_tetgen.py b/meshpy/examples/test_tetgen.py
new file mode 100644
index 0000000000000000000000000000000000000000..6f430aa3a00d6c804dc39bb60787ae5a2034bc75
--- /dev/null
+++ b/meshpy/examples/test_tetgen.py
@@ -0,0 +1,40 @@
+from meshpy.tet import MeshInfo, build
+
+
+def main():
+    mesh_info = MeshInfo()
+
+    mesh_info.set_points([
+        (0, 0, 0),
+        (2, 0, 0),
+        (2, 2, 0),
+        (0, 2, 0),
+        (0, 0, 12),
+        (2, 0, 12),
+        (2, 2, 12),
+        (0, 2, 12),
+        ])
+
+    mesh_info.set_facets([
+        [0, 1, 2, 3],
+        [4, 5, 6, 7],
+        [0, 4, 5, 1],
+        [1, 5, 6, 2],
+        [2, 6, 7, 3],
+        [3, 7, 4, 0],
+        ])
+
+    mesh_info.save_nodes("bar")
+    mesh_info.save_poly("bar")
+
+    mesh = build(mesh_info)
+
+    mesh.save_nodes("barout")
+    mesh.save_elements("barout")
+    mesh.save_faces("barout")
+
+    mesh.write_vtk("test.vtk")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/meshpy/examples/test_tetgen_2.py b/meshpy/examples/test_tetgen_2.py
new file mode 100644
index 0000000000000000000000000000000000000000..6cf3fbb909a08533ec454aba7ca833ae56c7c097
--- /dev/null
+++ b/meshpy/examples/test_tetgen_2.py
@@ -0,0 +1,37 @@
+
+
+
+
+def main():
+    from meshpy.tet import MeshInfo, build
+    from meshpy.geometry import \
+            generate_surface_of_revolution, \
+            GeometryBuilder
+
+    simple_rz = [
+        (0,0),
+        (1,1),
+        (1,2),
+        (0,3),
+        ]
+
+
+    geob = GeometryBuilder()
+    geob.add_geometry(*generate_surface_of_revolution(simple_rz))
+
+    mesh_info = MeshInfo()
+    geob.set(mesh_info)
+
+    #mesh_info.save_nodes("test")
+    #mesh_info.save_poly("test")
+    #mesh_info.load_poly("test")
+    mesh = build(mesh_info)
+    mesh.write_vtk("my_mesh.vtk")
+    #mesh.save_elements("gun")
+    #mesh.save_nodes("gun")
+
+
+
+
+if __name__ == "__main__":
+    main()
diff --git a/meshpy/examples/test_tri_pml.py b/meshpy/examples/test_tri_pml.py
new file mode 100644
index 0000000000000000000000000000000000000000..c206181dbbe1bd4404e3251257fb034903a2c25b
--- /dev/null
+++ b/meshpy/examples/test_tri_pml.py
@@ -0,0 +1,42 @@
+from __future__ import absolute_import
+from six.moves import range
+def main():
+    import meshpy.triangle as triangle
+    import math
+    import pickle
+
+    segments = 50
+
+    points = [(-5,-1), (-1,-1), (0,-1), (0,0), (1,0), (5,0), (5,1), (1,1),
+      (-1,1), (-5,1)]
+
+    def round_trip_connect(seq):
+      result = []
+      for i in range(len(seq)):
+        result.append((seq[i], seq[(i+1)%len(seq)]))
+      return result
+
+    info = triangle.MeshInfo()
+    info.set_points(points)
+
+    info.set_facets(
+            round_trip_connect([0,1,8,9])
+            +round_trip_connect([1,2,3,4,7,8])
+            +round_trip_connect([4,5,6,7])
+            )
+    info.regions.resize(3)
+    info.regions[0] = (-2,0,     1,0.1)
+    info.regions[1] = (-0.5,0,   0,0.01)
+    info.regions[2] = (1.5,0.5,  1,0.1)
+
+    mesh = triangle.build(info)
+
+    triangle.write_gnuplot_mesh("triangles.dat", mesh)
+
+    mesh.write_neu(open("tri_pml.neu", "w"))
+
+
+
+
+if __name__ == "__main__":
+    main()
diff --git a/meshpy/examples/test_tri_quadratic.py b/meshpy/examples/test_tri_quadratic.py
new file mode 100644
index 0000000000000000000000000000000000000000..14fc7b6cdb97fa2979ea0397eaad81519adcf538
--- /dev/null
+++ b/meshpy/examples/test_tri_quadratic.py
@@ -0,0 +1,38 @@
+# Quadratic element demo, by Aravind Alwan
+
+from numpy import *
+from matplotlib.pyplot import *
+from meshpy.triangle import MeshInfo, build
+
+# Utility function to create lists of the form [(1,2), (2,3), (3,4),
+#(4,1)], given two numbers 1 and 4
+from itertools import islice, cycle
+from six.moves import range
+from six.moves import zip
+loop = lambda a, b: list(zip(list(range(a, b)), islice(cycle(list(range(a, b))), 1, None)))
+
+info = MeshInfo()
+info.set_points([(0,0), (1,0), (1,1), (0,1), (2,0), (3,0), (3,1), (2,1)])
+info.set_facets(loop(0,4) + loop(4,8), list(range(1,9))) # Create 8 facets and apply markers 1-8 on them
+info.regions.resize(2)
+info.regions[0] = [0.5, 0.5, 1, 0.1] # Fourth item specifies maximum area of triangles as a region attribute
+info.regions[1] = [2.5, 0.5, 2, 0.1] # Replace 0.1 by a smaller value to produce a finer mesh
+
+mesh = build(info, volume_constraints=True, attributes=True,
+generate_faces=True, min_angle=33, mesh_order=2)
+
+pts = vstack(mesh.points) # (npoints, 2)-array of points
+elements = vstack(mesh.elements) # (ntriangles, 6)-array specifying element connectivity
+
+# Matplotlib's Triangulation module uses only linear elements, so use only first 3 columns when plotting
+triplot(pts[:,0], pts[:,1], elements[:,:3])
+
+plot(pts[:,0], pts[:,1], 'ko') # Manually plot all points including the ones at the midpoints of triangle faces
+
+# Plot a filled contour plot of the function (x - 1.5)^2 + y^2 over
+# the mesh. Note tricontourf interpolation uses only linear elements
+tricontourf(pts[:,0], pts[:,1], elements[:,:3], (pts[:,0]-1.5)**2 +
+        pts[:,1]**2, 100)
+
+axis([-0.1, 3.1, -0.8, 1.8])
+show()
diff --git a/meshpy/examples/test_tri_simple_square.py b/meshpy/examples/test_tri_simple_square.py
new file mode 100644
index 0000000000000000000000000000000000000000..cbb2bc3c70e82076e9e3f83faa8266b24657a775
--- /dev/null
+++ b/meshpy/examples/test_tri_simple_square.py
@@ -0,0 +1,27 @@
+from __future__ import absolute_import
+from __future__ import print_function
+from six.moves import range
+def main():
+    import meshpy.triangle as triangle
+
+    points = [ (1,1),(-1,1),(-1,-1),(1,-1)]
+
+    def round_trip_connect(start, end):
+      result = []
+      for i in range(start, end):
+        result.append((i, i+1))
+      result.append((end, start))
+      return result
+
+    info = triangle.MeshInfo()
+    info.set_points(points)
+    info.set_facets(round_trip_connect(0, len(points)-1))
+
+    mesh = triangle.build(info, max_volume=1e-3, min_angle=25)
+
+    print("A")
+    triangle.write_gnuplot_mesh("triangles.dat", mesh)
+
+if __name__ == "__main__":
+    main()
+
diff --git a/meshpy/examples/test_triangle.py b/meshpy/examples/test_triangle.py
new file mode 100644
index 0000000000000000000000000000000000000000..d88e7c81675bf53268fc9a96e1c75f0948370cec
--- /dev/null
+++ b/meshpy/examples/test_triangle.py
@@ -0,0 +1,45 @@
+from __future__ import division
+from __future__ import absolute_import
+
+import meshpy.triangle as triangle
+import numpy as np
+import numpy.linalg as la
+from six.moves import range
+
+
+def round_trip_connect(start, end):
+    return [(i, i+1) for i in range(start, end)] + [(end, start)]
+
+
+def main():
+    points = [(1, 0), (1, 1), (-1, 1), (-1, -1), (1, -1), (1, 0)]
+    facets = round_trip_connect(0, len(points)-1)
+
+    circ_start = len(points)
+    points.extend(
+            (3 * np.cos(angle), 3 * np.sin(angle))
+            for angle in np.linspace(0, 2*np.pi, 30, endpoint=False))
+
+    facets.extend(round_trip_connect(circ_start, len(points)-1))
+
+    def needs_refinement(vertices, area):
+        bary = np.sum(np.array(vertices), axis=0)/3
+        max_area = 0.001 + (la.norm(bary, np.inf)-1)*0.01
+        return bool(area > max_area)
+
+    info = triangle.MeshInfo()
+    info.set_points(points)
+    info.set_holes([(0, 0)])
+    info.set_facets(facets)
+
+    mesh = triangle.build(info, refinement_func=needs_refinement)
+
+    mesh_points = np.array(mesh.points)
+    mesh_tris = np.array(mesh.elements)
+
+    import matplotlib.pyplot as pt
+    pt.triplot(mesh_points[:, 0], mesh_points[:, 1], mesh_tris)
+    pt.show()
+
+if __name__ == "__main__":
+    main()
diff --git a/meshpy/examples/test_triangle_refine.py b/meshpy/examples/test_triangle_refine.py
new file mode 100644
index 0000000000000000000000000000000000000000..16183f892f6a19489adff6af245b152dcf098276
--- /dev/null
+++ b/meshpy/examples/test_triangle_refine.py
@@ -0,0 +1,57 @@
+from __future__ import absolute_import
+from __future__ import print_function
+from six.moves import range
+def main():
+    import meshpy.triangle as triangle
+    import math
+    import pickle
+
+    segments = 50
+
+    points = [ (1,0),(1,1),(-1,1),(-1,-1),(1,-1),(1,0) ]
+
+    for i in range( 0, segments + 1 ):
+      angle = i * 2 * math.pi / segments
+      points.append( ( 0.5 * math.cos( angle ), 0.5 * math.sin( angle ) ) )
+
+    def round_trip_connect(start, end):
+      result = []
+      for i in range(start, end):
+        result.append((i, i+1))
+      result.append((end, start))
+      return result
+
+    def needs_refinement(vertices, area ):
+        vert_origin, vert_destination, vert_apex = vertices
+        bary_x = (vert_origin.x + vert_destination.x + vert_apex.x) / 3
+        bary_y = (vert_origin.y + vert_destination.y + vert_apex.y) / 3
+
+        dist_center = math.sqrt( bary_x**2 + bary_y**2 )
+        max_area = 100*(math.fabs( 0.002 * (dist_center-0.5) ) + 0.0001)
+        return area > max_area
+
+    info = triangle.MeshInfo()
+    info.set_points(points)
+    info.set_holes([(0,0)])
+    info.set_facets(round_trip_connect(0, len(points)-1))
+
+    mesh = triangle.build(info, refinement_func=needs_refinement,
+            )
+
+    triangle.write_gnuplot_mesh("triangles-unrefined.dat", mesh)
+    print(len(mesh.elements))
+
+    mesh.element_volumes.setup()
+
+    for i in range(len(mesh.elements)):
+        mesh.element_volumes[i] = -1
+    for i in range(0, len(mesh.elements), 10):
+        mesh.element_volumes[i] = 1e-8
+
+    mesh = triangle.refine(mesh)
+    print(len(mesh.elements))
+
+    triangle.write_gnuplot_mesh("triangles.dat", mesh)
+
+if __name__ == "__main__":
+    main()
diff --git a/meshpy/examples/test_triangle_with_specified_points.py b/meshpy/examples/test_triangle_with_specified_points.py
new file mode 100644
index 0000000000000000000000000000000000000000..3719daaca3e1b2652f779e3f56573f29806ebc29
--- /dev/null
+++ b/meshpy/examples/test_triangle_with_specified_points.py
@@ -0,0 +1,27 @@
+def main():
+    import meshpy.triangle as triangle
+    import numpy as np
+
+    points = [ (1,1),(-1,1),(-1,-1),(1,-1) ]
+
+    for pt in np.random.randn(100, 2):
+        points.append(pt*0.1)
+
+    def round_trip_connect(start, end):
+      result = []
+      for i in range(start, end):
+        result.append((i, i+1))
+      result.append((end, start))
+      return result
+
+    info = triangle.MeshInfo()
+    info.set_points(points)
+    info.set_facets(round_trip_connect(0, 3))
+
+    mesh = triangle.build(info, allow_volume_steiner=False,
+            allow_boundary_steiner=False)
+
+    triangle.write_gnuplot_mesh("triangles.dat", mesh)
+
+if __name__ == "__main__":
+    main()
diff --git a/meshpy/examples/tet-size-control.py b/meshpy/examples/tet-size-control.py
new file mode 100644
index 0000000000000000000000000000000000000000..9ad7fa946ee2024e0bc77a14a01f64a4d5a94679
--- /dev/null
+++ b/meshpy/examples/tet-size-control.py
@@ -0,0 +1,56 @@
+from meshpy.tet import MeshInfo, build
+
+mesh_info = MeshInfo()
+
+# construct a two-box extrusion of this base
+base = [(-2,-2,0), (2,-2,0), (2,2,0), (-2,2,0)]
+
+# first, the nodes
+mesh_info.set_points(
+        base
+        +[(x,y,z+5) for x,y,z in base]
+        +[(x,y,z+10) for x,y,z in base]
+        )
+
+# next, the facets
+
+# vertex indices for a box missing the -z face
+box_without_minus_z = [ 
+    [4,5,6,7],
+    [0,4,5,1],
+    [1,5,6,2],
+    [2,6,7,3],
+    [3,7,4,0],
+    ]
+
+def add_to_all_vertex_indices(facets, increment):
+    return [[pt+increment for pt in facet] for facet in facets]
+
+mesh_info.set_facets(
+    [[0,1,2,3]] # base
+    +box_without_minus_z # first box
+    +add_to_all_vertex_indices(box_without_minus_z, 4) # second box
+    )
+
+# set the volume properties -- this is where the tet size constraints are
+mesh_info.regions.resize(2)
+mesh_info.regions[0] = [0,0,2, # point in volume -> first box
+        0, # region tag (user-defined number)
+        1e-1, # max tet volume in region
+        ]
+mesh_info.regions[1] = [0,0,7, # point in volume -> second box
+        0, # region tag (user-defined number, arbitrary)
+        1e-2, # max tet volume in region
+        ]
+
+mesh = build(mesh_info, area_constraints=True)
+
+# this is a no-op, but it shows how to access the output data
+for point in mesh.points:
+    [x,y,z] = point
+
+for element in mesh.elements:
+    [pt_1, pt_2, pt_3, pt_4] = element
+
+# this writes the mesh as a vtk file, requires pyvtk
+mesh.write_vtk("test.vtk")
diff --git a/meshpy/examples/tri-boundary-markers.py b/meshpy/examples/tri-boundary-markers.py
new file mode 100644
index 0000000000000000000000000000000000000000..3550a084627671559e57cdb62ce367714bde703d
--- /dev/null
+++ b/meshpy/examples/tri-boundary-markers.py
@@ -0,0 +1,59 @@
+# Provided by Liu Benyuan in https://github.com/inducer/meshpy/pull/11
+
+from __future__ import division
+
+import meshpy.triangle as triangle
+import numpy as np
+
+def round_trip_connect(start, end):
+    return [(i, i+1) for i in range(start, end)] + [(end, start)]
+
+def refinement_func(tri_points, area):
+    max_area=0.1
+    return bool(area>max_area);
+
+def main():
+    points = [(1, 0), (1, 1), (-1, 1), (-1, -1), (1, -1), (1, 0)]
+    facets = round_trip_connect(0, len(points)-1)
+    markers = [2,2,2,2,2,2]
+
+    outter_start = len(points)
+    points.extend([(2, 0), (2, 2), (-2, 2), (-2, -2), (2, -2), (2, 0)])
+    facets.extend(round_trip_connect(outter_start, len(points) - 1))
+    markers.extend([3,3,3,3,3,3])
+
+    # build
+    info = triangle.MeshInfo()
+    info.set_points(points)
+    info.set_holes([(0, 0)])
+    info.set_facets(facets, facet_markers=markers)
+
+    #
+    mesh = triangle.build(info, refinement_func=refinement_func)
+
+    #
+    mesh_points = np.array(mesh.points)
+    mesh_tris = np.array(mesh.elements)
+    mesh_attr = np.array(mesh.point_markers)
+
+    print(mesh_attr)
+
+    import matplotlib.pyplot as plt
+    plt.triplot(mesh_points[:, 0], mesh_points[:, 1], mesh_tris)
+    plt.xlabel('x')
+    plt.ylabel('y')
+    #
+    n = np.size(mesh_attr);
+    inner_nodes = [i for i in range(n) if mesh_attr[i]==2]
+    outer_nodes = [i for i in range(n) if mesh_attr[i]==3]
+    plt.plot(mesh_points[inner_nodes, 0], mesh_points[inner_nodes, 1], 'ro')
+    plt.plot(mesh_points[outer_nodes, 0], mesh_points[outer_nodes, 1], 'go')
+    plt.axis([-2.5, 2.5, -2.5, 2.5])
+    #plt.show()
+    #
+    fig = plt.gcf()
+    fig.set_size_inches(4.2, 4.2)
+    plt.savefig('sec5-meshpy-triangle-ex5.pdf')
+
+if __name__ == "__main__":
+    main()
diff --git a/meshpy/examples/tri-refinement-spec.py b/meshpy/examples/tri-refinement-spec.py
new file mode 100644
index 0000000000000000000000000000000000000000..87fb7abb877b2ba981fca531f931b4f68282c44b
--- /dev/null
+++ b/meshpy/examples/tri-refinement-spec.py
@@ -0,0 +1,51 @@
+# Provided by Liu Benyuan in https://github.com/inducer/meshpy/pull/11
+
+from __future__ import division
+
+import meshpy.triangle as triangle
+import numpy as np
+from matplotlib.path import Path
+
+def round_trip_connect(start, end):
+    return [(i, i+1) for i in range(start, end)] + [(end, start)]
+
+def main():
+    points = [(1, 0), (1, 1), (-1, 1), (-1, -1), (1, -1), (1, 0)]
+    facets = round_trip_connect(0, len(points)-1)
+
+    circ_start = len(points)
+    points.extend(
+            (3 * np.cos(angle), 3 * np.sin(angle))
+            for angle in np.linspace(0, 2*np.pi, 30, endpoint=False))
+    facets.extend(round_trip_connect(circ_start, len(points)-1))
+
+    markers = [2,2,2,2,2,2]
+    markers.extend(list(np.ones(30, dtype='int')))
+    markers = [int(i) for i in markers]
+
+    info = triangle.MeshInfo()
+    info.set_points(points)
+    info.set_facets(facets, facet_markers=markers)
+    #
+    info.regions.resize(1)
+    # points [x,y] in region, + region number, + regional area constraints
+    info.regions[0] = ([0,0] + [1,0.05])
+
+    mesh = triangle.build(info, volume_constraints=True, max_volume=0.1)
+
+    mesh_points = np.array(mesh.points)
+    mesh_tris = np.array(mesh.elements)
+    mesh_attr = np.array(mesh.point_markers)
+    print(mesh_attr)
+
+    import matplotlib.pyplot as plt
+    plt.triplot(mesh_points[:, 0], mesh_points[:, 1], mesh_tris)
+    plt.xlabel('x')
+    plt.ylabel('y')
+    #
+    fig = plt.gcf()
+    fig.set_size_inches(4.2, 4.2)
+    plt.savefig('sec5-meshpy-triangle-ex4.pdf')
+
+if __name__ == "__main__":
+    main()
diff --git a/meshpy/examples/write_dolfin.py b/meshpy/examples/write_dolfin.py
new file mode 100644
index 0000000000000000000000000000000000000000..ec8c9317a00a0bc73e28caab4ca338c617c868b8
--- /dev/null
+++ b/meshpy/examples/write_dolfin.py
@@ -0,0 +1,41 @@
+from __future__ import absolute_import
+from __future__ import print_function
+def main():
+    import meshpy.triangle as triangle
+
+    info = triangle.MeshInfo()
+    info.set_points([ (1.5,1),(-1.2,1),(-1,-1),(1,-1)])
+    info.set_facets([(0, 1), (1, 2), (2, 3), (3, 0)])
+
+    mesh = triangle.build(info, max_volume=1e-3, min_angle=25)
+
+    print("""
+        <?xml version="1.0" encoding="UTF-8"?>
+
+        <dolfin xmlns:dolfin="http://www.fenics.org/dolfin/">
+          <mesh celltype="triangle" dim="2">
+            <vertices size="%d">
+        """ % len(mesh.points))
+
+    for i, pt in enumerate(mesh.points):
+      print('<vertex index="%d" x="%g" y="%g"/>' % (
+              i, pt[0], pt[1]))
+
+    print("""
+        </vertices>
+        <cells size="%d">
+        """ % len(mesh.elements))
+
+    for i, element in enumerate(mesh.elements):
+      print('<triangle index="%d" v0="%d" v1="%d" v2="%d"/>' % (
+              i, element[0], element[1], element[2]))
+
+    print("""
+            </cells>
+          </mesh>
+        </dolfin>
+        """)
+
+if __name__ == "__main__":
+    main()
+
diff --git a/meshpy/meshpy/__init__.py b/meshpy/meshpy/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..f778647a74af58556760005a3a081f73c2b20b9e
--- /dev/null
+++ b/meshpy/meshpy/__init__.py
@@ -0,0 +1 @@
+version = "2018.1.1"
diff --git a/meshpy/meshpy/common.py b/meshpy/meshpy/common.py
new file mode 100644
index 0000000000000000000000000000000000000000..5715a6fd35f074d7a23e0763e17468d614ccfb05
--- /dev/null
+++ b/meshpy/meshpy/common.py
@@ -0,0 +1,280 @@
+from __future__ import absolute_import
+from __future__ import print_function
+from six.moves import range
+from six.moves import zip
+class _Table:
+    def __init__(self):
+        self.Rows = []
+
+    def add_row(self, row):
+        self.Rows.append([str(i) for i in row])
+
+    def __str__(self):
+        columns = len(self.Rows[0])
+        col_widths = [max(len(row[i]) for row in self.Rows)
+                      for i in range(columns)]
+
+        lines = [
+            " ".join([cell.ljust(col_width)
+                      for cell, col_width in zip(row, col_widths)])
+            for row in self.Rows]
+        return "\n".join(lines)
+
+
+
+
+def _linebreak_list(list, per_line=10, pad=None):
+    def format(s):
+        if pad is None:
+            return str(s)
+        else:
+            return str(s).rjust(pad)
+
+    result = ""
+    while len(list) > per_line:
+        result += " ".join(format(l) for l in list[:per_line]) + "\n"
+        list = list[per_line:]
+    return result + " ".join(format(l) for l in list)
+
+
+
+class MeshInfoBase:
+    @property
+    def face_vertex_indices_to_face_marker(self):
+        try:
+            return self._fvi2fm
+        except AttributeError:
+            result = {}
+
+            for i, face in enumerate(self.faces):
+                result[frozenset(face)] = self.face_markers[i]
+
+            self._fvi2fm = result
+            return result
+
+
+
+
+
+    def set_points(self, points, point_markers=None):
+        if point_markers is not None:
+            assert len(point_markers) == len(point_markers)
+
+        self.points.resize(len(points))
+
+        for i, pt in enumerate(points):
+            self.points[i] = pt
+
+        if point_markers is not None:
+            self.point_markers.setup()
+            for i, mark in enumerate(point_markers):
+                self.point_markers[i] = mark
+
+
+
+
+
+    def set_holes(self, hole_starts):
+        self.holes.resize(len(hole_starts))
+        for i, hole in enumerate(hole_starts):
+            self.holes[i] = hole
+
+
+
+
+    def write_neu(self, outfile, bc={}, periodicity=None, description="MeshPy Output"):
+        """Write the mesh out in (an approximation to) Gambit neutral mesh format.
+
+        outfile is a file-like object opened for writing.
+
+        bc is a dictionary mapping single face markers (or frozensets of them)
+        to a tuple (bc_name, bc_code).
+
+        periodicity is either a tuple (face_marker, (px,py,..)) giving the
+        face marker of the periodic boundary and the period in each coordinate
+        direction (0 if none) or the value None for no periodicity.
+        """
+
+        from meshpy import version
+        from datetime import datetime
+
+        # header --------------------------------------------------------------
+        outfile.write("CONTROL INFO 2.1.2\n")
+        outfile.write("** GAMBIT NEUTRAL FILE\n")
+        outfile.write("%s\n" % description)
+        outfile.write("PROGRAM: MeshPy VERSION: %s\n" % version)
+        outfile.write("%s\n" % datetime.now().ctime())
+
+        bc_markers = list(bc.keys())
+        if periodicity:
+            periodic_marker, periods = periodicity
+            bc_markers.append(periodic_marker)
+
+        assert len(self.points)
+
+        dim = len(self.points[0])
+        data = (
+                ("NUMNP", len(self.points)),
+                ("NELEM", len(self.elements)),
+                ("NGRPS", 1),
+                ("NBSETS", len(bc_markers)),
+                ("NDFCD", dim),
+                ("NDFVL", dim),
+                )
+
+        tbl = _Table()
+        tbl.add_row(key for key, value in data)
+        tbl.add_row(value for key, value in data)
+        outfile.write(str(tbl))
+        outfile.write("\n")
+        outfile.write("ENDOFSECTION\n")
+
+        # nodes ---------------------------------------------------------------
+        outfile.write("NODAL COORDINATES 2.1.2\n")
+        for i, pt in enumerate(self.points):
+            outfile.write("%d %s\n" %
+                    (i+1, " ".join(repr(c) for c in pt)))
+        outfile.write("ENDOFSECTION\n")
+
+        # elements ------------------------------------------------------------
+        outfile.write("ELEMENTS/CELLS 2.1.2\n")
+        if dim == 2:
+            eltype = 3
+        else:
+            eltype = 6
+
+        for i, el in enumerate(self.elements):
+            outfile.write("%8d%3d%3d %s\n" %
+                    (i+1, eltype, len(el),
+                        "".join("%8d" % (p+1) for p in el)))
+        outfile.write("ENDOFSECTION\n")
+
+        # element groups ------------------------------------------------------
+        outfile.write("ELEMENT GROUP 1.3.0\n")
+        # FIXME
+        i = 0
+        grp_elements = list(range(len(self.elements)))
+        material = 1
+        flags = 0
+        outfile.write("GROUP:%11d ELEMENTS:%11d MATERIAL:%11s NFLAGS: %11d\n"
+                % (1, len(grp_elements), repr(material), flags))
+        outfile.write(("epsilon: %s\n" % material).rjust(32)) # FIXME
+        outfile.write("0\n")
+        outfile.write(_linebreak_list([str(i+1) for i in grp_elements],
+            pad=8)
+                + "\n")
+        outfile.write("ENDOFSECTION\n")
+
+        # boundary conditions -------------------------------------------------
+        # build mapping face -> (tet, neu_face_index)
+        face2el = {}
+
+        if dim == 2:
+            for ti, el in enumerate(self.elements):
+                # Sledge++ Users' Guide, figure 4
+                faces = [
+                        frozenset([el[0], el[1]]),
+                        frozenset([el[1], el[2]]),
+                        frozenset([el[2], el[0]]),
+                        ]
+                for fi, face in enumerate(faces):
+                    face2el.setdefault(face, []).append((ti, fi+1))
+
+        elif dim == 3:
+            face2el = {}
+            for ti, el in enumerate(self.elements):
+                # Sledge++ Users' Guide, figure 5
+                faces = [
+                        frozenset([el[1], el[0], el[2]]),
+                        frozenset([el[0], el[1], el[3]]),
+                        frozenset([el[1], el[2], el[3]]),
+                        frozenset([el[2], el[0], el[3]]),
+                        ]
+                for fi, face in enumerate(faces):
+                    face2el.setdefault(face, []).append((ti, fi+1))
+
+        else:
+            raise ValueError("invalid number of dimensions (%d)" % dim)
+
+        # actually output bc sections
+        if not self.faces.allocated:
+            from warnings import warn
+            warn("no exterior faces in mesh data structure, not writing boundary conditions")
+        else:
+            # requires -f option in tetgen, -e in triangle
+
+            for bc_marker in bc_markers:
+                if isinstance(bc_marker, frozenset):
+                    face_indices = [i
+                            for i, face in enumerate(self.faces)
+                            if self.face_markers[i] in bc_marker]
+                else:
+                    face_indices = [i
+                            for i, face in enumerate(self.faces)
+                            if bc_marker == self.face_markers[i]]
+
+                if not face_indices:
+                    continue
+
+                outfile.write("BOUNDARY CONDITIONS 2.1.2\n")
+                if bc_marker in bc:
+                    # regular BC
+
+                    bc_name, bc_code = bc[bc_marker]
+                    outfile.write("%32s%8d%8d%8d%8d\n"
+                            % (bc_name,
+                                1, # face BC
+                                len(face_indices),
+                                0, # zero additional values per face,
+                                bc_code,
+                                )
+                            )
+                else:
+                    # periodic BC
+
+                    outfile.write("%s%s%8d%8d%8d\n"
+                            % ("periodic", " ".join(repr(p) for p in periods),
+                                len(face_indices),
+                                0, # zero additional values per face,
+                                0,
+                                )
+                            )
+
+                for i, fi in enumerate(face_indices):
+                    face_nodes = frozenset(self.faces[fi])
+                    adj_el = face2el[face_nodes]
+                    assert len(adj_el) == 1
+
+                    el_index, el_face_number = adj_el[0]
+
+                    outfile.write("%10d%5d%5d\n" %
+                            (el_index+1, eltype, el_face_number))
+
+                outfile.write("ENDOFSECTION\n")
+
+            outfile.close()
+            # FIXME curved boundaries?
+            # FIXME proper element group support
+
+
+
+
+
+def dump_array(name, array):
+    print("array %s: %d elements, %d values per element" % (name, len(array), array.unit))
+
+    if len(array) == 0 or array.unit == 0:
+        return
+
+    try:
+        array[0]
+    except RuntimeError:
+        print("  not allocated")
+        return
+
+    for i, entry in enumerate(array):
+        if isinstance(entry, list):
+            print("  %d: %s" % (i, ",".join(str(sub) for sub in entry)))
+        else:
+            print("  %d: %s" % (i, entry))
+
diff --git a/meshpy/meshpy/geometry.py b/meshpy/meshpy/geometry.py
new file mode 100644
index 0000000000000000000000000000000000000000..36f901fc00fe2b417d90c4edb2509ce831c93d25
--- /dev/null
+++ b/meshpy/meshpy/geometry.py
@@ -0,0 +1,554 @@
+from __future__ import division, absolute_import
+
+__doc__ = """
+
+Geometry builder
+----------------
+
+.. autoclass:: GeometryBuilder
+
+Geometries
+----------
+
+These functions are designed so that their output can be splat-passed to
+:meth:`GeometryBuilder.add_geometry`::
+
+    builder = GeometryBuilder()
+    builder.add_geometry(*make_ball(10))
+
+.. autoclass:: Marker
+    :members:
+    :undoc-members:
+
+.. autofunction:: make_box
+.. autofunction:: make_circle
+.. autofunction:: make_ball
+.. autofunction:: make_cylinder
+
+Extrusions and surfaces of revolution
+-------------------------------------
+
+.. data:: EXT_OPEN
+.. data:: EXT_CLOSED_IN_RZ
+
+.. autofunction:: generate_extrusion
+.. autofunction:: generate_surface_of_revolution
+"""
+
+import numpy as np
+from six.moves import range
+from six.moves import zip
+
+
+# {{{ geometry building
+
+def bounding_box(points):
+    return (
+            np.asarray(np.min(points, axis=0), dtype=np.float64),
+            np.asarray(np.max(points, axis=0), dtype=np.float64))
+
+
+def is_multi_polygon(facets):
+    if not len(facets):
+        return False
+
+    try:
+        facets[0][0][0]  # facet 0, poly 0, point 0
+    except TypeError:
+        # pure python raises this
+        return False
+    except IndexError:
+        # numpy raises this
+        return False
+    else:
+        return True
+
+
+def offset_point_indices(facets, offset):
+    if is_multi_polygon(facets):
+        return [[tuple(p_i+offset for p_i in poly)
+            for poly in facet]
+            for facet in facets]
+    else:
+        return [tuple(p_i+offset for p_i in facet) for facet in facets]
+
+
+class GeometryBuilder(object):
+    """
+    .. automethod:: add_geometry
+    .. automethod:: set
+    .. automethod:: wrap_in_box
+    .. automethod:: bounding_box
+    .. automethod:: center
+    .. automethod:: apply_transform
+    """
+    def __init__(self):
+        self.points = []
+        self.facets = []
+        self.facet_hole_starts = None
+        self.facet_markers = None
+        self.point_markers = None
+
+    def add_geometry(self, points, facets, facet_hole_starts=None,
+            facet_markers=None, point_markers=None):
+        if isinstance(facet_markers, int):
+            facet_markers = len(facets) * [facet_markers]
+
+        if facet_hole_starts and not self.facet_hole_starts:
+            self.facet_hole_starts = len(self.facets) * []
+        if facet_markers and not self.facet_markers:
+            self.facet_markers = len(self.facets) * [0]
+        if point_markers and not self.point_markers:
+            self.point_markers = len(self.points) * [0]
+
+        if not facet_hole_starts and self.facet_hole_starts:
+            facet_hole_starts = len(facets) * [[]]
+        if not facet_markers and self.facet_markers:
+            facet_markers = len(facets) * [0]
+        if not point_markers and self.point_markers:
+            point_markers = len(points) * [0]
+
+        if is_multi_polygon(facets) and not is_multi_polygon(self.facets):
+            self.facets = [[facet] for facet in self.facets]
+
+        if not is_multi_polygon(facets) and is_multi_polygon(self.facets):
+            facets = [[facet] for facet in facets]
+
+        self.facets.extend(offset_point_indices(facets, len(self.points)))
+        self.points.extend(points)
+
+        if facet_markers:
+            self.facet_markers.extend(facet_markers)
+            assert len(facets) == len(facet_markers)
+        if facet_hole_starts:
+            self.facet_hole_starts.extend(facet_hole_starts)
+            assert len(facets) == len(facet_hole_starts)
+        if point_markers:
+            self.point_markers.extend(point_markers)
+            assert len(points) == len(point_markers)
+
+    def add_cycle(self, points, facet_markers=None, point_markers=None):
+        def make_facets():
+            end = len(points)-1
+            for i in range(end):
+                yield i, i+1
+            yield end, 0
+
+        self.add_geometry(points, list(make_facets()),
+                facet_markers=facet_markers,
+                point_markers=point_markers)
+
+    def dimensions(self):
+        return len(self.points[0])
+
+    def set(self, mesh_info):
+        """Transfer the built geometry into a :class:`meshpy.triangle.MeshInfo`
+        or a :class:`meshpy.tet.MeshInfo`.
+        """
+
+        mesh_info.set_points(self.points, self.point_markers)
+        if self.facet_hole_starts or is_multi_polygon(self.facets):
+            mesh_info.set_facets_ex(self.facets,
+                    self.facet_hole_starts, self.facet_markers)
+        else:
+            mesh_info.set_facets(self.facets, self.facet_markers)
+
+    def mesher_module(self):
+        dim = self.dimensions()
+        if dim == 2:
+            import meshpy.triangle
+            return meshpy.triangle
+        elif dim == 3:
+            import meshpy.tet
+            return meshpy.tet
+        else:
+            raise ValueError("unsupported dimensionality %d" % dim)
+
+    def bounding_box(self):
+        return bounding_box(self.points)
+
+    def center(self):
+        a, b = bounding_box(self.points)
+        return (a+b)/2
+
+    def wrap_in_box(self, distance, subdivisions=None):
+        """
+        :param subdivisions: is a tuple of integers specifying
+          the number of subdivisions along each axis.
+        """
+
+        a, b = bounding_box(self.points)
+        points, facets, _, facet_markers = \
+                make_box(a-distance, b+distance, subdivisions)
+
+        self.add_geometry(points, facets, facet_markers=facet_markers)
+
+    def apply_transform(self, f):
+        self.points = [f(x) for x in self.points]
+
+# }}}
+
+
+# {{{ actual geometries
+
+class Marker:
+    MINUS_X = 1
+    PLUS_X = 2
+    MINUS_Y = 3
+    PLUS_Y = 4
+    MINUS_Z = 5
+    PLUS_Z = 6
+    SHELL = 100
+
+    FIRST_USER_MARKER = 1000
+
+
+def make_box(a, b, subdivisions=None):
+    """
+    :param subdivisions: is a tuple of integers specifying
+      the number of subdivisions along each axis.
+    """
+
+    a = [float(ai) for ai in a]
+    b = [float(bi) for bi in b]
+
+    assert len(a) == len(b)
+
+    dimensions = len(a)
+    if dimensions == 2:
+        # CAUTION: Do not change point or facet order here.
+        # Other code depends on this staying the way it is.
+
+        points = [
+                (a[0], a[1]),
+                (b[0], a[1]),
+                (b[0], b[1]),
+                (a[0], b[1]),
+                ]
+
+        facets = [(0, 1), (1, 2), (2, 3), (3, 0)]
+
+        facet_markers = [
+                Marker.MINUS_Y, Marker.PLUS_X,
+                Marker.PLUS_Y, Marker.MINUS_X]
+
+    elif dimensions == 3:
+        #    7--------6
+        #   /|       /|
+        #  4--------5 |  z
+        #  | |      | |  ^
+        #  | 3------|-2  | y
+        #  |/       |/   |/
+        #  0--------1    +--->x
+
+        points = [
+                (a[0], a[1], a[2]),
+                (b[0], a[1], a[2]),
+                (b[0], b[1], a[2]),
+                (a[0], b[1], a[2]),
+                (a[0], a[1], b[2]),
+                (b[0], a[1], b[2]),
+                (b[0], b[1], b[2]),
+                (a[0], b[1], b[2]),
+                ]
+
+        facets = [
+                (0, 1, 2, 3),
+                (0, 1, 5, 4),
+                (1, 2, 6, 5),
+                (7, 6, 2, 3),
+                (7, 3, 0, 4),
+                (4, 5, 6, 7)
+                ]
+
+        facet_markers = [Marker.MINUS_Z, Marker.MINUS_Y, Marker.PLUS_X,
+                Marker.PLUS_Y, Marker.MINUS_X, Marker.PLUS_Z]
+    else:
+        raise ValueError("unsupported dimension count: %d" % len(a))
+
+    if subdivisions is not None:
+        if dimensions != 2:
+            raise NotImplementedError(
+                    "subdivision not implemented for any "
+                    "dimension count other than 2")
+
+        from meshpy.triangle import subdivide_facets
+        points, facets, facet_markers = subdivide_facets(
+                [subdivisions[0], subdivisions[1],
+                    subdivisions[0], subdivisions[1]],
+                points, facets, facet_markers)
+
+    return points, facets, None, facet_markers
+
+
+def make_circle(r, center=(0, 0), subdivisions=40, marker=Marker.SHELL):
+    def round_trip_connect(seq):
+        result = []
+        for i in range(len(seq)):
+            result.append((i, (i+1) % len(seq)))
+        return result
+
+    phi = np.linspace(0, 2*np.pi, num=subdivisions, endpoint=False)
+    cx, cy = center
+    x = r*np.cos(phi) + cx
+    y = r*np.sin(phi) + cy
+
+    return ([np.array(pt) for pt in zip(x, y)],
+            round_trip_connect(list(range(subdivisions))),
+            None,
+            subdivisions*[marker])
+
+
+def make_ball(r, subdivisions=10):
+    from math import pi, cos, sin
+
+    dphi = pi/subdivisions
+
+    def truncate(my_r):
+        if abs(my_r) < 1e-9*r:
+            return 0
+        else:
+            return my_r
+
+    rz = [(truncate(r*sin(i*dphi)), r*cos(i*dphi)) for i in range(subdivisions+1)]
+
+    return generate_surface_of_revolution(
+            rz, closure=EXT_OPEN, radial_subdiv=subdivisions)
+
+
+def make_cylinder(radius, height, radial_subdivisions=10,
+        height_subdivisions=1):
+    dz = height/height_subdivisions
+    rz = [(0, 0)] \
+            + [(radius, i*dz) for i in range(height_subdivisions+1)] \
+            + [(0, height)]
+    ring_markers = [Marker.MINUS_Z] \
+            + ((height_subdivisions)*[Marker.SHELL]) \
+            + [Marker.PLUS_Z]
+
+    return generate_surface_of_revolution(rz,
+            closure=EXT_OPEN, radial_subdiv=radial_subdivisions,
+            ring_markers=ring_markers)
+
+# }}}
+
+
+# {{{ extrusions
+
+def _is_same_float(a, b, threshold=1e-10):
+    if abs(a) > abs(b):
+        a, b = b, a
+
+    # now abs(a) <= abs(b) always
+    return abs(b) < threshold or abs(a-b) < threshold*abs(b)
+
+
+EXT_OPEN = 0
+EXT_CLOSED_IN_RZ = 1
+
+
+def generate_extrusion(rz_points, base_shape, closure=EXT_OPEN,
+        point_idx_offset=0, ring_point_indices=None,
+        ring_markers=None, rz_closure_marker=0):
+    """Extrude a given connected *base_shape* (a list of (x,y) points)
+    along the z axis. For each step in the extrusion, the base shape
+    is multiplied by a radius and shifted in the z direction. Radius
+    and z offset are given by *rz_points*, which is a list of
+    (r, z) tuples.
+
+    Returns ``(points, facets, facet_holestarts, markers)``, where *points* is
+    a list of (3D) points and facets is a list of polygons. Each polygon is, in
+    turn, represented by a tuple of indices into *points*. If
+    *point_idx_offset* is not zero, these indices start at that number.
+    *markers* is a list equal in length to *facets*, each specifying the facet
+    marker of that facet.  *facet_holestarts* is also equal in length to
+    *facets*, each element is a list of hole starting points for the
+    corresponding facet.
+
+    Use L{MeshInfo.set_facets_ex} to add the extrusion to a L{MeshInfo}
+    structure.
+
+    The extrusion proceeds by generating quadrilaterals connecting each
+    ring.  If any given radius in *rz_points* is 0, triangle fans are
+    produced instead of quads to provide non-degenerate closure.
+
+    If *closure* is :data:`EXT_OPEN`, no efforts are made to put end caps on the
+    extrusion.
+
+    If *closure* is :data:`EXT_CLOSED_IN_RZ`, then a torus-like structure
+    is assumed and the last ring is just connected to the first.
+
+    If *ring_markers* is not None, it is an list of markers added to each
+    ring. There should be len(rz_points)-1 entries in this list.
+    If rings are added because of closure options, they receive the
+    corresponding *XXX_closure_marker*.  If *facet_markers* is given, this function
+    returns (points, facets, markers), where markers is is a list containing
+    a marker for each generated facet. Unspecified markers generally
+    default to 0.
+
+    If *ring_point_indices* is given, it must be a list of the same
+    length as *rz_points*. Each entry in the list may either be None,
+    or a list of point indices. This list must contain the same number
+    of points as the *base_shape*; it is taken as the indices of
+    pre-existing points that are to be used for the given ring, instead
+    of generating new points.
+    """
+
+    assert len(rz_points) > 0
+
+    if ring_markers is not None:
+        assert len(rz_points) == len(ring_markers)+1
+
+    def get_ring(ring_idx):
+        try:
+            return rings[ring_idx]
+        except KeyError:
+            # need to generate fresh ring, continue
+            pass
+
+        p_indices = None
+        if ring_point_indices is not None:
+            p_indices = ring_point_indices[ring_idx]
+
+        first_idx = point_idx_offset+len(points)
+
+        r, z = rz_points[ring_idx]
+
+        if r == 0:
+            p_indices = (first_idx,)
+            points.append((0, 0, z))
+        else:
+            p_indices = tuple(range(first_idx, first_idx+len(base_shape)))
+            points.extend([(x*r, y*r, z) for (x, y) in base_shape])
+
+        rings[ring_idx] = p_indices
+        return p_indices
+
+    def pair_with_successor(l):
+        n = len(l)
+        return [(l[i], l[(i+1) % n]) for i in range(n)]
+
+    def add_polygons(new_polys, marker):
+        """Add several new facets, each polygon in new_polys corresponding
+        to a new facet.
+        """
+        facets.extend([poly] for poly in new_polys)
+        markers.extend(len(new_polys)*[marker])
+        holelists.extend(len(new_polys)*[[]])
+
+    def add_facet(facet_polygons, holestarts, marker):
+        """Add a single facet, with each polygon in *facet_polygons*
+        belonging to a single facet.
+        """
+        facets.append(facet_polygons)
+        markers.append(marker)
+        holelists.append(holestarts)
+
+    def connect_ring(ring1_idx, ring2_idx, marker):
+        r1, z1 = rz_points[ring1_idx]
+        r2, z2 = rz_points[ring2_idx]
+
+        if _is_same_float(z2, z1):
+            assert not _is_same_float(r1, r2)
+            # we're moving purely outward--this doesn't need fans, only plane
+            # surfaces. Special casing this leads to more freedom for TetGen
+            # and hence better meshes.
+
+            if r1 == 0:
+                # make opening surface
+                if r2 != 0:
+                    add_polygons([get_ring(ring2_idx)], marker=marker)
+            elif r2 == 0:
+                # make closing surface
+                add_polygons([get_ring(ring1_idx)], marker=marker)
+            else:
+                # make single-surface interface with hole
+                add_facet([
+                    get_ring(ring1_idx),
+                    get_ring(ring2_idx),
+                    ],
+                    holestarts=[(0, 0, z1)], marker=marker)
+        else:
+            ring1 = get_ring(ring1_idx)
+            ring2 = get_ring(ring2_idx)
+            if r1 == 0:
+                # make opening fan
+                assert len(ring1) == 1
+                start_pt = ring1[0]
+
+                if r2 != 0:
+                    add_polygons(
+                            [(start_pt, succ, pt)
+                            for pt, succ in pair_with_successor(ring2)],
+                            marker=marker)
+            elif r2 == 0:
+                # make closing fan
+                assert len(ring2) == 1
+                end_pt = ring2[0]
+                add_polygons(
+                        [(pt, succ, end_pt)
+                        for pt, succ in pair_with_successor(ring1)],
+                        marker=marker)
+            else:
+                # make quad strip
+                pairs1 = pair_with_successor(ring1)
+                pairs2 = pair_with_successor(ring2)
+                add_polygons(
+                        [(a, b, c, d) for ((a, b), (d, c)) in zip(pairs1, pairs2)],
+                        marker=marker)
+
+    points = []
+    facets = []
+    markers = []
+    holelists = []
+
+    rings = {}
+
+    # pre-populate ring dict with ring_point_indices
+    if ring_point_indices is not None:
+        for i, ring_points in enumerate(ring_point_indices):
+            if ring_points is not None:
+                assert isinstance(ring_points, tuple)
+
+                if rz_points[i][0] == 0:
+                    assert len(ring_points) == 1
+                else:
+                    assert len(ring_points) == len(base_shape), \
+                            ("Ring points length (%d) does not "
+                                    "match base shape length (%d)"
+                                    % (len(ring_points), len(base_shape)))
+
+                rings[i] = ring_points
+
+    for i in range(len(rz_points)-1):
+        if ring_markers is not None:
+            ring_marker = ring_markers[i]
+        else:
+            ring_marker = 0
+
+        connect_ring(i, i+1, ring_marker)
+
+    if closure == EXT_CLOSED_IN_RZ:
+        connect_ring(len(rz_points)-1, 0, rz_closure_marker)
+
+    return points, facets, holelists, markers
+
+
+def generate_surface_of_revolution(rz_points,
+        closure=EXT_OPEN, radial_subdiv=16,
+        point_idx_offset=0, ring_point_indices=None,
+        ring_markers=None, rz_closure_marker=0):
+    from math import sin, cos, pi
+
+    dphi = 2*pi/radial_subdiv
+    base_shape = [(cos(dphi*i), sin(dphi*i)) for i in range(radial_subdiv)]
+    return generate_extrusion(
+            rz_points, base_shape, closure=closure,
+            point_idx_offset=point_idx_offset,
+            ring_point_indices=ring_point_indices,
+            ring_markers=ring_markers, rz_closure_marker=rz_closure_marker,
+            )
+
+# }}}
+
+# vim: foldmethod=marker
diff --git a/meshpy/meshpy/gmsh.py b/meshpy/meshpy/gmsh.py
new file mode 100644
index 0000000000000000000000000000000000000000..867706e65332bfc3552d3a90399f47861d7a7f6b
--- /dev/null
+++ b/meshpy/meshpy/gmsh.py
@@ -0,0 +1,4 @@
+from gmsh_interop.runner import *
+
+from warnings import warn
+warn("meshpy.gmsh is deprecated. Use gmsh_interop.runner instead.", DeprecationWarning)
diff --git a/meshpy/meshpy/gmsh_reader.py b/meshpy/meshpy/gmsh_reader.py
new file mode 100644
index 0000000000000000000000000000000000000000..75d92b54fb9b984875aff41db151ce3c46aa1351
--- /dev/null
+++ b/meshpy/meshpy/gmsh_reader.py
@@ -0,0 +1,4 @@
+from gmsh_interop.reader import *
+
+from warnings import warn
+warn("meshpy.gmsh_reader is deprecated. Use gmsh_interop.reader instead.", DeprecationWarning)
diff --git a/meshpy/meshpy/naca.py b/meshpy/meshpy/naca.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f55d65d0c64851667ff236efdbc57dbe3e78484
--- /dev/null
+++ b/meshpy/meshpy/naca.py
@@ -0,0 +1,274 @@
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
+
+import numpy
+from six.moves import range
+
+
+class FourDigitsSymmetric:
+    def __init__(self, thickness, edge_coeff):
+        self.thickness = thickness
+        self.edge_coeff = edge_coeff
+
+    def __call__(self, x, side):
+        t = self.thickness
+
+        def y_upper(y):
+            return y
+
+        def y_lower(y):
+            return -y
+
+        def x_upper(x):
+            return x
+
+        def x_lower(x):
+            return x
+
+        y = t * 5 * (0.2969 * numpy.sqrt(x) + ((((-self.edge_coeff * x +
+            0.2843) * x - 0.3516) * x) - 0.126) * x)
+
+        if side == "upper":
+            return numpy.array([x_upper(x), y_upper(y)])
+        elif side == "lower":
+            return numpy.array([x_lower(x), y_lower(y)])
+        else:
+            raise ValueError("Neither upper nor lower side selected in the call.")
+
+
+class FourDigitsCambered:
+    def __init__(self, thickness, max_camber, max_camber_pos, edge_coeff):
+        self.thickness = thickness
+        self.max_camber = max_camber
+        self.max_camber_pos = max_camber_pos
+        self.edge_coeff = edge_coeff
+
+    def __call__(self, x, side):
+        t = self.thickness
+        m = self.max_camber
+        p = self.max_camber_pos
+
+        def y_upper(y_c, y, theta):
+            return y_c + y * numpy.cos(theta)
+
+        def y_lower(y_c, y, theta):
+            return y_c - y * numpy.cos(theta)
+
+        def x_upper(x, y, theta):
+            return x - y * numpy.sin(theta)
+
+        def x_lower(x, y, theta):
+            return x + y * numpy.sin(theta)
+
+        y = t * 5 * (0.2969 * numpy.sqrt(x) + ((((-self.edge_coeff * x +
+            0.2843) * x - 0.3516) * x) - 0.126) * x)
+
+        if x <= p:
+            y_c = m * x / p ** 2 * (2 * p - x)
+            theta = numpy.arctan(2 * m / p ** 2 * (p - x))
+        else:
+            y_c = m * (1 - x) / (1 - p) ** 2 * (1 + x - 2 * p)
+            theta = numpy.arctan(m / (1 - p) ** 2 * (2 * p - 2 * x))
+
+        if side == "upper":
+            return numpy.array([x_upper(x, y, theta), y_upper(y_c, y, theta)])
+        elif side == "lower":
+            return numpy.array([x_lower(x, y, theta), y_lower(y_c, y, theta)])
+        else:
+            raise ValueError("Neither upper nor lower side selected in the call.")
+
+
+class FiveDigits:
+    def __init__(self, thickness, m, k1, edge_coeff):
+        self.thickness = thickness
+        self.edge_coeff = edge_coeff
+        self.m = m
+        self.k1 = k1
+
+    def __call__(self, x, side):
+        t = self.thickness
+        m = self.m
+        k1 = self.k1
+
+        def y_upper(y_c, y, theta):
+            return y_c + y * numpy.cos(theta)
+
+        def y_lower(y_c, y, theta):
+            return y_c - y * numpy.cos(theta)
+
+        def x_upper(x, y, theta):
+            return x - y * numpy.sin(theta)
+
+        def x_lower(x, y, theta):
+            return x + y * numpy.sin(theta)
+
+        y = t * 5 * (0.2969 * numpy.sqrt(x) + ((((-self.edge_coeff * x +
+            0.2843) * x - 0.3516) * x) - 0.126) * x)
+
+        if x <= m:
+            y_c = k1 / 6 * x * ((x - 3 * m) * x + m ** 2 * (3 - m))
+            theta = numpy.arctan(k1 / 6 * ((3 * x - 6 * m) * x +
+                m ** 2 * (3 - m)))
+        else:
+            y_c = k1 * m ** 3 / 6 * (1 - x)
+            theta = numpy.arctan(-k1 * m ** 3 / 6)
+
+        if side == "upper":
+            return numpy.array([x_upper(x, y, theta), y_upper(y_c, y, theta)])
+        elif side == "lower":
+            return numpy.array([x_lower(x, y, theta), y_lower(y_c, y, theta)])
+        else:
+            raise ValueError("Neither upper nor lower side selected in the call.")
+
+
+def get_naca_points(naca_digits, number_of_points=100,
+        sharp_trailing_edge=True,
+        abscissa_map=lambda x: 0.03*x+0.97*x**2,
+        verbose=False):
+    """
+    Return a list of coordinates of NACA 4-digit and 5-digit series
+    airfoils.
+    """
+
+    if verbose:
+        def explain(*s):
+            print(" ".join(str(s_i) for s_i in s))
+    else:
+        def explain(*s):
+            pass
+
+    explain("Airfoil: NACA-%s" % naca_digits)
+
+    if sharp_trailing_edge:
+        explain("Sharp trailing edge")
+        edge_coeff = 0.1036
+    else:
+        explain("Blunt trailing edge")
+        edge_coeff = 0.1015
+
+    raw_abscissae = numpy.linspace(0, 1, number_of_points, endpoint=True)
+    abscissae = numpy.empty_like(raw_abscissae)
+    for i in range(number_of_points):
+        abscissae[i] = abscissa_map(raw_abscissae[i])
+
+    digits_int = int(naca_digits)
+    if len(naca_digits) == 4:
+        thickness = (digits_int % 100)
+        max_camber_pos = (digits_int % 1000) - thickness
+        max_camber = (digits_int % 10000) - max_camber_pos - thickness
+
+        thickness = thickness / 1e2
+        max_camber_pos = max_camber_pos / 1e3
+        max_camber = max_camber / 1e5
+
+        explain("Thickness:", thickness)
+        explain("Position of maximum camber:", max_camber_pos)
+        explain("Maximum camber:", max_camber)
+
+        if max_camber == 0 and max_camber_pos == 0:
+            explain("Symmetric 4-digit airfoil")
+            points = FourDigitsSymmetric(thickness, edge_coeff)
+        elif max_camber != 0 and max_camber_pos != 0:
+            explain("Cambered 4-digit airfoil")
+            points = FourDigitsCambered(thickness, max_camber,
+                    max_camber_pos, edge_coeff)
+        else:
+            raise NotImplementedError(
+                    "You must decide whether your airfoil shall be cambered or not!")
+
+    elif len(naca_digits) == 5:
+        thickness = (digits_int % 100)
+        max_camber_pos = (digits_int % 10000) - thickness
+
+        thickness = thickness / 1e2
+        max_camber_pos = max_camber_pos / 2e4
+
+        explain("Thickness:", thickness)
+        explain("Position of maximum camber:", max_camber_pos)
+
+        identifier = digits_int // 100
+        if identifier == 210:
+            m = 0.058
+            k1 = 361.4
+        elif identifier == 220:
+            m = 0.126
+            k1 = 51.64
+        elif identifier == 230:
+            m = 0.2025
+            k1 = 15.957
+        elif identifier == 240:
+            m = 0.29
+            k1 = 6.643
+        elif identifier == 250:
+            m = 0.391
+            k1 = 3.23
+        else:
+            raise NotImplementedError("5-digit series only implemented for "
+                    "the first three digits in 210, 220, 230, 240, 250!")
+
+        explain("5-digit airfoil")
+        points = FiveDigits(thickness, m, k1, edge_coeff)
+
+    else:
+        raise NotImplementedError(
+                "Only the 4-digit and 5-digit series are implemented!")
+
+    points_upper = numpy.zeros((len(abscissae), 2))
+    points_lower = numpy.zeros((len(abscissae), 2))
+
+    for i in range(len(abscissae)):
+        points_upper[i] = points(abscissae[i], "upper")
+        points_lower[i] = points(abscissae[i], "lower")
+
+    if sharp_trailing_edge:
+        return list(points_upper)[1:-1] + list(points_lower[::-1])
+    else:
+        return list(points_upper)[1:] + list(points_lower[::-1])
+
+
+def write_points(points, filename):
+    file = open(filename, "w")
+    for pt in points:
+        print("\t".join(repr(p_comp) for p_comp in pt), file=file)
+
+
+def main():
+    from optparse import OptionParser
+
+    parser = OptionParser(usage="%prog AIRFOIL-ID")
+    parser.add_option("-o", "--output",
+            help="write ouput to FILE", metavar="FILE")
+    parser.add_option("-p", "--points", type="int",
+            help="generate N points", metavar="N")
+    parser.add_option("-s", "--sharp-trailing-edge", action="store_true")
+    parser.add_option("-u", "--uniform-distribution", action="store_true")
+    parser.add_option("-q", "--quiet",
+            action="store_false", dest="verbose", default=True,
+            help="Don't print status messages to stdout")
+
+    (options, args) = parser.parse_args()
+
+    if not args:
+        parser.print_help()
+        return
+
+    if options.points is None:
+        options.points = 100
+
+    digits = args[0]
+    points = get_naca_points(digits,
+            number_of_points=options.points,
+            sharp_trailing_edge=options.sharp_trailing_edge,
+            uniform_distribution=options.uniform_distribution,
+            verbose=options.verbose)
+
+    if options.output is None:
+        options.output = "naca-%s.dat" % digits
+
+    print("Output file:", options.output)
+    write_points(points, options.output)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/meshpy/meshpy/ply.py b/meshpy/meshpy/ply.py
new file mode 100644
index 0000000000000000000000000000000000000000..872620c0ccd0ea2f67564ac08578ac76bd1094e7
--- /dev/null
+++ b/meshpy/meshpy/ply.py
@@ -0,0 +1,81 @@
+from __future__ import absolute_import
+from six.moves import range
+from six.moves import zip
+def parse_int(it):
+    return int(next(it))
+def parse_float(it):
+    return float(next(it))
+class ListParser:
+    def __init__(self, len_parser, item_parser):
+        self.len_parser = len_parser
+        self.item_parser = item_parser
+
+    def __call__(self, it):
+        return [self.item_parser(it) for i in range(self.len_parser(it))]
+
+def make_parser(it):
+    tp = next(it)
+    if tp == "list":
+        len_parser = make_parser(it)
+        item_parser = make_parser(it)
+        return ListParser(len_parser, item_parser)
+    elif tp in "float double float32 float64".split():
+        return parse_float
+    elif tp in "char uchar short ushort int uint int8 uint8 int16 uint16 int32".split():
+        return parse_int
+    else:
+        raise ValueError("unknown type '%s'" % tp)
+
+def parse_ply(name):
+    lines = [l.strip().lower() for l in open(name).readlines()]
+
+    assert lines[0] == "ply"
+    assert lines[1].split() == ["format", "ascii", "1.0"]
+    
+    i = 2
+
+    data_queue = []
+
+    # parse header
+    while lines[i] != "end_header":
+        words = lines[i].split()
+        if words[0] == "element":
+            i += 1
+            props = []
+            lsplit = lines[i].split()
+            while lsplit[0] == "property":
+                props.append((lsplit[-1], make_parser(iter(lsplit[1:-1]))))
+                i += 1
+                lsplit = lines[i].split()
+
+            data_queue.append((words[1], int(words[2]), props))
+        elif words[0] in ["comment", "created"]:
+            i += 1
+        else:
+            raise ValueError("invalid header field")
+    i += 1 # skip end_header
+
+    result = {}
+
+    def parse_line(parsers, line):
+        it = iter(line.split())
+        result = []
+        for p in parsers:
+            result.append(p(it))
+        return result
+
+    from pytools import Record
+    class DataBlock(Record):
+        pass
+
+    for name, line_count, props in data_queue:
+        prop_names, parsers = list(zip(*props))
+        result[name] = DataBlock(
+                properties=prop_names, 
+                data=[parse_line(parsers, l) for l in lines[i:i+line_count]])
+
+        i += line_count
+
+    return result
+
+
diff --git a/meshpy/meshpy/tet.py b/meshpy/meshpy/tet.py
new file mode 100644
index 0000000000000000000000000000000000000000..113aed600c8a4651cb2bc0af5af209264c3a9519
--- /dev/null
+++ b/meshpy/meshpy/tet.py
@@ -0,0 +1,190 @@
+from __future__ import absolute_import
+from __future__ import print_function
+from meshpy.common import MeshInfoBase, dump_array
+import meshpy._tetgen as internals
+import six
+from six.moves import range
+
+
+class MeshInfo(internals.MeshInfo, MeshInfoBase):
+    def set_facets(self, facets, markers=None):
+        """Set a list of simple, single-polygon factes. Unlike :meth:`set_facets_ex`,
+        :meth:`set_facets` does not allow hole and only lets you use a single
+        polygon per facet.
+
+        :param facets: a list of facets, where each facet is a single
+          polygons, represented by a list of point indices.
+        :param markers: Either None or a list of integers of the same
+          length as *facets*. Each integer is the facet marker assigned
+          to its corresponding facet.
+
+        :note: When the above says "list", any repeatable iterable
+          also accepted instead.
+        """
+
+        if markers:
+            assert len(markers) == len(facets)
+
+        self.facets.resize(len(facets))
+
+        for i, vlist in enumerate(facets):
+            facet = self.facets[i]
+            polys = facet.polygons
+            polys.resize(1)
+            poly = facet.polygons[0]
+            poly.vertices.resize(len(vlist))
+            for j, pt_idx in enumerate(vlist):
+                poly.vertices[j] = pt_idx
+
+        if markers:
+            self.facet_markers.setup()
+            for i, mark in enumerate(markers):
+                self.facet_markers[i] = mark
+
+    def set_facets_ex(self, facets, facet_holestarts=None, markers=None):
+        """Set a list of complicated factes. Unlike :meth:`set_facets`,
+        :meth:`set_facets_ex` allows holes and multiple polygons per
+        facet.
+
+        :param facets: a list of facets, where each facet is a list
+          of polygons, and each polygon is represented by a list
+          of point indices.
+        :param facet_holestarts: Either None or a list of hole starting points
+          for each facet. Each facet may have several hole starting points.
+          The mesh generator starts "eating" a hole into the facet at each
+          starting point and continues until it hits a polygon specified
+          in this facet's record in *facets*.
+        :param markers: Either None or a list of integers of the same
+          length as *facets*. Each integer is the facet marker assigned
+          to its corresponding facet.
+
+        :note: When the above says "list", any repeatable iterable
+          also accepted instead.
+        """
+
+        if markers:
+            assert len(markers) == len(facets)
+        if facet_holestarts is not None:
+            assert len(facet_holestarts) == len(facets)
+
+        self.facets.resize(len(facets))
+        for i_facet, poly_list in enumerate(facets):
+            facet = self.facets[i_facet]
+            polys = facet.polygons
+
+            polys.resize(len(poly_list))
+            for i_poly, vertex_list in enumerate(poly_list):
+                poly = facet.polygons[i_poly]
+
+                poly.vertices.resize(len(vertex_list))
+                for i_point, point in enumerate(vertex_list):
+                    poly.vertices[i_point] = point
+
+            if facet_holestarts is not None:
+                hole_list = facet_holestarts[i_facet]
+                facet_holes = facet.holes
+                facet_holes.resize(len(hole_list))
+                for i_hole, hole_start in enumerate(hole_list):
+                    for i_coordinate, co_value in enumerate(hole_start):
+                        facet_holes[i_hole, i_coordinate] = co_value
+
+        if markers:
+            self.facet_markers.setup()
+            for i, mark in enumerate(markers):
+                self.facet_markers[i] = mark
+
+    def dump(self):
+        for name in ["points"]:
+            dump_array(name, getattr(self, name))
+        for ifacet, facet in enumerate(self.faces):
+            print("facet %d:" % ifacet)
+            for ipolygon, polygon in enumerate(facet.polygons):
+                print("  polygon %d: vertices [%s]" % \
+                        (ipolygon, ",".join(str(vi) for vi in polygon.vertices)))
+
+    def write_vtk(self, filename):
+        import pyvtk
+        vtkelements = pyvtk.VtkData(
+            pyvtk.UnstructuredGrid(
+                self.points,
+                tetra=self.elements),
+            "Mesh")
+        vtkelements.tofile(filename)
+
+    def set_elements(self, elements):
+        self.elements.resize(len(elements))
+
+        for i, element in enumerate(elements):
+            self.elements[i] = element
+
+    def set_element_constraints(self, element_constraints):
+        self.element_volumes.setup()
+
+        for i in range(len(self.element_volumes)):
+            if i in element_constraints:
+                self.element_volumes[i] = element_constraints[i]
+            else:
+                self.element_volumes[i] = -1
+
+
+class Options(internals.Options):
+    def __init__(self, switches, **kwargs):
+        internals.Options.__init__(self)
+        if len(switches) == 0:
+            from warnings import warn
+            warn("Recommend non-empty 'switches' for crash-free meshing")
+        self.parse_switches(switches)
+        self.quiet = 1
+
+        for k, v in six.iteritems(kwargs):
+            try:
+                getattr(self, k)
+            except AttributeError:
+                raise ValueError("invalid option: %s" % k)
+            else:
+                setattr(self, k, v)
+
+
+def tetrahedralize(mesh_info, options):
+    mesh = MeshInfo()
+
+    # restore "C" locale--otherwise tetgen might mis-parse stuff like "a0.01"
+    try:
+        import locale
+    except ImportError:
+        have_locale = False
+    else:
+        have_locale = True
+        prev_num_locale = locale.getlocale(locale.LC_NUMERIC)
+        locale.setlocale(locale.LC_NUMERIC, "C")
+
+    try:
+        internals.tetrahedralize(options, mesh_info, mesh)
+    finally:
+        # restore previous locale if we've changed it
+        if have_locale:
+            locale.setlocale(locale.LC_NUMERIC, prev_num_locale)
+
+    return mesh
+
+
+def build(mesh_info, options=Options("pq"), verbose=False,
+        attributes=False, volume_constraints=False, max_volume=None,
+        diagnose=False, insert_points=None):
+    if not verbose:
+        options.quiet = 1
+
+    if insert_points is not None:
+        options.insertaddpoints = 1
+
+    if attributes:
+        options.regionattrib = 1
+    if volume_constraints:
+        options.varvolume = 1
+    if max_volume:
+        options.fixedvolume = 1
+        options.maxvolume = max_volume
+    if diagnose:
+        options.diagnose = 1
+
+    return tetrahedralize(mesh_info, options)
diff --git a/meshpy/meshpy/tools.py b/meshpy/meshpy/tools.py
new file mode 100644
index 0000000000000000000000000000000000000000..ee73182a34bb3ec362bb93ebdd5a4dbbf92b8492
--- /dev/null
+++ b/meshpy/meshpy/tools.py
@@ -0,0 +1,127 @@
+from __future__ import absolute_import
+
+import six
+from six.moves import range
+
+
+def uniform_refine_triangles(points, elements, factor=2):
+    new_points = points[:]
+    new_elements = []
+    old_face_to_new_faces = {}
+    face_point_dict = {}
+
+    points_per_edge = factor+1
+
+    def get_refined_face(a, b):
+        if a > b:
+            a, b = b, a
+            flipped = True
+        else:
+            flipped = False
+
+        try:
+            face_points = face_point_dict[a, b]
+        except KeyError:
+            a_pt, b_pt = [points[idx] for idx in [a, b]]
+            dx = (b_pt - a_pt)/factor
+
+            # build subdivided facet
+            face_points = [a]
+
+            for i in range(1, points_per_edge-1):
+                face_points.append(len(new_points))
+                new_points.append(a_pt + dx*i)
+
+            face_points.append(b)
+
+            face_point_dict[a, b] = face_points
+
+            # build old_face_to_new_faces
+            old_face_to_new_faces[frozenset([a, b])] = [
+                    (face_points[i], face_points[i+1])
+                    for i in range(factor)]
+
+        if flipped:
+            return face_points[::-1]
+        else:
+            return face_points
+
+    for a, b, c in elements:
+        a_pt, b_pt, c_pt = [points[idx] for idx in [a, b, c]]
+        dr = (b_pt - a_pt)/factor
+        ds = (c_pt - a_pt)/factor
+
+        ab_refined, bc_refined, ac_refined = [
+                get_refined_face(*pt_indices)
+                for pt_indices in [(a, b), (b, c), (a, c)]]
+
+        el_point_dict = {}
+
+        # fill out edges of el_point_dict
+        for i in range(points_per_edge):
+            el_point_dict[i, 0] = ab_refined[i]
+            el_point_dict[0, i] = ac_refined[i]
+            el_point_dict[points_per_edge-1-i, i] = bc_refined[i]
+
+        # fill out interior of el_point_dict
+        for i in range(1, points_per_edge-1):
+            for j in range(1, points_per_edge-1-i):
+                el_point_dict[i, j] = len(new_points)
+                new_points.append(a_pt + dr*i + ds*j)
+
+        # generate elements
+        for i in range(0, points_per_edge-1):
+            for j in range(0, points_per_edge-1-i):
+                new_elements.append((
+                    el_point_dict[i, j],
+                    el_point_dict[i+1, j],
+                    el_point_dict[i, j+1],
+                    ))
+                if i+1+j+1 <= factor:
+                    new_elements.append((
+                        el_point_dict[i+1, j+1],
+                        el_point_dict[i+1, j],
+                        el_point_dict[i, j+1],
+                        ))
+
+    from meshpy.triangle import MeshInfo
+    mi = MeshInfo()
+    mi.set_points(new_points)
+    mi.elements.resize(len(new_elements))
+    for i, el in enumerate(new_elements):
+        mi.elements[i] = el
+    from meshpy.triangle import write_gnuplot_mesh
+    write_gnuplot_mesh("mesh.dat", mi)
+
+    return new_points, new_elements, old_face_to_new_faces
+
+
+def make_swizzle_matrix(spec):
+    import numpy
+    axes = ["x", "y", "z"]
+
+    mapping = dict((axis, axis) for axis in axes)
+    for one_spec in spec.split(","):
+        import_axis, final_axis = one_spec.split(":")
+        mapping[import_axis] = final_axis
+
+    assert set(mapping.keys()) == set(axes), \
+            "axis mapping not complete"
+    assert set(axis.lstrip("-") for axis in six.itervalues(mapping)) == set(axes), \
+            "Axis mapping not onto"
+
+    n = len(axes)
+    result = numpy.zeros((n, n), dtype=int)
+
+    for imp_axis, final_axis in six.iteritems(mapping):
+        imp_axis = axes.index(imp_axis)
+
+        sign = 1
+        while final_axis.startswith("-"):
+            sign *= -1
+            final_axis = final_axis[1:]
+        final_axis = axes.index(final_axis)
+
+        result[final_axis, imp_axis] = sign
+
+    return result
diff --git a/meshpy/meshpy/triangle.py b/meshpy/meshpy/triangle.py
new file mode 100644
index 0000000000000000000000000000000000000000..3a5e3851f16ccfa4133c83ad7ec60eb607f06171
--- /dev/null
+++ b/meshpy/meshpy/triangle.py
@@ -0,0 +1,234 @@
+from __future__ import division
+from __future__ import absolute_import
+from meshpy.common import MeshInfoBase, dump_array
+import meshpy._triangle as internals
+from six.moves import range
+from six.moves import zip
+
+
+class MeshInfo(internals.MeshInfo, MeshInfoBase):
+    _constituents = [
+            "points", "point_attributes", "point_markers",
+            "elements", "element_attributes", "element_volumes",
+            "neighbors",
+            "facets", "facet_markers",
+            "holes",
+            "regions",
+            "faces", "face_markers",
+            "normals",
+            ]
+
+    def __getstate__(self):
+        return self.number_of_point_attributes, \
+               self.number_of_element_attributes, \
+               [(name, getattr(self, name)) for name in self._constituents]
+
+    def __setstate__(self, xxx_todo_changeme):
+        (p_attr_count, e_attr_count, state) = xxx_todo_changeme
+        self.number_of_point_attributes = p_attr_count
+        self.number_of_element_attributes = e_attr_count
+        for name, array in state:
+            if name not in self._constituents:
+                raise RuntimeError("Unknown constituent during unpickling")
+
+            dest_array = getattr(self, name)
+
+            if array is None:
+                dest_array.deallocate()
+            else:
+                if len(dest_array) != len(array):
+                    dest_array.resize(len(array))
+                if not dest_array.allocated and len(array) > 0:
+                    dest_array.setup()
+
+                for i, tup in enumerate(array):
+                    for j, v in enumerate(tup):
+                        dest_array[i, j] = v
+
+    def set_facets(self, facets, facet_markers=None):
+        self.facets.resize(len(facets))
+
+        for i, facet in enumerate(facets):
+            self.facets[i] = facet
+
+        if facet_markers is not None:
+            self.facet_markers.setup()
+            for i, mark in enumerate(facet_markers):
+                self.facet_markers[i] = mark
+
+    def dump(self):
+        for name in self._constituents:
+            dump_array(name, getattr(self, name))
+
+
+def subdivide_facets(subdivisions, points, facets, facet_markers=None):
+    """Return a new facets array in which the original facets are
+    each subdivided into C{subdivisions} subfacets.
+
+    This routine is useful if you have to prohibit the insertion of Steiner
+    points on the boundary  of your triangulation to allow the mesh to conform
+    either to itself periodically or another given mesh. In this case, you may
+    use this routine to create the necessary resolution along the boundary
+    in a predefined way.
+
+    @arg subdivisions: Either an C{int}, indicating a uniform number of subdivisions
+      throughout, or a list of the same length as C{facets}, specifying a subdivision
+      count for each individual facet.
+    @arg points: A list of points referred to from the facets list.
+    @arg facets: The list of old facets, in the form C{[(p1, p2), (p3,p4), ...]}.
+    @arg facet_markers: Either C{None} or a list of facet markers of the same length
+      as C{facets}.
+    @return: The new tuple C{(new_points, new_facets)}.
+      (Or C{(new_points, new_facets, new_facet_markers)} if C{facet_markers} is not
+      C{None}.)
+    """
+
+    def intermediate_points(pa, pb, n):
+        for i in range(1, n):
+            tau = i/n
+            yield [pai*(1-tau) + tau*pbi for pai, pbi in zip(pa, pb)]
+
+    if isinstance(subdivisions, int):
+        from itertools import repeat
+        subdiv_it = repeat(subdivisions, len(facets))
+    else:
+        assert len(facets) == len(subdivisions)
+        subdiv_it = subdivisions.__iter__()
+
+    new_points = points[:]
+    new_facets = []
+
+    if facet_markers is not None:
+        assert len(facets) == len(facet_markers)
+        new_facet_markers = []
+
+    for facet_idx, ((pidx_a, pidx_b), subdiv) in enumerate(zip(facets, subdiv_it)):
+        facet_points = [pidx_a]
+        for p in intermediate_points(points[pidx_a], points[pidx_b], subdiv):
+            facet_points.append(len(new_points))
+            new_points.append(p)
+        facet_points.append(pidx_b)
+
+        for i, p1 in enumerate(facet_points[:-1]):
+            p2 = facet_points[i+1]
+            new_facets.append((p1, p2))
+
+            if facet_markers is not None:
+                new_facet_markers.append(facet_markers[facet_idx])
+
+    if facet_markers is not None:
+        return new_points, new_facets, new_facet_markers
+    else:
+        return new_points, new_facets
+
+
+def build(mesh_info, verbose=False, refinement_func=None, attributes=False,
+        volume_constraints=False, max_volume=None, allow_boundary_steiner=True,
+        allow_volume_steiner=True, quality_meshing=True,
+        generate_edges=None, generate_faces=False, min_angle=None,
+        mesh_order=None, generate_neighbor_lists=False):
+    """Triangulate the domain given in `mesh_info'."""
+    opts = "pzj"
+    if quality_meshing:
+        if min_angle is not None:
+            opts += "q%f" % min_angle
+        else:
+            opts += "q"
+
+    if mesh_order is not None:
+        opts += "o%d" % mesh_order
+
+    if verbose:
+        opts += "VV"
+    else:
+        opts += "Q"
+
+    if attributes:
+        opts += "A"
+
+    if volume_constraints:
+        opts += "a"
+    if max_volume:
+        opts += "a%.20f" % max_volume
+
+    if refinement_func is not None:
+        opts += "u"
+
+    if generate_edges is not None:
+        from warnings import warn
+        warn("generate_edges is deprecated--use generate_faces instead")
+        generate_faces = generate_edges
+    if generate_neighbor_lists is not None:
+        opts += "n"
+
+    if generate_faces:
+        opts += "e"
+
+    if not allow_volume_steiner:
+        opts += "YY"
+        if allow_boundary_steiner:
+            raise ValueError("cannot allow boundary Steiner points when volume "
+                    "Steiner points are forbidden")
+    else:
+        if not allow_boundary_steiner:
+            opts += "Y"
+
+    # restore "C" locale--otherwise triangle might mis-parse stuff like "a0.01"
+    try:
+        import locale
+    except ImportError:
+        have_locale = False
+    else:
+        have_locale = True
+        prev_num_locale = locale.getlocale(locale.LC_NUMERIC)
+        locale.setlocale(locale.LC_NUMERIC, "C")
+
+    try:
+        mesh = MeshInfo()
+        internals.triangulate(opts, mesh_info, mesh, MeshInfo(), refinement_func)
+    finally:
+        # restore previous locale if we've changed it
+        if have_locale:
+            locale.setlocale(locale.LC_NUMERIC, prev_num_locale)
+
+    return mesh
+
+
+def refine(input_p, verbose=False, refinement_func=None,  quality_meshing=True,
+        min_angle=None, generate_neighbor_lists=False):
+    opts = "razj"
+
+    if quality_meshing:
+        if min_angle is not None:
+            opts += "q%f" % min_angle
+        else:
+            opts += "q"
+
+    if len(input_p.faces) != 0:
+        opts += "p"
+    if verbose:
+        opts += "VV"
+    else:
+        opts += "Q"
+    if refinement_func is not None:
+        opts += "u"
+    if generate_neighbor_lists is not None:
+        opts += "n"
+
+    output_p = MeshInfo()
+    internals.triangulate(opts, input_p, output_p, MeshInfo(), refinement_func)
+    return output_p
+
+
+def write_gnuplot_mesh(filename, out_p, facets=False):
+    gp_file = open(filename, "w")
+
+    if facets:
+        segments = out_p.facets
+    else:
+        segments = out_p.elements
+
+    for points in segments:
+        for pt in points:
+            gp_file.write("%f %f\n" % tuple(out_p.points[pt]))
+        gp_file.write("%f %f\n\n" % tuple(out_p.points[points[0]]))
diff --git a/meshpy/patches/mk-patch b/meshpy/patches/mk-patch
new file mode 100755
index 0000000000000000000000000000000000000000..218f2ce903a6b831c8211b6905505bca3c4ae144
--- /dev/null
+++ b/meshpy/patches/mk-patch
@@ -0,0 +1,5 @@
+#! /bin/sh
+
+diff -u $1/tetgen.h ../src/cpp/tetgen.h 
+diff -u $1/tetgen.cxx ../src/cpp/tetgen.cpp 
+diff -u $1/predicates.cxx ../src/cpp/predicates.cpp
diff --git a/meshpy/patches/tetgen-1.4.2.patch b/meshpy/patches/tetgen-1.4.2.patch
new file mode 100644
index 0000000000000000000000000000000000000000..d47ba72358e3a2f9bc80192878f31bdbd4e4880e
--- /dev/null
+++ b/meshpy/patches/tetgen-1.4.2.patch
@@ -0,0 +1,225 @@
+--- /home/andreas/tetgen1.4.2/tetgen.h	2007-04-16 10:45:13.000000000 -0400
++++ ../src/cpp/tetgen.h	2007-08-19 03:03:45.000000000 -0400
+@@ -87,6 +87,7 @@
+ #include <math.h>                     // Math lib: sin(), sqrt(), pow(), ...
+ #include <time.h>           // Defined type clock_t, constant CLOCKS_PER_SEC.
+ #include <assert.h> 
++#include <boost/noncopyable.hpp>
+ 
+ ///////////////////////////////////////////////////////////////////////////////
+ //                                                                           //
+@@ -194,10 +195,13 @@
+     // 'vertexlist' is a list of vertex indices (integers), its length is
+     //   indicated by 'numberofvertices'.  The vertex indices are odered in
+     //   either counterclockwise or clockwise way.
+-    typedef struct {
++    struct polygon : public boost::noncopyable {
+       int *vertexlist;
+       int numberofvertices;
+-    } polygon;
++
++      polygon();
++      ~polygon();
++    };
+ 
+     static void init(polygon* p) {
+       p->vertexlist = (int *) NULL;
+@@ -208,12 +212,15 @@
+     //   to represent a planar straight line graph (PSLG) in two dimension.
+     //   A PSLG contains a list of polygons. It also may conatin holes in it,
+     //   indicated by a list of hole points (their coordinates).
+-    typedef struct {
++    struct facet {
+       polygon *polygonlist;
+       int numberofpolygons;
+       REAL *holelist;
+       int numberofholes;
+-    } facet;
++
++      facet();
++      ~facet();
++    };
+ 
+     static void init(facet* f) {
+       f->polygonlist = (polygon *) NULL;
+@@ -253,12 +260,15 @@
+     //   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 {
++    struct pbcgroup {
+       int fmark1, fmark2;
+       REAL transmat[4][4];
+       int numberofpointpairs;
+       int *pointpairlist;
+-    } pbcgroup;
++
++      pbcgroup();
++      ~pbcgroup();
++    };
+ 
+   public:
+ 
+@@ -568,6 +578,7 @@
+ ///////////////////////////////////////////////////////////////////////////////
+ 
+ REAL exactinit();
++void exactdeinit();
+ REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd);
+ REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe);
+ 
+--- /home/andreas/tetgen1.4.2/tetgen.cxx	2007-04-16 10:45:11.000000000 -0400
++++ ../src/cpp/tetgen.cpp	2007-08-19 03:05:28.000000000 -0400
+@@ -49,6 +49,45 @@
+ // Begin of class 'tetgenio' implementation
+ //
+ 
++tetgenio::polygon::polygon()
++{
++  vertexlist = 0;
++  numberofvertices = 0;
++}
++
++tetgenio::polygon::~polygon()
++{
++  if (vertexlist)
++    delete [] vertexlist;
++}
++
++tetgenio::facet::facet()
++{
++  polygonlist = 0;
++  numberofpolygons = 0;
++  holelist = 0;
++  numberofholes = 0;
++}
++
++tetgenio::facet::~facet()
++{
++  if (polygonlist)
++    delete[] polygonlist;
++  if (holelist)
++    delete[] holelist;
++}
++
++tetgenio::pbcgroup::pbcgroup()
++{ 
++  numberofpointpairs = 0;
++  pointpairlist = 0;
++}
++
++tetgenio::pbcgroup::~pbcgroup()
++{
++  delete[] pointpairlist;
++}
++
+ ///////////////////////////////////////////////////////////////////////////////
+ //                                                                           //
+ // initialize()    Initialize all variables of 'tetgenio'.                   //
+@@ -143,6 +182,7 @@
+   pbcgroup *pg;
+   int i, j;
+ 
++  using namespace std;
+   if (pointlist != (REAL *) NULL) {
+     delete [] pointlist;
+   }
+@@ -187,19 +227,9 @@
+   }
+ 
+   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;
+   }
+@@ -217,12 +247,6 @@
+     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) {
+@@ -34887,6 +34911,7 @@
+   if (b->metric) {
+     delete m.bgm;
+   }
++  exactdeinit();
+ }
+ 
+ #ifndef TETLIBRARY
+--- /home/andreas/tetgen1.4.2/predicates.cxx	2007-04-16 10:45:04.000000000 -0400
++++ ../src/cpp/predicates.cpp	2007-07-19 20:55:24.000000000 -0400
+@@ -113,6 +113,10 @@
+ /*                                                                           */
+ /*****************************************************************************/
+ 
++#if defined(__linux__) && defined(__i386__)
++  #define LINUX 1
++#endif
++
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <math.h>
+@@ -149,8 +153,8 @@
+ /*   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) */
++/* #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       */
+@@ -660,6 +664,8 @@
+ /*                                                                           */
+ /*****************************************************************************/
+ 
++static int previous_cword;
++
+ REAL exactinit()
+ {
+   REAL half;
+@@ -676,7 +682,9 @@
+   _control87(_PC_53, _MCW_PC); /* Set FPU control word for double precision. */
+ #endif /* not SINGLE */
+ #endif /* CPU86 */
++
+ #ifdef LINUX
++  _FPU_GETCW(previous_cword);
+ #ifdef SINGLE
+   /*  cword = 4223; */
+   cword = 4210;                 /* set FPU control word for single precision */
+@@ -725,6 +733,13 @@
+   return epsilon; /* Added by H. Si 30 Juli, 2004. */
+ }
+ 
++void exactdeinit()
++{
++#ifdef LINUX
++  _FPU_SETCW(previous_cword);
++#endif /* LINUX */
++}
++
+ /*****************************************************************************/
+ /*                                                                           */
+ /*  grow_expansion()   Add a scalar to an expansion.                         */
diff --git a/meshpy/patches/tetgen-1.4.3.patch b/meshpy/patches/tetgen-1.4.3.patch
new file mode 100644
index 0000000000000000000000000000000000000000..75a88cc0eea8a653d17945c1c764a364f61e6117
--- /dev/null
+++ b/meshpy/patches/tetgen-1.4.3.patch
@@ -0,0 +1,214 @@
+--- /home/andreas/pack/tetgen1.4.3/tetgen.h	2009-12-13 16:20:33.000000000 -0500
++++ ../src/cpp/tetgen.h	2010-01-22 19:41:28.590818901 -0500
+@@ -87,6 +87,7 @@
+ #include <math.h>
+ #include <time.h>
+ #include <assert.h> 
++#include <boost/noncopyable.hpp>
+ 
+ // The types 'intptr_t' and 'uintptr_t' are signed and unsigned integer types,
+ //   respectively. They are guaranteed to be the same width as a pointer.
+@@ -213,10 +214,13 @@
+   // Note that the points of the polygon must be given in either counter-
+   //   clockwise or clockwise order and they form a ring, so every two
+   //   consective points forms an edge of the polygon.
+-  typedef struct {
++  struct polygon : public boost::noncopyable {
+     int *vertexlist;
+     int numberofvertices;
+-  } polygon;
++
++    polygon();
++   ~polygon();
++  };
+ 
+   static void init(polygon* p) {
+     p->vertexlist = (int *) NULL;
+@@ -225,12 +229,15 @@
+ 
+   // The facet data structure.  A "facet" describes a facet. Each facet is 
+   //   a polygonal region possibly with holes, edges, and points in it.
+-  typedef struct {
++  struct facet {
+     polygon *polygonlist;
+     int numberofpolygons;
+     REAL *holelist;
+     int numberofholes;
+-  } facet;
++
++    facet();
++    ~facet();
++  };
+ 
+   static void init(facet* f) {
+     f->polygonlist = (polygon *) NULL;
+@@ -270,12 +277,15 @@
+   //   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 {
++  struct pbcgroup {
+     int fmark1, fmark2;
+     REAL transmat[4][4];
+     int numberofpointpairs;
+     int *pointpairlist;
+-  } pbcgroup;
++
++    pbcgroup();
++    ~pbcgroup();
++  };
+ 
+   // A callback function for mesh refinement.
+   typedef bool (* TetSizeFunc)(REAL*, REAL*, REAL*, REAL*, REAL*, REAL);
+@@ -549,17 +559,6 @@
+     }
+ 
+     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) {
+@@ -579,12 +578,6 @@
+       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) {
+@@ -2381,6 +2374,7 @@
+ ///////////////////////////////////////////////////////////////////////////////
+ 
+ REAL exactinit();
++void exactdeinit();
+ REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd);
+ REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe);
+ 
+--- /home/andreas/pack/tetgen1.4.3/tetgen.cxx	2009-12-13 16:21:08.000000000 -0500
++++ ../src/cpp/tetgen.cpp	2010-01-22 19:41:28.590818901 -0500
+@@ -34,6 +34,45 @@
+ ////                                                                       ////
+ ////                                                                       ////
+ 
++tetgenio::polygon::polygon()
++{
++  vertexlist = 0;
++  numberofvertices = 0;
++}
++
++tetgenio::polygon::~polygon()
++{
++  if (vertexlist)
++    delete [] vertexlist;
++}
++
++tetgenio::facet::facet()
++{
++  polygonlist = 0;
++  numberofpolygons = 0;
++  holelist = 0;
++  numberofholes = 0;
++}
++
++tetgenio::facet::~facet()
++{
++  if (polygonlist)
++    delete[] polygonlist;
++  if (holelist)
++    delete[] holelist;
++}
++
++tetgenio::pbcgroup::pbcgroup()
++{ 
++  numberofpointpairs = 0;
++  pointpairlist = 0;
++}
++
++tetgenio::pbcgroup::~pbcgroup()
++{
++  delete[] pointpairlist;
++}
++
+ ///////////////////////////////////////////////////////////////////////////////
+ //                                                                           //
+ // load_node_call()    Read a list of points from a file.                    //
+@@ -34751,6 +34790,7 @@
+   if (b->metric) {
+     delete m.bgm;
+   }
++  exactdeinit();
+ }
+ 
+ #ifndef TETLIBRARY
+--- /home/andreas/pack/tetgen1.4.3/predicates.cxx	2009-12-13 16:18:56.000000000 -0500
++++ ../src/cpp/predicates.cpp	2010-01-22 19:41:28.576309963 -0500
+@@ -113,6 +113,10 @@
+ /*                                                                           */
+ /*****************************************************************************/
+ 
++#if defined(__linux__) && defined(__i386__)
++  #define LINUX 1
++#endif
++
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <math.h>
+@@ -149,8 +153,8 @@
+ /*   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) */
++/* #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       */
+@@ -660,6 +664,8 @@
+ /*                                                                           */
+ /*****************************************************************************/
+ 
++static int previous_cword;
++
+ REAL exactinit()
+ {
+   REAL half;
+@@ -676,7 +682,9 @@
+   _control87(_PC_53, _MCW_PC); /* Set FPU control word for double precision. */
+ #endif /* not SINGLE */
+ #endif /* CPU86 */
++
+ #ifdef LINUX
++  _FPU_GETCW(previous_cword);
+ #ifdef SINGLE
+   /*  cword = 4223; */
+   cword = 4210;                 /* set FPU control word for single precision */
+@@ -725,6 +733,13 @@
+   return epsilon; /* Added by H. Si 30 Juli, 2004. */
+ }
+ 
++void exactdeinit()
++{
++#ifdef LINUX
++  _FPU_SETCW(previous_cword);
++#endif /* LINUX */
++}
++
+ /*****************************************************************************/
+ /*                                                                           */
+ /*  grow_expansion()   Add a scalar to an expansion.                         */
diff --git a/meshpy/setup.cfg b/meshpy/setup.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..512924240ea5f744029e9dd0395769ca66267ca1
--- /dev/null
+++ b/meshpy/setup.cfg
@@ -0,0 +1,3 @@
+[flake8]
+ignore = E126,E127,E128,E123,E226,E241,E242,E265,W503,E402
+max-line-length=85
diff --git a/meshpy/setup.py b/meshpy/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..855d9c7b57628d581d4631414cc1cb711e580de1
--- /dev/null
+++ b/meshpy/setup.py
@@ -0,0 +1,209 @@
+#!/usr/bin/env python
+
+import sys
+import setuptools
+from setuptools import Extension
+from setuptools.command.build_ext import build_ext
+
+
+def get_config_schema():
+    from aksetup_helper import (ConfigSchema, StringListOption)
+
+    return ConfigSchema([
+        StringListOption("CXXFLAGS", [],
+            help="Any extra C++ compiler options to include"),
+        StringListOption("LDFLAGS", [],
+            help="Any extra linker options to include"),
+        ])
+
+
+# {{{ pybind11 gunk
+
+class get_pybind_include(object):  # noqa
+    """Helper class to determine the pybind11 include path
+
+    The purpose of this class is to postpone importing pybind11
+    until it is actually installed, so that the ``get_include()``
+    method can be invoked. """
+
+    def __init__(self, user=False):
+        self.user = user
+
+    def __str__(self):
+        import pybind11
+        return pybind11.get_include(self.user)
+
+
+ext_modules = [
+    Extension(
+        'python_example',
+        ['src/main.cpp'],
+        include_dirs=[
+            # Path to pybind11 headers
+            get_pybind_include(),
+            get_pybind_include(user=True)
+        ],
+        language='c++'
+    ),
+]
+
+
+# As of Python 3.6, CCompiler has a `has_flag` method.
+# cf http://bugs.python.org/issue26689
+def has_flag(compiler, flagname):
+    """Return a boolean indicating whether a flag name is supported on
+    the specified compiler.
+    """
+    import tempfile
+    with tempfile.NamedTemporaryFile('w', suffix='.cpp') as f:
+        f.write('int main (int argc, char **argv) { return 0; }')
+        try:
+            compiler.compile([f.name], extra_postargs=[flagname])
+        except setuptools.distutils.errors.CompileError:
+            return False
+    return True
+
+
+def cpp_flag(compiler):
+    """Return the -std=c++[11/14] compiler flag.
+
+    The c++14 is prefered over c++11 (when it is available).
+    """
+    if has_flag(compiler, '-std=c++14'):
+        return '-std=c++14'
+    elif has_flag(compiler, '-std=c++11'):
+        return '-std=c++11'
+    else:
+        raise RuntimeError('Unsupported compiler -- at least C++11 support '
+                           'is needed!')
+
+
+class BuildExt(build_ext):
+    """A custom build extension for adding compiler-specific options."""
+    c_opts = {
+        'msvc': ['/EHsc'],
+        'unix': [],
+    }
+
+    if sys.platform == 'darwin':
+        c_opts['unix'] += ['-stdlib=libc++', '-mmacosx-version-min=10.7']
+
+    def build_extensions(self):
+        ct = self.compiler.compiler_type
+        opts = self.c_opts.get(ct, [])
+        if ct == 'unix':
+            opts.append('-DVERSION_INFO="%s"' % self.distribution.get_version())
+            opts.append(cpp_flag(self.compiler))
+            if has_flag(self.compiler, '-fvisibility=hidden'):
+                opts.append('-fvisibility=hidden')
+        elif ct == 'msvc':
+            opts.append('/DVERSION_INFO=\\"%s\\"' % self.distribution.get_version())
+        for ext in self.extensions:
+            ext.extra_compile_args = opts
+        build_ext.build_extensions(self)
+
+# }}}
+
+
+def main():
+    from aksetup_helper import (hack_distutils,
+            get_config, setup, check_git_submodules)
+
+    check_git_submodules()
+
+    hack_distutils(what_opt=1)
+    conf = get_config(get_config_schema())
+
+    triangle_macros = [
+            ("EXTERNAL_TEST", 1),
+            ("ANSI_DECLARATORS", 1),
+            ("TRILIBRARY", 1),
+            ]
+
+    tetgen_macros = [
+            ("TETLIBRARY", 1),
+            ("SELF_CHECK", 1),
+            ]
+
+    # }}}
+
+    include_dirs = [
+            get_pybind_include(),
+            get_pybind_include(user=True)
+            ] + ["src/cpp"]
+
+    init_filename = "meshpy/__init__.py"
+    exec(compile(open(init_filename, "r").read(), init_filename, "exec"), conf)
+
+    import codecs
+    setup(name="MeshPy",
+          version=conf["version"],
+          description="Triangular and Tetrahedral Mesh Generator",
+          long_description=codecs.open("README.rst", "r", "utf-8").read(),
+          author="Andreas Kloeckner",
+          author_email="inform@tiker.net",
+          license=("MIT for the wrapper/non-commercial for "
+              "the Triangle/GNU Affero Public License for TetGen"),
+          url="http://mathema.tician.de/software/meshpy",
+          classifiers=[
+              'Development Status :: 4 - Beta',
+              'Intended Audience :: Developers',
+              'Intended Audience :: Other Audience',
+              'Intended Audience :: Science/Research',
+              'License :: OSI Approved :: MIT License',
+              'License :: Free for non-commercial use',
+              'Natural Language :: English',
+              'Programming Language :: C++',
+              'Programming Language :: Python',
+              'Programming Language :: Python :: 2.7',
+              'Programming Language :: Python :: 3',
+              'Programming Language :: Python :: 3.2',
+              'Programming Language :: Python :: 3.3',
+              'Programming Language :: Python :: 3.4',
+              'Topic :: Multimedia :: Graphics :: 3D Modeling',
+              'Topic :: Scientific/Engineering',
+              'Topic :: Scientific/Engineering :: Mathematics',
+              'Topic :: Scientific/Engineering :: Physics',
+              'Topic :: Scientific/Engineering :: Visualization',
+              'Topic :: Software Development :: Libraries',
+              ],
+
+          packages=["meshpy"],
+          setup_requires=["pybind11"],
+          install_requires=[
+                  "pytools>=2011.2",
+                  "pytest>=2",
+                  "numpy",
+                  "gmsh_interop",
+                  "six",
+                  ],
+          ext_modules=[
+              Extension(
+                  "meshpy._triangle",
+                  ["src/cpp/wrap_triangle.cpp", "src/cpp/triangle.c"],
+                  include_dirs=include_dirs,
+                  define_macros=triangle_macros,
+                  extra_compile_args=conf["CXXFLAGS"],
+                  extra_link_args=conf["LDFLAGS"],
+                  ),
+              Extension(
+                  "meshpy._tetgen",
+                  [
+                      "src/cpp/tetgen.cpp",
+                      "src/cpp/predicates.cpp",
+                      "src/cpp/wrap_tetgen.cpp"],
+                  include_dirs=include_dirs,
+                  define_macros=tetgen_macros,
+                  extra_compile_args=conf["CXXFLAGS"],
+                  extra_link_args=conf["LDFLAGS"],
+                  ),
+              ],
+          cmdclass={'build_ext': BuildExt},
+          zip_safe=False,
+          )
+
+
+if __name__ == '__main__':
+    main()
+
+# vim: foldmethod=marker
diff --git a/meshpy/src/cpp/foreign_array.hpp b/meshpy/src/cpp/foreign_array.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..56bb4ca9bdcdd6a02e876cbfff2d15af8e5080d7
--- /dev/null
+++ b/meshpy/src/cpp/foreign_array.hpp
@@ -0,0 +1,290 @@
+#ifndef _HEADER_SEEN_FOREIGN_ARRAY
+#define _HEADER_SEEN_FOREIGN_ARRAY
+
+
+
+
+#include <vector>
+#include <stdexcept>
+
+
+// https://stackoverflow.com/a/44175911
+class noncopyable {
+public:
+  noncopyable() = default;
+  ~noncopyable() = default;
+
+private:
+  noncopyable(const noncopyable&) = delete;
+  noncopyable& operator=(const noncopyable&) = delete;
+};
+
+
+namespace {
+
+class tSizeChangeNotifier;
+
+
+
+
+class tSizeChangeNotificationReceiver
+{
+  public:
+    virtual ~tSizeChangeNotificationReceiver()
+    { }
+    virtual void notifySizeChange(tSizeChangeNotifier *master, unsigned size) = 0;
+};
+
+
+
+
+class tSizeChangeNotifier
+{
+    typedef std::vector<tSizeChangeNotificationReceiver *> tNotificationReceiverList;
+    tNotificationReceiverList NotificationReceivers;
+
+  public:
+    virtual ~tSizeChangeNotifier()
+    { }
+    virtual unsigned size() const = 0;
+    virtual void setSize(unsigned size)
+    {
+      tNotificationReceiverList::iterator first = NotificationReceivers.begin(),
+      last = NotificationReceivers.end();
+      while (first != last)
+        (*first++)->notifySizeChange(this, size);
+    }
+
+    void registerForNotification(tSizeChangeNotificationReceiver *rec)
+    {
+      NotificationReceivers.push_back(rec);
+    }
+
+    void unregisterForNotification(tSizeChangeNotificationReceiver *rec)
+    {
+      tNotificationReceiverList::iterator first = NotificationReceivers.begin(),
+      last = NotificationReceivers.end();
+      while (first != last)
+      {
+        if (rec == *first)
+        {
+          NotificationReceivers.erase(first);
+          return;
+        }
+        first++;
+      }
+    }
+};
+
+
+
+
+template<class ElementT>
+class tReadOnlyForeignArray : public tSizeChangeNotifier, public tSizeChangeNotificationReceiver,
+  public noncopyable
+{
+  protected:
+    ElementT                    *&Contents;
+    int                         &NumberOf;
+    unsigned                    Unit;
+    tSizeChangeNotifier         *SlaveTo;
+    bool                        AssumeOwnership;
+
+  public:
+    typedef ElementT value_type;
+
+    tReadOnlyForeignArray(
+        ElementT *&cts, int &number_of, unsigned unit=1, tSizeChangeNotifier *slave_to=NULL,
+        bool assume_ownership=false)
+      : Contents(cts), NumberOf(number_of), Unit(unit), SlaveTo(slave_to),
+      AssumeOwnership(assume_ownership)
+    {
+      if (AssumeOwnership)
+        Contents = NULL;
+
+      if (SlaveTo)
+      {
+        SlaveTo->registerForNotification(this);
+        setSizeInternal(SlaveTo->size());
+      }
+      else
+      {
+        if (AssumeOwnership)
+          setSize(0);
+      }
+    }
+
+    ~tReadOnlyForeignArray()
+    {
+      if (SlaveTo)
+        SlaveTo->unregisterForNotification(this);
+
+      if (AssumeOwnership)
+      {
+        deallocate();
+
+        if (!SlaveTo)
+          NumberOf = 0;
+      }
+    }
+
+    unsigned size() const
+    {
+      return NumberOf;
+    }
+
+    unsigned unit() const
+    {
+      return Unit;
+    }
+
+    bool is_allocated()
+    {
+      return Contents != NULL;
+    }
+
+    void deallocate()
+    {
+      if (Contents != NULL)
+        delete[] Contents;
+      Contents = NULL;
+    }
+
+    void setSize(unsigned size)
+    {
+      if (SlaveTo)
+        throw std::runtime_error("sizes of slave arrays cannot be changed");
+      else
+        setSizeInternal(size);
+    }
+
+    void setup()
+    {
+      if (!SlaveTo)
+        throw std::runtime_error("cannot setup non-slave array");
+      else
+      {
+        if (!Contents)
+          setSizeInternal(NumberOf);
+      }
+    }
+
+    void notifySizeChange(tSizeChangeNotifier *master, unsigned size)
+    {
+      if (!SlaveTo)
+        throw std::runtime_error("non-slave array should not get size notifications");
+
+      // only perform size change if we actually existed
+      if (Contents)
+        setSizeInternal(size);
+    }
+
+    void setSizeInternal(unsigned size)
+    {
+      if (!SlaveTo)
+        NumberOf = size;
+
+      if (Contents != NULL)
+        free(Contents);
+
+      if (size == 0 || Unit == 0)
+        Contents = NULL;
+      else
+      {
+        Contents = new ElementT[Unit*size];
+        if (Contents == NULL)
+          throw std::bad_alloc();
+      }
+
+      tSizeChangeNotifier::setSize(size);
+    }
+
+    /** Set the unit size of the array and reallocate the foreign array.
+     */
+    void setUnit(unsigned unit)
+    {
+      if (unit != Unit)
+      {
+        Unit = unit;
+        setSizeInternal(NumberOf);
+      }
+    }
+
+    /** Set the unit size of the array without reallocating. It is assumed
+     * that the correct amount of memory has already been allocated.
+     */
+    void fixUnit(unsigned unit)
+    {
+      Unit = unit;
+    }
+
+    ElementT &get(unsigned index)
+    {
+      if (index >= NumberOf * Unit)
+        throw std::runtime_error("index out of bounds");
+      if (!Contents)
+        throw std::runtime_error("Array unallocated");
+      return Contents[ index ];
+    }
+
+    ElementT &getSub(unsigned index, unsigned sub_index)
+    {
+      return get(index * Unit + sub_index);
+    }
+};
+
+
+
+
+
+template<class ElementT>
+class tForeignArray : public tReadOnlyForeignArray<ElementT>
+{
+    typedef tReadOnlyForeignArray<ElementT> super;
+
+  public:
+    tForeignArray(
+        ElementT *&cts, int &number_of, unsigned unit=1,
+        tSizeChangeNotifier *slave_to=NULL,
+        bool assume_ownership=false)
+      : super(cts, number_of, unit, slave_to, assume_ownership)
+    {
+    }
+
+    void set(unsigned index, ElementT value)
+    {
+      if (index >= this->NumberOf * this->Unit)
+        throw std::runtime_error("index out of bounds");
+      if (!this->Contents)
+        throw std::runtime_error("Array unallocated");
+      this->Contents[ index ] = value;
+    }
+
+    void setSub(unsigned index, unsigned sub_index, ElementT value)
+    {
+      set(index * this->Unit + sub_index, value);
+    }
+
+    tForeignArray &operator=(tForeignArray const &src)
+    {
+      if (this->SlaveTo)
+        assert(src.size() == this->SlaveTo->size());
+      else
+        this->setSize(src.size());
+
+      this->setUnit(src.Unit);
+
+      if (src.Contents)
+        memcpy(this->Contents, src.Contents, sizeof(ElementT) * this->Unit * src.size());
+      else
+        this->deallocate();
+
+      return *this;
+    }
+};
+
+}
+
+
+
+#endif
diff --git a/meshpy/src/cpp/foreign_array_wrap.hpp b/meshpy/src/cpp/foreign_array_wrap.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f94751db107507ea20c5ee6a8b412c85d27ce638
--- /dev/null
+++ b/meshpy/src/cpp/foreign_array_wrap.hpp
@@ -0,0 +1,172 @@
+#ifndef _HEADER_SEEN_FOREIGN_ARRAY_WRAP
+#define _HEADER_SEEN_FOREIGN_ARRAY_WRAP
+
+
+
+
+#include "foreign_array.hpp"
+#include <pybind11/pybind11.h>
+
+
+
+
+#define PYTHON_ERROR(TYPE, REASON) \
+{ \
+  PyErr_SetString(PyExc_##TYPE, REASON); \
+  throw pybind11::error_already_set(); \
+}
+
+
+namespace {
+  /* This wrap helper works as long as the value_type is a plain old data (POD)
+   * type.
+   *
+   * In exchange for this, it nicely wraps the "unit" abstraction provided by
+   * foreign arrays.
+   */
+  template <typename FA>
+  struct tPODForeignArrayWrapHelper
+  {
+    typedef typename FA::value_type value_type;
+
+    static pybind11::object getitem(FA &self, long idx)
+    {
+      if (idx < 0) idx += self.size();
+      if (idx < 0 || idx >= (long) self.size())
+        PYTHON_ERROR(IndexError, "index out of bounds");
+
+      if (self.unit() > 1)
+      {
+        pybind11::list l;
+        for (unsigned i = 0; i<self.unit();i++)
+          l.append(self.getSub(idx, i));
+        return l;
+      }
+      else
+        return pybind11::cast(self.get(idx));
+    }
+
+    static pybind11::object getitem_tup(FA &self, pybind11::tuple idx)
+    {
+      if (len(idx) != 2)
+        PYTHON_ERROR(IndexError, "expected index tuple of length 2");
+      long i_main = pybind11::cast<int>(idx[0]);
+      long i_sub = pybind11::cast<int>(idx[1]);
+
+      if (i_main < 0 || i_main >= (long) self.size())
+        PYTHON_ERROR(IndexError, "index out of bounds");
+      if (i_sub < 0 || i_sub >= (long) self.unit())
+        PYTHON_ERROR(IndexError, "subindex out of bounds");
+
+      return pybind11::cast(self.getSub(i_main, i_sub));
+    }
+
+    static void setitem(FA &self, long idx, pybind11::object value)
+    {
+      if (idx < 0) idx += self.size();
+      if (idx < 0 || idx >= (long) self.size())
+        PYTHON_ERROR(IndexError, "index out of bounds");
+
+      if (self.unit() > 1)
+      {
+        pybind11::sequence value_seq = pybind11::cast<pybind11::sequence>(value);
+
+        if ((long) self.unit() != len(value))
+          PYTHON_ERROR(ValueError, "value must be a sequence of length self.unit");
+
+        for (size_t i = 0; i<len(value);i++)
+          self.setSub(idx, i, pybind11::cast<value_type>(value_seq[i]));
+      }
+      else
+        self.set(idx, pybind11::cast<value_type>(value));
+    }
+
+    static void setitem_tup(FA &self, pybind11::tuple idx, const value_type &v)
+    {
+      if (len(idx) != 2)
+        PYTHON_ERROR(IndexError, "expected index tuple of length 2");
+      long i_main = pybind11::cast<int>(idx[0]);
+      long i_sub = pybind11::cast<int>(idx[1]);
+
+      if (i_main < 0 || i_main >= (long) self.size())
+        PYTHON_ERROR(IndexError, "index out of bounds");
+      if (i_main < 0 || i_sub >= (long) self.unit())
+        PYTHON_ERROR(IndexError, "subindex out of bounds");
+
+      self.setSub(i_main, i_sub, v);
+    }
+  };
+
+
+
+
+  /* This wrap helper works for more complicated data structures, for which we
+   * just ship out internal references--boost::python takes care of life support
+   * for us.
+   *
+   * In exchange for this, it does not allow setting entries or support the unit API.
+   */
+  template <typename FA>
+  struct tStructureForeignArrayWrapHelper
+  {
+    typedef typename FA::value_type value_type;
+
+    static value_type &getitem(FA &self, long idx)
+    {
+      if (idx < 0) idx += self.size();
+      if (idx >= (long) self.size()) PYTHON_ERROR(IndexError, "index out of bounds");
+
+      return self.get(idx);
+    }
+  };
+}
+
+
+
+
+template <typename T>
+void exposePODForeignArray(pybind11::module &m,const std::string &name)
+{
+  typedef tForeignArray<T> cl;
+  typedef tPODForeignArrayWrapHelper<cl> w_cl;
+
+  pybind11::class_<cl>(m, name.c_str())
+    .def("__len__", &cl::size)
+    .def("resize", &cl::setSize)
+    .def("setup", &cl::setup)
+    .def_property_readonly("unit", &cl::unit)
+    .def_property_readonly("allocated", &cl::is_allocated)
+    .def("__getitem__", &w_cl::getitem)
+    .def("__getitem__", &w_cl::getitem_tup)
+    .def("__setitem__", &w_cl::setitem)
+    .def("__setitem__", &w_cl::setitem_tup)
+    .def("deallocate", &cl::deallocate)
+    ;
+}
+
+
+
+
+
+template <typename T>
+void exposeStructureForeignArray(pybind11::module &m, const std::string &name)
+{
+  typedef tForeignArray<T> cl;
+  typedef tStructureForeignArrayWrapHelper<cl> w_cl;
+
+  pybind11::class_<cl>(m, name.c_str())
+    .def("__len__", &cl::size)
+    .def("resize", &cl::setSize)
+    .def("setup", &cl::setup)
+    .def_property_readonly("unit", &cl::unit)
+    .def_property_readonly("allocated", &cl::is_allocated)
+    .def("__getitem__", &w_cl::getitem, pybind11::return_value_policy::reference_internal)
+    .def("deallocate", &cl::deallocate)
+    ;
+}
+
+
+
+
+
+#endif
diff --git a/meshpy/src/cpp/predicates.cpp b/meshpy/src/cpp/predicates.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0aa253301c9b458414c38ae8d738b8f573db904a
--- /dev/null
+++ b/meshpy/src/cpp/predicates.cpp
@@ -0,0 +1,4717 @@
+/*****************************************************************************/
+/*                                                                           */
+/*  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).
+
+#ifdef USE_CGAL_PREDICATES
+  #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+  typedef CGAL::Exact_predicates_inexact_constructions_kernel cgalEpick;
+  typedef cgalEpick::Point_3 Point;
+  cgalEpick cgal_pred_obj;
+#endif // #ifdef USE_CGAL_PREDICATES
+
+/* 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;
+
+// Options to choose types of geometric computtaions. 
+// Added by H. Si, 2012-08-23.
+static int  _use_inexact_arith; // -X option.
+static int  _use_static_filter; // Default option, disable it by -X1
+
+// Static filters for orient3d() and insphere(). 
+// They are pre-calcualted and set in exactinit().
+// Added by H. Si, 2012-08-23.
+static REAL o3dstaticfilter;
+static REAL ispstaticfilter;
+
+
+
+// The following codes were part of "IEEE 754 floating-point test software"
+//          http://www.math.utah.edu/~beebe/software/ieee/
+// The original program was "fpinfo2.c".
+
+double fppow2(int n)
+{
+  double x, power;
+  x = (n < 0) ? ((double)1.0/(double)2.0) : (double)2.0;
+  n = (n < 0) ? -n : n;
+  power = (double)1.0;
+  while (n-- > 0)
+	power *= x;
+  return (power);
+}
+
+#ifdef SINGLE
+
+float fstore(float x)
+{
+  return (x);
+}
+
+int test_float(int verbose)
+{
+  float x;
+  int pass = 1;
+
+  //(void)printf("float:\n");
+
+  if (verbose) {
+    (void)printf("  sizeof(float) = %2u\n", (unsigned int)sizeof(float));
+#ifdef CPU86  // <float.h>
+    (void)printf("  FLT_MANT_DIG = %2d\n", FLT_MANT_DIG);
+#endif
+  }
+
+  x = (float)1.0;
+  while (fstore((float)1.0 + x/(float)2.0) != (float)1.0)
+    x /= (float)2.0;
+  if (verbose)
+    (void)printf("  machine epsilon = %13.5e  ", x);
+
+  if (x == (float)fppow2(-23)) {
+    if (verbose)
+      (void)printf("[IEEE 754 32-bit macheps]\n");
+  } else {
+    (void)printf("[not IEEE 754 conformant] !!\n");
+    pass = 0;
+  }
+
+  x = (float)1.0;
+  while (fstore(x / (float)2.0) != (float)0.0)
+    x /= (float)2.0;
+  if (verbose)
+    (void)printf("  smallest positive number =  %13.5e  ", x);
+
+  if (x == (float)fppow2(-149)) {
+    if (verbose)
+      (void)printf("[smallest 32-bit subnormal]\n");
+  } else if (x == (float)fppow2(-126)) {
+    if (verbose)
+      (void)printf("[smallest 32-bit normal]\n");
+  } else {
+	(void)printf("[not IEEE 754 conformant] !!\n");
+    pass = 0;
+  }
+
+  return pass;
+}
+
+# else
+
+double dstore(double x)
+{
+  return (x);
+}
+
+int test_double(int verbose)
+{
+  double x;
+  int pass = 1;
+
+  // (void)printf("double:\n");
+  if (verbose) {
+    (void)printf("  sizeof(double) = %2u\n", (unsigned int)sizeof(double));
+#ifdef CPU86  // <float.h>
+    (void)printf("  DBL_MANT_DIG = %2d\n", DBL_MANT_DIG);
+#endif
+  }
+
+  x = 1.0;
+  while (dstore(1.0 + x/2.0) != 1.0)
+    x /= 2.0;
+  if (verbose) 
+    (void)printf("  machine epsilon = %13.5le ", x);
+
+  if (x == (double)fppow2(-52)) {
+    if (verbose)
+      (void)printf("[IEEE 754 64-bit macheps]\n");
+  } else {
+    (void)printf("[not IEEE 754 conformant] !!\n");
+    pass = 0;
+  }
+
+  x = 1.0;
+  while (dstore(x / 2.0) != 0.0)
+    x /= 2.0;
+  //if (verbose)
+  //  (void)printf("  smallest positive number = %13.5le ", x);
+
+  if (x == (double)fppow2(-1074)) {
+    //if (verbose)
+    //  (void)printf("[smallest 64-bit subnormal]\n");
+  } else if (x == (double)fppow2(-1022)) {
+    //if (verbose)
+    //  (void)printf("[smallest 64-bit normal]\n");
+  } else {
+    (void)printf("[not IEEE 754 conformant] !!\n");
+    pass = 0;
+  }
+
+  return pass;
+}
+
+#endif
+
+/*****************************************************************************/
+/*                                                                           */
+/*  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.                */
+/*                                                                           */
+/*****************************************************************************/
+static int previous_cword;
+
+void exactinit(int verbose, int noexact, int nofilter, REAL maxx, REAL maxy, 
+               REAL maxz)
+{
+  REAL half;
+  REAL check, lastcheck;
+  int every_other;
+#ifdef LINUX
+  int cword;
+#endif /* LINUX */
+
+#ifdef CPU86
+#error yo
+  _FPU_GETCW(previous_cword);
+#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 */
+
+  if (verbose) {
+    printf("  Initializing robust predicates.\n");
+  }
+
+#ifdef USE_CGAL_PREDICATES
+  if (cgal_pred_obj.Has_static_filters) {
+    printf("  Use static filter.\n");
+  } else {
+    printf("  No static filter.\n");
+  }
+#endif // USE_CGAL_PREDICATES
+
+#ifdef SINGLE
+  test_float(verbose);
+#else
+  test_double(verbose);
+#endif
+
+  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;
+
+  // Set TetGen options.  Added by H. Si, 2012-08-23.
+  _use_inexact_arith = noexact;
+  _use_static_filter = !nofilter;
+
+  // Calculate the two static filters for orient3d() and insphere() tests.
+  // Added by H. Si, 2012-08-23.
+
+  // Sort maxx < maxy < maxz. Re-use 'half' for swapping.
+  assert(maxx > 0);
+  assert(maxy > 0);
+  assert(maxz > 0);
+
+  if (maxx > maxz) {
+    half = maxx; maxx = maxz; maxz = half;
+  }
+  if (maxy > maxz) {
+    half = maxy; maxy = maxz; maxz = half;
+  }
+  else if (maxy < maxx) {
+    half = maxy; maxy = maxx; maxx = half;
+  }
+
+  o3dstaticfilter = 5.1107127829973299e-15 * maxx * maxy * maxz;
+  ispstaticfilter = 1.2466136531027298e-13 * maxx * maxy * maxz * (maxz * maxz);
+
+}
+
+void exactdeinit()
+{
+#ifdef CPU86
+  _FPU_SETCW(previous_cword);
+#endif
+}
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*  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;
+
+
+  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];
+}
+
+#ifdef USE_CGAL_PREDICATES
+
+REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
+{
+  return (REAL) 
+    - cgal_pred_obj.orientation_3_object()
+        (Point(pa[0], pa[1], pa[2]), 
+         Point(pb[0], pb[1], pb[2]),
+         Point(pc[0], pc[1], pc[2]),
+         Point(pd[0], pd[1], pd[2]));
+}
+
+#else
+
+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;
+
+
+  adx = pa[0] - pd[0];
+  ady = pa[1] - pd[1];
+  adz = pa[2] - pd[2];
+  bdx = pb[0] - pd[0];
+  bdy = pb[1] - pd[1];
+  bdz = pb[2] - pd[2];
+  cdx = pc[0] - pd[0];
+  cdy = pc[1] - pd[1];
+  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);
+
+  if (_use_inexact_arith) {
+    return det;
+  }
+
+  if (_use_static_filter) {
+    //if (fabs(det) > o3dstaticfilter) return det;
+    if (det > o3dstaticfilter) return det;
+    if (det < -o3dstaticfilter) return det;
+  }
+
+
+  REAL permanent, errbound;
+
+  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);
+}
+
+#endif // #ifdef USE_CGAL_PREDICATES
+
+/*****************************************************************************/
+/*                                                                           */
+/*  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;
+
+  // Avoid compiler warnings. H. Si, 2012-02-16.
+  axtbclen = aytbclen = bxtcalen = bytcalen = cxtablen = cytablen = 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);
+}
+
+#ifdef USE_CGAL_PREDICATES
+
+REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe)
+{
+  return (REAL)
+    - cgal_pred_obj.side_of_oriented_sphere_3_object()
+        (Point(pa[0], pa[1], pa[2]),
+         Point(pb[0], pb[1], pb[2]),
+         Point(pc[0], pc[1], pc[2]),
+         Point(pd[0], pd[1], pd[2]),
+         Point(pe[0], pe[1], pe[2]));
+}
+
+#else
+
+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 det;
+
+
+  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);
+
+  if (_use_inexact_arith) {
+    return det;
+  }
+
+  if (_use_static_filter) {
+    if (fabs(det) > ispstaticfilter) return det;
+    //if (det > ispstaticfilter) return det;
+    //if (det < minus_ispstaticfilter) return det;
+
+  }
+
+  REAL aezplus, bezplus, cezplus, dezplus;
+  REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus;
+  REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus;
+  REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus;
+  REAL permanent, errbound;
+
+  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);
+}
+
+#endif // #ifdef USE_CGAL_PREDICATES
+
+/*****************************************************************************/
+/*                                                                           */
+/*  orient4d()   Return a positive value if the point pe lies above the      */
+/*               hyperplane passing through pa, pb, pc, and pd; "above" is   */
+/*               defined in a manner best found by trial-and-error.  Returns */
+/*               a negative value if pe lies below the hyperplane.  Returns  */
+/*               zero if the points are co-hyperplanar (not affinely         */
+/*               independent).  The result is also a rough approximation of  */
+/*               24 times the signed volume of the 4-simplex defined by the  */
+/*               five points.                                                */
+/*                                                                           */
+/*  Uses exact arithmetic if necessary to ensure a correct answer.  The      */
+/*  result returned is the determinant of a matrix.  This determinant is     */
+/*  computed adaptively, in the sense that exact arithmetic is used only to  */
+/*  the degree it is needed to ensure that the returned value has the        */
+/*  correct sign.  Hence, orient4d() is usually quite fast, but will run     */
+/*  more slowly when the input points are hyper-coplanar or nearly so.       */
+/*                                                                           */
+/*  See my Robust Predicates paper for details.                              */
+/*                                                                           */
+/*****************************************************************************/
+
+REAL orient4dexact(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe,
+                   REAL aheight, REAL bheight, REAL cheight, REAL dheight, 
+                   REAL eheight)
+{
+  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 adet[192], bdet[192], cdet[192], ddet[192], edet[192];
+  int alen, blen, clen, dlen, elen;
+  REAL abdet[384], cddet[384], cdedet[576];
+  int ablen, cdlen;
+  REAL deter[960];
+  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);
+  alen = scale_expansion_zeroelim(bcdelen, bcde, aheight, 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);
+  blen = scale_expansion_zeroelim(cdealen, cdea, bheight, 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);
+  clen = scale_expansion_zeroelim(deablen, deab, cheight, 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);
+  dlen = scale_expansion_zeroelim(eabclen, eabc, dheight, 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);
+  elen = scale_expansion_zeroelim(abcdlen, abcd, eheight, 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 orient4dadapt(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe,
+                   REAL aheight, REAL bheight, REAL cheight, REAL dheight, 
+                   REAL eheight, REAL permanent)
+{
+  INEXACT REAL aex, bex, cex, dex, aey, bey, cey, dey, aez, bez, cez, dez;
+  INEXACT REAL aeheight, beheight, ceheight, deheight;
+  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];
+  int temp8alen, temp8blen, temp8clen, temp16len, temp24len;
+  REAL adet[48], bdet[48], cdet[48], ddet[48];
+  int alen, blen, clen, dlen;
+  REAL abdet[96], cddet[96];
+  int ablen, cdlen;
+  REAL fin1[192];
+  int finlength;
+
+  REAL aextail, bextail, cextail, dextail;
+  REAL aeytail, beytail, ceytail, deytail;
+  REAL aeztail, beztail, ceztail, deztail;
+  REAL aeheighttail, beheighttail, ceheighttail, deheighttail;
+
+  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]);
+  aeheight = (REAL) (aheight - eheight);
+  beheight = (REAL) (bheight - eheight);
+  ceheight = (REAL) (cheight - eheight);
+  deheight = (REAL) (dheight - eheight);
+
+  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);
+  alen = scale_expansion_zeroelim(temp24len, temp24, -aeheight, 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);
+  blen = scale_expansion_zeroelim(temp24len, temp24, beheight, 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);
+  clen = scale_expansion_zeroelim(temp24len, temp24, -ceheight, 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);
+  dlen = scale_expansion_zeroelim(temp24len, temp24, deheight, 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(aheight, eheight, aeheight, aeheighttail);
+  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(bheight, eheight, beheight, beheighttail);
+  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(cheight, eheight, ceheight, ceheighttail);
+  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);
+  Two_Diff_Tail(dheight, eheight, deheight, deheighttail);
+  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)
+      && (aeheighttail == 0.0) && (beheighttail == 0.0)
+      && (ceheighttail == 0.0) && (deheighttail == 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 += ((beheight
+           * ((cez * daeps + dez * aceps + aez * cdeps)
+              + (ceztail * da3 + deztail * ac3 + aeztail * cd3))
+           + deheight
+           * ((aez * bceps - bez * aceps + cez * abeps)
+              + (aeztail * bc3 - beztail * ac3 + ceztail * ab3)))
+          - (aeheight
+           * ((bez * cdeps - cez * bdeps + dez * bceps)
+              + (beztail * cd3 - ceztail * bd3 + deztail * bc3))
+           + ceheight
+           * ((dez * abeps + aez * bdeps + bez * daeps)
+              + (deztail * ab3 + aeztail * bd3 + beztail * da3))))
+       + ((beheighttail * (cez * da3 + dez * ac3 + aez * cd3)
+           + deheighttail * (aez * bc3 - bez * ac3 + cez * ab3))
+          - (aeheighttail * (bez * cd3 - cez * bd3 + dez * bc3)
+           + ceheighttail * (dez * ab3 + aez * bd3 + bez * da3)));
+  if ((det >= errbound) || (-det >= errbound)) {
+    return det;
+  }
+
+  return orient4dexact(pa, pb, pc, pd, pe,
+                       aheight, bheight, cheight, dheight, eheight);
+}
+
+REAL orient4d(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe, 
+              REAL aheight, REAL bheight, REAL cheight, REAL dheight, 
+              REAL eheight)
+{
+ 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 aeheight, beheight, ceheight, deheight;
+ 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];
+ aeheight = aheight - eheight;
+ beheight = bheight - eheight;
+ ceheight = cheight - eheight;
+ deheight = dheight - eheight;
+
+ 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;
+
+ det = (deheight * abc - ceheight * dab) + (beheight * cda - aeheight * 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)
+           * Absolute(aeheight)
+           + ((dexaeyplus + aexdeyplus) * cezplus
+              + (aexceyplus + cexaeyplus) * dezplus
+              + (cexdeyplus + dexceyplus) * aezplus)
+           * Absolute(beheight)
+           + ((aexbeyplus + bexaeyplus) * dezplus
+              + (bexdeyplus + dexbeyplus) * aezplus
+              + (dexaeyplus + aexdeyplus) * bezplus)
+           * Absolute(ceheight)
+           + ((bexceyplus + cexbeyplus) * aezplus
+              + (cexaeyplus + aexceyplus) * bezplus
+              + (aexbeyplus + bexaeyplus) * cezplus)
+           * Absolute(deheight);
+ errbound = isperrboundA * permanent;
+ if ((det > errbound) || (-det > errbound)) {
+   return det;
+ }
+
+ return orient4dadapt(pa, pb, pc, pd, pe,
+                      aheight, bheight, cheight, dheight, eheight, permanent);
+}
+
+
+
diff --git a/meshpy/src/cpp/tetgen-LICENSE b/meshpy/src/cpp/tetgen-LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..e253c3d965ddda3797c1ce80fedde3c84c54ecd4
--- /dev/null
+++ b/meshpy/src/cpp/tetgen-LICENSE
@@ -0,0 +1,666 @@
+TetGen License
+--------------
+
+TetGen is distributed under a dual licensing scheme. You can
+redistribute it and/or modify it under the terms of the GNU Affero
+General Public License as published by the Free Software Foundation,
+either version 3 of the License, or (at your option) any later
+version. A copy of the GNU Affero General Public License is reproduced
+below.
+
+If the terms and conditions of the AGPL v.3. would prevent you from
+using TetGen, please consider the option to obtain a commercial
+license for a fee. These licenses are offered by the Weierstrass
+Institute for Applied Analysis and Stochastics (WIAS). As a rule,
+licenses are provided "as-is", unlimited in time for a one time
+fee. Please send corresponding requests to:
+tetgen@wias-berlin.de. Please do not forget to include some
+description of your company and the realm of its activities.
+
+=====================================================================
+GNU AFFERO GENERAL PUBLIC LICENSE
+
+Version 3, 19 November 2007
+
+Copyright © 2007 Free Software Foundation, Inc. <http://fsf.org/>
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+Preamble
+
+The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains
+free software for all its users.
+
+When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come
+about. The GNU General Public License permits making a modified
+version and letting the public access it on a server without ever
+releasing its source code to the public.
+
+The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing
+under this license.
+
+The precise terms and conditions for copying, distribution and
+modification follow.
+
+TERMS AND CONDITIONS
+
+0. Definitions.
+
+"This License" refers to version 3 of the GNU Affero General Public
+License.
+
+"Copyright" also means copyright-like laws that apply to other kinds
+of works, such as semiconductor masks.
+
+"The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of
+an exact copy. The resulting work is called a "modified version" of
+the earlier work or a work "based on" the earlier work.
+
+A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user
+through a computer network, with no transfer of a copy, is not
+conveying.
+
+An interactive user interface displays "Appropriate Legal Notices" to
+the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+1. Source Code.
+
+The "source code" for a work means the preferred form of the work for
+making modifications to it. "Object code" means any non-source form of
+a work.
+
+A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+The Corresponding Source need not include anything that users can
+regenerate automatically from other parts of the Corresponding Source.
+
+The Corresponding Source for a work in source code form is that same
+work.
+
+2. Basic Permissions.
+
+All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+You may make, run and propagate covered works that you do not convey,
+without conditions so long as your license otherwise remains in
+force. You may convey covered works to others for the sole purpose of
+having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+Conveying under any other circumstances is permitted solely under the
+conditions stated below. Sublicensing is not allowed; section 10 makes
+it unnecessary.
+
+3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such
+circumvention is effected by exercising rights under this License with
+respect to the covered work, and you disclaim any intention to limit
+operation or modification of the work as a means of enforcing, against
+the work's users, your or third parties' legal rights to forbid
+circumvention of technological measures.
+
+4. Conveying Verbatim Copies.
+
+You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+5. Conveying Modified Source Versions.
+
+You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these
+conditions:
+
+a) The work must carry prominent notices stating that you modified it,
+and giving a relevant date.  b) The work must carry prominent notices
+stating that it is released under this License and any conditions
+added under section 7. This requirement modifies the requirement in
+section 4 to "keep intact all notices".  c) You must license the
+entire work, as a whole, under this License to anyone who comes into
+possession of a copy. This License will therefore apply, along with
+any applicable section 7 additional terms, to the whole of the work,
+and all its parts, regardless of how they are packaged. This License
+gives no permission to license the work in any other way, but it does
+not invalidate such permission if you have separately received it.  d)
+If the work has interactive user interfaces, each must display
+Appropriate Legal Notices; however, if the Program has interactive
+interfaces that do not display Appropriate Legal Notices, your work
+need not make them do so.  A compilation of a covered work with other
+separate and independent works, which are not by their nature
+extensions of the covered work, and which are not combined with it
+such as to form a larger program, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the compilation and
+its resulting copyright are not used to limit the access or legal
+rights of the compilation's users beyond what the individual works
+permit. Inclusion of a covered work in an aggregate does not cause
+this License to apply to the other parts of the aggregate.
+
+6. Conveying Non-Source Forms.
+
+You may convey a covered work in object code form under the terms of
+sections 4 and 5, provided that you also convey the machine-readable
+Corresponding Source under the terms of this License, in one of these
+ways:
+
+a) Convey the object code in, or embodied in, a physical product
+(including a physical distribution medium), accompanied by the
+Corresponding Source fixed on a durable physical medium customarily
+used for software interchange.  b) Convey the object code in, or
+embodied in, a physical product (including a physical distribution
+medium), accompanied by a written offer, valid for at least three
+years and valid for as long as you offer spare parts or customer
+support for that product model, to give anyone who possesses the
+object code either (1) a copy of the Corresponding Source for all the
+software in the product that is covered by this License, on a durable
+physical medium customarily used for software interchange, for a price
+no more than your reasonable cost of physically performing this
+conveying of source, or (2) access to copy the Corresponding Source
+from a network server at no charge.  c) Convey individual copies of
+the object code with a copy of the written offer to provide the
+Corresponding Source. This alternative is allowed only occasionally
+and noncommercially, and only if you received the object code with
+such an offer, in accord with subsection 6b.  d) Convey the object
+code by offering access from a designated place (gratis or for a
+charge), and offer equivalent access to the Corresponding Source in
+the same way through the same place at no further charge. You need not
+require recipients to copy the Corresponding Source along with the
+object code. If the place to copy the object code is a network server,
+the Corresponding Source may be on a different server (operated by you
+or a third party) that supports equivalent copying facilities,
+provided you maintain clear directions next to the object code saying
+where to find the Corresponding Source. Regardless of what server
+hosts the Corresponding Source, you remain obligated to ensure that it
+is available for as long as needed to satisfy these requirements.  e)
+Convey the object code using peer-to-peer transmission, provided you
+inform other peers where the object code and Corresponding Source of
+the work are being offered to the general public at no charge under
+subsection 6d.  A separable portion of the object code, whose source
+code is excluded from the Corresponding Source as a System Library,
+need not be included in conveying the object code work.
+
+A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal,
+family, or household purposes, or (2) anything designed or sold for
+incorporation into a dwelling. In determining whether a product is a
+consumer product, doubtful cases shall be resolved in favor of
+coverage. For a particular product received by a particular user,
+"normally used" refers to a typical or common use of that class of
+product, regardless of the status of the particular user or of the way
+in which the particular user actually uses, or expects or is expected
+to use, the product. A product is a consumer product regardless of
+whether the product has substantial commercial, industrial or
+non-consumer uses, unless such uses represent the only significant
+mode of use of the product.
+
+"Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to
+install and execute modified versions of a covered work in that User
+Product from a modified version of its Corresponding Source. The
+information must suffice to ensure that the continued functioning of
+the modified object code is in no case prevented or interfered with
+solely because modification has been made.
+
+If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or
+updates for a work that has been modified or installed by the
+recipient, or for the User Product in which it has been modified or
+installed. Access to a network may be denied when the modification
+itself materially and adversely affects the operation of the network
+or violates the rules and protocols for communication across the
+network.
+
+Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+7. Additional Terms.
+
+"Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its
+conditions. Additional permissions that are applicable to the entire
+Program shall be treated as though they were included in this License,
+to the extent that they are valid under applicable law. If additional
+permissions apply only to part of the Program, that part may be used
+separately under those permissions, but the entire Program remains
+governed by this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders
+of that material) supplement the terms of this License with terms:
+
+a) Disclaiming warranty or limiting liability differently from the
+terms of sections 15 and 16 of this License; or b) Requiring
+preservation of specified reasonable legal notices or author
+attributions in that material or in the Appropriate Legal Notices
+displayed by works containing it; or c) Prohibiting misrepresentation
+of the origin of that material, or requiring that modified versions of
+such material be marked in reasonable ways as different from the
+original version; or d) Limiting the use for publicity purposes of
+names of licensors or authors of the material; or e) Declining to
+grant rights under trademark law for use of some trade names,
+trademarks, or service marks; or f) Requiring indemnification of
+licensors and authors of that material by anyone who conveys the
+material (or modified versions of it) with contractual assumptions of
+liability to the recipient, for any liability that these contractual
+assumptions directly impose on those licensors and authors.  All other
+non-permissive additional terms are considered "further restrictions"
+within the meaning of section 10. If the Program as you received it,
+or any part of it, contains a notice stating that it is governed by
+this License along with a term that is a further restriction, you may
+remove that term. If a license document contains a further restriction
+but permits relicensing or conveying under this License, you may add
+to a covered work material governed by the terms of that license
+document, provided that the further restriction does not survive such
+relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions; the
+above requirements apply either way.
+
+8. Termination.
+
+You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+However, if you cease all violation of this License, then your license
+from a particular copyright holder is reinstated (a) provisionally,
+unless and until the copyright holder explicitly and finally
+terminates your license, and (b) permanently, if the copyright holder
+fails to notify you of the violation by some reasonable means prior to
+60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+9. Acceptance Not Required for Having Copies.
+
+You are not required to accept this License in order to receive or run
+a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+10. Automatic Licensing of Downstream Recipients.
+
+Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+11. Patents.
+
+A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+A contributor's "essential patent claims" are all patent claims owned
+or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+A patent license is "discriminatory" if it does not include within the
+scope of its coverage, prohibits the exercise of, or is conditioned on
+the non-exercise of one or more of the rights that are specifically
+granted under this License. You may not convey a covered work if you
+are a party to an arrangement with a third party that is in the
+business of distributing software, under which you make payment to the
+third party based on the extent of your activity of conveying the
+work, and under which the third party grants, to any of the parties
+who would receive the covered work from you, a discriminatory patent
+license (a) in connection with copies of the covered work conveyed by
+you (or copies made from those copies), or (b) primarily for and in
+connection with specific products or compilations that contain the
+covered work, unless you entered into that arrangement, or that patent
+license was granted, prior to 28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+12. No Surrender of Others' Freedom.
+
+If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under
+this License and any other pertinent obligations, then as a
+consequence you may not convey it at all. For example, if you agree to
+terms that obligate you to collect a royalty for further conveying
+from those to whom you convey the Program, the only way you could
+satisfy both those terms and this License would be to refrain entirely
+from conveying the Program.
+
+13. Remote Network Interaction; Use with the GNU General Public
+License.
+
+Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your
+version supports such interaction) an opportunity to receive the
+Corresponding Source of your version by providing access to the
+Corresponding Source from a network server at no charge, through some
+standard or customary means of facilitating copying of software. This
+Corresponding Source shall include the Corresponding Source for any
+work covered by version 3 of the GNU General Public License that is
+incorporated pursuant to the following paragraph.
+
+Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+14. Revised Versions of this License.
+
+The Free Software Foundation may publish revised and/or new versions
+of the GNU Affero General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever
+published by the Free Software Foundation.
+
+If the Program specifies that a proxy can decide which future versions
+of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+15. Disclaimer of Warranty.
+
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
+WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
+DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
+CORRECTION.
+
+16. Limitation of Liability.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR
+CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
+NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR
+LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM
+TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER
+PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+17. Interpretation of Sections 15 and 16.
+
+If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+To do so, attach the following notices to the program. It is safest to
+attach them to the start of each source file to most effectively state
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it
+    does.> Copyright (C) <year> <name of author>
+
+    This program is free software: you can redistribute it and/or
+    modify it under the terms of the GNU Affero General Public License
+    as published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public
+    License along with this program.  If not, see
+    <http://www.gnu.org/licenses/>.  Also add information on how to
+    contact you by electronic and paper mail.
+
+If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for
+the specific requirements.
+
+You should also get your employer (if you work as a programmer) or
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. For more information on this, and how to apply and follow
+the GNU AGPL, see <http://www.gnu.org/licenses/>.
\ No newline at end of file
diff --git a/meshpy/src/cpp/tetgen.cpp b/meshpy/src/cpp/tetgen.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6468509bc291a95e4aec4a4350cdc72e3e4f3e7f
--- /dev/null
+++ b/meshpy/src/cpp/tetgen.cpp
@@ -0,0 +1,31275 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// TetGen                                                                    //
+//                                                                           //
+// A Quality Tetrahedral Mesh Generator and A 3D Delaunay Triangulator       //
+//                                                                           //
+// Version 1.5                                                               //
+// November 4, 2013                                                          //
+//                                                                           //
+// TetGen is freely available through the website: http://www.tetgen.org.    //
+//   It may be copied, modified, and redistributed for non-commercial use.   //
+//   Please consult the file LICENSE for the detailed copyright notices.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tetgen.h"
+
+extern void exactdeinit();
+
+//// io_cxx ///////////////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
+tetgenio::polygon::polygon()
+{
+  vertexlist = 0;
+  numberofvertices = 0;
+}
+
+tetgenio::polygon::~polygon()
+{
+  if (vertexlist)
+    delete [] vertexlist;
+}
+
+tetgenio::facet::facet()
+{
+  polygonlist = 0;
+  numberofpolygons = 0;
+  holelist = 0;
+  numberofholes = 0;
+}
+
+tetgenio::facet::~facet()
+{
+  if (polygonlist)
+    delete[] polygonlist;
+  if (holelist)
+    delete[] holelist;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_node_call()    Read a list of points from a file.                    //
+//                                                                           //
+// '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. 'uvflag' indicates each node contains //
+// u,v coordinates or not. It is reuqired by a PSC. 'infilename' is the name //
+// of the file being read,  it is only used in error messages.               //
+//                                                                           //
+// 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, int uvflag, 
+                              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) {
+    terminatetetgen(NULL, 1);
+  }
+  if (numberofpointattributes > 0) {
+    pointattributelist = new REAL[numberofpoints * numberofpointattributes];
+    if (pointattributelist == (REAL *) NULL) {
+      terminatetetgen(NULL, 1);
+    }
+  }
+  if (markers) {
+    pointmarkerlist = new int[numberofpoints];
+    if (pointmarkerlist == (int *) NULL) {
+      terminatetetgen(NULL, 1);
+    }
+  }
+  if (uvflag) {
+    pointparamlist = new pointparam[numberofpoints];
+    if (pointparamlist == NULL) {
+      terminatetetgen(NULL, 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 (uvflag) {
+      // Read point paramteters.
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  Point %d has no uv[0].\n", firstnumber + i);
+        break;
+      }
+      pointparamlist[i].uv[0] = (REAL) strtod(stringptr, &stringptr);
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  Point %d has no uv[1].\n", firstnumber + i);
+        break;
+      }
+      pointparamlist[i].uv[1] = (REAL) strtod(stringptr, &stringptr);
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  Point %d has no tag.\n", firstnumber + i);
+        break;
+      }
+      pointparamlist[i].tag = (int) strtol (stringptr, &stringptr, 0);
+      stringptr = findnextnumber(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  Point %d has no type.\n", firstnumber + i);
+        break;
+      }
+      pointparamlist[i].type = (int) strtol (stringptr, &stringptr, 0);
+      if ((pointparamlist[i].type < 0) || (pointparamlist[i].type > 2)) {
+        printf("Error:  Point %d has an invalid type.\n", firstnumber + i);
+        break;
+      }
+    }
+  }
+  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;
+    }
+    if (uvflag) {
+      delete [] pointparamlist;
+      pointparamlist = NULL;
+    }
+    numberofpoints = 0;
+    return false;
+  }
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_node()    Load a list of points from a .node file.                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_node(char* filebasename)
+{
+  FILE *infile;
+  char innodefilename[FILENAMESIZE];
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  bool okflag;
+  int markers;
+  int uvflag; // for psc input.
+
+  // Assembling the actual file names we want to open.
+  strcpy(innodefilename, filebasename);
+  strcat(innodefilename, ".node");
+
+  // Try to open a .node file.
+  infile = fopen(innodefilename, "r");
+  if (infile == (FILE *) NULL) {
+    printf("  Cannot access file %s.\n", innodefilename);
+    return false;
+  }
+  printf("Opening %s.\n", innodefilename); 
+
+  // Set initial flags.
+  mesh_dim = 3;
+  numberofpointattributes = 0;  // no point attribute.
+  markers = 0;  // no boundary marker.
+  uvflag = 0; // no uv parameters (required by a PSC). 
+
+  // Read the first line of the file.
+  stringptr = readnumberline(inputline, infile, innodefilename);
+  // Does this file contain an index column?
+  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 = (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);
+    }
+    stringptr = findnextnumber(stringptr);
+    if (*stringptr != '\0') {
+      uvflag = (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;
+  }
+
+  // Load the list of nodes.
+  okflag = load_node_call(infile, markers, uvflag, innodefilename);
+
+  fclose(infile);
+  return okflag;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_edge()    Load a list of edges from a .edge file.                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_edge(char* filebasename)
+{
+  FILE *infile;
+  char inedgefilename[FILENAMESIZE];
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  int markers, corner;
+  int index;
+  int i, j;
+
+  strcpy(inedgefilename, filebasename);
+  strcat(inedgefilename, ".edge");
+
+  infile = fopen(inedgefilename, "r");
+  if (infile != (FILE *) NULL) {
+    printf("Opening %s.\n", inedgefilename);
+  } else {
+    //printf("  Cannot access file %s.\n", inedgefilename);
+    return false;
+  }
+
+  // Read number of boundary edges.
+  stringptr = readnumberline(inputline, infile, inedgefilename);
+  numberofedges = (int) strtol (stringptr, &stringptr, 0);
+  if (numberofedges > 0) {
+    edgelist = new int[numberofedges * 2];
+    if (edgelist == (int *) NULL) {
+      terminatetetgen(NULL, 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 edges.
+  index = 0;
+  for (i = 0; i < numberofedges; i++) {
+    // Read edge index and the edge's two endpoints.
+    stringptr = readnumberline(inputline, infile, inedgefilename);
+    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, inedgefilename);
+        terminatetetgen(NULL, 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(NULL, 1);
+      }
+      edgelist[index++] = corner;
+    }
+    if (numberofcorners == 10) {
+      // Skip an extra vertex (generated by a previous -o2 option).
+      stringptr = findnextnumber(stringptr);
+    }
+    // Read the edge marker if it has.
+    if (markers) {
+      stringptr = findnextnumber(stringptr);
+      edgemarkerlist[i] = (int) strtol(stringptr, &stringptr, 0);
+    }
+  }
+
+  fclose(infile);
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_face()    Load a list of faces (triangles) from a .face file.        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_face(char* filebasename)
+{
+  FILE *infile;
+  char infilename[FILENAMESIZE];
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  REAL attrib;
+  int markers, corner;
+  int index;
+  int i, j;
+
+  strcpy(infilename, filebasename);
+  strcat(infilename, ".face");
+
+  infile = fopen(infilename, "r");
+  if (infile != (FILE *) NULL) {
+    printf("Opening %s.\n", infilename);
+  } else {
+    return false;
+  }
+
+  // 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) {
+      terminatetetgen(NULL, 1);
+    }
+    if (markers) {
+      trifacemarkerlist = new int[numberoftrifaces];
+      if (trifacemarkerlist == (int *) NULL) {
+        terminatetetgen(NULL, 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(NULL, 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(NULL, 1);
+      }
+      trifacelist[index++] = corner;
+    }
+    if (numberofcorners == 10) {
+      // Skip 3 extra vertices (generated by a previous -o2 option).
+      for (j = 0; j < 3; j++) {
+        stringptr = findnextnumber(stringptr);
+      }
+    }
+    // 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);
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_tet()    Load a list of tetrahedra from a .ele file.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_tet(char* filebasename)
+{
+  FILE *infile;
+  char infilename[FILENAMESIZE];
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  REAL attrib;
+  int corner;
+  int index, attribindex;
+  int i, j;
+
+  strcpy(infilename, filebasename);
+  strcat(infilename, ".ele");
+
+  infile = fopen(infilename, "r");
+  if (infile != (FILE *) NULL) {
+    printf("Opening %s.\n", infilename);
+  } else {
+    return false;
+  }
+
+  // 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);
+  if (numberoftetrahedra <= 0) {
+    printf("Error:  Invalid number of tetrahedra.\n");
+    fclose(infile);
+    return false;
+  }
+  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.
+  tetrahedronlist = new int[numberoftetrahedra * numberofcorners]; 
+  if (tetrahedronlist == (int *) NULL) {
+    terminatetetgen(NULL, 1);
+  }
+  // Allocate memory for output tetrahedron attributes if necessary.
+  if (numberoftetrahedronattributes > 0) {
+    tetrahedronattributelist = new REAL[numberoftetrahedra *
+                                        numberoftetrahedronattributes];
+    if (tetrahedronattributelist == (REAL *) NULL) {
+      terminatetetgen(NULL, 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(NULL, 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(NULL, 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);
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_vol()    Load a list of volume constraints from a .vol file.         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_vol(char* filebasename)
+{
+  FILE *infile;
+  char inelefilename[FILENAMESIZE];
+  char infilename[FILENAMESIZE];
+  char inputline[INPUTLINESIZE];
+  char *stringptr; 
+  REAL volume;
+  int volelements;
+  int i;
+
+  strcpy(infilename, filebasename);
+  strcat(infilename, ".vol");
+
+  infile = fopen(infilename, "r");
+  if (infile != (FILE *) NULL) {
+    printf("Opening %s.\n", infilename);
+  } else {
+    return false;
+  }
+
+  // Read number of tetrahedra.
+  stringptr = readnumberline(inputline, infile, infilename);
+  volelements = (int) strtol (stringptr, &stringptr, 0);
+  if (volelements != numberoftetrahedra) {
+    strcpy(inelefilename, filebasename);
+    strcat(infilename, ".ele");
+    printf("Warning:  %s and %s disagree on number of tetrahedra.\n",
+           inelefilename, infilename);
+    fclose(infile);
+    return false;
+  }
+
+  tetrahedronvolumelist = new REAL[volelements];
+  if (tetrahedronvolumelist == (REAL *) NULL) {
+    terminatetetgen(NULL, 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);
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_var()    Load constraints applied on facets, segments, and nodes     //
+//               from a .var file.                                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_var(char* filebasename)
+{
+  FILE *infile;
+  char varfilename[FILENAMESIZE];
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  int index;
+  int i;
+
+  // Variant constraints are saved in file "filename.var".
+  strcpy(varfilename, filebasename);
+  strcat(varfilename, ".var");
+  infile = fopen(varfilename, "r");
+  if (infile != (FILE *) NULL) {
+    printf("Opening %s.\n", varfilename);
+  } else {
+    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 a .mtr file.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_mtr(char* filebasename)
+{
+  FILE *infile;
+  char mtrfilename[FILENAMESIZE];
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  REAL mtr;
+  int ptnum;
+  int mtrindex;
+  int i, j;
+
+  strcpy(mtrfilename, filebasename);
+  strcat(mtrfilename, ".mtr");
+  infile = fopen(mtrfilename, "r");
+  if (infile != (FILE *) NULL) {
+    printf("Opening %s.\n", mtrfilename);
+  } else {
+    return false;
+  }
+
+  // Read the number of points.
+  stringptr = readnumberline(inputline, infile, mtrfilename);
+  ptnum = (int) strtol (stringptr, &stringptr, 0);
+  if (ptnum != numberofpoints) {
+    printf("  !! Point numbers are not equal. Ignored.\n");
+    fclose(infile);
+    return false;
+  }
+  // Read the number of columns (1, 3, or 6).
+  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) {
+    terminatetetgen(NULL, 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(NULL, 1);
+      }
+      mtr = (REAL) strtod(stringptr, &stringptr);
+      pointmtrlist[mtrindex++] = mtr;
+      stringptr = findnextnumber(stringptr);
+    }
+  }
+
+  fclose(infile);
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_poly()    Load a PL complex from a .poly or a .smesh file.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_poly(char* filebasename)
+{
+  FILE *infile;
+  char inpolyfilename[FILENAMESIZE];
+  char insmeshfilename[FILENAMESIZE];
+  char inputline[INPUTLINESIZE];
+  char *stringptr, *infilename;
+  int smesh, markers, uvflag, currentmarker;
+  int index;
+  int i, j, k;
+
+  // Assembling the actual file names we want to open.
+  strcpy(inpolyfilename, filebasename);
+  strcpy(insmeshfilename, filebasename);
+  strcat(inpolyfilename, ".poly");
+  strcat(insmeshfilename, ".smesh");
+
+  // First assume it is a .poly file.
+  smesh = 0;
+  // Try to open a .poly file.
+  infile = fopen(inpolyfilename, "r");
+  if (infile == (FILE *) NULL) {
+    // .poly doesn't exist! Try to open a .smesh file.
+    infile = fopen(insmeshfilename, "r");
+    if (infile == (FILE *) NULL) {
+      printf("  Cannot access file %s and %s.\n",
+             inpolyfilename, insmeshfilename);
+      return false;
+    } else {
+      printf("Opening %s.\n", insmeshfilename);
+      infilename = insmeshfilename;
+    }
+    smesh = 1;
+  } else {
+    printf("Opening %s.\n", inpolyfilename);
+    infilename = inpolyfilename;
+  }
+
+  // Initialize the default values.
+  mesh_dim = 3;  // Three-dimensional coordinates.
+  numberofpointattributes = 0;  // no point attribute.
+  markers = 0;  // no boundary marker.
+  uvflag = 0; // no uv parameters (required by a PSC).
+
+  // Read number of points, number of dimensions, number of point
+  //   attributes, and number of boundary markers.
+  stringptr = readnumberline(inputline, infile, infilename);
+  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
+  stringptr = findnextnumber(stringptr);
+  if (*stringptr != '\0') {
+    mesh_dim = (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 (*stringptr != '\0') {
+    uvflag = (int) strtol (stringptr, &stringptr, 0);
+  }
+
+  if (numberofpoints > 0) {
+    // Load the list of nodes.
+    if (!load_node_call(infile, markers, uvflag, infilename)) {
+      fclose(infile);
+      return false;
+    }
+  } else {
+    // If the .poly or .smesh file claims there are zero points, that
+    //   means the points should be read from a separate .node file.
+    if (!load_node(filebasename)) {
+      fclose(infile);
+      return false;
+    }
+  }
+
+  if ((mesh_dim != 3) && (mesh_dim != 2)) {
+    printf("Input error:  TetGen only works for 2D & 3D point sets.\n");
+    fclose(infile);
+    return false;
+  }
+  if (numberofpoints < (mesh_dim + 1)) {
+    printf("Input error:  TetGen needs at least %d points.\n", mesh_dim + 1);
+    fclose(infile);
+    return false;
+  }
+
+  facet *f;
+  polygon *p;
+
+  if (mesh_dim == 3) {
+
+    // Read number of facets and number of boundary markers.
+    stringptr = readnumberline(inputline, infile, infilename);
+    if (stringptr == NULL) {
+      // No facet list, return.
+      fclose(infile);
+      return true;
+    }
+    numberoffacets = (int) strtol (stringptr, &stringptr, 0);
+    if (numberoffacets <= 0) {
+      // No facet list, return.
+      fclose(infile);
+      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, infile, infilename);
+        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, infile, infilename);
+          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, infile, infilename);
+              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, infile, infilename);
+            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(infile);
+        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, infile, 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, infile, infilename);
+            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(infile);
+        return false;
+      }
+    }
+
+    // Read the hole section.
+    stringptr = readnumberline(inputline, infile, infilename);
+    if (stringptr == NULL) {
+      // No hole list, return.
+      fclose(infile);
+      return true;
+    }
+    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, infile, infilename);
+        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(infile);
+        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, infile, 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, infile, infilename);
+        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(infile);
+        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, infile, infilename);
+    // 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, infile, infilename);
+      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, infile, infilename);
+    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, infile, infilename);
+        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(infile);
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_off()    Load a polyhedron from 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.                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_off(char* filebasename)
+{
+  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;
+
+  // Default, the off file's index is from '0'. We check it by remembering the
+  //   smallest index we found in the file. It should be either 0 or 1.
+  int smallestidx = 0; 
+
+  strncpy(infilename, filebasename, 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("  Unable to open file %s\n", infilename);
+    return false;
+  }
+  printf("Opening %s.\n", infilename);
+
+  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];
+          smallestidx = nverts + 1; // A bigger enough number.
+        }
+        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);
+        // Detect the smallest index.
+        if (p->vertexlist[i] < smallestidx) {
+          smallestidx = p->vertexlist[i];
+        }
+      }
+      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);
+
+  // Decide the firstnumber of the index.
+  if (smallestidx == 0) {
+    firstnumber = 0;  
+  } else if (smallestidx == 1) {
+    firstnumber = 1;
+  } else {
+    printf("A wrong smallest index (%d) was detected in file %s\n",
+           smallestidx, infilename);
+    return false;
+  }
+
+  if (iverts != nverts) {
+    printf("Expected %d vertices, but read only %d vertices in file %s\n",
+           nverts, iverts, infilename);
+    return false;
+  }
+  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 from a .ply file.                         //
+//                                                                           //
+// 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.                                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_ply(char* filebasename)
+{
+  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;
+
+  // Default, the ply file's index is from '0'. We check it by remembering the
+  //   smallest index we found in the file. It should be either 0 or 1.
+  int smallestidx = 0; 
+
+  strncpy(infilename, filebasename, 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);
+
+  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];
+                smallestidx = nverts + 1; // A big enough index.
+              }
+            }
+          }
+          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);
+        if (p->vertexlist[i] < smallestidx) {
+          smallestidx = p->vertexlist[i];
+        }
+      }
+      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);
+
+  // Decide the firstnumber of the index.
+  if (smallestidx == 0) {
+    firstnumber = 0;  
+  } else if (smallestidx == 1) {
+    firstnumber = 1;
+  } else {
+    printf("A wrong smallest index (%d) was detected in file %s\n",
+           smallestidx, infilename);
+    return false;
+  }
+
+  if (iverts != nverts) {
+    printf("Expected %d vertices, but read only %d vertices in file %s\n",
+           nverts, iverts, infilename);
+    return false;
+  }
+  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 from a .stl file.                       //
+//                                                                           //
+// 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.                                                     //
+//                                                                           //
+// Comment: A .stl file many contain many duplicated points.  They will be   //
+// unified during the Delaunay tetrahedralization process.                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_stl(char* filebasename)
+{
+  FILE *fp;
+  tetgenmesh::arraypool *plist;
+  tetgenio::facet *f;
+  tetgenio::polygon *p;
+  char infilename[FILENAMESIZE];
+  char buffer[INPUTLINESIZE];
+  char *bufferp, *str;
+  double *coord;
+  int solid = 0;
+  int nverts = 0, iverts = 0;
+  int nfaces = 0;
+  int line_count = 0, i;
+
+  strncpy(infilename, filebasename, 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.
+  plist = new tetgenmesh::arraypool(sizeof(double) * 3, 10); 
+
+  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) {
+          plist->newindex((void **) &coord);
+          for (i = 0; i < 3; i++) {
+            bufferp = findnextnumber(bufferp);
+            if (*bufferp == '\0') {
+              printf("Syntax error reading vertex coords on line %d\n",
+                   line_count);
+              delete plist;
+              fclose(fp);
+              return false;
+            }
+            coord[i] = (REAL) strtod(bufferp, &bufferp);
+          }
+        }
+      }
+    }
+  }
+  fclose(fp);
+
+  nverts = (int) plist->objects;
+  // 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);
+    delete plist;
+    return false;
+  }
+  numberofpoints = nverts;
+  pointlist = new REAL[nverts * 3];
+  for (i = 0; i < nverts; i++) {
+    coord = (double *) fastlookup(plist, i);
+    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 tetgenio::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 tetgenio::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;
+  }
+
+  delete plist;
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_medit()    Load a surface mesh from a .mesh file.                    //
+//                                                                           //
+// The .mesh format is the file format of Medit, a user-friendly interactive //
+// mesh viewer program.                                                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_medit(char* filebasename, int istetmesh)
+{
+  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 ntets = 0;
+  int line_count = 0;
+  int corners = 0; // 3 (triangle) or 4 (quad).
+  int *plist;
+  int i, j;
+
+  int smallestidx = 0;
+
+  strncpy(infilename, filebasename, 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);
+
+  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);
+        // Initialize the smallest index.
+        smallestidx = nverts + 1;
+        // 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 (ntets == 0) {
+      // Find if it is the keyword "Tetrahedra"
+      corners = 0;
+      str = strstr(bufferp, "Tetrahedra");
+      if (!str) str = strstr(bufferp, "tetrahedra");
+      if (!str) str = strstr(bufferp, "TETRAHEDRA");
+      if (str) {
+        corners = 4;
+      }
+      if (corners == 4) {
+        // Read the number of tetrahedra
+        bufferp = findnextnumber(str); // Skip field "Tetrahedra".
+        if (*bufferp == '\0') {
+          // Read a non-empty line.
+          bufferp = readline(buffer, fp, &line_count);
+        }
+        ntets = strtol(bufferp, &bufferp, 0);
+        if (ntets > 0) {
+          // It is a tetrahedral mesh.
+          numberoftetrahedra = ntets;
+          numberofcorners = 4;
+          numberoftetrahedronattributes = 1;
+          tetrahedronlist = new int[ntets * 4];
+          tetrahedronattributelist = new REAL[ntets];
+        }
+      } // if (corners == 4)
+      // Read the list of tetrahedra.
+      for (i = 0; i < numberoftetrahedra; i++) {
+        plist = &(tetrahedronlist[i * 4]);
+        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 the vertices of the tet.
+        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;
+          }
+          plist[j] = (int) strtol(bufferp, &bufferp, 0);
+          // Remember the smallest index.
+          if (plist[j] < smallestidx) smallestidx = plist[j];
+          bufferp = findnextnumber(bufferp);
+        }
+        // Read the attribute of the tet if it exists.
+        tetrahedronattributelist[i] = 0;
+        if (*bufferp != '\0') {
+          tetrahedronattributelist[i] = (REAL) strtol(bufferp, &bufferp, 0);
+        }
+      } // i
+    } // Tetrahedra
+    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 (!istetmesh) {
+            // It is a PLC surface mesh.
+            if (numberoffacets > 0) {
+              // facetlist has already been allocated. Enlarge arrays.
+              // This happens when the surface mesh contains mixed cells.
+              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];
+            }
+          } else {
+            if (corners == 3) {
+              // It is a surface mesh of a tetrahedral mesh.
+              numberoftrifaces = nfaces;
+              trifacelist = new int[nfaces * 3];
+              trifacemarkerlist = new int[nfaces];
+            }
+          }
+        } // if (nfaces > 0)
+        // Read the following list of faces.
+        if (!istetmesh) {
+          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);
+              // Remember the smallest index.
+              if (p->vertexlist[j] < smallestidx) {
+                smallestidx = p->vertexlist[j];
+              }
+              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;
+        } else {
+          // It is a surface mesh of a tetrahedral mesh.
+          if (corners == 3) {
+            for (i = 0; i < numberoftrifaces; i++) {
+              plist = &(trifacelist[i * 3]);
+              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 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;
+                }
+                plist[j] = (int) strtol(bufferp, &bufferp, 0);
+                // Remember the smallest index.
+                if (plist[j] < smallestidx) {
+                  smallestidx = plist[j];
+                }
+                bufferp = findnextnumber(bufferp);
+              }
+              // Read the marker of the face if it exists.
+              trifacemarkerlist[i] = 0;
+              if (*bufferp != '\0') {
+                trifacemarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
+              }
+            } // i
+          } // if (corners == 3)
+        } // if (b->refine)
+      } // if (corners == 3 || corners == 4)
+    }
+  }
+
+  // Close file
+  fclose(fp);
+
+  // Decide the firstnumber of the index.
+  if (smallestidx == 0) {
+    firstnumber = 0;  
+  } else if (smallestidx == 1) {
+    firstnumber = 1;
+  } else {
+    printf("A wrong smallest index (%d) was detected in file %s\n",
+           smallestidx, infilename);
+    return false;
+  }
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_vtk()    Load VTK surface mesh from file (.vtk ascii or binary).     //
+//                                                                           //
+// This function is contributed by: Bryn Lloyd, Computer Vision Laboratory,  //
+// ETH, Zuerich. May 7, 2007.                                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// Two inline functions used in read/write VTK files.
+
+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(char* filebasename)
+{
+  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();
+
+  int smallestidx = 0;
+
+  strncpy(infilename, filebasename, 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];
+        smallestidx = nverts + 1;
+      }
+
+      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;
+            // Detect the smallest index.
+            for (j = 0; j < 3; j++) {
+              if (p->vertexlist[j] < smallestidx) {
+                smallestidx = p->vertexlist[j];
+              }
+            }
+          } 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;
+            // Detect the smallest index.
+            for (j = 0; j < 3; j++) {
+              if (p->vertexlist[j] < smallestidx) {
+                smallestidx = p->vertexlist[j];
+              }
+            }
+          } else {
+            printf("Error:  Only triangles are supported.\n");
+            return false;
+          }
+        }
+      }
+
+      fclose(fp);
+
+      // Decide the firstnumber of the index.
+      if (smallestidx == 0) {
+        firstnumber = 0;  
+      } else if (smallestidx == 1) {
+        firstnumber = 1;
+      } else {
+        printf("A wrong smallest index (%d) was detected in file %s\n",
+               smallestidx, infilename);
+        return false;
+      }
+
+      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(s).               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_plc(char* filebasename, int object)
+{
+  bool success;
+
+  if (object == (int) tetgenbehavior::NODES) {
+    success = load_node(filebasename);
+  } else if (object == (int) tetgenbehavior::POLY) {
+    success = load_poly(filebasename);
+  } else if (object == (int) tetgenbehavior::OFF) {
+    success = load_off(filebasename);
+  } else if (object == (int) tetgenbehavior::PLY) {
+    success = load_ply(filebasename);
+  } else if (object == (int) tetgenbehavior::STL) {
+    success = load_stl(filebasename);
+  } else if (object == (int) tetgenbehavior::MEDIT) {
+    success = load_medit(filebasename, 0);
+  } else if (object == (int) tetgenbehavior::VTK) {
+    success = load_vtk(filebasename);
+  } else {
+    success = load_poly(filebasename);
+  }
+
+  if (success) {
+    // Try to load the following files (.edge, .var, .mtr).
+    load_edge(filebasename);
+    load_var(filebasename);
+    load_mtr(filebasename);
+  }
+
+  return success;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// load_mesh()    Load a tetrahedral mesh from file(s).                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenio::load_tetmesh(char* filebasename, int object)
+{
+  bool success;
+
+  if (object == (int) tetgenbehavior::MEDIT) {
+    success = load_medit(filebasename, 1);
+  } else {
+    success = load_node(filebasename);
+    if (success) {
+      success = load_tet(filebasename);
+    }
+    if (success) {
+      // Try to load the following files (.face, .edge, .vol).
+      load_face(filebasename);
+      load_edge(filebasename);
+      load_vol(filebasename);
+    }
+  }
+
+  if (success) {
+    // Try to load the following files (.var, .mtr).
+    load_var(filebasename);
+    load_mtr(filebasename);
+  }
+
+  return success;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// save_nodes()    Save points to a .node file.                              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenio::save_nodes(char* filebasename)
+{
+  FILE *fout;
+  char outnodefilename[FILENAMESIZE];
+  char outmtrfilename[FILENAMESIZE];
+  int i, j;
+
+  sprintf(outnodefilename, "%s.node", filebasename);
+  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", filebasename);
+    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.                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenio::save_elements(char* filebasename)
+{
+  FILE *fout;
+  char outelefilename[FILENAMESIZE];
+  int i, j;
+
+  sprintf(outelefilename, "%s.ele", filebasename);
+  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.                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenio::save_faces(char* filebasename)
+{
+  FILE *fout;
+  char outfacefilename[FILENAMESIZE];
+  int i;
+
+  sprintf(outfacefilename, "%s.face", filebasename);
+  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.                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenio::save_edges(char* filebasename)
+{
+  FILE *fout;
+  char outedgefilename[FILENAMESIZE];
+  int i;
+
+  sprintf(outedgefilename, "%s.edge", filebasename);
+  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.                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenio::save_neighbors(char* filebasename)
+{
+  FILE *fout;
+  char outneighborfilename[FILENAMESIZE];
+  int i;
+
+  sprintf(outneighborfilename, "%s.neigh", filebasename);
+  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.                   //
+//                                                                           //
+// It only save the facets, holes and regions. No .node file is saved.       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenio::save_poly(char* filebasename)
+{
+  FILE *fout;
+  facet *f;
+  polygon *p;
+  char outpolyfilename[FILENAMESIZE];
+  int i, j, k;
+
+  sprintf(outpolyfilename, "%s.poly", filebasename);
+  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);  
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// save_faces2smesh()    Save triangular faces to a .smesh file.             //
+//                                                                           //
+// It only save the facets. No holes and regions. No .node file.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenio::save_faces2smesh(char* filebasename)
+{
+  FILE *fout;
+  char outsmeshfilename[FILENAMESIZE];
+  int i, j;
+
+  sprintf(outsmeshfilename, "%s.smesh", filebasename);
+  printf("Saving faces to %s\n", outsmeshfilename);
+  fout = fopen(outsmeshfilename, "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);
+
+  // Number of facets, number of boundary markers (zero or one).
+  fprintf(fout, "%d  %d\n", numberoftrifaces, 
+          trifacemarkerlist != NULL ? 1 : 0);
+
+  // Output triangular facets.
+  for (i = 0; i < numberoftrifaces; i++) {
+    j = i * 3;
+    fprintf(fout, "3  %d %d %d", trifacelist[j], trifacelist[j + 1], 
+            trifacelist[j + 2]);
+    if (trifacemarkerlist != NULL) {
+      fprintf(fout, "  %d", trifacemarkerlist[i]);
+    }
+    fprintf(fout, "\n");
+  }
+
+  // No holes and regions.
+  fprintf(fout, "0\n");
+  fprintf(fout, "0\n");
+
+  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') || (*result == '\r') || (*result == '\n'));
+  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, char *infilename)
+{
+  char *result;
+
+  // Search for something that looks like a number.
+  do {
+    result = fgets(string, INPUTLINESIZE, infile);
+    if (result == (char *) NULL) {
+      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;
+}
+
+////                                                                       ////
+////                                                                       ////
+//// io_cxx ///////////////////////////////////////////////////////////////////
+
+//// behavior_cxx /////////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// syntax()    Print list of command line switches.                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenbehavior::syntax()
+{
+  printf("  tetgen [-pYrq_Aa_miO_S_T_XMwcdzfenvgkJBNEFICQVh] input_file\n");
+  printf("    -p  Tetrahedralizes a piecewise linear complex (PLC).\n");
+  printf("    -Y  Preserves the input surface mesh (does not modify it).\n");
+  printf("    -r  Reconstructs a previously generated mesh.\n");
+  printf("    -q  Refines mesh (to improve mesh quality).\n");
+  printf("    -R  Mesh coarsening (to reduce the mesh elements).\n");
+  printf("    -A  Assigns attributes to tetrahedra in different regions.\n");
+  printf("    -a  Applies a maximum tetrahedron volume constraint.\n");
+  printf("    -m  Applies a mesh sizing function.\n");
+  printf("    -i  Inserts a list of additional points.\n");
+  printf("    -O  Specifies the level of mesh optimization.\n");
+  printf("    -S  Specifies maximum number of added points.\n");
+  printf("    -T  Sets a tolerance for coplanar test (default 1e-8).\n");
+  printf("    -X  Suppresses use of exact arithmetic.\n");
+  printf("    -M  No merge of coplanar facets or very close vertices.\n");
+  printf("    -w  Generates weighted Delaunay (regular) triangulation.\n");
+  printf("    -c  Retains the convex hull of the PLC.\n");
+  printf("    -d  Detects self-intersections of facets of the PLC.\n");
+  printf("    -z  Numbers all output items starting from zero.\n");
+  printf("    -f  Outputs all faces to .face 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("    -k  Outputs mesh to .vtk file for viewing by Paraview.\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 and .edge 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");
+  printf("Version 1.5\n");
+  printf("November 4, 2013\n");
+  printf("\n");
+  printf("What Can TetGen Do?\n");
+  printf("\n");
+  printf("  TetGen generates Delaunay tetrahedralizations, constrained\n");
+  printf("  Delaunay tetrahedralizations, and quality tetrahedral meshes.\n");
+  printf("\n");
+  printf("Command Line Syntax:\n");
+  printf("\n");
+  printf("  Below is the basic 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, ");
+  printf("object.1.ele\n  (tetrahedra), and object.1.face");
+  printf(" (convex hull faces).\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, ");
+  printf("object.1.face,\n");
+  printf("  (boundary faces) and object.1.edge (boundary edges).\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  object.1.face, and object.1.edge\n");
+  printf("\n");
+  printf("Please send bugs/comments to Hang Si <si@wias-berlin.de>\n");
+  terminatetetgen(NULL, 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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.                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenbehavior::parse_commandline(int argc, char **argv)
+{
+  int startindex;
+  int increment;
+  int meshnumber;
+  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, " ");
+  }
+
+  for (i = startindex; i < argc; i++) {
+    // Remember the command line for output.
+    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';
+        continue;                     
+      }
+    }
+    // Parse the individual switch from the string.
+    for (j = startindex; argv[i][j] != '\0'; j++) {
+      if (argv[i][j] == 'p') {
+        plc = 1;
+        if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+            (argv[i][j + 1] == '.')) {
+          k = 0;
+          while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+                 (argv[i][j + 1] == '.')) {
+            j++;
+            workstring[k] = argv[i][j];
+            k++;
+          }
+          workstring[k] = '\0';
+          facet_ang_tol = (REAL) strtod(workstring, (char **) NULL);
+        }
+      } else if (argv[i][j] == 's') {
+        psc = 1;
+      } else if (argv[i][j] == 'Y') {
+        nobisect = 1;
+        if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
+          nobisect_param = (argv[i][j + 1] - '0');
+          j++;
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
+            addsteiner_algo = (argv[i][j + 1] - '0');
+            j++;
+          }
+        }
+      } else if (argv[i][j] == 'r') {
+        refine = 1;
+      } else if (argv[i][j] == 'q') {
+        quality = 1;
+        if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+            (argv[i][j + 1] == '.')) {
+          k = 0;
+          while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+                 (argv[i][j + 1] == '.')) {
+            j++;
+            workstring[k] = argv[i][j];
+            k++;
+          }
+          workstring[k] = '\0';
+          minratio = (REAL) strtod(workstring, (char **) NULL);
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          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';
+            mindihedral = (REAL) strtod(workstring, (char **) NULL);
+          }
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          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';
+            optmaxdihedral = (REAL) strtod(workstring, (char **) NULL);
+          }
+        }
+      } else if (argv[i][j] == 'R') {
+        coarsen = 1;
+        if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
+          coarsen_param = (argv[i][j + 1] - '0');
+          j++;
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          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';
+            coarsen_percent = (REAL) strtod(workstring, (char **) NULL);
+          }
+        }
+      } else if (argv[i][j] == 'w') {
+        weighted = 1;
+        if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
+          weighted_param = (argv[i][j + 1] - '0');
+          j++;
+        }
+      } else if (argv[i][j] == 'b') {
+        // -b(brio_threshold/brio_ratio/hilbert_limit/hilbert_order)
+        brio_hilbert = 1;
+        if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+            (argv[i][j + 1] == '.')) {
+          k = 0;
+          while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+                 (argv[i][j + 1] == '.')) {
+            j++;
+            workstring[k] = argv[i][j];
+            k++;
+          }
+          workstring[k] = '\0';
+          brio_threshold = (int) strtol(workstring, (char **) &workstring, 0);
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          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';
+            brio_ratio = (REAL) strtod(workstring, (char **) NULL);
+          }
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+              (argv[i][j + 1] == '.') || (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] == '-')) {
+              j++;
+              workstring[k] = argv[i][j];
+              k++;
+            }
+            workstring[k] = '\0';
+            hilbert_limit = (int) strtol(workstring, (char **) &workstring, 0);
+          }
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+              (argv[i][j + 1] == '.') || (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] == '-')) {
+              j++;
+              workstring[k] = argv[i][j];
+              k++;
+            }
+            workstring[k] = '\0';
+            hilbert_order = (REAL) strtod(workstring, (char **) NULL);
+          }
+        }
+        if (brio_threshold == 0) { // -b0
+          brio_hilbert = 0; // Turn off BRIO-Hilbert sorting. 
+        }
+        if (brio_ratio >= 1.0) { // -b/1
+          no_sort = 1;
+          brio_hilbert = 0; // Turn off BRIO-Hilbert sorting.
+        }
+      } else if (argv[i][j] == 'l') {
+        incrflip = 1;
+      } else if (argv[i][j] == 'L') {
+        flipinsert = 1;
+      } else if (argv[i][j] == 'm') {
+        metric = 1;
+      } 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 = 1;
+      } else if (argv[i][j] == 'D') {
+        conforming = 1;
+        if ((argv[i][j + 1] >= '1') && (argv[i][j + 1] <= '3')) {
+          reflevel = (argv[i][j + 1] - '1') + 1; 
+          j++;
+        }
+      } else if (argv[i][j] == 'i') {
+        insertaddpoints = 1;
+      } else if (argv[i][j] == 'd') {
+        diagnose = 1;
+      } else if (argv[i][j] == 'c') {
+        convex = 1;
+      } else if (argv[i][j] == 'M') {
+        nomergefacet = 1;
+        nomergevertex = 1;
+        if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
+          nomergefacet = (argv[i][j + 1] - '0');
+          j++;
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
+            nomergevertex = (argv[i][j + 1] - '0');
+            j++;
+          }
+        }
+      } else if (argv[i][j] == 'X') {
+        if (argv[i][j + 1] == '1') {
+          nostaticfilter = 1;
+          j++;
+        } else {
+          noexact = 1;
+        }
+      } else if (argv[i][j] == 'z') {
+        zeroindex = 1;
+      } else if (argv[i][j] == 'f') {
+        facesout++;
+      } 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] == 'k') {
+        vtkview = 1;  
+      } 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;
+      } else if (argv[i][j] == 'F') {
+        nofacewritten = 1;
+      } else if (argv[i][j] == 'I') {
+        noiterationnum = 1;
+      } 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] == 'o') {
+        if (argv[i][j + 1] == '2') {
+          order = 2;
+          j++;
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          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';
+            optmaxdihedral = (REAL) strtod(workstring, (char **) NULL);
+          }
+        }
+      } else if (argv[i][j] == 'O') {
+        if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
+          optlevel = (argv[i][j + 1] - '0');
+          j++;
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '7')) {
+            optscheme = (argv[i][j + 1] - '0');
+            j++;
+          }
+        }
+      } 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] == 'R') {
+        reversetetori = 1;
+      } 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] == 'x') {
+        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';
+          tetrahedraperblock = (int) strtol(workstring, (char **) NULL, 0);
+          if (tetrahedraperblock > 8188) {
+            vertexperblock = tetrahedraperblock / 2;
+            shellfaceperblock = vertexperblock / 2;
+          } else {
+            tetrahedraperblock = 8188;
+          }
+        }
+      } else if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
+                 (argv[i][j] == '?')) {
+        usage();
+      } 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(NULL, 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;
+      if (!refine) 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;
+    }
+  }
+
+  if (nobisect && (!plc && !refine)) { // -Y
+    plc = 1; // Default -p option.
+  }
+  if (quality && (!plc && !refine)) { // -q
+    plc = 1; // Default -p option.
+  }
+  if (diagnose && !plc) { // -d
+    plc = 1;
+  }
+  if (refine && !quality) { // -r only
+    // Reconstruct a mesh, no mesh optimization.
+    optlevel = 0;
+  }
+  if (insertaddpoints && (optlevel == 0)) { // with -i option
+    optlevel = 2;
+  }
+  if (coarsen && (optlevel == 0)) { // with -R option
+    optlevel = 2;
+  }
+
+  // Detect improper combinations of switches.
+  if ((refine || plc) && weighted) {
+    printf("Error:  Switches -w cannot use together with -p or -r.\n");
+    return false;
+  }
+
+  if (convex) { // -c
+    if (plc && !regionattrib) {
+      // -A (region attribute) is needed for marking exterior tets (-1).
+      regionattrib = 1; 
+    }
+  }
+
+  // Note: -A must not used together with -r option. 
+  // 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;
+  }
+  // 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;
+  }
+  // If '-a' or '-aa' is in use, enable '-q' option too.
+  if (fixedvolume || varvolume) {
+    if (quality == 0) {
+      quality = 1;
+      if (!plc && !refine) {
+        plc = 1; // enable -p.
+      }
+    }
+  }
+  // No user-specified dihedral angle bound. Use default ones.
+  if (!quality) {
+    if (optmaxdihedral < 179.0) {
+      if (nobisect) {  // with -Y option
+        optmaxdihedral = 179.0;
+      } else { // -p only
+        optmaxdihedral = 179.999;
+      }
+    }
+    if (optminsmtdihed < 179.999) {
+      optminsmtdihed = 179.999;
+    }
+    if (optminslidihed < 179.999) {
+      optminslidihed = 179.999;
+    }
+  }
+
+  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;
+}
+
+////                                                                       ////
+////                                                                       ////
+//// behavior_cxx /////////////////////////////////////////////////////////////
+
+//// mempool_cxx //////////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
+// Initialize fast lookup tables for mesh maniplulation primitives.
+
+int tetgenmesh::bondtbl[12][12] = {{0,},};
+int tetgenmesh::enexttbl[12] = {0,};
+int tetgenmesh::eprevtbl[12] = {0,};
+int tetgenmesh::enextesymtbl[12] = {0,};
+int tetgenmesh::eprevesymtbl[12] = {0,};
+int tetgenmesh::eorgoppotbl[12] = {0,};
+int tetgenmesh::edestoppotbl[12] = {0,};
+int tetgenmesh::fsymtbl[12][12] = {{0,},};
+int tetgenmesh::facepivot1[12] = {0,};
+int tetgenmesh::facepivot2[12][12] = {{0,},};
+int tetgenmesh::tsbondtbl[12][6] = {{0,},};
+int tetgenmesh::stbondtbl[12][6] = {{0,},};
+int tetgenmesh::tspivottbl[12][6] = {{0,},};
+int tetgenmesh::stpivottbl[12][6] = {{0,},};
+
+// Table 'esymtbl' takes an directed edge (version) as input, returns the
+//   inversed edge (version) of it.
+
+int tetgenmesh::esymtbl[12] = {9, 6, 11, 4, 3, 7, 1, 5, 10, 0, 8, 2};
+
+// The following four tables give the 12 permutations of the set {0,1,2,3}.
+//   An offset 4 is added to each element for a direct access of the points
+//   in the tetrahedron data structure.
+
+int tetgenmesh:: orgpivot[12] = {7, 7, 5, 5, 6, 4, 4, 6, 5, 6, 7, 4};
+int tetgenmesh::destpivot[12] = {6, 4, 4, 6, 5, 6, 7, 4, 7, 7, 5, 5};
+int tetgenmesh::apexpivot[12] = {5, 6, 7, 4, 7, 7, 5, 5, 6, 4, 4, 6};
+int tetgenmesh::oppopivot[12] = {4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7};
+
+// The twelve versions correspond to six undirected edges. The following two
+//   tables map a version to an undirected edge and vice versa.
+
+int tetgenmesh::ver2edge[12] = {0, 1, 2, 3, 3, 5, 1, 5, 4, 0, 4, 2};
+int tetgenmesh::edge2ver[ 6] = {0, 1, 2, 3, 8, 5};
+
+// Edge versions whose apex or opposite may be dummypoint.
+
+int tetgenmesh::epivot[12] = {4, 5, 2, 11, 4, 5, 2, 11, 4, 5, 2, 11};
+
+
+// Table 'snextpivot' takes an edge version as input, returns the next edge
+//   version in the same edge ring.
+
+int tetgenmesh::snextpivot[6] = {2, 5, 4, 1, 0, 3};
+
+// The following three tables give the 6 permutations of the set {0,1,2}.
+//   An offset 3 is added to each element for a direct access of the points
+//   in the triangle data structure.
+
+int tetgenmesh::sorgpivot [6] = {3, 4, 4, 5, 5, 3};
+int tetgenmesh::sdestpivot[6] = {4, 3, 5, 4, 3, 5};
+int tetgenmesh::sapexpivot[6] = {5, 5, 3, 3, 4, 4};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// inittable()    Initialize the look-up tables.                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::inittables()
+{
+  int i, j;
+
+
+  // i = t1.ver; j = t2.ver;
+  for (i = 0; i < 12; i++) {
+    for (j = 0; j < 12; j++) {
+      bondtbl[i][j] = (j & 3) + (((i & 12) + (j & 12)) % 12);
+    }
+  }
+
+
+  // i = t1.ver; j = t2.ver
+  for (i = 0; i < 12; i++) {
+    for (j = 0; j < 12; j++) {
+      fsymtbl[i][j] = (j + 12 - (i & 12)) % 12;
+    }
+  }
+
+
+  for (i = 0; i < 12; i++) {
+    facepivot1[i] = (esymtbl[i] & 3);
+  }
+
+  for (i = 0; i < 12; i++) {
+    for (j = 0; j < 12; j++) {
+      facepivot2[i][j] = fsymtbl[esymtbl[i]][j];
+    }
+  }
+
+  for (i = 0; i < 12; i++) {
+    enexttbl[i] = (i + 4) % 12;
+    eprevtbl[i] = (i + 8) % 12;
+  }
+
+  for (i = 0; i < 12; i++) {
+    enextesymtbl[i] = esymtbl[enexttbl[i]];
+    eprevesymtbl[i] = esymtbl[eprevtbl[i]];
+  }
+
+  for (i = 0; i < 12; i++) {
+    eorgoppotbl [i] = eprevtbl[esymtbl[enexttbl[i]]];
+    edestoppotbl[i] = enexttbl[esymtbl[eprevtbl[i]]];
+  }
+
+  int soffset, toffset;
+
+  // i = t.ver, j = s.shver
+  for (i = 0; i < 12; i++) {
+    for (j = 0; j < 6; j++) {
+      if ((j & 1) == 0) {
+        soffset = (6 - ((i & 12) >> 1)) % 6;
+        toffset = (12 - ((j & 6) << 1)) % 12;
+      } else {
+        soffset = (i & 12) >> 1;
+        toffset = (j & 6) << 1;
+      }
+      tsbondtbl[i][j] = (j & 1) + (((j & 6) + soffset) % 6);
+      stbondtbl[i][j] = (i & 3) + (((i & 12) + toffset) % 12);
+    }
+  }
+
+
+  // i = t.ver, j = s.shver
+  for (i = 0; i < 12; i++) {
+    for (j = 0; j < 6; j++) {
+      if ((j & 1) == 0) {
+        soffset = (i & 12) >> 1;
+        toffset = (j & 6) << 1;
+      } else {
+        soffset = (6 - ((i & 12) >> 1)) % 6;
+        toffset = (12 - ((j & 6) << 1)) % 12;
+      }
+      tspivottbl[i][j] = (j & 1) + (((j & 6) + soffset) % 6);
+      stpivottbl[i][j] = (i & 3) + (((i & 12) + toffset) % 12);
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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;
+  objectsperblockmark = objectsperblock - 1;
+
+  // 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 * (uintptr_t) 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.            //
+//                                                                           //
+// 'newptr' returns a pointer to the new object (it must not be a NULL).     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::arraypool::newindex(void **newptr)
+{
+  // Allocate an object at index 'firstvirgin'.
+  int newindex = objects;
+  *newptr = (void *) (getblock(objects) +
+    (objects & (objectsperblock - 1)) * objectbytes);
+  objects++;
+
+  return newindex;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// memorypool()   The constructors of memorypool.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+tetgenmesh::memorypool::memorypool()
+{
+  firstblock = nowblock = (void **) NULL;
+  nextitem = (void *) NULL;
+  deaditemstack = (void *) NULL;
+  pathblock = (void **) NULL;
+  pathitem = (void *) NULL;
+  alignbytes = 0;
+  itembytes = itemwords = 0;
+  itemsperblock = 0;
+  items = maxitems = 0l;
+  unallocateditems = 0;
+  pathitemsleft = 0;
+}
+
+tetgenmesh::memorypool::memorypool(int bytecount, int itemcount, int wsize, 
+                                   int alignment)
+{
+  poolinit(bytecount, itemcount, wsize, 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;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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,int wordsize,
+                                      int alignment)
+{
+  // 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) {
+    terminatetetgen(NULL, 1);
+  }
+  // Set the next block pointer to NULL.
+  *(firstblock) = (void *) NULL;
+  restart();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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()
+{
+  uintptr_t 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 = (uintptr_t) (nowblock + 1);
+  // Align the item on an `alignbytes'-byte boundary.
+  nextitem = (void *)
+    (alignptr + (uintptr_t) alignbytes -
+     (alignptr % (uintptr_t) 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;
+  uintptr_t 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) {
+          terminatetetgen(NULL, 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 = (uintptr_t) (nowblock + 1);
+      // Align the item on an `alignbytes'-byte boundary.
+      nextitem = (void *)
+        (alignptr + (uintptr_t) alignbytes -
+         (alignptr % (uintptr_t) 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.
+    nextitem = (void *) ((uintptr_t) nextitem + itembytes);
+    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()
+{
+  uintptr_t alignptr;
+
+  // Begin the traversal in the first block.
+  pathblock = firstblock;
+  // Find the first item in the block.  Increment by the size of (void *).
+  alignptr = (uintptr_t) (pathblock + 1);
+  // Align with item on an `alignbytes'-byte boundary.
+  pathitem = (void *)
+    (alignptr + (uintptr_t) alignbytes -
+     (alignptr % (uintptr_t) 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;
+  uintptr_t 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 = (uintptr_t) (pathblock + 1);
+    // Align with item on an `alignbytes'-byte boundary.
+    pathitem = (void *)
+      (alignptr + (uintptr_t) alignbytes -
+       (alignptr % (uintptr_t) alignbytes));
+    // Set the number of items left in the current block.
+    pathitemsleft = itemsperblock;
+  }
+  newitem = pathitem;
+  // Find the next item in the block.
+  pathitem = (void *) ((uintptr_t) pathitem + itembytes);
+  pathitemsleft--;
+  return newitem;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// makeindex2pointmap()    Create a map from index to vertices.              //
+//                                                                           //
+// 'idx2verlist' returns the created map.  Traverse all vertices, a pointer  //
+// to each vertex is set into the array.  The pointer to the first vertex is //
+// saved in 'idx2verlist[in->firstnumber]'.                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::makeindex2pointmap(point*& idx2verlist)
+{
+  point pointloop;
+  int idx;
+
+  if (b->verbose > 1) {
+    printf("  Constructing mapping from indices to points.\n");
+  }
+
+  idx2verlist = new point[points->items + 1];
+
+  points->traversalinit();
+  pointloop = pointtraverse();
+  idx =  in->firstnumber;
+  while (pointloop != (point) NULL) {
+    idx2verlist[idx++] = pointloop;
+    pointloop = 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[points->items + 1];
+  for (i = 0; i < points->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 < points->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 = points->items - 1; i >= 0; i--) {
+    idx2faclist[i + 1] = idx2faclist[i];
+  }
+  idx2faclist[0] = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetrahedrondealloc()    Deallocate space for a tet., marking it dead.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::tetrahedrondealloc(tetrahedron *dyingtetrahedron)
+{
+  // Set tetrahedron's vertices to NULL. This makes it possible to detect
+  //   dead tetrahedra when traversing the list of all tetrahedra.
+  dyingtetrahedron[4] = (tetrahedron) NULL;
+
+  // Dealloc the space to subfaces/subsegments.
+  if (dyingtetrahedron[8] != NULL) {
+    tet2segpool->dealloc((shellface *) dyingtetrahedron[8]);
+  }
+  if (dyingtetrahedron[9] != NULL) {
+    tet2subpool->dealloc((shellface *) dyingtetrahedron[9]);
+  }
+
+  tetrahedrons->dealloc((void *) dyingtetrahedron);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetrahedrontraverse()    Traverse the tetrahedra, skipping dead ones.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+tetgenmesh::tetrahedron* tetgenmesh::tetrahedrontraverse()
+{
+  tetrahedron *newtetrahedron;
+
+  do {
+    newtetrahedron = (tetrahedron *) tetrahedrons->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 *) tetrahedrons->traverse();
+    if (newtetrahedron == (tetrahedron *) NULL) {
+      return (tetrahedron *) NULL;
+    }
+  } while (newtetrahedron[4] == (tetrahedron) NULL); // Skip dead ones.
+  return newtetrahedron;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// shellfacedealloc()    Deallocate space for a shellface, marking it dead.  //
+//                       Used both for dealloc a subface and subsegment.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::shellfacedealloc(memorypool *pool, shellface *dyingsh)
+{
+  // Set shellface's vertices to NULL. This makes it possible to detect dead
+  //   shellfaces when traversing the list of all shellfaces.
+  dyingsh[3] = (shellface) NULL;
+  pool->dealloc((void *) dyingsh);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// shellfacetraverse()    Traverse the subfaces, skipping dead ones. Used    //
+//                        for both subfaces and subsegments pool traverse.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+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;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// pointdealloc()    Deallocate space for a point, marking it dead.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::pointdealloc(point dyingpoint)
+{
+  // Mark the point as dead. This  makes it possible to detect dead points
+  //   when traversing the list of all points.
+  setpointtype(dyingpoint, DEADVERTEX);
+  points->dealloc((void *) dyingpoint);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// pointtraverse()    Traverse the points, skipping dead ones.               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+tetgenmesh::point tetgenmesh::pointtraverse()
+{
+  point newpoint;
+
+  do {
+    newpoint = (point) points->traverse();
+    if (newpoint == (point) NULL) {
+      return (point) NULL;
+    }
+  } while (pointtype(newpoint) == DEADVERTEX);            // Skip dead ones.
+  return newpoint;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// maketetrahedron()    Create a new tetrahedron.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::maketetrahedron(triface *newtet)
+{
+  newtet->tet = (tetrahedron *) tetrahedrons->alloc();
+
+  // Initialize the four adjoining tetrahedra to be "outer space".
+  newtet->tet[0] = NULL;
+  newtet->tet[1] = NULL;
+  newtet->tet[2] = NULL;
+  newtet->tet[3] = NULL;
+  // Four NULL vertices.
+  newtet->tet[4] = NULL;
+  newtet->tet[5] = NULL;
+  newtet->tet[6] = NULL;
+  newtet->tet[7] = NULL;
+  // No attached segments and subfaces yet.
+  newtet->tet[8] = NULL; 
+  newtet->tet[9] = NULL; 
+  // Initialize the marker (clear all flags).
+  setelemmarker(newtet->tet, 0);
+  for (int i = 0; i < numelemattrib; i++) {
+    setelemattribute(newtet->tet, i, 0.0);
+  }
+  if (b->varvolume) {
+    setvolumebound(newtet->tet, -1.0);
+  }
+
+  // Initialize the version to be Zero.
+  newtet->ver = 11;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// makeshellface()    Create a new shellface with version zero. Used for     //
+//                    both subfaces and subsegments.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::makeshellface(memorypool *pool, face *newface)
+{
+  newface->sh = (shellface *) pool->alloc();
+
+  // No adjointing subfaces.
+  newface->sh[0] = NULL;
+  newface->sh[1] = NULL;
+  newface->sh[2] = NULL;
+  // Three NULL vertices.
+  newface->sh[3] = NULL;
+  newface->sh[4] = NULL;
+  newface->sh[5] = NULL;
+  // No adjoining subsegments.
+  newface->sh[6] = NULL;
+  newface->sh[7] = NULL;
+  newface->sh[8] = NULL;
+  // No adjoining tetrahedra.
+  newface->sh[9] = NULL;
+  newface->sh[10] = NULL;
+  if (checkconstraints) {
+    // Initialize the maximum area bound.
+    setareabound(*newface, 0.0);
+  }
+  // Clear the infection and marktest bits.
+  ((int *) (newface->sh))[shmarkindex + 1] = 0;
+  if (useinsertradius) {
+    setfacetindex(*newface, 0);
+  }
+  // Set the boundary marker to zero.
+  setshellmark(*newface, 0);
+
+  newface->shver = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// makepoint()    Create a new point.                                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::makepoint(point* pnewpoint, enum verttype vtype)
+{
+  int i;
+
+  *pnewpoint = (point) points->alloc();
+
+  // Initialize the point attributes.
+  for (i = 0; i < numpointattrib; i++) {
+    (*pnewpoint)[3 + i] = 0.0;
+  }
+  // Initialize the metric tensor.
+  for (i = 0; i < sizeoftensor; i++) {
+    (*pnewpoint)[pointmtrindex + i] = 0.0;
+  }
+  setpoint2tet(*pnewpoint, NULL);
+  setpoint2ppt(*pnewpoint, NULL);
+  if (b->plc || b->refine) {
+    // Initialize the point-to-simplex field.
+    setpoint2sh(*pnewpoint, NULL);
+    if (b->metric && (bgm != NULL)) {
+      setpoint2bgmtet(*pnewpoint, NULL);
+    }
+  }
+  // Initialize the point marker (starting from in->firstnumber).
+  setpointmark(*pnewpoint, (int) (points->items) - (!in->firstnumber));
+  // Clear all flags.
+  ((int *) (*pnewpoint))[pointmarkindex + 1] = 0;
+  // Initialize (set) the point type. 
+  setpointtype(*pnewpoint, vtype);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// initializepools()    Calculate the sizes of the point, tetrahedron, and   //
+//                      subface. Initialize their memory pools.              //
+//                                                                           //
+// This routine also computes the indices 'pointmarkindex', 'point2simindex',//
+// 'point2pbcptindex', 'elemattribindex', and 'volumeboundindex'.  They are  //
+// used to find values within each point and tetrahedron, respectively.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::initializepools()
+{
+  int pointsize = 0, elesize = 0, shsize = 0;
+  int i;
+
+  if (b->verbose) {
+    printf("  Initializing memorypools.\n");
+    printf("  tetrahedron per block: %d.\n", b->tetrahedraperblock);
+  }
+
+  inittables();
+
+  // There are three input point lists available, which are in, addin,
+  //   and bgm->in. These point lists may have different number of 
+  //   attributes. Decide the maximum number.
+  numpointattrib = in->numberofpointattributes;
+  if (bgm != NULL) {
+    if (bgm->in->numberofpointattributes > numpointattrib) {
+      numpointattrib = bgm->in->numberofpointattributes;
+    }
+  }
+  if (addin != NULL) {
+    if (addin->numberofpointattributes > numpointattrib) {
+      numpointattrib = addin->numberofpointattributes;
+    }
+  }
+  if (b->weighted || b->flipinsert) { // -w or -L.
+    // The internal number of point attribute needs to be at least 1
+    //   (for storing point weights).
+    if (numpointattrib == 0) {    
+      numpointattrib = 1;
+    }
+  }
+
+  // Default varconstraint = 0;
+  if (in->segmentconstraintlist || in->facetconstraintlist) {
+    checkconstraints = 1;
+  }
+  if (b->plc || b->refine) {
+    // Save the insertion radius for Steiner points if boundaries
+    //   are allowed be split.
+    if (!b->nobisect || checkconstraints) {
+      useinsertradius = 1;
+    }
+  }
+
+  // The index within each point at which its metric tensor is found. 
+  // Each vertex has three coordinates.
+  if (b->psc) {
+    // '-s' option (PSC), the u,v coordinates are provided.
+    pointmtrindex = 5 + numpointattrib;
+    // The index within each point at which its u, v coordinates are found.
+    // Comment: They are saved after the list of point attributes.
+    pointparamindex = pointmtrindex - 2;
+  } else {
+    pointmtrindex = 3 + numpointattrib;
+  }
+  // For '-m' option. A tensor field is provided (*.mtr or *.b.mtr file).
+  if (b->metric) {
+    // Decide the size (1, 3, or 6) of the metric tensor.
+    if (bgm != (tetgenmesh *) NULL) {
+      // A background mesh is allocated. It may not exist though.
+      sizeoftensor = (bgm->in != (tetgenio *) NULL) ? 
+        bgm->in->numberofpointmtrs : in->numberofpointmtrs;
+    } else {
+      // No given background mesh - Itself is a background mesh.
+      sizeoftensor = in->numberofpointmtrs;
+    }
+    // Make sure sizeoftensor is at least 1.
+    sizeoftensor = (sizeoftensor > 0) ? sizeoftensor : 1;
+  } else {
+    // For '-q' option. Make sure to have space for saving a scalar value.
+    sizeoftensor = b->quality ? 1 : 0;
+  }
+  if (useinsertradius) {
+    // Increase a space (REAL) for saving point insertion radius, it is
+    //   saved directly after the metric. 
+    sizeoftensor++;
+  }
+  // The index within each point at which an element pointer is found, where
+  //   the index is measured in pointers. Ensure the index is aligned to a
+  //   sizeof(tetrahedron)-byte address.
+  point2simindex = ((pointmtrindex + sizeoftensor) * sizeof(REAL)
+                 + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
+  if (b->plc || b->refine || b->voroout) {
+    // Increase the point size by three pointers, which are:
+    //   - a pointer to a tet, read by point2tet();
+    //   - a pointer to a parent point, read by point2ppt()).
+    //   - a pointer to a subface or segment, read by point2sh();
+    if (b->metric && (bgm != (tetgenmesh *) NULL)) {
+      // Increase one pointer into the background mesh, point2bgmtet().
+      pointsize = (point2simindex + 4) * sizeof(tetrahedron);
+    } else {
+      pointsize = (point2simindex + 3) * sizeof(tetrahedron);
+    }
+  } else {
+    // Increase the point size by two pointer, which are:
+    //   - a pointer to a tet, read by point2tet();
+    //   - a pointer to a parent point, read by point2ppt()). -- Used by btree.
+    pointsize = (point2simindex + 2) * sizeof(tetrahedron);
+  }
+  // The index within each point at which the boundary marker is found,
+  //   Ensure the point marker is aligned to a sizeof(int)-byte address.
+  pointmarkindex = (pointsize + sizeof(int) - 1) / sizeof(int);
+  // Now point size is the ints (indicated by pointmarkindex) plus:
+  //   - an integer for boundary marker;
+  //   - an integer for vertex type;
+  //   - an integer for geometry tag (optional, -s option).
+  pointsize = (pointmarkindex + 2 + (b->psc ? 1 : 0)) * sizeof(tetrahedron);
+
+  // Initialize the pool of vertices.
+  points = new memorypool(pointsize, b->vertexperblock, sizeof(REAL), 0);
+
+  if (b->verbose) {
+    printf("  Size of a point: %d bytes.\n", points->itembytes);
+  }
+
+  // Initialize the infinite vertex.
+  dummypoint = (point) new char[pointsize];
+  // Initialize all fields of this point.
+  dummypoint[0] = 0.0;
+  dummypoint[1] = 0.0;
+  dummypoint[2] = 0.0;
+  for (i = 0; i < numpointattrib; i++) {
+    dummypoint[3 + i] = 0.0;
+  }
+  // Initialize the metric tensor.
+  for (i = 0; i < sizeoftensor; i++) {
+    dummypoint[pointmtrindex + i] = 0.0;
+  }
+  setpoint2tet(dummypoint, NULL);
+  setpoint2ppt(dummypoint, NULL);
+  if (b->plc || b->psc || b->refine) {
+    // Initialize the point-to-simplex field.
+    setpoint2sh(dummypoint, NULL);
+    if (b->metric && (bgm != NULL)) {
+      setpoint2bgmtet(dummypoint, NULL);
+    }
+  }
+  // Initialize the point marker (starting from in->firstnumber).
+  setpointmark(dummypoint, -1); // The unique marker for dummypoint.
+  // Clear all flags.
+  ((int *) (dummypoint))[pointmarkindex + 1] = 0;
+  // Initialize (set) the point type. 
+  setpointtype(dummypoint, UNUSEDVERTEX); // Does not matter.
+
+  // The number of bytes occupied by a tetrahedron is varying by the user-
+  //   specified options. The contents of the first 12 pointers are listed
+  //   in the following table:
+  //     [0]  |__ neighbor at f0 __|
+  //     [1]  |__ neighbor at f1 __|
+  //     [2]  |__ neighbor at f2 __|
+  //     [3]  |__ neighbor at f3 __|
+  //     [4]  |_____ vertex p0 ____|
+  //     [5]  |_____ vertex p1 ____|
+  //     [6]  |_____ vertex p2 ____|
+  //     [7]  |_____ vertex p3 ____|
+  //     [8]  |__ segments array __| (used by -p)
+  //     [9]  |__ subfaces array __| (used by -p)
+  //    [10]  |_____ reserved _____|
+  //    [11]  |___ elem marker ____| (used as an integer)
+
+  elesize = 12 * sizeof(tetrahedron); 
+
+  // The index to find the element markers. An integer containing varies
+  //   flags and element counter. 
+  assert(sizeof(int) <= sizeof(tetrahedron));
+  assert((sizeof(tetrahedron) % sizeof(int)) == 0);
+  elemmarkerindex = (elesize - sizeof(tetrahedron)) / sizeof(int);
+
+  // The actual number of element attributes. Note that if the
+  //   `b->regionattrib' flag is set, an additional attribute will be added.
+  numelemattrib = in->numberoftetrahedronattributes + (b->regionattrib > 0);
+
+  // 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 volume bound is
+  //   found, where the index is measured in REALs.
+  volumeboundindex = elemattribindex + numelemattrib;
+  // If element attributes or an constraint are needed, increase the number
+  //   of bytes occupied by an element.
+  if (b->varvolume) {
+    elesize = (volumeboundindex + 1) * sizeof(REAL);
+  } else if (numelemattrib > 0) {
+    elesize = volumeboundindex * sizeof(REAL);
+  }
+
+
+  // Having determined the memory size of an element, initialize the pool.
+  tetrahedrons = new memorypool(elesize, b->tetrahedraperblock, sizeof(void *),
+                                16);
+
+  if (b->verbose) {
+    printf("  Size of a tetrahedron: %d (%d) bytes.\n", elesize,
+           tetrahedrons->itembytes);
+  }
+
+  if (b->plc || b->refine) { // 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, two to tetrahedra.
+    shsize = 11 * 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 (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) * sizeof(shellface);
+    if (useinsertradius) {
+      // Increase the number of byte by one integer for storing facet index.
+      //    set/read by setfacetindex() and getfacetindex.
+      shsize = (shmarkindex + 3) * sizeof(shellface);
+    }
+
+    // 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.
+    subfaces = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8);
+
+    if (b->verbose) {
+      printf("  Size of a shellface: %d (%d) bytes.\n", shsize,
+             subfaces->itembytes);
+    }
+
+    // Initialize the pool of subsegments. The subsegment's record is same
+    //   with subface.
+    subsegs = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8);
+
+    // Initialize the pool for tet-subseg connections.
+    tet2segpool = new memorypool(6 * sizeof(shellface), b->shellfaceperblock, 
+                                 sizeof(void *), 0);
+    // Initialize the pool for tet-subface connections.
+    tet2subpool = new memorypool(4 * sizeof(shellface), b->shellfaceperblock, 
+                                 sizeof(void *), 0);
+
+    // Initialize arraypools for segment & facet recovery.
+    subsegstack = new arraypool(sizeof(face), 10);
+    subfacstack = new arraypool(sizeof(face), 10);
+    subvertstack = new arraypool(sizeof(point), 8);
+
+    // Initialize arraypools for surface point insertion/deletion.
+    caveshlist = new arraypool(sizeof(face), 8);
+    caveshbdlist = new arraypool(sizeof(face), 8);
+    cavesegshlist = new arraypool(sizeof(face), 4);
+
+    cavetetshlist = new arraypool(sizeof(face), 8);
+    cavetetseglist = new arraypool(sizeof(face), 8);
+    caveencshlist = new arraypool(sizeof(face), 8);
+    caveencseglist = new arraypool(sizeof(face), 8);
+  }
+
+  // Initialize the pools for flips.
+  flippool = new memorypool(sizeof(badface), 1024, sizeof(void *), 0);
+  unflipqueue = new arraypool(sizeof(badface), 10);
+
+  // Initialize the arraypools for point insertion.
+  cavetetlist = new arraypool(sizeof(triface), 10);
+  cavebdrylist = new arraypool(sizeof(triface), 10);
+  caveoldtetlist = new arraypool(sizeof(triface), 10);
+  cavetetvertlist = new arraypool(sizeof(point), 10);
+}
+
+////                                                                       ////
+////                                                                       ////
+//// mempool_cxx //////////////////////////////////////////////////////////////
+
+//// geom_cxx /////////////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
+// PI is the ratio of a circle's circumference to its diameter.
+REAL tetgenmesh::PI = 3.14159265358979323846264338327950288419716939937510582;
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insphere_s()    Insphere test with symbolic perturbation.                 //
+//                                                                           //
+// Given four points pa, pb, pc, and pd, test if the point pe lies inside or //
+// outside the circumscribed sphere of the four points.                      //
+//                                                                           //
+// Here we assume that the 3d orientation of the point sequence {pa, pb, pc, //
+// pd} is positive (NOT zero), i.e., pd lies above the plane passing through //
+// points pa, pb, and pc. Otherwise, the returned sign is flipped.           //
+//                                                                           //
+// Return a positive value (> 0) if pe lies inside, a negative value (< 0)   //
+// if pe lies outside the sphere, the returned value will not be zero.       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL tetgenmesh::insphere_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe)
+{
+  REAL sign;
+
+  sign = insphere(pa, pb, pc, pd, pe);
+  if (sign != 0.0) {
+    return sign;
+  }
+
+  // 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;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// orient4d_s()    4d orientation test with symbolic perturbation.           //
+//                                                                           //
+// Given four lifted points pa', pb', pc', and pd' in R^4,test if the lifted //
+// point pe' in R^4 lies below or above the hyperplane passing through the   //
+// four points pa', pb', pc', and pd'.                                       //
+//                                                                           //
+// Here we assume that the 3d orientation of the point sequence {pa, pb, pc, //
+// pd} is positive (NOT zero), i.e., pd lies above the plane passing through //
+// the points pa, pb, and pc. Otherwise, the returned sign is flipped.       //
+//                                                                           //
+// Return a positive value (> 0) if pe' lies below, a negative value (< 0)   //
+// if pe' lies above the hyperplane, the returned value should not be zero.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL tetgenmesh::orient4d_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe,
+                            REAL aheight, REAL bheight, REAL cheight, 
+                            REAL dheight, REAL eheight)
+{
+  REAL sign;
+
+  sign = orient4d(pa, pb, pc, pd, pe, 
+                  aheight, bheight, cheight, dheight, eheight);
+  if (sign != 0.0) {
+    return sign;
+  }
+
+  // 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;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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.                         //
+//                                                                           //
+// 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 T and E intersect each other, they may intersect in different ways. If //
+// 'level' > 0, their intersection type will be reported 'types' and 'pos'.  //
+//                                                                           //
+// The return value indicates one of the following cases:                    //
+//   - 0, T and E are disjoint.                                              //
+//   - 1, T and E intersect each other.                                      //
+//   - 2, T and E are not coplanar. They intersect at a single point.        //
+//   - 4, T and E are coplanar. They intersect at a single point or a line   //
+//        segment (if types[1] != DISJOINT).                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#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)
+
+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 abovept[3];
+  REAL sA, sB, sC;
+  REAL s1, s2, s3, s4;
+  int z1;
+
+  if (R == NULL) {
+    // Calculate a lift point.
+    if (1) {
+      REAL n[3], len;
+      // Calculate a lift point, saved in dummypoint.
+      facenormal(A, B, C, n, 1, NULL);
+      len = sqrt(dot(n, n));
+      if (len != 0) {
+        n[0] /= len;
+        n[1] /= len;
+        n[2] /= len;
+        len = distance(A, B);
+        len += distance(B, C);
+        len += distance(C, A);
+        len /= 3.0;
+        R = abovept; //dummypoint;
+        R[0] = A[0] + len * n[0];
+        R[1] = A[1] + len * n[1];
+        R[2] = A[2] + len * n[2];
+      } else {
+        // The triangle [A,B,C] is (nearly) degenerate, i.e., it is (close)
+        //   to a line.  We need a line-line intersection test.
+        //assert(0);
+        // !!! A non-save return value.!!!
+        return 0;  // DISJOINT
+      }
+    }
+  }
+
+  // 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);
+
+
+  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.
+              // Avoiding compiler warnings.
+              SETVECTOR3(U, A, B, C);  // I3
+              SETVECTOR3(V, P, Q, R);  // I2
+              SETVECTOR3(pu, 0, 1, 2);
+              SETVECTOR3(pv, 0, 1, 2);
+              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
+
+  if (s1 > 0) {
+    return 0;
+  }
+  if (s2 < 0) {
+    return 0;
+  }
+
+  if (level == 0) {
+    return 1;  // They are intersected.
+  }
+
+  assert(z1 != 4); // SELF_CHECK
+
+  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 4;
+  }
+
+  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
+      
+  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 4;
+}
+
+int tetgenmesh::tri_edge_tail(point A,point B,point C,point P,point Q,point R,
+                              REAL sP,REAL sQ,int level,int *types,int *pos)
+{
+  point U[3], V[3]; //, Ptmp;
+  int pu[3], pv[3]; //, itmp;
+  REAL s1, s2, s3;
+  int z1;
+
+
+  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]);
+  if (s1 < 0) {
+    return 0;
+  }
+
+  s2 = orient3d(U[1], U[2], V[0], V[1]);
+  if (s2 < 0) {
+    return 0;
+  }
+
+  s3 = orient3d(U[2], U[0], V[0], V[1]);
+  if (s3 < 0) {
+    return 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);
+        }
+      }
+    }
+  }
+
+  // T and E intersect in a single point.
+  return 2;
+}
+
+int tetgenmesh::tri_edge_test(point A, point B, point C, point P, point Q, 
+                              point R, int level, int *types, int *pos)
+{
+  REAL sP, sQ;
+
+  // Test the locations of P and Q with respect to ABC.
+  sP = orient3d(A, B, C, P);
+  sQ = orient3d(A, B, C, Q);
+
+  return tri_edge_tail(A, B, C, P, Q, R, sP, sQ, level, types, pos);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tri_tri_inter()    Test whether two triangle (abc) and (opq) are          //
+//                    intersecting or not.                                   //
+//                                                                           //
+// Return 0 if they are disjoint. Otherwise, return 1. 'type' returns one of //
+// the four cases: SHAREVERTEX, SHAREEDGE, SHAREFACE, and INTERSECT.         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::tri_edge_inter_tail(REAL* A, REAL* B, REAL* C,  REAL* P, 
+                                    REAL* Q, REAL s_p, REAL s_q)
+{
+  int types[2], pos[4];
+  int ni;  // =0, 2, 4
+
+  ni = tri_edge_tail(A, B, C, P, Q, NULL, s_p, s_q, 1, types, pos);
+
+  if (ni > 0) {
+    if (ni == 2) {
+      // Get the intersection type.
+      if (types[0] == (int) SHAREVERT) {
+        return (int) SHAREVERT;
+      } else {
+        return (int) INTERSECT;
+      }
+    } else if (ni == 4) { 
+      // There may be two intersections.
+      if (types[0] == (int) SHAREVERT) {
+        if (types[1] == (int) DISJOINT) {
+          return (int) SHAREVERT;
+        } else {
+          assert(types[1] != (int) SHAREVERT);
+          return (int) INTERSECT;
+        }
+      } else {
+        if (types[0] == (int) SHAREEDGE) {
+          return (int) SHAREEDGE;
+        } else {
+          return (int) INTERSECT;
+        }
+      }
+    } else {
+      assert(0);
+    }
+  }
+
+  return (int) DISJOINT;
+}
+
+int tetgenmesh::tri_tri_inter(REAL* A,REAL* B,REAL* C,REAL* O,REAL* P,REAL* Q)
+{
+  REAL s_o, s_p, s_q;
+  REAL s_a, s_b, s_c;
+
+  s_o = orient3d(A, B, C, O);
+  s_p = orient3d(A, B, C, P);
+  s_q = orient3d(A, B, C, Q);
+  if ((s_o * s_p > 0.0) && (s_o * s_q > 0.0)) {
+    // o, p, q are all in the same halfspace of ABC.
+    return 0; // DISJOINT;
+  }
+
+  s_a = orient3d(O, P, Q, A);
+  s_b = orient3d(O, P, Q, B);
+  s_c = orient3d(O, P, Q, C);
+  if ((s_a * s_b > 0.0) && (s_a * s_c > 0.0)) {
+    // a, b, c are all in the same halfspace of OPQ.
+    return 0; // DISJOINT;
+  }
+
+  int abcop, abcpq, abcqo;
+  int shareedge = 0;
+
+  abcop = tri_edge_inter_tail(A, B, C, O, P, s_o, s_p);
+  if (abcop == (int) INTERSECT) {
+    return (int) INTERSECT;
+  } else if (abcop == (int) SHAREEDGE) {
+    shareedge++;
+  }
+  abcpq = tri_edge_inter_tail(A, B, C, P, Q, s_p, s_q);
+  if (abcpq == (int) INTERSECT) {
+    return (int) INTERSECT;
+  } else if (abcpq == (int) SHAREEDGE) {
+    shareedge++;
+  }
+  abcqo = tri_edge_inter_tail(A, B, C, Q, O, s_q, s_o);
+  if (abcqo == (int) INTERSECT) {
+    return (int) INTERSECT;
+  } else if (abcqo == (int) SHAREEDGE) {
+    shareedge++;
+  }
+  if (shareedge == 3) {
+    // opq are coincident with abc.
+    return (int) SHAREFACE;
+  }
+
+  // It is only possible either no share edge or one.
+  assert(shareedge == 0 || shareedge == 1);
+
+  // Continue to detect whether opq and abc are intersecting or not.
+  int opqab, opqbc, opqca;
+
+  opqab = tri_edge_inter_tail(O, P, Q, A, B, s_a, s_b);
+  if (opqab == (int) INTERSECT) {
+    return (int) INTERSECT;
+  }
+  opqbc = tri_edge_inter_tail(O, P, Q, B, C, s_b, s_c);
+  if (opqbc == (int) INTERSECT) {
+    return (int) INTERSECT;
+  }
+  opqca = tri_edge_inter_tail(O, P, Q, C, A, s_c, s_a);
+  if (opqca == (int) INTERSECT) {
+    return (int) INTERSECT;
+  }
+
+  // At this point, two triangles are not intersecting and not coincident.
+  //   They may be share an edge, or share a vertex, or disjoint.
+  if (abcop == (int) SHAREEDGE) {
+    assert((abcpq == (int) SHAREVERT) && (abcqo == (int) SHAREVERT));
+    // op is coincident with an edge of abc.
+    return (int) SHAREEDGE;
+  }
+  if (abcpq == (int) SHAREEDGE) {
+    assert((abcop == (int) SHAREVERT) && (abcqo == (int) SHAREVERT));
+    // pq is coincident with an edge of abc.
+    return (int) SHAREEDGE;
+  }
+  if (abcqo == (int) SHAREEDGE) {
+    assert((abcop == (int) SHAREVERT) && (abcpq == (int) SHAREVERT));
+    // qo is coincident with an edge of abc.
+    return (int) SHAREEDGE;
+  }
+
+  // They may share a vertex or disjoint.
+  if (abcop == (int) SHAREVERT) {
+    // o or p is coincident with a vertex of abc.
+    if (abcpq == (int) SHAREVERT) {
+      // p is the coincident vertex.
+      assert(abcqo != (int) SHAREVERT);
+    } else {
+      // o is the coincident vertex.
+      assert(abcqo == (int) SHAREVERT);
+    }
+    return (int) SHAREVERT;
+  }
+  if (abcpq == (int) SHAREVERT) {
+    // q is the coincident vertex.
+    assert(abcqo == (int) SHAREVERT);
+    return (int) SHAREVERT;
+  }
+
+  // They are disjoint.
+  return (int) DISJOINT;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// incircle3d()    3D in-circle test.                                        //
+//                                                                           //
+// Return a negative value if pd is inside the circumcircle of the triangle  //
+// pa, pb, and pc.                                                           //
+//                                                                           //
+// IMPORTANT: It assumes that [a,b] is the common edge, i.e., the two input  //
+// triangles are [a,b,c] and [b,a,d].                                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+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, NULL);
+  area2[0] = dot(n1, n1);
+  facenormal(pb, pa, pd, n2, 1, NULL);
+  area2[1] = dot(n2, n2);
+
+  if (area2[0] > area2[1]) {
+    // Choose [a, b, c] as the base triangle.
+    circumsphere(pa, pb, pc, NULL, c, &r);
+    d = distance(c, pd);
+  } else {
+    // Choose [b, a, d] as the base triangle.
+    if (area2[1] > 0) {
+      circumsphere(pb, pa, pd, NULL, c, &r);
+      d = distance(c, pc);
+    } else {
+      // The four points are collinear. This case only happens on the boundary.
+      return 0; // Return "not inside".
+    }
+  }
+
+  sign = d - r;
+  if (fabs(sign) / r < b->epsilon) {
+    sign = 0;
+  }
+
+  return sign;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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.                        //
+//                                                                           //
+// If 'lav' is not NULL and if 'pivot' is set, the average edge length of    //
+// the edges of the face [a,b,c] is returned.                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::facenormal(point pa, point pb, point pc, REAL *n, int pivot,
+                            REAL* lav)
+{
+  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).
+      }
+    }
+    if (lav) {
+      // return the average edge length.
+      *lav = (sqrt(L1) + sqrt(L2) + sqrt(L3)) / 3.0;
+    }
+  } 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];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// shortdistance()    Returns the shortest distance from point p to a line   //
+//                    defined by two points e1 and e2.                       //
+//                                                                           //
+// First compute the projection length l_p of the vector v1 = p - e1 along   //
+// the vector v2 = e2 - e1. Then Pythagoras' Theorem is used to compute the  //
+// shortest distance.                                                        //
+//                                                                           //
+// This routine allows that p is collinear with the line. In this case, the  //
+// return value is zero. The two points e1 and e2 should not be identical.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2)
+{
+  REAL v1[3], v2[3];
+  REAL len, l_p;
+
+  v1[0] = e2[0] - e1[0];
+  v1[1] = e2[1] - e1[1];
+  v1[2] = e2[2] - e1[2];
+  v2[0] = p[0] - e1[0];
+  v2[1] = p[1] - e1[1];
+  v2[2] = p[2] - e1[2];
+
+  len = sqrt(dot(v1, v1));
+  assert(len != 0.0);
+
+  v1[0] /= len;
+  v1[1] /= len;
+  v1[2] /= len;
+  l_p = dot(v1, v2);
+
+  return sqrt(dot(v2, v2) - l_p * l_p);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// triarea()    Return the area of a triangle.                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL tetgenmesh::triarea(REAL* pa, REAL* pb, REAL* pc)
+{
+  REAL A[4][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]; // vector V1 (pa->pb)
+  A[1][0] = pc[0] - pa[0];
+  A[1][1] = pc[1] - pa[1];
+  A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
+
+  cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
+
+  return 0.5 * sqrt(dot(A[2], A[2])); // The area of [a,b,c].
+}
+
+REAL tetgenmesh::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);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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(REAL* o, REAL* p1, REAL* 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);
+
+  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;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// projpt2edge()    Return the projection point from a point to an edge.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj)
+{
+  REAL v1[3], v2[3];
+  REAL len, l_p;
+
+  v1[0] = e2[0] - e1[0];
+  v1[1] = e2[1] - e1[1];
+  v1[2] = e2[2] - e1[2];
+  v2[0] = p[0] - e1[0];
+  v2[1] = p[1] - e1[1];
+  v2[2] = p[2] - e1[2];
+
+  len = sqrt(dot(v1, v1));
+  assert(len != 0.0);
+  v1[0] /= len;
+  v1[1] /= len;
+  v1[2] /= len;
+  l_p = dot(v1, v2);
+
+  prj[0] = e1[0] + l_p * v1[0];
+  prj[1] = e1[1] + l_p * v1[1];
+  prj[2] = e1[2] + l_p * v1[2];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// projpt2face()    Return the projection point from a point to a face.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj)
+{
+  REAL fnormal[3], v1[3];
+  REAL len, dist;
+
+  // Get the unit face normal.
+  facenormal(f1, f2, f3, fnormal, 1, NULL);
+  len = sqrt(fnormal[0]*fnormal[0] + fnormal[1]*fnormal[1] + 
+             fnormal[2]*fnormal[2]);
+  fnormal[0] /= len;
+  fnormal[1] /= len;
+  fnormal[2] /= len;
+  // Get the vector v1 = |p - f1|.
+  v1[0] = p[0] - f1[0];
+  v1[1] = p[1] - f1[1];
+  v1[2] = p[2] - f1[2];
+  // Get the project distance.
+  dist = dot(fnormal, v1);
+  
+  // Get the project point.
+  prj[0] = p[0] - dist * fnormal[0];
+  prj[1] = p[1] - dist * fnormal[1];
+  prj[2] = p[2] - dist * fnormal[2];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// facedihedral()    Return the dihedral angle (in radian) between two       //
+//                   adjoining faces.                                        //
+//                                                                           //
+// 'pa', 'pb' are the shared edge of these two faces, 'pc1', and 'pc2' are   //
+// apexes of these two faces.  Return the angle (between 0 to 2*pi) between  //
+// the normal of face (pa, pb, pc1) and normal of face (pa, pb, pc2).        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL tetgenmesh::facedihedral(REAL* pa, REAL* pb, REAL* pc1, REAL* pc2)
+{
+  REAL n1[3], n2[3];
+  REAL n1len, n2len;
+  REAL costheta, ori;
+  REAL theta;
+
+  facenormal(pa, pb, pc1, n1, 1, NULL);
+  facenormal(pa, pb, pc2, n2, 1, NULL);
+  n1len = sqrt(dot(n1, n1));
+  n2len = sqrt(dot(n2, n2));
+  costheta = dot(n1, n2) / (n1len * n2len);
+  // Be careful rounding error!
+  if (costheta > 1.0) {
+    costheta = 1.0;
+  } else if (costheta < -1.0) {
+    costheta = -1.0;
+  }
+  theta = acos(costheta);
+  ori = orient3d(pa, pb, pc1, pc2);
+  if (ori > 0.0) {
+    theta = 2 * PI - theta;
+  }
+
+  return theta;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetalldihedral()    Get all (six) dihedral angles of a tet.               //
+//                                                                           //
+// If 'cosdd' is not NULL, it returns the cosines of the 6 dihedral angles,  //
+// the edge indices are given in the global array 'edge2ver'. If 'cosmaxd'   //
+// (or 'cosmind') is not NULL, it returns the cosine of the maximal (or      //
+// minimal) dihedral angle.                                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::tetalldihedral(point pa, point pb, point pc, point pd,
+                                REAL* cosdd, REAL* cosmaxd, REAL* cosmind)
+{
+  REAL N[4][3], vol, cosd, len;
+  int f1 = 0, f2 = 0, i, j;
+
+  vol = 0; // Check if the tet is valid or not.
+
+  // Get four normals of faces of the tet.
+  tetallnormal(pa, pb, pc, pd, N, &vol);
+
+  if (vol > 0) {
+    // Normalize the normals.
+    for (i = 0; i < 4; i++) {
+      len = sqrt(dot(N[i], N[i]));
+      if (len != 0.0) {
+        for (j = 0; j < 3; j++) N[i][j] /= len;
+      } else {
+        // There are degeneracies, such as duplicated vertices.
+        vol = 0; //assert(0);
+      }
+    }
+  }
+
+  if (vol <= 0) { // if (vol == 0.0) {
+    // A degenerated tet or an inverted tet.
+    facenormal(pc, pb, pd, N[0], 1, NULL);
+    facenormal(pa, pc, pd, N[1], 1, NULL);
+    facenormal(pb, pa, pd, N[2], 1, NULL);
+    facenormal(pa, pb, pc, N[3], 1, NULL);
+    // Normalize the normals.
+    for (i = 0; i < 4; i++) {
+      len = sqrt(dot(N[i], N[i]));
+      if (len != 0.0) {
+        for (j = 0; j < 3; j++) N[i][j] /= len;
+      } else {
+        // There are degeneracies, such as duplicated vertices.
+        break; // Not a valid normal.
+      }
+    }
+    if (i < 4) {
+      // Do not calculate dihedral angles.
+      // Set all angles be 0 degree. There will be no quality optimization for
+      //   this tet! Use volume optimization to correct it.
+      if (cosdd != NULL) {
+        for (i = 0; i < 6; i++) {
+          cosdd[i] = -1.0; // 180 degree.
+        }
+      }
+      // This tet has zero volume.
+      if (cosmaxd != NULL) {
+        *cosmaxd = -1.0; // 180 degree.
+      }
+      if (cosmind != NULL) {
+        *cosmind = -1.0; // 180 degree.
+      }
+      return false;
+    }
+  }
+
+  // Calculate the cosine of the dihedral angles of the edges.
+  for (i = 0; i < 6; i++) {
+    switch (i) {
+    case 0: f1 = 0; f2 = 1; break; // [c,d].
+    case 1: f1 = 1; f2 = 2; break; // [a,d].
+    case 2: f1 = 2; f2 = 3; break; // [a,b].
+    case 3: f1 = 0; f2 = 3; break; // [b,c].
+    case 4: f1 = 2; f2 = 0; break; // [b,d].
+    case 5: f1 = 1; f2 = 3; break; // [a,c].
+    }
+    cosd = -dot(N[f1], N[f2]);
+    if (cosd < -1.0) cosd = -1.0; // Rounding.
+    if (cosd >  1.0) cosd =  1.0; // Rounding.
+    if (cosdd) cosdd[i] = cosd;
+    if (cosmaxd || cosmind) {
+      if (i == 0) {
+        if (cosmaxd) *cosmaxd = cosd;
+        if (cosmind) *cosmind = cosd;
+      } else {
+        if (cosmaxd) *cosmaxd = cosd < *cosmaxd ? cosd : *cosmaxd;
+        if (cosmind) *cosmind = cosd > *cosmind ? cosd : *cosmind;
+      }
+    }
+  }
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetallnormal()    Get the in-normals of the four faces of a given tet.    //
+//                                                                           //
+// Let tet be abcd. N[4][3] returns the four normals, which are: N[0] cbd,   //
+// N[1] acd, N[2] bad, N[3] abc (exactly corresponding to the face indices   //
+// of the mesh data structure). These normals are unnormalized.              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::tetallnormal(point pa, point pb, point pc, point pd,
+                              REAL N[4][3], REAL* volume)
+{
+  REAL A[4][4], rhs[4], D;
+  int indx[4];
+  int i, j;
+
+  // get the entries of A[3][3].
+  for (i = 0; i < 3; i++) A[0][i] = pa[i] - pd[i];  // d->a vec
+  for (i = 0; i < 3; i++) A[1][i] = pb[i] - pd[i];  // d->b vec
+  for (i = 0; i < 3; i++) A[2][i] = pc[i] - pd[i];  // d->c vec
+
+  // Compute the inverse of matrix A, to get 3 normals of the 4 faces.
+  if (lu_decmp(A, 3, indx, &D, 0)) { // Decompose the matrix just once.
+    if (volume != NULL) {
+      // Get the volume of the tet.
+      *volume = fabs((A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2])) / 6.0;
+    }
+    for (j = 0; j < 3; j++) {
+      for (i = 0; i < 3; i++) rhs[i] = 0.0;
+      rhs[j] = 1.0;  // Positive means the inside direction
+      lu_solve(A, 3, indx, rhs, 0);
+      for (i = 0; i < 3; i++) N[j][i] = rhs[i];
+    }
+    // Get the fourth normal by summing up the first three.
+    for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
+  } else {
+    // The tet is degenerated.
+    if (volume != NULL) {
+      *volume = 0;
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetaspectratio()    Calculate the aspect ratio of the tetrahedron.        //
+//                                                                           //
+// The aspect ratio of a tet is R/h, where R is the circumradius and h is    //
+// the shortest height of the tet.                                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL tetgenmesh::tetaspectratio(point pa, point pb, point pc, point pd)
+{
+  REAL vda[3], vdb[3], vdc[3];
+  REAL N[4][3], A[4][4], rhs[4], D;
+  REAL H[4], volume, radius2, minheightinv;
+  int indx[4];
+  int i, j; 
+
+  // Set the matrix A = [vda, vdb, vdc]^T.
+  for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
+  for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
+  for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
+  // Lu-decompose the matrix A.
+  lu_decmp(A, 3, indx, &D, 0);
+  // Get the volume of abcd.
+  volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
+  // Check if it is zero.
+  if (volume == 0.0) return 1.0e+200; // A degenerate tet.
+  // if (volume < 0.0) volume = -volume;
+  // Check the radiu-edge ratio of the tet.
+  rhs[0] = 0.5 * dot(vda, vda);
+  rhs[1] = 0.5 * dot(vdb, vdb);
+  rhs[2] = 0.5 * dot(vdc, vdc);
+  lu_solve(A, 3, indx, rhs, 0);
+  // Get the circumcenter.
+  // for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i];
+  // Get the square of the circumradius.
+  radius2 = dot(rhs, rhs);
+
+  // Compute the 4 face normals (N[0], ..., N[3]).
+  for (j = 0; j < 3; j++) {
+    for (i = 0; i < 3; i++) rhs[i] = 0.0;
+    rhs[j] = 1.0;  // Positive means the inside direction
+    lu_solve(A, 3, indx, rhs, 0);
+    for (i = 0; i < 3; i++) N[j][i] = rhs[i];
+  }
+  // Get the fourth normal by summing up the first three.
+  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
+  // Normalized the normals.
+  for (i = 0; i < 4; i++) {
+    // H[i] is the inverse of the height of its corresponding face.
+    H[i] = sqrt(dot(N[i], N[i]));
+    // if (H[i] > 0.0) {
+    //   for (j = 0; j < 3; j++) N[i][j] /= H[i];
+    // }
+  }
+  // Get the radius of the inscribed sphere.
+  // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
+  // Get the biggest H[i] (corresponding to the smallest height).
+  minheightinv = H[0];
+  for (i = 1; i < 3; i++) {
+    if (H[i] > minheightinv) minheightinv = H[i];
+  }
+
+  return sqrt(radius2) * minheightinv;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// circumsphere()    Calculate the smallest circumsphere (center and radius) //
+//                   of the given three or four points.                      //
+//                                                                           //
+// 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 if they are not degenerate.          //
+//                                                                           //
+// Return TRUE if the input points are not degenerate and the circumcenter   //
+// and circumradius are returned in 'cent' and 'radius' respectively if they //
+// are not NULLs.  Otherwise, return FALSE, the four points are co-planar.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::circumsphere(REAL* pa, REAL* pb, REAL* pc, REAL* 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)) {
+    if (radius != (REAL *) NULL) *radius = 0.0;
+    return false;
+  }    
+  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]);
+  }
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// orthosphere()    Calulcate the orthosphere of four weighted points.       //
+//                                                                           //
+// A weighted point (p, P^2) can be interpreted as a sphere centered at the  //
+// point 'p' with a radius 'P'. The 'height' of 'p' is pheight = p[0]^2 +    //
+// p[1]^2 + p[2]^2 - P^2.                                                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::orthosphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd,
+                             REAL  aheight, REAL bheight, REAL cheight, 
+                             REAL  dheight, REAL* orthocent, REAL* radius)
+{
+  REAL A[4][4], rhs[4], D;
+  int indx[4];
+
+  // Set the coefficient matrix A (4 x 4).
+  A[0][0] = 1.0; A[0][1] = pa[0]; A[0][2] = pa[1]; A[0][3] = pa[2];
+  A[1][0] = 1.0; A[1][1] = pb[0]; A[1][2] = pb[1]; A[1][3] = pb[2];
+  A[2][0] = 1.0; A[2][1] = pc[0]; A[2][2] = pc[1]; A[2][3] = pc[2];
+  A[3][0] = 1.0; A[3][1] = pd[0]; A[3][2] = pd[1]; A[3][3] = pd[2];
+
+  // Set the right hand side vector (4 x 1).
+  rhs[0] = 0.5 * aheight;
+  rhs[1] = 0.5 * bheight;
+  rhs[2] = 0.5 * cheight;
+  rhs[3] = 0.5 * dheight;
+
+  // Solve the 4 by 4 equations use LU decomposition with partial pivoting
+  //   and backward and forward substitute..
+  if (!lu_decmp(A, 4, indx, &D, 0)) {
+    if (radius != (REAL *) NULL) *radius = 0.0;
+    return false;
+  }
+  lu_solve(A, 4, indx, rhs, 0);
+
+  if (orthocent != (REAL *) NULL) {
+    orthocent[0] = rhs[1];
+    orthocent[1] = rhs[2];
+    orthocent[2] = rhs[3];
+  }
+  if (radius != (REAL *) NULL) {
+    // rhs[0] = - rheight / 2;
+    // rheight  = - 2 * rhs[0];
+    //          =  r[0]^2 + r[1]^2 + r[2]^2 - radius^2
+    // radius^2 = r[0]^2 + r[1]^2 + r[2]^2 -rheight
+    //          = r[0]^2 + r[1]^2 + r[2]^2 + 2 * rhs[0]
+    *radius = sqrt(rhs[1] * rhs[1] + rhs[2] * rhs[2] + rhs[3] * rhs[3]
+                   + 2.0 * rhs[0]);
+  }
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// planelineint()    Calculate the intersection of a line and a plane.       //
+//                                                                           //
+// The equation of a plane (points P are on the plane with normal N and P3   //
+// on the plane) can be written as: N dot (P - P3) = 0. The equation of the  //
+// line (points P on the line passing through P1 and P2) can be written as:  //
+// P = P1 + u (P2 - P1). The intersection of these two occurs when:          //
+//   N dot (P1 + u (P2 - P1)) = N dot P3.                                    //
+// Solving for u gives:                                                      //
+//         N dot (P3 - P1)                                                   //
+//   u = ------------------.                                                 //
+//         N dot (P2 - P1)                                                   //
+// If the denominator is 0 then N (the normal to the plane) is perpendicular //
+// to the line.  Thus the line is either parallel to the plane and there are //
+// no solutions or the line is on the plane in which case there are an infi- //
+// nite number of solutions.                                                 //
+//                                                                           //
+// The plane is given by three points pa, pb, and pc, e1 and e2 defines the  //
+// line. If u is non-zero, The intersection point (if exists) returns in ip. //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::planelineint(REAL* pa, REAL* pb, REAL* pc, REAL* e1, REAL* e2,
+                              REAL* ip, REAL* u)
+{
+  REAL n[3], det, det1;
+
+  // Calculate N.
+  facenormal(pa, pb, pc, n, 1, NULL);
+  // Calculate N dot (e2 - e1).
+  det = n[0] * (e2[0] - e1[0]) + n[1] * (e2[1] - e1[1])
+      + n[2] * (e2[2] - e1[2]);
+  if (det != 0.0) {
+    // Calculate N dot (pa - e1)
+    det1 = n[0] * (pa[0] - e1[0]) + n[1] * (pa[1] - e1[1])
+         + n[2] * (pa[2] - e1[2]);
+    *u = det1 / det;
+    ip[0] = e1[0] + *u * (e2[0] - e1[0]);
+    ip[1] = e1[1] + *u * (e2[1] - e1[1]);
+    ip[2] = e1[2] + *u * (e2[2] - e1[2]);
+  } else {
+    *u = 0.0;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// linelineint()    Calculate the intersection(s) of two line segments.      //
+//                                                                           //
+// Calculate the line segment [P, Q] that is the shortest route between two  //
+// lines from A to B and C to D. Calculate also the values of tp and tq      //
+// where: P = A + tp (B - A), and Q = C + tq (D - C).                        //
+//                                                                           //
+// Return 1 if the line segment exists. Otherwise, return 0.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::linelineint(REAL* A, REAL* B, REAL* C, REAL* D, REAL* P, 
+		            REAL* Q, REAL* tp, REAL* tq)
+{
+  REAL vab[3], vcd[3], vca[3];
+  REAL vab_vab, vcd_vcd, vab_vcd;
+  REAL vca_vab, vca_vcd;
+  REAL det, eps;
+  int i;
+
+  for (i = 0; i < 3; i++) {
+    vab[i] = B[i] - A[i];
+    vcd[i] = D[i] - C[i];
+    vca[i] = A[i] - C[i];
+  }
+
+  vab_vab = dot(vab, vab);
+  vcd_vcd = dot(vcd, vcd);
+  vab_vcd = dot(vab, vcd);
+
+  det = vab_vab * vcd_vcd - vab_vcd * vab_vcd;
+  // Round the result.
+  eps = det / (fabs(vab_vab * vcd_vcd) + fabs(vab_vcd * vab_vcd));
+  if (eps < b->epsilon) {
+    return 0;
+  }
+
+  vca_vab = dot(vca, vab);
+  vca_vcd = dot(vca, vcd);
+
+  *tp = (vcd_vcd * (- vca_vab) + vab_vcd * vca_vcd) / det;
+  *tq = (vab_vcd * (- vca_vab) + vab_vab * vca_vcd) / det;
+
+  for (i = 0; i < 3; i++) P[i] = A[i] + (*tp) * vab[i];
+  for (i = 0; i < 3; i++) Q[i] = C[i] + (*tq) * vcd[i];
+
+  return 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetprismvol()    Calculate the volume of a tetrahedral prism in 4D.       //
+//                                                                           //
+// A tetrahedral prism is a convex uniform polychoron (four dimensional poly-//
+// tope). It has 6 polyhedral cells: 2 tetrahedra connected by 4 triangular  //
+// prisms. It has 14 faces: 8 triangular and 6 square. It has 16 edges and 8 //
+// vertices. (Wikipedia).                                                    //
+//                                                                           //
+// Let 'p0', ..., 'p3' be four affinely independent points in R^3. They form //
+// the lower tetrahedral facet of the prism.  The top tetrahedral facet is   //
+// formed by four vertices, 'p4', ..., 'p7' in R^4, which is obtained by     //
+// lifting each vertex of the lower facet into R^4 by a weight (height).  A  //
+// canonical choice of the weights is the square of Euclidean norm of of the //
+// points (vectors).                                                         //
+//                                                                           //
+//                                                                           //
+// The return value is (4!) 24 times of the volume of the tetrahedral prism. //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL tetgenmesh::tetprismvol(REAL* p0, REAL* p1, REAL* p2, REAL* p3)
+{
+  REAL *p4, *p5, *p6, *p7;
+  REAL w4, w5, w6, w7;
+  REAL vol[4];
+
+  p4 = p0;
+  p5 = p1;
+  p6 = p2;
+  p7 = p3;
+
+  // TO DO: these weights can be pre-calculated!
+  w4 = dot(p0, p0);
+  w5 = dot(p1, p1);
+  w6 = dot(p2, p2);
+  w7 = dot(p3, p3);
+
+  // Calculate the volume of the tet-prism.
+  vol[0] = orient4d(p5, p6, p4, p3, p7, w5, w6, w4, 0, w7);
+  vol[1] = orient4d(p3, p6, p2, p0, p1,  0, w6,  0, 0,  0);
+  vol[2] = orient4d(p4, p6, p3, p0, p1, w4, w6,  0, 0,  0);
+  vol[3] = orient4d(p6, p5, p4, p3, p1, w6, w5, w4, 0,  0);
+
+  return fabs(vol[0]) + fabs(vol[1]) + fabs(vol[2]) + fabs(vol[3]);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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.
+  pb = pc = NULL; // Avoid compiler warnings.
+
+  // 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, NULL);
+  len = sqrt(dot(n, n));
+  n[0] /= len;
+  n[1] /= len;
+  n[2] /= len;
+  lab /= 2.0; // Half the maximal length.
+  dummypoint[0] = pa[0] + lab * n[0];
+  dummypoint[1] = pa[1] + lab * n[1];
+  dummypoint[2] = pa[2] + lab * n[2];
+
+  if (ppa != NULL) {
+    // Return the three points.
+    *ppa = pa;
+    *ppb = pb;
+    *ppc = pc;
+  }
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Calculate an above point. It lies above the plane containing  the subface //
+//   [a,b,c], and save it in dummypoint. Moreover, the vector pa->dummypoint //
+//   is the normal of the plane.                                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::calculateabovepoint4(point pa, point pb, point pc, point pd)
+{
+  REAL n1[3], n2[3], *norm;
+  REAL len, len1, len2;
+
+  // Select a base.
+  facenormal(pa, pb, pc, n1, 1, NULL);
+  len1 = sqrt(dot(n1, n1));
+  facenormal(pa, pb, pd, n2, 1, NULL);
+  len2 = sqrt(dot(n2, n2));
+  if (len1 > len2) {
+    norm = n1;
+    len = len1;
+  } else {
+    norm = n2;
+    len = len2;
+  }
+  assert(len > 0);
+  norm[0] /= len;
+  norm[1] /= len;
+  norm[2] /= len;
+  len = distance(pa, pb);
+  dummypoint[0] = pa[0] + len * norm[0];
+  dummypoint[1] = pa[1] + len * norm[1];
+  dummypoint[2] = pa[2] + len * norm[2];
+}
+
+////                                                                       ////
+////                                                                       ////
+//// geom_cxx /////////////////////////////////////////////////////////////////
+
+//// flip_cxx /////////////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip23()    Perform a 2-to-3 flip (face-to-edge flip).                    //
+//                                                                           //
+// 'fliptets' is an array of three tets (handles), where the [0] and [1] are  //
+// [a,b,c,d] and [b,a,c,e].  The three new tets: [e,d,a,b], [e,d,b,c], and   //
+// [e,d,c,a] are returned in [0], [1], and [2] of 'fliptets'.  As a result,  //
+// The face [a,b,c] is removed, and the edge [d,e] is created.               //
+//                                                                           //
+// If 'hullflag' > 0, hull tets may be involved in this flip, i.e., one of   //
+// the five vertices may be 'dummypoint'. There are two canonical cases:     //
+//   (1) d is 'dummypoint', then all three new tets are hull tets.  If e is  //
+//       'dummypoint', we reconfigure e to d, i.e., turn it up-side down.    //
+//   (2) c is 'dummypoint', then two new tets: [e,d,b,c] and [e,d,c,a], are  //
+//       hull tets. If a or b is 'dummypoint', we reconfigure it to c, i.e., //
+//       rotate the three input tets counterclockwisely (right-hand rule)    //
+//       until a or b is in c's position.                                    //
+//                                                                           //
+// If 'fc->enqflag' is set, convex hull faces will be queued for flipping.   //
+// In particular, if 'fc->enqflag' is 1, it is called by incrementalflip()   //
+// after the insertion of a new point.  It is assumed that 'd' is the new    //
+// point. IN this case, only link faces of 'd' are queued.                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flip23(triface* fliptets, int hullflag, flipconstraints *fc)
+{
+  triface topcastets[3], botcastets[3];
+  triface newface, casface;
+  point pa, pb, pc, pd, pe;
+  REAL attrib, volume;
+  int dummyflag = 0;  // range = {-1, 0, 1, 2}.
+  int i;
+
+  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;  // d is dummypoint.
+    } else {
+      // Check if either a or b is dummypoint.
+      if (org(fliptets[0]) == dummypoint) {
+        dummyflag = 1; // a is dummypoint.
+        enextself(fliptets[0]);
+        eprevself(fliptets[1]);
+      } else if (dest(fliptets[0]) == dummypoint) {
+        dummyflag = 2; // b is dummypoint.
+        eprevself(fliptets[0]);
+        enextself(fliptets[1]);
+      } else {
+        dummyflag = 0; // either c or d may be dummypoint.
+      }
+    }
+  }
+
+  pa =  org(fliptets[0]);
+  pb = dest(fliptets[0]);
+  pc = apex(fliptets[0]);
+  pd = oppo(fliptets[0]);
+  pe = oppo(fliptets[1]);
+
+  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]);
+    eprevself(fliptets[1]);
+  }
+
+  // Re-use fliptets[0] and fliptets[1].
+  fliptets[0].ver = 11;
+  fliptets[1].ver = 11;
+  setelemmarker(fliptets[0].tet, 0); // Clear all flags.
+  setelemmarker(fliptets[1].tet, 0);
+  // NOTE: the element attributes and volume constraint remain unchanged.
+  if (checksubsegflag) {
+    // 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 (checksubfaceflag) {
+    // 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;
+    }
+  }
+  // Create a new tet.
+  maketetrahedron(&(fliptets[2]));
+  // The new tet have the same attributes from the old tet.
+  for (i = 0; i < numelemattrib; i++) {
+    attrib = elemattribute(fliptets[0].tet, i);
+    setelemattribute(fliptets[2].tet, i, attrib);
+  }
+  if (b->varvolume) {
+    volume = volumebound(fliptets[0].tet);
+    setvolumebound(fliptets[2].tet, volume);
+  }
+
+  if (hullflag > 0) {
+    // Check if d is dummytet.
+    if (pd != dummypoint) {
+      setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] *
+      setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] *
+      // Check if c is dummypoint.
+      if (pc != dummypoint) {
+        setvertices(fliptets[2], pe, pd, pc, pa);  // [e,d,c,a] *
+      } else {
+        setvertices(fliptets[2], pd, pe, pa, pc); // [d,e,a,c]
+        esymself(fliptets[2]);                    // [e,d,c,a] *
+      }
+      // The hullsize does not change.
+    } else {
+      // d is dummypoint.
+      setvertices(fliptets[0], pa, pb, pe, pd); // [a,b,e,d]
+      setvertices(fliptets[1], pb, pc, pe, pd); // [b,c,e,d]
+      setvertices(fliptets[2], pc, pa, pe, pd); // [c,a,e,d]
+      // Adjust the faces to [e,d,a,b], [e,d,b,c], [e,d,c,a] *
+      for (i = 0; i < 3; i++) {
+        eprevesymself(fliptets[i]);
+        enextself(fliptets[i]);
+      }
+      // We deleted one hull tet, and created three hull tets.
+      hullsize += 2;
+    }
+  } else {
+    setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] *
+    setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] *
+    setvertices(fliptets[2], pe, pd, pc, pa); // [e,d,c,a] *
+  }
+
+  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
+    REAL volneg[2], volpos[3], vol_diff;
+    if (pd != dummypoint) {
+      if (pc != dummypoint) {
+        volpos[0] = tetprismvol(pe, pd, pa, pb);
+        volpos[1] = tetprismvol(pe, pd, pb, pc);
+        volpos[2] = tetprismvol(pe, pd, pc, pa);
+        volneg[0] = tetprismvol(pa, pb, pc, pd);
+        volneg[1] = tetprismvol(pb, pa, pc, pe);
+      } else { // pc == dummypoint
+        volpos[0] = tetprismvol(pe, pd, pa, pb);
+        volpos[1] = 0.;
+        volpos[2] = 0.;
+        volneg[0] = 0.;
+        volneg[1] = 0.;
+      }
+    } else { // pd == dummypoint.
+      volpos[0] = 0.;
+      volpos[1] = 0.;
+      volpos[2] = 0.;
+      volneg[0] = 0.;
+      volneg[1] = tetprismvol(pb, pa, pc, pe);
+    }
+    vol_diff = volpos[0] + volpos[1] + volpos[2] - volneg[0] - volneg[1];
+    fc->tetprism_vol_sum  += vol_diff; // Update the total sum.
+  }
+
+  // Bond three new tets together.
+  for (i = 0; i < 3; i++) {
+    esym(fliptets[i], newface);
+    bond(newface, fliptets[(i + 1) % 3]);
+  }
+  // Bond to top outer boundary faces (at [a,b,c,d]).
+  for (i = 0; i < 3; i++) {
+    eorgoppo(fliptets[i], newface); // At edges [b,a], [c,b], [a,c].
+    bond(newface, topcastets[i]);
+  }
+  // Bond bottom outer boundary faces (at [b,a,c,e]).
+  for (i = 0; i < 3; i++) {
+    edestoppo(fliptets[i], newface); // At edges [a,b], [b,c], [c,a].
+    bond(newface, botcastets[i]);
+  }
+
+  if (checksubsegflag) {
+    // Bond subsegments if there are.
+    // Each new tet has 5 edges to be checked (except the edge [e,d]). 
+    face checkseg;
+    // The middle three: [a,b], [b,c], [c,a].
+    for (i = 0; i < 3; i++) {      
+      if (issubseg(topcastets[i])) {
+        tsspivot1(topcastets[i], checkseg);
+        eorgoppo(fliptets[i], newface);
+        tssbond1(newface, checkseg);
+        sstbond1(checkseg, newface);
+        if (fc->chkencflag & 1) {
+          enqueuesubface(badsubsegs, &checkseg);
+        }
+      }
+    }
+    // The top three: [d,a], [d,b], [d,c]. Two tets per edge.
+    for (i = 0; i < 3; i++) {
+      eprev(topcastets[i], casface);      
+      if (issubseg(casface)) {
+        tsspivot1(casface, checkseg);
+        enext(fliptets[i], newface);
+        tssbond1(newface, checkseg);
+        sstbond1(checkseg, newface);
+        esym(fliptets[(i + 2) % 3], newface);
+        eprevself(newface);
+        tssbond1(newface, checkseg);
+        sstbond1(checkseg, newface);
+        if (fc->chkencflag & 1) {
+          enqueuesubface(badsubsegs, &checkseg);
+        }
+      }
+    }
+    // The bot three: [a,e], [b,e], [c,e]. Two tets per edge.
+    for (i = 0; i < 3; i++) {
+      enext(botcastets[i], casface);
+      if (issubseg(casface)) {
+        tsspivot1(casface, checkseg);
+        eprev(fliptets[i], newface);
+        tssbond1(newface, checkseg);
+        sstbond1(checkseg, newface);
+        esym(fliptets[(i + 2) % 3], newface);
+        enextself(newface);
+        tssbond1(newface, checkseg);
+        sstbond1(checkseg, newface);
+        if (fc->chkencflag & 1) {
+          enqueuesubface(badsubsegs, &checkseg);
+        }
+      }
+    }
+  } // if (checksubsegflag)
+
+  if (checksubfaceflag) {
+    // Bond 6 subfaces if there are.
+    face checksh;
+    for (i = 0; i < 3; i++) {      
+      if (issubface(topcastets[i])) {
+        tspivot(topcastets[i], checksh);
+        eorgoppo(fliptets[i], newface);
+        sesymself(checksh);
+        tsbond(newface, checksh);
+        if (fc->chkencflag & 2) {
+          enqueuesubface(badsubfacs, &checksh);
+        }
+      }
+    }
+    for (i = 0; i < 3; i++) {
+      if (issubface(botcastets[i])) {
+        tspivot(botcastets[i], checksh);
+        edestoppo(fliptets[i], newface);
+        sesymself(checksh);
+        tsbond(newface, checksh);
+        if (fc->chkencflag & 2) {
+          enqueuesubface(badsubfacs, &checksh);
+        }
+      }
+    }
+  } // if (checksubfaceflag)
+
+  if (fc->chkencflag & 4) {
+    // Put three new tets into check list.
+    for (i = 0; i < 3; i++) {
+      enqueuetetrahedron(&(fliptets[i]));
+    }
+  }
+
+  // Update the point-to-tet map.
+  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pc, (tetrahedron) fliptets[1].tet);
+  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pe, (tetrahedron) fliptets[0].tet);
+
+  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++) {
+          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.
+        if (dummyflag == 1) {
+          // a is dummypoint.
+          newface = fliptets[0];
+          fliptets[0] = fliptets[2];
+          fliptets[2] = fliptets[1];
+          fliptets[1] = newface;
+        } else { // dummyflag == 2
+          // b is dummypoint.
+          newface = fliptets[0];
+          fliptets[0] = fliptets[1];
+          fliptets[1] = fliptets[2];
+          fliptets[2] = newface;
+        }
+      }
+    }
+  }
+
+  if (fc->enqflag > 0) {
+    // Queue faces which may be locally non-Delaunay.  
+    for (i = 0; i < 3; i++) {
+      eprevesym(fliptets[i], newface);
+      flippush(flipstack, &newface);
+    }
+    if (fc->enqflag > 1) {
+      for (i = 0; i < 3; i++) {
+        enextesym(fliptets[i], newface);
+        flippush(flipstack, &newface);
+      }
+    }
+  }
+
+  recenttet = fliptets[0];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip32()    Perform a 3-to-2 flip (edge-to-face flip).                    //
+//                                                                           //
+// 'fliptets' is an array of three tets (handles),  which are [e,d,a,b],     //
+// [e,d,b,c], and [e,d,c,a].  The two new tets: [a,b,c,d] and [b,a,c,e] are  //
+// returned in [0] and [1] of 'fliptets'.  As a result, the edge [e,d] is    //
+// replaced by the face [a,b,c].                                             //
+//                                                                           //
+// If 'hullflag' > 0, hull tets may be involved in this flip, i.e., one of   //
+// the five vertices may be 'dummypoint'. There are two canonical cases:     //
+//   (1) d is 'dummypoint', then [a,b,c,d] is hull tet. If e is 'dummypoint',//
+//       we reconfigure e to d, i.e., turnover it.                           //
+//   (2) c is 'dummypoint' then both [a,b,c,d] and [b,a,c,e] 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.                                                 //
+//                                                                           //
+// If 'fc->enqflag' is set, convex hull faces will be queued for flipping.   //
+// In particular, if 'fc->enqflag' is 1, it is called by incrementalflip()   //
+// after the insertion of a new point.  It is assumed that 'a' is the new    //
+// point. In this case, only link faces of 'a' are queued.                   //
+//                                                                           //
+// If 'checksubfaceflag' is on (global variable), and assume [e,d] is not a  //
+// segment. There may be two (interior) subfaces sharing at [e,d], which are //
+// [e,d,p] and [e,d,q], where the pair (p,q) may be either (a,b), or (b,c),  //
+// or (c,a)  In such case, a 2-to-2 flip is performed on these two subfaces  //
+// and two new subfaces [p,q,e] and [p,q,d] are created. They are inserted   //
+// back into the tetrahedralization.                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flip32(triface* fliptets, int hullflag, flipconstraints *fc)
+{
+  triface topcastets[3], botcastets[3];
+  triface newface, casface;
+  face flipshs[3]; 
+  face checkseg; 
+  point pa, pb, pc, pd, pe;
+  REAL attrib, volume;
+  int dummyflag = 0;  // Rangle = {-1, 0, 1, 2}
+  int spivot = -1, scount = 0; // for flip22()
+  int t1ver; 
+  int i, j;
+
+  if (hullflag > 0) {
+    // Check if e is 'dummypoint'.
+    if (org(fliptets[0]) == dummypoint) {
+      // Reverse the edge.
+      for (i = 0; i < 3; 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.
+        newface = fliptets[0];
+        fliptets[0] = fliptets[1];
+        fliptets[1] = fliptets[2];
+        fliptets[2] = newface;
+      } else if (apex(fliptets[1]) == dummypoint) {
+        dummyflag = 2;  // b is dummypoint.
+        newface = fliptets[0];
+        fliptets[0] = fliptets[2];
+        fliptets[2] = fliptets[1];
+        fliptets[1] = newface;
+      } else {
+        dummyflag = 0;  // either c or d may be dummypoint.
+      }
+    }
+  }
+
+  pa = apex(fliptets[0]);
+  pb = apex(fliptets[1]);
+  pc = apex(fliptets[2]);
+  pd = dest(fliptets[0]);
+  pe = org(fliptets[0]);
+
+  flip32count++;
+
+  // Get the outer boundary faces.
+  for (i = 0; i < 3; i++) {
+    eorgoppo(fliptets[i], casface);
+    fsym(casface, topcastets[i]);
+  }
+  for (i = 0; i < 3; i++) {
+    edestoppo(fliptets[i], casface);
+    fsym(casface, botcastets[i]);
+  }
+
+  if (checksubfaceflag) {
+    // Check if there are interior subfaces at the edge [e,d].
+    for (i = 0; i < 3; i++) {
+      tspivot(fliptets[i], flipshs[i]);
+      if (flipshs[i].sh != NULL) {
+        // Found an interior subface.
+        stdissolve(flipshs[i]); // Disconnect the sub-tet bond.
+        scount++;
+      } else {
+        spivot = i;
+      }
+    }
+  }
+
+  // Re-use fliptets[0] and fliptets[1].
+  fliptets[0].ver = 11;
+  fliptets[1].ver = 11;
+  setelemmarker(fliptets[0].tet, 0); // Clear all flags.
+  setelemmarker(fliptets[1].tet, 0);
+  if (checksubsegflag) {
+    // 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 (checksubfaceflag) {
+    // 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 (checksubfaceflag) {
+    if (scount > 0) {
+      // The element attributes and volume constraint must be set correctly.
+      // There are two subfaces involved in this flip. The three tets are
+      //   separated into two different regions, one may be exterior. The
+      //   first region has two tets, and the second region has only one.
+      //   The two created tets must be in the same region as the first region. 
+      //   The element attributes and volume constraint must be set correctly.
+      //assert(spivot != -1);
+      // The tet fliptets[spivot] is in the first region.
+      for (j = 0; j < 2; j++) {
+        for (i = 0; i < numelemattrib; i++) {
+          attrib = elemattribute(fliptets[spivot].tet, i);
+          setelemattribute(fliptets[j].tet, i, attrib);
+        }
+        if (b->varvolume) {
+          volume = volumebound(fliptets[spivot].tet);
+          setvolumebound(fliptets[j].tet, volume);
+        }
+      }
+    }
+  }
+  // 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 deleted three hull tets, and created one 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.
+      esymself(fliptets[0]);
+      // Adjust abec -> bace.
+      esymself(fliptets[1]);
+      // The hullsize does not change.
+    }
+  } else {
+    setvertices(fliptets[0], pa, pb, pc, pd);
+    setvertices(fliptets[1], pb, pa, pc, pe);
+  }
+
+  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
+    REAL volneg[3], volpos[2], vol_diff;
+    if (pc != dummypoint) {
+      if (pd != dummypoint) {
+        volneg[0] = tetprismvol(pe, pd, pa, pb);
+        volneg[1] = tetprismvol(pe, pd, pb, pc);
+        volneg[2] = tetprismvol(pe, pd, pc, pa);
+        volpos[0] = tetprismvol(pa, pb, pc, pd);
+        volpos[1] = tetprismvol(pb, pa, pc, pe);
+      } else { // pd == dummypoint
+        volneg[0] = 0.;
+        volneg[1] = 0.;
+        volneg[2] = 0.;
+        volpos[0] = 0.;
+        volpos[1] = tetprismvol(pb, pa, pc, pe);
+      }
+    } else { // pc == dummypoint.
+      volneg[0] = tetprismvol(pe, pd, pa, pb);
+      volneg[1] = 0.;
+      volneg[2] = 0.;
+      volpos[0] = 0.;
+      volpos[1] = 0.;
+    }
+    vol_diff = volpos[0] + volpos[1] - volneg[0] - volneg[1] - volneg[2];
+    fc->tetprism_vol_sum  += vol_diff; // Update the total sum.
+  }
+
+  // Bond abcd <==> bace.
+  bond(fliptets[0], fliptets[1]);
+  // Bond new faces to top outer boundary faces (at abcd).
+  for (i = 0; i < 3; i++) {
+    esym(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++) {
+    esym(fliptets[1], newface);
+    bond(newface, botcastets[i]);
+    eprevself(fliptets[1]);
+  }
+
+  if (checksubsegflag) {
+    // Bond 9 segments to new (flipped) tets.
+    for (i = 0; i < 3; i++) { // edges a->b, b->c, c->a.      
+      if (issubseg(topcastets[i])) {
+        tsspivot1(topcastets[i], checkseg);
+        tssbond1(fliptets[0], checkseg);
+        sstbond1(checkseg, fliptets[0]);
+        tssbond1(fliptets[1], checkseg);
+        sstbond1(checkseg, fliptets[1]);
+        if (fc->chkencflag & 1) {
+          enqueuesubface(badsubsegs, &checkseg);
+        }
+      }
+      enextself(fliptets[0]);
+      eprevself(fliptets[1]);
+    }
+    // The three top edges.
+    for (i = 0; i < 3; i++) { // edges b->d, c->d, a->d.
+      esym(fliptets[0], newface);
+      eprevself(newface); 
+      enext(topcastets[i], casface);      
+      if (issubseg(casface)) {
+        tsspivot1(casface, checkseg);
+        tssbond1(newface, checkseg);
+        sstbond1(checkseg, newface);
+        if (fc->chkencflag & 1) {
+          enqueuesubface(badsubsegs, &checkseg);
+        }
+      }
+      enextself(fliptets[0]);
+    }
+    // The three bot edges.
+    for (i = 0; i < 3; i++) { // edges b<-e, c<-e, a<-e.
+      esym(fliptets[1], newface);
+      enextself(newface); 
+      eprev(botcastets[i], casface);
+      if (issubseg(casface)) {
+        tsspivot1(casface, checkseg);
+        tssbond1(newface, checkseg);
+        sstbond1(checkseg, newface);
+        if (fc->chkencflag & 1) {
+          enqueuesubface(badsubsegs, &checkseg);
+        }
+      }
+      eprevself(fliptets[1]);
+    }
+  } // if (checksubsegflag)
+
+  if (checksubfaceflag) {
+    face checksh;
+    // Bond the top three casing subfaces.
+    for (i = 0; i < 3; i++) { // At edges [b,a], [c,b], [a,c]
+      if (issubface(topcastets[i])) {
+        tspivot(topcastets[i], checksh);
+        esym(fliptets[0], newface); 
+        sesymself(checksh);
+        tsbond(newface, checksh);
+        if (fc->chkencflag & 2) {
+          enqueuesubface(badsubfacs, &checksh);
+        }
+      }
+      enextself(fliptets[0]);
+    }
+    // Bond the bottom three casing subfaces.
+    for (i = 0; i < 3; i++) { // At edges [a,b], [b,c], [c,a]
+      if (issubface(botcastets[i])) {
+        tspivot(botcastets[i], checksh);
+        esym(fliptets[1], newface); 
+        sesymself(checksh);
+        tsbond(newface, checksh);
+        if (fc->chkencflag & 2) {
+          enqueuesubface(badsubfacs, &checksh);
+        }
+      }
+      eprevself(fliptets[1]);
+    }
+
+    if (scount > 0) {
+      face flipfaces[2];
+      // Perform a 2-to-2 flip in subfaces.
+      flipfaces[0] = flipshs[(spivot + 1) % 3];
+      flipfaces[1] = flipshs[(spivot + 2) % 3];
+      sesymself(flipfaces[1]);
+      flip22(flipfaces, 0, fc->chkencflag);
+      // Connect the flipped subfaces to flipped tets.
+      // First go to the corresponding flipping edge.
+      //   Re-use top- and botcastets[0].
+      topcastets[0] = fliptets[0];
+      botcastets[0] = fliptets[1];
+      for (i = 0; i < ((spivot + 1) % 3); i++) {
+        enextself(topcastets[0]);
+        eprevself(botcastets[0]);
+      }
+      // Connect the top subface to the top tets.
+      esymself(topcastets[0]);
+      sesymself(flipfaces[0]);
+      // Check if there already exists a subface.
+      tspivot(topcastets[0], checksh);
+      if (checksh.sh == NULL) {
+        tsbond(topcastets[0], flipfaces[0]);
+        fsymself(topcastets[0]);
+        sesymself(flipfaces[0]);
+        tsbond(topcastets[0], flipfaces[0]);
+      } else {
+        // An invalid 2-to-2 flip. Report a bug.
+        terminatetetgen(this, 2); 
+      }
+      // Connect the bot subface to the bottom tets.
+      esymself(botcastets[0]);
+      sesymself(flipfaces[1]);
+      // Check if there already exists a subface.
+      tspivot(botcastets[0], checksh);
+      if (checksh.sh == NULL) {
+        tsbond(botcastets[0], flipfaces[1]);
+        fsymself(botcastets[0]);
+        sesymself(flipfaces[1]);
+        tsbond(botcastets[0], flipfaces[1]);
+      } else {
+        // An invalid 2-to-2 flip. Report a bug.
+        terminatetetgen(this, 2);  
+      }
+    } // if (scount > 0)
+  } // if (checksubfaceflag)
+
+  if (fc->chkencflag & 4) {
+    // Put two new tets into check list.
+    for (i = 0; i < 2; i++) {
+      enqueuetetrahedron(&(fliptets[i]));
+    }
+  }
+
+  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pc, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pe, (tetrahedron) fliptets[1].tet);
+
+  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.
+        if (dummyflag == 1) {
+          eprevself(fliptets[0]);
+          enextself(fliptets[1]);
+        } else { // dummyflag == 2
+          enextself(fliptets[0]);
+          eprevself(fliptets[1]);
+        }
+      }
+    }
+  }
+  
+  if (fc->enqflag > 0) {
+    // Queue faces which may be locally non-Delaunay.
+    // pa = org(fliptets[0]); // 'a' may be a new vertex.
+    enextesym(fliptets[0], newface);
+    flippush(flipstack, &newface);
+    eprevesym(fliptets[1], newface);
+    flippush(flipstack, &newface);
+    if (fc->enqflag > 1) {
+      //pb = dest(fliptets[0]);
+      eprevesym(fliptets[0], newface);
+      flippush(flipstack, &newface);
+      enextesym(fliptets[1], newface);
+      flippush(flipstack, &newface);
+      //pc = apex(fliptets[0]);
+      esym(fliptets[0], newface);
+      flippush(flipstack, &newface);
+      esym(fliptets[1], newface);
+      flippush(flipstack, &newface);
+    }
+  }
+
+  recenttet = fliptets[0];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip41()    Perform a 4-to-1 flip (Remove a vertex).                      //
+//                                                                           //
+// 'fliptets' is an array of four tetrahedra in the star of the removing     //
+// vertex 'p'. Let the four vertices in the star of p be a, b, c, and d. The //
+// four tets in 'fliptets' are: [p,d,a,b], [p,d,b,c], [p,d,c,a], and [a,b,c, //
+// p].  On return, 'fliptets[0]' is the new tet [a,b,c,d].                   //
+//                                                                           //
+// If 'hullflag' is set (> 0), one of the five vertices may be 'dummypoint'. //
+// The 'hullsize' may be changed.  Note that p may be dummypoint.  In this   //
+// case, four hull tets are replaced by one real tet.                        //
+//                                                                           //
+// If 'checksubface' flag is set (>0), it is possible that there are three   //
+// interior subfaces connecting at p.  If so, a 3-to-1 flip is performed to  //
+// to remove p from the surface triangulation.                               //
+//                                                                           //
+// If it is called by the routine incrementalflip(), we assume that d is the //
+// newly inserted vertex.                                                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flip41(triface* fliptets, int hullflag, flipconstraints *fc)
+{
+  triface topcastets[3], botcastet;
+  triface newface, neightet;
+  face flipshs[4];
+  point pa, pb, pc, pd, pp;
+  int dummyflag = 0; // in {0, 1, 2, 3, 4}
+  int spivot = -1, scount = 0;
+  int t1ver; 
+  int i;
+
+  pa =  org(fliptets[3]);
+  pb = dest(fliptets[3]);
+  pc = apex(fliptets[3]);
+  pd = dest(fliptets[0]);
+  pp =  org(fliptets[0]); // The removing vertex.
+
+  flip41count++;
+
+  // Get the outer boundary faces.
+  for (i = 0; i < 3; i++) {
+    enext(fliptets[i], topcastets[i]);
+    fnextself(topcastets[i]); // [d,a,b,#], [d,b,c,#], [d,c,a,#]
+    enextself(topcastets[i]); // [a,b,d,#], [b,c,d,#], [c,a,d,#]
+  }
+  fsym(fliptets[3], botcastet); // [b,a,c,#]
+
+  if (checksubfaceflag) {
+    // Check if there are three subfaces at 'p'.
+    //   Re-use 'newface'.
+    for (i = 0; i < 3; i++) {
+      fnext(fliptets[3], newface); // [a,b,p,d],[b,c,p,d],[c,a,p,d].
+      tspivot(newface, flipshs[i]);
+      if (flipshs[i].sh != NULL) {
+        spivot = i; // Remember this subface.
+        scount++;
+      }
+      enextself(fliptets[3]);
+    }
+    if (scount > 0) {
+      // There are three subfaces connecting at p.
+      if (scount < 3) {
+        // The new subface is one of {[a,b,d], [b,c,d], [c,a,d]}.
+        assert(scount == 1); // spivot >= 0
+        // Go to the tet containing the three subfaces.
+        fsym(topcastets[spivot], neightet);
+        // Get the three subfaces connecting at p.
+        for (i = 0; i < 3; i++) {
+          esym(neightet, newface);
+          tspivot(newface, flipshs[i]);
+          assert(flipshs[i].sh != NULL);
+          eprevself(neightet);
+        }
+      } else {
+        spivot = 3; // The new subface is [a,b,c].
+      }
+    }
+  } // if (checksubfaceflag)
+
+
+  // Re-use fliptets[0] for [a,b,c,d].
+  fliptets[0].ver = 11;
+  setelemmarker(fliptets[0].tet, 0); // Clean all flags.
+  // NOTE: the element attributes and volume constraint remain unchanged.
+  if (checksubsegflag) {
+    // Dealloc the space to subsegments.
+    if (fliptets[0].tet[8] != NULL) {
+      tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
+      fliptets[0].tet[8] = NULL;
+    }
+  }
+  if (checksubfaceflag) {
+    // Dealloc the space to subfaces.
+    if (fliptets[0].tet[9] != NULL) {
+      tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
+      fliptets[0].tet[9] = NULL;
+    }
+  }
+  // Delete the other three tets.
+  for (i = 1; i < 4; i++) {
+    tetrahedrondealloc(fliptets[i].tet);
+  }
+
+  if (pp != dummypoint) {
+    // Mark the point pp as unused.
+    setpointtype(pp, UNUSEDVERTEX);
+    unuverts++;
+  }
+
+  // Create the new tet [a,b,c,d].
+  if (hullflag > 0) {
+    // One of the five vertices may be 'dummypoint'.
+    if (pa == dummypoint) {
+      // pa is dummypoint.
+      setvertices(fliptets[0], pc, pb, pd, pa);
+      esymself(fliptets[0]);  // [b,c,a,d]
+      eprevself(fliptets[0]); // [a,b,c,d]
+      dummyflag = 1;
+    } else if (pb == dummypoint) {
+      setvertices(fliptets[0], pa, pc, pd, pb);
+      esymself(fliptets[0]);  // [c,a,b,d]
+      enextself(fliptets[0]); // [a,b,c,d]
+      dummyflag = 2;
+    } else if (pc == dummypoint) {
+      setvertices(fliptets[0], pb, pa, pd, pc);
+      esymself(fliptets[0]);  // [a,b,c,d]
+      dummyflag = 3;
+    } else if (pd == dummypoint) {
+      setvertices(fliptets[0], pa, pb, pc, pd);
+      dummyflag = 4;
+    } else {
+      setvertices(fliptets[0], pa, pb, pc, pd);
+      if (pp == dummypoint) {
+        dummyflag = -1;
+      } else {
+        dummyflag = 0;
+      }
+    }
+    if (dummyflag > 0) {
+      // We deleted 3 hull tets, and create 1 hull tet.
+      hullsize -= 2;
+    } else if (dummyflag < 0) {
+      // We deleted 4 hull tets.
+      hullsize -= 4;
+      // meshedges does not change.
+    }
+  } else {
+    setvertices(fliptets[0], pa, pb, pc, pd);
+  }
+
+  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
+    REAL volneg[4], volpos[1], vol_diff;
+    if (dummyflag > 0) {
+      if (pa == dummypoint) {
+        volneg[0] = 0.;
+        volneg[1] = tetprismvol(pp, pd, pb, pc);
+        volneg[2] = 0.;
+        volneg[3] = 0.;
+      } else if (pb == dummypoint) {
+        volneg[0] = 0.;
+        volneg[1] = 0.;
+        volneg[2] = tetprismvol(pp, pd, pc, pa);
+        volneg[3] = 0.;
+      } else if (pc == dummypoint) {
+        volneg[0] = tetprismvol(pp, pd, pa, pb);
+        volneg[1] = 0.;
+        volneg[2] = 0.;
+        volneg[3] = 0.;
+      } else { // pd == dummypoint
+        volneg[0] = 0.;
+        volneg[1] = 0.;
+        volneg[2] = 0.;
+        volneg[3] = tetprismvol(pa, pb, pc, pp);
+      }
+      volpos[0] = 0.;
+    } else if (dummyflag < 0) {
+      volneg[0] = 0.;
+      volneg[1] = 0.;
+      volneg[2] = 0.;
+      volneg[3] = 0.;
+      volpos[0] = tetprismvol(pa, pb, pc, pd);
+    } else {
+      volneg[0] = tetprismvol(pp, pd, pa, pb);
+      volneg[1] = tetprismvol(pp, pd, pb, pc);
+      volneg[2] = tetprismvol(pp, pd, pc, pa);
+      volneg[3] = tetprismvol(pa, pb, pc, pp);
+      volpos[0] = tetprismvol(pa, pb, pc, pd);
+    }
+    vol_diff = volpos[0] - volneg[0] - volneg[1] - volneg[2] - volneg[3];
+    fc->tetprism_vol_sum  += vol_diff; // Update the total sum.
+  }
+
+  // Bond the new tet to adjacent tets.
+  for (i = 0; i < 3; i++) {
+    esym(fliptets[0], newface); // At faces [b,a,d], [c,b,d], [a,c,d].
+    bond(newface, topcastets[i]);
+    enextself(fliptets[0]);
+  }
+  bond(fliptets[0], botcastet);
+
+  if (checksubsegflag) {
+    face checkseg;
+    // Bond 6 segments (at edges of [a,b,c,d]) if there there are.
+    for (i = 0; i < 3; i++) {
+      eprev(topcastets[i], newface); // At edges [d,a],[d,b],[d,c].
+      if (issubseg(newface)) {
+        tsspivot1(newface, checkseg);
+        esym(fliptets[0], newface);
+        enextself(newface); // At edges [a,d], [b,d], [c,d].
+        tssbond1(newface, checkseg);
+        sstbond1(checkseg, newface);
+        if (fc->chkencflag & 1) {
+          enqueuesubface(badsubsegs, &checkseg);
+        }
+      }
+      enextself(fliptets[0]);
+    }
+    for (i = 0; i < 3; i++) {
+      if (issubseg(topcastets[i])) {
+        tsspivot1(topcastets[i], checkseg); // At edges [a,b],[b,c],[c,a].
+        tssbond1(fliptets[0], checkseg);
+        sstbond1(checkseg, fliptets[0]);
+        if (fc->chkencflag & 1) {
+          enqueuesubface(badsubsegs, &checkseg);
+        }
+      }
+      enextself(fliptets[0]);
+    }
+  }
+
+  if (checksubfaceflag) {
+    face checksh;
+    // Bond 4 subfaces (at faces of [a,b,c,d]) if there are.
+    for (i = 0; i < 3; i++) {
+      if (issubface(topcastets[i])) {
+        tspivot(topcastets[i], checksh); // At faces [a,b,d],[b,c,d],[c,a,d]
+        esym(fliptets[0], newface); // At faces [b,a,d],[c,b,d],[a,c,d]
+        sesymself(checksh);
+        tsbond(newface, checksh);
+        if (fc->chkencflag & 2) {
+          enqueuesubface(badsubfacs, &checksh);
+        }
+      }
+      enextself(fliptets[0]);
+    }
+    if (issubface(botcastet)) {
+      tspivot(botcastet, checksh); // At face [b,a,c]
+      sesymself(checksh);
+      tsbond(fliptets[0], checksh);
+      if (fc->chkencflag & 2) {
+        enqueuesubface(badsubfacs, &checksh);
+      }
+    }
+
+    if (spivot >= 0) {
+      // Perform a 3-to-1 flip in surface triangulation.
+      // Depending on the value of 'spivot', the three subfaces are:
+      //   - 0: [a,b,p], [b,d,p], [d,a,p]
+      //   - 1: [b,c,p], [c,d,p], [d,b,p] 
+      //   - 2: [c,a,p], [a,d,p], [d,c,p] 
+      //   - 3: [a,b,p], [b,c,p], [c,a,p]
+      // Adjust the three subfaces such that their origins are p, i.e., 
+      //   - 3: [p,a,b], [p,b,c], [p,c,a]. (Required by the flip31()).
+      for (i = 0; i < 3; i++) {
+        senext2self(flipshs[i]);
+      }
+      flip31(flipshs, 0);
+      // Delete the three old subfaces.
+      for (i = 0; i < 3; i++) {
+        shellfacedealloc(subfaces, flipshs[i].sh);
+      }
+      if (spivot < 3) {
+        // // Bond the new subface to the new tet [a,b,c,d].
+        tsbond(topcastets[spivot], flipshs[3]);
+        fsym(topcastets[spivot], newface);
+        sesym(flipshs[3], checksh);
+        tsbond(newface, checksh);
+      } else {
+        // Bound the new subface [a,b,c] to the new tet [a,b,c,d].
+        tsbond(fliptets[0], flipshs[3]);
+        fsym(fliptets[0], newface);
+        sesym(flipshs[3], checksh);
+        tsbond(newface, checksh);
+      }
+    } // if (spivot > 0)
+  } // if (checksubfaceflag)
+
+  if (fc->chkencflag & 4) {
+    enqueuetetrahedron(&(fliptets[0]));
+  }
+
+  // Update the point-to-tet map.
+  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pc, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
+
+  if (fc->enqflag > 0) {
+    // Queue faces which may be locally non-Delaunay.
+    flippush(flipstack, &(fliptets[0])); // [a,b,c] (opposite to new point).
+    if (fc->enqflag > 1) {
+      for (i = 0; i < 3; i++) {
+        esym(fliptets[0], newface);
+        flippush(flipstack, &newface);
+        enextself(fliptets[0]);
+      }
+    }
+  }
+
+  recenttet = fliptets[0];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flipnm()    Flip an edge through a sequence of elementary flips.          //
+//                                                                           //
+// 'abtets' is an array of 'n' tets in the star of edge [a,b].These tets are //
+// ordered in a counterclockwise cycle with respect to the vector a->b, i.e.,//
+// use the right-hand rule.                                                  //
+//                                                                           //
+// 'level' (>= 0) indicates the current link level. If 'level > 0', we are   //
+// flipping a link edge of an edge [a',b'],  and 'abedgepivot' indicates     //
+// which link edge, i.e., [c',b'] or [a',c'], is [a,b]  These two parameters //
+// allow us to determine the new tets after a 3-to-2 flip, i.e., tets that   //
+// do not inside the reduced star of edge [a',b'].                           //
+//                                                                           //
+// If the flag 'fc->unflip' is set, this routine un-does the flips performed //
+// in flipnm([a,b]) so that the mesh is returned to its original state       //
+// before doing the flipnm([a,b]) operation.                                 //
+//                                                                           //
+// The return value is an integer nn, where nn <= n.  If nn is 2, then the   //
+// edge is flipped.  The first and the second tets in 'abtets' are new tets. //
+// Otherwise, nn > 2, the edge is not flipped, and nn is the number of tets  //
+// in the current star of [a,b].                                             //
+//                                                                           //
+// ASSUMPTIONS:                                                              //
+//  - Neither a nor b is 'dummypoint'.                                       //
+//  - [a,b] must not be a segment.                                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
+                       flipconstraints* fc)
+{
+  triface fliptets[3], spintet, flipedge;
+  triface *tmpabtets, *parytet;
+  point pa, pb, pc, pd, pe, pf;
+  REAL ori;
+  int hullflag, hulledgeflag;
+  int reducflag, rejflag;
+  int reflexlinkedgecount;
+  int edgepivot;
+  int n1, nn;
+  int t1ver;
+  int i, j;
+
+  pa = org(abtets[0]);
+  pb = dest(abtets[0]);
+
+  if (n > 3) {
+    // Try to reduce the size of the Star(ab) by flipping a face in it. 
+    reflexlinkedgecount = 0;
+
+    for (i = 0; i < n; i++) {
+      // Let the face of 'abtets[i]' be [a,b,c].
+      if (checksubfaceflag) {
+        if (issubface(abtets[i])) {
+          continue; // Skip a subface.
+        }
+      }
+      // Do not flip this face if it is involved in two Stars.
+      if ((elemcounter(abtets[i]) > 1) ||
+          (elemcounter(abtets[(i - 1 + n) % n]) > 1)) {
+        continue;
+      }
+
+      pc = apex(abtets[i]); 
+      pd = apex(abtets[(i + 1) % n]);
+      pe = apex(abtets[(i - 1 + n) % n]);
+      if ((pd == dummypoint) || (pe == dummypoint)) {
+        continue; // [a,b,c] is a hull face.
+      }
+
+
+      // Decide whether [a,b,c] is flippable or not.
+      reducflag = 0; 
+
+      hullflag = (pc == dummypoint); // pc may be dummypoint.
+      hulledgeflag = 0;
+      if (hullflag == 0) {
+        ori = orient3d(pb, pc, pd, pe); // Is [b,c] locally convex?
+        if (ori > 0) {
+          ori = orient3d(pc, pa, pd, pe); // Is [c,a] locally convex?
+          if (ori > 0) {
+            // Test if [a,b] is locally convex OR flat.
+            ori = orient3d(pa, pb, pd, pe);
+            if (ori > 0) {
+              // Found a 2-to-3 flip: [a,b,c] => [e,d]
+              reducflag = 1;
+            } else if (ori == 0) {
+              // [a,b] is flat.
+              if (n == 4) {
+                // The "flat" tet can be removed immediately by a 3-to-2 flip.
+                reducflag = 1;
+                // Check if [e,d] is a hull edge.
+                pf = apex(abtets[(i + 2) % n]);
+                hulledgeflag = (pf == dummypoint);
+              }
+            }
+          }
+        }
+        if (!reducflag) {
+          reflexlinkedgecount++;
+        }
+      } else {
+        // 'c' is dummypoint.
+        if (n == 4) {
+          // Let the vertex opposite to 'c' is 'f'.
+          // A 4-to-4 flip is possible if the two tets [d,e,f,a] and [e,d,f,b]
+          //   are valid tets. 
+          // Note: When the mesh is not convex, it is possible that [a,b] is
+          //   locally non-convex (at hull faces [a,b,e] and [b,a,d]).
+          //   In this case, an edge flip [a,b] to [e,d] is still possible.
+          pf = apex(abtets[(i + 2) % n]);
+          assert(pf != dummypoint);
+          ori = orient3d(pd, pe, pf, pa);
+          if (ori < 0) {
+            ori = orient3d(pe, pd, pf, pb);
+            if (ori < 0) {
+              // Found a 4-to-4 flip: [a,b] => [e,d]
+              reducflag = 1;
+              ori = 0; // Signal as a 4-to-4 flip (like a co-planar case).
+              hulledgeflag = 1; // [e,d] is a hull edge.
+            }
+          }
+        }
+      } // if (hullflag)
+
+      if (reducflag) {
+        if (nonconvex && hulledgeflag) {
+          // We will create a hull edge [e,d]. Make sure it does not exist.
+          if (getedge(pe, pd, &spintet)) {
+            // The 2-to-3 flip is not a topological valid flip. 
+            reducflag = 0;
+          }
+        }
+      }
+
+      if (reducflag) {
+        // [a,b,c] could be removed by a 2-to-3 flip.
+        rejflag = 0;
+        if (fc->checkflipeligibility) {
+          // Check if the flip can be performed.
+          rejflag = checkflipeligibility(1, pa, pb, pc, pd, pe, level,
+                                         abedgepivot, fc);
+        }
+        if (!rejflag) {
+          // Do flip: [a,b,c] => [e,d].
+          fliptets[0] = abtets[i];
+          fsym(fliptets[0], fliptets[1]); // abtets[i-1].
+          flip23(fliptets, hullflag, fc);
+
+          // Shrink the array 'abtets', maintain the original order.
+          //   Two tets 'abtets[i-1] ([a,b,e,c])' and 'abtets[i] ([a,b,c,d])'
+          //   are flipped, i.e., they do not in Star(ab) anymore. 
+          //   'fliptets[0]' ([e,d,a,b]) is in Star(ab), it is saved in
+          //   'abtets[i-1]' (adjust it to be [a,b,e,d]), see below: 
+          // 
+          //            before                   after
+          //     [0] |___________|        [0] |___________| 
+          //     ... |___________|        ... |___________|
+          //   [i-1] |_[a,b,e,c]_|      [i-1] |_[a,b,e,d]_|
+          //     [i] |_[a,b,c,d]_| -->    [i] |_[a,b,d,#]_|
+          //   [i+1] |_[a,b,d,#]_|      [i+1] |_[a,b,#,*]_|
+          //     ... |___________|        ... |___________|
+          //   [n-2] |___________|      [n-2] |___________| 
+          //   [n-1] |___________|      [n-1] |_[i]_2-t-3_|
+          //
+          edestoppoself(fliptets[0]); // [a,b,e,d]
+          // Increase the counter of this new tet (it is in Star(ab)).
+          increaseelemcounter(fliptets[0]); 
+          abtets[(i - 1 + n) % n] = fliptets[0];
+          for (j = i; j < n - 1; j++) {
+            abtets[j] = abtets[j + 1];  // Upshift
+          }
+          // The last entry 'abtets[n-1]' is empty. It is used in two ways:
+          //   (i) it remembers the vertex 'c' (in 'abtets[n-1].tet'), and
+          //  (ii) it remembers the position [i] where this flip took place.
+          // These informations let us to either undo this flip or recover
+          //   the original edge link (for collecting new created tets).
+          //abtets[n - 1] = fliptets[1]; // [e,d,b,c] is remembered.
+          abtets[n - 1].tet = (tetrahedron *) pc;
+          abtets[n - 1].ver = 0; // Clear it.
+          // 'abtets[n - 1].ver' is in range [0,11] -- only uses 4 bits.
+          // Use the 5th bit in 'abtets[n - 1].ver' to signal a 2-to-3 flip.
+          abtets[n - 1].ver |= (1 << 4);
+          // The poisition [i] of this flip is saved above the 7th bit.
+          abtets[n - 1].ver |= (i << 6);
+
+          if (fc->collectnewtets) {
+            // Push the two new tets [e,d,b,c] and [e,d,c,a] into a stack.
+            //   Re-use the global array 'cavetetlist'.
+            for (j = 1; j < 3; j++) {
+              cavetetlist->newindex((void **) &parytet);
+              *parytet = fliptets[j]; // fliptets[1], fliptets[2].
+            }
+          }
+
+          // Star(ab) is reduced. Try to flip the edge [a,b].
+          nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
+
+          if (nn == 2) {
+            // The edge has been flipped.
+            return nn;
+          } else { // if (nn > 2)
+            // The edge is not flipped.
+            if (fc->unflip || (ori == 0)) {
+              // Undo the previous 2-to-3 flip, i.e., do a 3-to-2 flip to 
+              //   transform [e,d] => [a,b,c].
+              // 'ori == 0' means that the previous flip created a degenerated
+              //   tet. It must be removed. 
+              // Remember that 'abtets[i-1]' is [a,b,e,d]. We can use it to
+              //   find another two tets [e,d,b,c] and [e,d,c,a].
+              fliptets[0] = abtets[(i-1 + (n-1)) % (n-1)]; // [a,b,e,d]
+              edestoppoself(fliptets[0]); // [e,d,a,b]
+              fnext(fliptets[0], fliptets[1]); // [1] is [e,d,b,c]
+              fnext(fliptets[1], fliptets[2]); // [2] is [e,d,c,a]
+              assert(apex(fliptets[0]) == oppo(fliptets[2])); // SELF_CHECK
+              // Restore the two original tets in Star(ab). 
+              flip32(fliptets, hullflag, fc);
+              // Marktest the two restored tets in Star(ab).
+              for (j = 0; j < 2; j++) {
+                increaseelemcounter(fliptets[j]);
+              }
+              // Expand the array 'abtets', maintain the original order.
+              for (j = n - 2; j>= i; j--) {
+                abtets[j + 1] = abtets[j];  // Downshift
+              }
+              // Insert the two new tets 'fliptets[0]' [a,b,c,d] and 
+              //  'fliptets[1]' [b,a,c,e] into the (i-1)-th and i-th entries, 
+              //  respectively.
+              esym(fliptets[1], abtets[(i - 1 + n) % n]); // [a,b,e,c]
+              abtets[i] = fliptets[0]; // [a,b,c,d]
+              nn++;
+              if (fc->collectnewtets) {
+                // Pop two (flipped) tets from the stack.
+                cavetetlist->objects -= 2;
+              }
+            } // if (unflip || (ori == 0))
+          } // if (nn > 2)
+
+          if (!fc->unflip) {
+            // The flips are not reversed. The current Star(ab) can not be
+            //   further reduced. Return its current size (# of tets).
+            return nn; 
+          }
+          // unflip is set. 
+          // Continue the search for flips.
+        }
+      } // if (reducflag)
+    } // i
+
+    // The Star(ab) is not reduced. 
+    if (reflexlinkedgecount > 0) {
+      // There are reflex edges in the Link(ab).
+      if (((b->fliplinklevel < 0) && (level < autofliplinklevel)) || 
+          ((b->fliplinklevel >= 0) && (level < b->fliplinklevel))) {
+        // Try to reduce the Star(ab) by flipping a reflex edge in Link(ab).
+        for (i = 0; i < n; i++) {
+          // Do not flip this face [a,b,c] if there are two Stars involved.
+          if ((elemcounter(abtets[i]) > 1) ||
+              (elemcounter(abtets[(i - 1 + n) % n]) > 1)) {
+            continue;
+          }
+          pc = apex(abtets[i]);
+          if (pc == dummypoint) {
+            continue; // [a,b] is a hull edge.
+          }
+          pd = apex(abtets[(i + 1) % n]);
+          pe = apex(abtets[(i - 1 + n) % n]);
+          if ((pd == dummypoint) || (pe == dummypoint)) {
+            continue; // [a,b,c] is a hull face.
+          }
+
+
+          edgepivot = 0; // No edge is selected yet.
+
+          // Test if [b,c] is locally convex or flat.
+          ori = orient3d(pb, pc, pd, pe);
+          if (ori <= 0) {
+            // Select the edge [c,b].
+            enext(abtets[i], flipedge); // [b,c,a,d]
+            edgepivot = 1;
+          }
+          if (!edgepivot) {
+            // Test if [c,a] is locally convex or flat.
+            ori = orient3d(pc, pa, pd, pe);
+            if (ori <= 0) {
+              // Select the edge [a,c].
+              eprev(abtets[i], flipedge); // [c,a,b,d].
+              edgepivot = 2;
+            }
+          }
+
+          if (!edgepivot) continue;
+
+          // An edge is selected.
+          if (checksubsegflag) {
+            // Do not flip it if it is a segment.
+            if (issubseg(flipedge)) {
+              if (fc->collectencsegflag) {
+                face checkseg, *paryseg;
+                tsspivot1(flipedge, checkseg);
+                if (!sinfected(checkseg)) {
+                  // Queue this segment in list.
+                  sinfect(checkseg);                
+                  caveencseglist->newindex((void **) &paryseg);
+                  *paryseg = checkseg;
+                }
+              }
+              continue;
+            }
+          }
+
+          // Try to flip the selected edge ([c,b] or [a,c]).
+          esymself(flipedge); 
+          // Count the number of tets at the edge.
+          n1 = 0;
+          j = 0; // Sum of the star counters.
+          spintet = flipedge;
+          while (1) {
+            n1++;
+            j += (elemcounter(spintet)); 
+            fnextself(spintet);
+            if (spintet.tet == flipedge.tet) break;
+          }
+          assert(n1 >= 3);
+          if (j > 2) {
+            // The Star(flipedge) overlaps other Stars.
+            continue; // Do not flip this edge.
+          }
+          // Only two tets can be marktested.
+          assert(j == 2); 
+
+          if ((b->flipstarsize > 0) && (n1 > b->flipstarsize)) {
+            // The star size exceeds the given limit.
+            continue; // Do not flip it.
+          }
+
+          // Allocate spaces for Star(flipedge).
+          tmpabtets = new triface[n1];
+          // Form the Star(flipedge).
+          j = 0;
+          spintet = flipedge;
+          while (1) {
+            tmpabtets[j] = spintet;
+            // Increase the star counter of this tet.
+            increaseelemcounter(tmpabtets[j]); 
+            j++;
+            fnextself(spintet);
+            if (spintet.tet == flipedge.tet) break;
+          }
+
+          // Try to flip the selected edge away.
+          nn = flipnm(tmpabtets, n1, level + 1, edgepivot, fc);
+
+          if (nn == 2) {
+            // The edge is flipped. Star(ab) is reduced.
+            // Shrink the array 'abtets', maintain the original order.
+            if (edgepivot == 1) {
+              // 'tmpabtets[0]' is [d,a,e,b] => contains [a,b].
+              spintet = tmpabtets[0]; // [d,a,e,b]
+              enextself(spintet);
+              esymself(spintet);
+              enextself(spintet); // [a,b,e,d]
+            } else {
+              // 'tmpabtets[1]' is [b,d,e,a] => contains [a,b].
+              spintet = tmpabtets[1]; // [b,d,e,a]
+              eprevself(spintet);
+              esymself(spintet);
+              eprevself(spintet); // [a,b,e,d]
+            } // edgepivot == 2
+            assert(elemcounter(spintet) == 0); // It's a new tet.
+            increaseelemcounter(spintet); // It is in Star(ab).
+            // Put the new tet at [i-1]-th entry.
+            abtets[(i - 1 + n) % n] = spintet;
+            for (j = i; j < n - 1; j++) {
+              abtets[j] = abtets[j + 1];  // Upshift
+            }
+            // Remember the flips in the last entry of the array 'abtets'.
+            // They can be used to recover the flipped edge.
+            abtets[n - 1].tet = (tetrahedron *) tmpabtets; // The star(fedge).
+            abtets[n - 1].ver = 0; // Clear it.
+            // Use the 1st and 2nd bit to save 'edgepivot' (1 or 2).
+            abtets[n - 1].ver |= edgepivot;
+            // Use the 6th bit to signal this n1-to-m1 flip.
+            abtets[n - 1].ver |= (1 << 5); 
+            // The poisition [i] of this flip is saved from 7th to 19th bit.
+            abtets[n - 1].ver |= (i << 6);
+            // The size of the star 'n1' is saved from 20th bit.
+            abtets[n - 1].ver |= (n1 << 19);
+
+            // Remember the flipped link vertex 'c'. It can be used to recover
+            //   the original edge link of [a,b], and to collect new tets.
+            tmpabtets[0].tet = (tetrahedron *) pc;
+            tmpabtets[0].ver = (1 << 5); // Flag it as a vertex handle.
+
+            // Continue to flip the edge [a,b].
+            nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
+
+            if (nn == 2) { 
+              // The edge has been flipped.
+              return nn;
+            } else { // if (nn > 2) {
+              // The edge is not flipped.
+              if (fc->unflip) {
+                // Recover the flipped edge ([c,b] or [a,c]).
+                assert(nn == (n - 1));
+                // The sequence of flips are saved in 'tmpabtets'. 
+                // abtets[(i-1) % (n-1)] is [a,b,e,d], i.e., the tet created by
+                //   the flipping of edge [c,b] or [a,c].It must still exist in
+                //   Star(ab). It is the start tet to recover the flipped edge.
+                if (edgepivot == 1) { 
+                  // The flip edge is [c,b].
+                  tmpabtets[0] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d]
+                  eprevself(tmpabtets[0]);
+                  esymself(tmpabtets[0]);
+                  eprevself(tmpabtets[0]); // [d,a,e,b]
+                  fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c]
+                } else {
+                  // The flip edge is [a,c].
+                  tmpabtets[1] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d]
+                  enextself(tmpabtets[1]);
+                  esymself(tmpabtets[1]);
+                  enextself(tmpabtets[1]); // [b,d,e,a]
+                  fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c]
+                } // if (edgepivot == 2)
+
+                // Recover the flipped edge ([c,b] or [a,c]).
+                flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
+
+                // Insert the two recovered tets into Star(ab).
+                for (j = n - 2; j >= i; j--) {
+                  abtets[j + 1] = abtets[j];  // Downshift
+                }
+                if (edgepivot == 1) {
+                  // tmpabtets[0] is [c,b,d,a] ==> contains [a,b]
+                  // tmpabtets[1] is [c,b,a,e] ==> contains [a,b]
+                  // tmpabtets[2] is [c,b,e,d]
+                  fliptets[0] = tmpabtets[1];
+                  enextself(fliptets[0]);
+                  esymself(fliptets[0]); // [a,b,e,c]
+                  fliptets[1] = tmpabtets[0];
+                  esymself(fliptets[1]);
+                  eprevself(fliptets[1]); // [a,b,c,d]
+                } else {
+                  // tmpabtets[0] is [a,c,d,b] ==> contains [a,b]
+                  // tmpabtets[1] is [a,c,b,e] ==> contains [a,b]
+                  // tmpabtets[2] is [a,c,e,d]
+                  fliptets[0] = tmpabtets[1];
+                  eprevself(fliptets[0]);
+                  esymself(fliptets[0]); // [a,b,e,c]
+                  fliptets[1] = tmpabtets[0];
+                  esymself(fliptets[1]);
+                  enextself(fliptets[1]); // [a,b,c,d]
+                } // edgepivot == 2
+                for (j = 0; j < 2; j++) {
+                  increaseelemcounter(fliptets[j]);
+                }
+                // Insert the two recovered tets into Star(ab).
+                abtets[(i - 1 + n) % n] = fliptets[0];
+                abtets[i] = fliptets[1];
+                nn++;
+                // Release the allocated spaces.
+                delete [] tmpabtets;
+              } // if (unflip)
+            } // if (nn > 2)
+
+            if (!fc->unflip) {
+              // The flips are not reversed. The current Star(ab) can not be
+              //   further reduced. Return its size (# of tets).
+              return nn; 
+            }
+            // unflip is set. 
+            // Continue the search for flips.
+          } else {
+            // The selected edge is not flipped.
+            if (fc->unflip) {
+              // The memory should already be freed.
+              assert(nn == n1);
+            } else {
+              // Release the memory used in this attempted flip.
+              flipnm_post(tmpabtets, n1, nn, edgepivot, fc);
+            }
+            // Decrease the star counters of tets in Star(flipedge).
+            for (j = 0; j < nn; j++) {
+              assert(elemcounter(tmpabtets[j]) > 0); // SELF_CHECK
+              decreaseelemcounter(tmpabtets[j]);
+            }
+            // Release the allocated spaces.
+            delete [] tmpabtets;
+          }
+        } // i
+      } // if (level...)
+    } // if (reflexlinkedgecount > 0)
+  } else {
+    // Check if a 3-to-2 flip is possible.
+    // Let the three apexes be c, d,and e. Hull tets may be involved. If so, 
+    //   we rearrange them such that the vertex e is dummypoint. 
+    hullflag = 0;
+
+    if (apex(abtets[0]) == dummypoint) {
+      pc = apex(abtets[1]);
+      pd = apex(abtets[2]);
+      pe = apex(abtets[0]);
+      hullflag = 1;
+    } else if (apex(abtets[1]) == dummypoint) {
+      pc = apex(abtets[2]);
+      pd = apex(abtets[0]);
+      pe = apex(abtets[1]);
+      hullflag = 2;
+    } else {
+      pc = apex(abtets[0]);
+      pd = apex(abtets[1]);
+      pe = apex(abtets[2]);
+      hullflag = (pe == dummypoint) ? 3 : 0;
+    }
+
+    reducflag = 0;
+    rejflag = 0;
+
+
+    if (hullflag == 0) {
+      // Make sure that no inverted tet will be created, i.e. the new tets
+      //   [d,c,e,a] and [c,d,e,b] must be valid tets. 
+      ori = orient3d(pd, pc, pe, pa);
+      if (ori < 0) {
+        ori = orient3d(pc, pd, pe, pb);
+        if (ori < 0) {
+          reducflag = 1;
+        }
+      }
+    } else {
+      // [a,b] is a hull edge.
+      //   Note: This can happen when it is in the middle of a 4-to-4 flip.
+      //   Note: [a,b] may even be a non-convex hull edge.
+      if (!nonconvex) {
+        //  The mesh is convex, only do flip if it is a coplanar hull edge.
+        ori = orient3d(pa, pb, pc, pd); 
+        if (ori == 0) {
+          reducflag = 1;
+        }
+      } else { // nonconvex
+        reducflag = 1;
+      }
+      if (reducflag == 1) {
+        // [a,b], [a,b,c] and [a,b,d] are on the convex hull.
+        // Make sure that no inverted tet will be created.
+        point searchpt = NULL, chkpt;
+        REAL bigvol = 0.0, ori1, ori2;
+        // Search an interior vertex which is an apex of edge [c,d].
+        //   In principle, it can be arbitrary interior vertex.  To avoid
+        //   numerical issue, we choose the vertex which belongs to a tet
+        //   't' at edge [c,d] and 't' has the biggest volume.  
+        fliptets[0] = abtets[hullflag % 3]; // [a,b,c,d].
+        eorgoppoself(fliptets[0]);  // [d,c,b,a]
+        spintet = fliptets[0];
+        while (1) {
+          fnextself(spintet);
+          chkpt = oppo(spintet);
+          if (chkpt == pb) break;
+          if ((chkpt != dummypoint) && (apex(spintet) != dummypoint)) {
+            ori = -orient3d(pd, pc, apex(spintet), chkpt);
+            assert(ori > 0);
+            if (ori > bigvol) {
+              bigvol = ori;
+              searchpt = chkpt;
+            }
+          }
+        }
+        if (searchpt != NULL) { 
+          // Now valid the configuration.
+          ori1 = orient3d(pd, pc, searchpt, pa);
+          ori2 = orient3d(pd, pc, searchpt, pb);
+          if (ori1 * ori2 >= 0.0) {
+            reducflag = 0; // Not valid. 
+          } else {
+            ori1 = orient3d(pa, pb, searchpt, pc);
+            ori2 = orient3d(pa, pb, searchpt, pd);
+            if (ori1 * ori2 >= 0.0) {
+              reducflag = 0; // Not valid.
+            }
+          }
+        } else {
+          // No valid searchpt is found.
+          reducflag = 0; // Do not flip it.
+        }
+      } // if (reducflag == 1)
+    } // if (hullflag == 1)
+
+    if (reducflag) {
+      // A 3-to-2 flip is possible.
+      if (checksubfaceflag) {
+        // This edge (must not be a segment) can be flipped ONLY IF it belongs
+        //   to either 0 or 2 subfaces.  In the latter case, a 2-to-2 flip in 
+        //   the surface mesh will be automatically performed within the 
+        //   3-to-2 flip.
+        nn = 0;
+        edgepivot = -1; // Re-use it.
+        for (j = 0; j < 3; j++) {
+          if (issubface(abtets[j])) {
+            nn++; // Found a subface.
+          } else {
+            edgepivot = j;
+          }
+        }
+        assert(nn < 3);
+        if (nn == 1) {
+          // Found only 1 subface containing this edge. This can happen in 
+          //   the boundary recovery phase. The neighbor subface is not yet 
+          //   recovered. This edge should not be flipped at this moment.
+          rejflag = 1; 
+        } else if (nn == 2) {
+          // Found two subfaces. A 2-to-2 flip is possible. Validate it.
+          // Below we check if the two faces [p,q,a] and [p,q,b] are subfaces.
+          eorgoppo(abtets[(edgepivot + 1) % 3], spintet); // [q,p,b,a]
+          if (issubface(spintet)) {
+            rejflag = 1; // Conflict to a 2-to-2 flip.
+          } else {
+            esymself(spintet);
+            if (issubface(spintet)) {
+              rejflag = 1; // Conflict to a 2-to-2 flip.
+            }
+          }
+        }
+      }
+      if (!rejflag && fc->checkflipeligibility) {
+        // Here we must exchange 'a' and 'b'. Since in the check... function,
+        //   we assume the following point sequence, 'a,b,c,d,e', where
+        //   the face [a,b,c] will be flipped and the edge [e,d] will be
+        //   created. The two new tets are [a,b,c,d] and [b,a,c,e]. 
+        rejflag = checkflipeligibility(2, pc, pd, pe, pb, pa, level, 
+                                       abedgepivot, fc);
+      }
+      if (!rejflag) {
+        // Do flip: [a,b] => [c,d,e]
+        flip32(abtets, hullflag, fc);
+        if (fc->remove_ndelaunay_edge) {
+          if (level == 0) {
+            // It is the desired removing edge. Check if we have improved
+            //   the objective function.
+            if ((fc->tetprism_vol_sum >= 0.0) ||
+                (fabs(fc->tetprism_vol_sum) < fc->bak_tetprism_vol)) {
+              // No improvement! flip back: [c,d,e] => [a,b].
+              flip23(abtets, hullflag, fc);
+              // Increase the element counter -- They are in cavity.
+              for (j = 0; j < 3; j++) {
+                increaseelemcounter(abtets[j]); 
+              }
+              return 3;
+            }
+          } // if (level == 0)
+        }
+        if (fc->collectnewtets) {
+          // Collect new tets.
+          if (level == 0) {
+            // Push the two new tets into stack.
+            for (j = 0; j < 2; j++) {
+              cavetetlist->newindex((void **) &parytet);
+              *parytet = abtets[j];
+            }
+          } else {
+            // Only one of the new tets is collected. The other one is inside
+            //   the reduced edge star. 'abedgepivot' is either '1' or '2'.
+            cavetetlist->newindex((void **) &parytet);
+            if (abedgepivot == 1) { // [c,b]
+              *parytet = abtets[1];
+            } else { 
+              assert(abedgepivot == 2); // [a,c]
+              *parytet = abtets[0];
+            }
+          }
+        } // if (fc->collectnewtets)
+        return 2;
+      }
+    } // if (reducflag)
+  } // if (n == 3)
+
+  // The current (reduced) Star size.
+  return n;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flipnm_post()    Post process a n-to-m flip.                              //
+//                                                                           //
+// IMPORTANT: This routine only works when there is no other flip operation  //
+// is done after flipnm([a,b]) which attempts to remove an edge [a,b].       //
+//                                                                           //
+// 'abtets' is an array of 'n' (>= 3) tets which are in the original star of //
+// [a,b] before flipnm([a,b]).  'nn' (< n) is the value returned by flipnm.  //
+// If 'nn == 2', the edge [a,b] has been flipped. 'abtets[0]' and 'abtets[1]'//
+// are [c,d,e,b] and [d,c,e,a], i.e., a 2-to-3 flip can recover the edge [a, //
+// b] and its initial Star([a,b]).  If 'nn >= 3' edge [a,b] still exists in  //
+// current mesh and 'nn' is the current number of tets in Star([a,b]).       //
+//                                                                           //
+// Each 'abtets[i]', where nn <= i < n, saves either a 2-to-3 flip or a      //
+// flipnm([p1,p2]) operation ([p1,p2] != [a,b]) which created the tet        //
+// 'abtets[t-1]', where '0 <= t <= i'.  These information can be used to     //
+// undo the flips performed in flipnm([a,b]) or to collect new tets created  //
+// by the flipnm([a,b]) operation.                                           //
+//                                                                           //
+// Default, this routine only walks through the flips and frees the spaces   //
+// allocated during the flipnm([a,b]) operation.                             //
+//                                                                           //
+// If the flag 'fc->unflip' is set, this routine un-does the flips performed //
+// in flipnm([a,b]) so that the mesh is returned to its original state       //
+// before doing the flipnm([a,b]) operation.                                 //
+//                                                                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::flipnm_post(triface* abtets, int n, int nn, int abedgepivot,
+                            flipconstraints* fc)
+{
+  triface fliptets[3], flipface;
+  triface *tmpabtets;
+  int fliptype;
+  int edgepivot;
+  int t, n1;
+  int i, j;
+
+
+  if (nn == 2) {
+    // The edge [a,b] has been flipped.
+    // 'abtets[0]' is [c,d,e,b] or [#,#,#,b].
+    // 'abtets[1]' is [d,c,e,a] or [#,#,#,a].
+    if (fc->unflip) {
+      // Do a 2-to-3 flip to recover the edge [a,b]. There may be hull tets.
+      flip23(abtets, 1, fc);
+      if (fc->collectnewtets) {
+        // Pop up new (flipped) tets from the stack.
+        if (abedgepivot == 0) {
+          // Two new tets were collected.
+          cavetetlist->objects -= 2;
+        } else {
+          // Only one of the two new tets was collected.
+          cavetetlist->objects -= 1;
+        }
+      }
+    } 
+    // The initial size of Star(ab) is 3.
+    nn++;
+  } 
+
+  // Walk through the performed flips.
+  for (i = nn; i < n; i++) {
+    // At the beginning of each step 'i', the size of the Star([a,b]) is 'i'.
+    // At the end of this step, the size of the Star([a,b]) is 'i+1'.
+    // The sizes of the Link([a,b]) are the same.
+    fliptype = ((abtets[i].ver >> 4) & 3); // 0, 1, or 2.
+    if (fliptype == 1) {
+      // It was a 2-to-3 flip: [a,b,c]->[e,d].
+      t = (abtets[i].ver >> 6);
+      assert(t <= i);
+      if (fc->unflip) {
+        if (b->verbose > 2) {
+          printf("      Recover a 2-to-3 flip at f[%d].\n", t);
+        }
+        // 'abtets[(t-1)%i]' is the tet [a,b,e,d] in current Star(ab), i.e.,
+        //   it is created by a 2-to-3 flip [a,b,c] => [e,d].
+        fliptets[0] = abtets[((t - 1) + i) % i]; // [a,b,e,d]
+        eprevself(fliptets[0]);
+        esymself(fliptets[0]);
+        enextself(fliptets[0]); // [e,d,a,b]
+        fnext(fliptets[0], fliptets[1]); // [e,d,b,c]
+        fnext(fliptets[1], fliptets[2]); // [e,d,c,a]
+        // Do a 3-to-2 flip: [e,d] => [a,b,c].
+        // NOTE: hull tets may be invloved.
+        flip32(fliptets, 1, fc);
+        // Expand the array 'abtets', maintain the original order.
+        // The new array length is (i+1).
+        for (j = i - 1; j >= t; j--) {
+          abtets[j + 1] = abtets[j];  // Downshift
+        }
+        // The tet abtets[(t-1)%i] is deleted. Insert the two new tets 
+        //   'fliptets[0]' [a,b,c,d] and 'fliptets[1]' [b,a,c,e] into
+        //   the (t-1)-th and t-th entries, respectively.
+        esym(fliptets[1], abtets[((t-1) + (i+1)) % (i+1)]); // [a,b,e,c]
+        abtets[t] = fliptets[0]; // [a,b,c,d]
+        if (fc->collectnewtets) {
+          // Pop up two (flipped) tets from the stack.
+          cavetetlist->objects -= 2;
+        }
+      } 
+    } else if (fliptype == 2) {
+      tmpabtets = (triface *) (abtets[i].tet);
+      n1 = ((abtets[i].ver >> 19) & 8191); // \sum_{i=0^12}{2^i} = 8191
+      edgepivot = (abtets[i].ver & 3); 
+      t = ((abtets[i].ver >> 6) & 8191);
+      assert(t <= i);
+      if (fc->unflip) {        
+        if (b->verbose > 2) {
+          printf("      Recover a %d-to-m flip at e[%d] of f[%d].\n", n1, 
+                 edgepivot, t);
+        }
+        // Recover the flipped edge ([c,b] or [a,c]).
+        // abtets[(t - 1 + i) % i] is [a,b,e,d], i.e., the tet created by
+        //   the flipping of edge [c,b] or [a,c]. It must still exist in
+        //   Star(ab). Use it to recover the flipped edge.
+        if (edgepivot == 1) { 
+          // The flip edge is [c,b].
+          tmpabtets[0] = abtets[(t - 1 + i) % i]; // [a,b,e,d]
+          eprevself(tmpabtets[0]);
+          esymself(tmpabtets[0]);
+          eprevself(tmpabtets[0]); // [d,a,e,b]
+          fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c]
+        } else {
+          // The flip edge is [a,c].
+          tmpabtets[1] = abtets[(t - 1 + i) % i]; // [a,b,e,d]
+          enextself(tmpabtets[1]);
+          esymself(tmpabtets[1]);
+          enextself(tmpabtets[1]); // [b,d,e,a]
+          fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c]
+        } // if (edgepivot == 2)
+
+        // Do a n1-to-m1 flip to recover the flipped edge ([c,b] or [a,c]).
+        flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
+
+        // Insert the two recovered tets into the original Star(ab).
+        for (j = i - 1; j >= t; j--) {
+          abtets[j + 1] = abtets[j];  // Downshift
+        }
+        if (edgepivot == 1) {
+          // tmpabtets[0] is [c,b,d,a] ==> contains [a,b]
+          // tmpabtets[1] is [c,b,a,e] ==> contains [a,b]
+          // tmpabtets[2] is [c,b,e,d]
+          fliptets[0] = tmpabtets[1];
+          enextself(fliptets[0]);
+          esymself(fliptets[0]); // [a,b,e,c]
+          fliptets[1] = tmpabtets[0];
+          esymself(fliptets[1]);
+          eprevself(fliptets[1]); // [a,b,c,d]
+        } else {
+          // tmpabtets[0] is [a,c,d,b] ==> contains [a,b]
+          // tmpabtets[1] is [a,c,b,e] ==> contains [a,b]
+          // tmpabtets[2] is [a,c,e,d]
+          fliptets[0] = tmpabtets[1];
+          eprevself(fliptets[0]);
+          esymself(fliptets[0]); // [a,b,e,c]
+          fliptets[1] = tmpabtets[0];
+          esymself(fliptets[1]);
+          enextself(fliptets[1]); // [a,b,c,d]
+        } // edgepivot == 2
+        // Insert the two recovered tets into Star(ab).
+        abtets[((t-1) + (i+1)) % (i+1)] = fliptets[0];
+        abtets[t] = fliptets[1];
+      } 
+      else {
+        // Only free the spaces.
+        flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
+      } // if (!unflip)
+      if (b->verbose > 2) {
+        printf("      Release %d spaces at f[%d].\n", n1, i);
+      }
+      delete [] tmpabtets;
+    }
+  } // i
+
+  return 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertpoint()    Insert a point into current tetrahedralization.          //
+//                                                                           //
+// The Bowyer-Watson (B-W) algorithm is used to add a new point p into the   //
+// tetrahedralization T. It first finds a "cavity", denoted as C, in T,  C   //
+// consists of tetrahedra in T that "conflict" with p.  If T is a Delaunay   //
+// tetrahedralization, then all boundary faces (triangles) of C are visible  //
+// by p, i.e.,C is star-shaped. We can insert p into T by first deleting all //
+// tetrahedra in C, then creating new tetrahedra formed by boundary faces of //
+// C and p.  If T is not a DT, then C may be not star-shaped.  It must be    //
+// modified so that it becomes star-shaped.                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::insertpoint(point insertpt, triface *searchtet, face *splitsh,
+                            face *splitseg, insertvertexflags *ivf)
+{
+  arraypool *swaplist;
+  triface *cavetet, spintet, neightet, neineitet, *parytet;
+  triface oldtet, newtet, newneitet;
+  face checksh, neighsh, *parysh;
+  face checkseg, *paryseg;
+  point *pts, pa, pb, pc, *parypt;
+  enum locateresult loc = OUTSIDE;
+  REAL sign, ori;
+  REAL attrib, volume;
+  bool enqflag;
+  int t1ver;
+  int i, j, k, s;
+
+  if (b->verbose > 2) {
+    printf("      Insert point %d\n", pointmark(insertpt));
+  }
+
+  // Locate the point.
+  if (searchtet->tet != NULL) {
+    loc = (enum locateresult) ivf->iloc;
+  }
+
+  if (loc == OUTSIDE) {
+    if (searchtet->tet == NULL) {
+      if (!b->weighted) {
+        randomsample(insertpt, searchtet);
+      } else {
+        // Weighted DT. There may exist dangling vertex. 
+        *searchtet = recenttet;
+      }
+    }
+    // Locate the point.
+    loc = locate(insertpt, searchtet); 
+  }
+
+  ivf->iloc = (int) loc; // The return value.
+
+  if (b->weighted) {
+    if (loc != OUTSIDE) {
+      // Check if this vertex is regular.
+      pts = (point *) searchtet->tet;
+      assert(pts[7] != dummypoint);
+      sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt,
+                        pts[4][3], pts[5][3], pts[6][3], pts[7][3],
+                        insertpt[3]);
+      if (sign > 0) {
+        // This new vertex does not lie below the lower hull. Skip it.
+        setpointtype(insertpt, NREGULARVERTEX);
+        nonregularcount++;
+        ivf->iloc = (int) NONREGULAR;
+        return 0;
+      }
+    }
+  }
+
+  // Create the initial cavity C(p) which contains all tetrahedra that
+  //   intersect p. It may include 1, 2, or n tetrahedra.
+  // If p lies on a segment or subface, also create the initial sub-cavity
+  //   sC(p) which contains all subfaces (and segment) which intersect p.
+
+  if (loc == OUTSIDE) {
+    flip14count++;
+    // The current hull will be enlarged.
+    // Add four adjacent boundary tets into list.
+    for (i = 0; i < 4; i++) {
+      decode(searchtet->tet[i], neightet);
+      neightet.ver = epivot[neightet.ver];
+      cavebdrylist->newindex((void **) &parytet);
+      *parytet = neightet;
+    }
+    infect(*searchtet);
+    caveoldtetlist->newindex((void **) &parytet);
+    *parytet = *searchtet;
+  } else if (loc == INTETRAHEDRON) {
+    flip14count++;
+    // Add four adjacent boundary tets into list.
+    for (i = 0; i < 4; i++) {
+      decode(searchtet->tet[i], neightet);
+      neightet.ver = epivot[neightet.ver];
+      cavebdrylist->newindex((void **) &parytet);
+      *parytet = neightet;
+    }
+    infect(*searchtet);
+    caveoldtetlist->newindex((void **) &parytet);
+    *parytet = *searchtet;
+  } else if (loc == ONFACE) {
+    flip26count++;
+    // Add six adjacent boundary tets into list.
+    j = (searchtet->ver & 3); // The current face number.
+    for (i = 1; i < 4; i++) { 
+      decode(searchtet->tet[(j + i) % 4], neightet);
+      neightet.ver = epivot[neightet.ver];
+      cavebdrylist->newindex((void **) &parytet);
+      *parytet = neightet;
+    }
+    decode(searchtet->tet[j], spintet);
+    j = (spintet.ver & 3); // The current face number.
+    for (i = 1; i < 4; i++) {
+      decode(spintet.tet[(j + i) % 4], neightet);
+      neightet.ver = epivot[neightet.ver];
+      cavebdrylist->newindex((void **) &parytet);
+      *parytet = neightet;
+    }
+    infect(spintet);
+    caveoldtetlist->newindex((void **) &parytet);
+    *parytet = spintet;
+    infect(*searchtet);
+    caveoldtetlist->newindex((void **) &parytet);
+    *parytet = *searchtet;
+
+    if (ivf->splitbdflag) { 
+      if ((splitsh != NULL) && (splitsh->sh != NULL)) {
+        // Create the initial sub-cavity sC(p).
+        smarktest(*splitsh);
+        caveshlist->newindex((void **) &parysh);
+        *parysh = *splitsh;
+      }
+    } // if (splitbdflag)
+  } else if (loc == ONEDGE) {
+    flipn2ncount++;
+    // Add all adjacent boundary tets into list.
+    spintet = *searchtet;
+    while (1) {
+      eorgoppo(spintet, neightet);
+      decode(neightet.tet[neightet.ver & 3], neightet);
+      neightet.ver = epivot[neightet.ver];
+      cavebdrylist->newindex((void **) &parytet);
+      *parytet = neightet;
+      edestoppo(spintet, neightet);
+      decode(neightet.tet[neightet.ver & 3], neightet);
+      neightet.ver = epivot[neightet.ver];
+      cavebdrylist->newindex((void **) &parytet);
+      *parytet = neightet;
+      infect(spintet);
+      caveoldtetlist->newindex((void **) &parytet);
+      *parytet = spintet;
+      fnextself(spintet);
+      if (spintet.tet == searchtet->tet) break;
+    } // while (1)
+
+    if (ivf->splitbdflag) {
+      // Create the initial sub-cavity sC(p).
+      if ((splitseg != NULL) && (splitseg->sh != NULL)) {
+        smarktest(*splitseg);
+        splitseg->shver = 0;
+        spivot(*splitseg, *splitsh);
+      }
+      if (splitsh != NULL) {
+        if (splitsh->sh != NULL) {
+          // Collect all subfaces share at this edge.
+          pa = sorg(*splitsh);
+          neighsh = *splitsh;
+          while (1) {
+            // Adjust the origin of its edge to be 'pa'.
+            if (sorg(neighsh) != pa) {
+              sesymself(neighsh);
+            }
+            // Add this face into list (in B-W cavity).
+            smarktest(neighsh);
+            caveshlist->newindex((void **) &parysh);
+            *parysh = neighsh;
+            // Add this face into face-at-splitedge list.
+            cavesegshlist->newindex((void **) &parysh);
+            *parysh = neighsh;
+            // Go to the next face at the edge.
+            spivotself(neighsh);
+            // Stop if all faces at the edge have been visited.
+            if (neighsh.sh == splitsh->sh) break;
+            if (neighsh.sh == NULL) break;
+          } // while (1)
+        } // if (not a dangling segment)
+      }
+    } // if (splitbdflag)
+  } else if (loc == INSTAR) {
+    // We assume that all tets in the star are given in 'caveoldtetlist',
+    //   and they are all infected.
+    assert(caveoldtetlist->objects > 0);
+    // Collect the boundary faces of the star.
+    for (i = 0; i < caveoldtetlist->objects; i++) {
+      cavetet = (triface *) fastlookup(caveoldtetlist, i);
+      // Check its 4 neighbor tets.
+      for (j = 0; j < 4; j++) {
+        decode(cavetet->tet[j], neightet);
+        if (!infected(neightet)) {
+          // It's a boundary face.
+          neightet.ver = epivot[neightet.ver];
+          cavebdrylist->newindex((void **) &parytet);
+          *parytet = neightet;
+        }
+      }
+    }
+  } else if (loc == ONVERTEX) {
+    // The point already exist. Do nothing and return.
+    return 0;
+  } 
+
+
+  if (ivf->assignmeshsize) {
+    // Assign mesh size for the new point.
+    if (bgm != NULL) {
+      // Interpolate the mesh size from the background mesh. 
+      bgm->decode(point2bgmtet(org(*searchtet)), neightet);
+      int bgmloc = (int) bgm->scoutpoint(insertpt, &neightet, 0);
+      if (bgmloc != (int) OUTSIDE) {
+        insertpt[pointmtrindex] =  
+          bgm->getpointmeshsize(insertpt, &neightet, bgmloc);
+        setpoint2bgmtet(insertpt, bgm->encode(neightet));
+      }
+    } else {
+      insertpt[pointmtrindex] = getpointmeshsize(insertpt,searchtet,(int)loc);
+    }
+  } // if (assignmeshsize)
+
+  if (ivf->bowywat) {
+    // Update the cavity C(p) using the Bowyer-Watson algorithm.
+    swaplist = cavetetlist;
+    cavetetlist = cavebdrylist;
+    cavebdrylist = swaplist;
+    for (i = 0; i < cavetetlist->objects; i++) {
+      // 'cavetet' is an adjacent tet at outside of the cavity.
+      cavetet = (triface *) fastlookup(cavetetlist, i);
+      // The tet may be tested and included in the (enlarged) cavity.
+      if (!infected(*cavetet)) {
+        // Check for two possible cases for this tet: 
+        //   (1) It is a cavity tet, or
+        //   (2) it is a cavity boundary face.
+        enqflag = false;
+        if (!marktested(*cavetet)) {
+          // Do Delaunay (in-sphere) test.
+          pts = (point *) cavetet->tet;
+          if (pts[7] != dummypoint) {
+            // A volume tet. Operate on it.
+            if (b->weighted) {
+              sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt,
+                                pts[4][3], pts[5][3], pts[6][3], pts[7][3],
+                                insertpt[3]);
+            } else {
+              sign = insphere_s(pts[4], pts[5], pts[6], pts[7], insertpt);
+            }
+            enqflag = (sign < 0.0);
+          } else {
+            if (!nonconvex) {
+              // Test if this hull face is visible by the new point. 
+              ori = orient3d(pts[4], pts[5], pts[6], insertpt); 
+              if (ori < 0) {
+                // A visible hull face. 
+                //if (!nonconvex) { 
+                // Include it in the cavity. The convex hull will be enlarged.
+                enqflag = true; // (ori < 0.0);
+		        //}
+              } else if (ori == 0.0) {
+                // A coplanar hull face. We need to test if this hull face is
+                //   Delaunay or not. We test if the adjacent tet (not faked)
+                //   of this hull face is Delaunay or not.
+                decode(cavetet->tet[3], neineitet);
+                if (!infected(neineitet)) {
+                  if (!marktested(neineitet)) {
+                    // Do Delaunay test on this tet.
+                    pts = (point *) neineitet.tet;
+                    assert(pts[7] != dummypoint);
+                    if (b->weighted) {
+                      sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt,
+                                        pts[4][3], pts[5][3], pts[6][3], 
+                                        pts[7][3], insertpt[3]);
+                    } else {
+                      sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt);
+                    }
+                    enqflag = (sign < 0.0);
+                  } 
+                } else {
+                  // The adjacent tet is non-Delaunay. The hull face is non-
+                  //   Delaunay as well. Include it in the cavity.
+                  enqflag = true;
+                } // if (!infected(neineitet))
+              } // if (ori == 0.0)
+            } else {
+              // A hull face (must be a subface).
+              // We FIRST include it in the initial cavity if the adjacent tet
+              //   (not faked) of this hull face is not Delaunay wrt p.
+              //   Whether it belongs to the final cavity will be determined
+              //   during the validation process. 'validflag'.
+              decode(cavetet->tet[3], neineitet);
+              if (!infected(neineitet)) {
+                if (!marktested(neineitet)) {
+                  // Do Delaunay test on this tet.
+                  pts = (point *) neineitet.tet;
+                  assert(pts[7] != dummypoint);
+                  if (b->weighted) {
+                    sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt,
+                                      pts[4][3], pts[5][3], pts[6][3], 
+                                      pts[7][3], insertpt[3]);
+                  } else {
+                    sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt);
+                  }
+                  enqflag = (sign < 0.0);
+                } 
+              } else {
+                // The adjacent tet is non-Delaunay. The hull face is non-
+                //   Delaunay as well. Include it in the cavity.
+                enqflag = true;
+              } // if (infected(neineitet))
+            } // if (nonconvex)
+          } // if (pts[7] != dummypoint)
+          marktest(*cavetet); // Only test it once.
+        } // if (!marktested(*cavetet))
+
+        if (enqflag) {
+          // Found a tet in the cavity. Put other three faces in check list.
+          k = (cavetet->ver & 3); // The current face number
+          for (j = 1; j < 4; j++) {
+            decode(cavetet->tet[(j + k) % 4], neightet);
+            cavetetlist->newindex((void **) &parytet);
+            *parytet = neightet;
+          }
+          infect(*cavetet);
+          caveoldtetlist->newindex((void **) &parytet);
+          *parytet = *cavetet;
+        } else {
+          // Found a boundary face of the cavity. 
+          cavetet->ver = epivot[cavetet->ver];
+          cavebdrylist->newindex((void **) &parytet);
+          *parytet = *cavetet;
+        }
+      } // if (!infected(*cavetet))
+    } // i
+
+    cavetetlist->restart(); // Clear the working list.
+  } // if (ivf->bowywat)
+
+  if (checksubsegflag) {
+    // Collect all segments of C(p).
+    shellface *ssptr;
+    for (i = 0; i < caveoldtetlist->objects; i++) {
+      cavetet = (triface *) fastlookup(caveoldtetlist, i);
+      if ((ssptr = (shellface*) cavetet->tet[8]) != NULL) {
+        for (j = 0; j < 6; j++) {
+          if (ssptr[j]) {
+            sdecode(ssptr[j], checkseg);
+            if (!sinfected(checkseg)) {
+              sinfect(checkseg);
+              cavetetseglist->newindex((void **) &paryseg);
+              *paryseg = checkseg;
+            }
+          }
+        } // j
+      }
+    } // i
+    // Uninfect collected segments.
+    for (i = 0; i < cavetetseglist->objects; i++) {
+      paryseg = (face *) fastlookup(cavetetseglist, i);
+      suninfect(*paryseg);
+    }
+
+    if (ivf->rejflag & 1) {
+      // Reject this point if it encroaches upon any segment.
+      face *paryseg1;
+      for (i = 0; i < cavetetseglist->objects; i++) {
+        paryseg1 = (face *) fastlookup(cavetetseglist, i);
+        if (checkseg4encroach((point) paryseg1->sh[3], (point) paryseg1->sh[4], 
+                              insertpt)) {
+          encseglist->newindex((void **) &paryseg);
+          *paryseg = *paryseg1;
+        }
+      } // i
+      if (encseglist->objects > 0) {
+        insertpoint_abort(splitseg, ivf);
+        ivf->iloc = (int) ENCSEGMENT;
+        return 0;
+      }
+    }
+  } // if (checksubsegflag)
+
+  if (checksubfaceflag) {
+    // Collect all subfaces of C(p).
+    shellface *sptr;
+    for (i = 0; i < caveoldtetlist->objects; i++) {
+      cavetet = (triface *) fastlookup(caveoldtetlist, i);
+      if ((sptr = (shellface*) cavetet->tet[9]) != NULL) {
+        for (j = 0; j < 4; j++) {
+          if (sptr[j]) {
+            sdecode(sptr[j], checksh);
+            if (!sinfected(checksh)) {
+              sinfect(checksh);
+              cavetetshlist->newindex((void **) &parysh);
+              *parysh = checksh;
+            }
+          }
+        } // j
+      }
+    } // i
+    // Uninfect collected subfaces.
+    for (i = 0; i < cavetetshlist->objects; i++) {
+      parysh = (face *) fastlookup(cavetetshlist, i);
+      suninfect(*parysh);
+    }
+
+    if (ivf->rejflag & 2) {
+      REAL rd, cent[3];
+      badface *bface;
+      // Reject this point if it encroaches upon any subface.
+      for (i = 0; i < cavetetshlist->objects; i++) {
+        parysh = (face *) fastlookup(cavetetshlist, i);
+        if (checkfac4encroach((point) parysh->sh[3], (point) parysh->sh[4], 
+                              (point) parysh->sh[5], insertpt, cent, &rd)) {
+          encshlist->newindex((void **) &bface);
+          bface->ss = *parysh;
+          bface->forg = (point) parysh->sh[3]; // Not a dad one.
+          for (j = 0; j < 3; j++) bface->cent[j] = cent[j];
+          bface->key = rd;
+        }
+      }
+      if (encshlist->objects > 0) {
+        insertpoint_abort(splitseg, ivf);
+        ivf->iloc = (int) ENCSUBFACE;
+        return 0;
+      }
+    }
+  } // if (checksubfaceflag)
+
+  if ((ivf->iloc == (int) OUTSIDE) && ivf->refineflag) {
+    // The vertex lies outside of the domain. And it does not encroach
+    //   upon any boundary segment or subface. Do not insert it.
+    insertpoint_abort(splitseg, ivf);
+    return 0;
+  }
+
+  if (ivf->splitbdflag) { 
+    // The new point locates in surface mesh. Update the sC(p). 
+    // We have already 'smarktested' the subfaces which directly intersect
+    //   with p in 'caveshlist'. From them, we 'smarktest' their neighboring
+    //   subfaces which are included in C(p). Do not across a segment.
+    for (i = 0; i < caveshlist->objects; i++) {
+      parysh = (face *) fastlookup(caveshlist, i);
+      assert(smarktested(*parysh));
+      checksh = *parysh;
+      for (j = 0; j < 3; j++) {
+        if (!isshsubseg(checksh)) {
+          spivot(checksh, neighsh);
+          assert(neighsh.sh != NULL);
+          if (!smarktested(neighsh)) {
+            stpivot(neighsh, neightet);
+            if (infected(neightet)) {
+              fsymself(neightet);
+              if (infected(neightet)) {
+                // This subface is inside C(p). 
+                // Check if its diametrical circumsphere encloses 'p'.
+                //   The purpose of this check is to avoid forming invalid
+                //   subcavity in surface mesh.
+                sign = incircle3d(sorg(neighsh), sdest(neighsh),
+                                  sapex(neighsh), insertpt);
+                if (sign < 0) {
+                  smarktest(neighsh);
+                  caveshlist->newindex((void **) &parysh);
+                  *parysh = neighsh;
+                }
+              }
+            }
+          }
+        }
+        senextself(checksh);
+      } // j
+    } // i
+  } // if (ivf->splitbdflag)
+
+  if (ivf->validflag) {
+    // Validate C(p) and update it if it is not star-shaped.
+    int cutcount = 0;
+
+    if (ivf->respectbdflag) {
+      // The initial cavity may include subfaces which are not on the facets
+      //   being splitting. Find them and make them as boundary of C(p). 
+      // Comment: We have already 'smarktested' the subfaces in sC(p). They
+      //   are completely inside C(p). 
+      for (i = 0; i < cavetetshlist->objects; i++) {
+        parysh = (face *) fastlookup(cavetetshlist, i);
+        stpivot(*parysh, neightet);
+        if (infected(neightet)) {
+          fsymself(neightet);
+          if (infected(neightet)) {
+            // Found a subface inside C(p).
+            if (!smarktested(*parysh)) {
+              // It is possible that this face is a boundary subface.
+              // Check if it is a hull face.
+              //assert(apex(neightet) != dummypoint);
+              if (oppo(neightet) != dummypoint) {
+                fsymself(neightet);
+              }
+              if (oppo(neightet) != dummypoint) {
+                ori = orient3d(org(neightet), dest(neightet), apex(neightet),
+                               insertpt);
+                if (ori < 0) {
+                  // A visible face, get its neighbor face.
+                  fsymself(neightet);
+                  ori = -ori; // It must be invisible by p.
+                }
+              } else {
+                // A hull tet. It needs to be cut.
+                ori = 1;
+              }
+              // Cut this tet if it is either invisible by or coplanar with p.
+              if (ori >= 0) {
+                uninfect(neightet);
+                unmarktest(neightet);
+                cutcount++;
+                neightet.ver = epivot[neightet.ver];
+                cavebdrylist->newindex((void **) &parytet);
+                *parytet = neightet;
+                // Add three new faces to find new boundaries.
+                for (j = 0; j < 3; j++) {
+                  esym(neightet, neineitet);
+                  neineitet.ver = epivot[neineitet.ver];
+                  cavebdrylist->newindex((void **) &parytet);
+                  *parytet = neineitet;
+                  enextself(neightet);
+                }
+              } // if (ori >= 0) 
+            }
+          }
+        }
+      } // i
+
+      // The initial cavity may include segments in its interior. We need to
+      //   Update the cavity so that these segments are on the boundary of
+      //   the cavity.
+      for (i = 0; i < cavetetseglist->objects; i++) {
+        paryseg = (face *) fastlookup(cavetetseglist, i);
+        // Check this segment if it is not a splitting segment.
+        if (!smarktested(*paryseg)) {
+          sstpivot1(*paryseg, neightet);
+          spintet = neightet;
+          while (1) {
+            if (!infected(spintet)) break;
+            fnextself(spintet);
+            if (spintet.tet == neightet.tet) break;
+          }
+          if (infected(spintet)) {
+            // Find an adjacent tet at this segment such that both faces
+            //   at this segment are not visible by p.
+            pa = org(neightet);
+            pb = dest(neightet);
+            spintet = neightet;
+            j = 0;
+            while (1) {
+              // Check if this face is visible by p.
+              pc = apex(spintet);
+              if (pc != dummypoint) {
+                ori = orient3d(pa, pb, pc, insertpt);
+                if (ori >= 0) {
+                  // Not visible. Check another face in this tet.
+                  esym(spintet, neineitet);
+                  pc = apex(neineitet);
+                  if (pc != dummypoint) {
+                    ori = orient3d(pb, pa, pc, insertpt);
+                    if (ori >= 0) {
+                      // Not visible. Found this face.
+                      j = 1; // Flag that it is found.
+                      break;
+                    }
+                  }
+                }
+              }
+              fnextself(spintet);
+              if (spintet.tet == neightet.tet) break;
+            }
+            if (j == 0) {
+              // Not found such a face.
+              assert(0); // debug this case.
+            }
+            neightet = spintet;
+            if (b->verbose > 3) {
+               printf("        Cut tet (%d, %d, %d, %d)\n", 
+                      pointmark(org(neightet)), pointmark(dest(neightet)),
+                      pointmark(apex(neightet)), pointmark(oppo(neightet)));
+            }
+            uninfect(neightet);
+            unmarktest(neightet);
+            cutcount++;
+            neightet.ver = epivot[neightet.ver];
+            cavebdrylist->newindex((void **) &parytet);
+            *parytet = neightet;
+            // Add three new faces to find new boundaries.
+            for (j = 0; j < 3; j++) {
+              esym(neightet, neineitet);
+              neineitet.ver = epivot[neineitet.ver];
+              cavebdrylist->newindex((void **) &parytet);
+              *parytet = neineitet;
+              enextself(neightet);
+            }
+          }
+        }
+      } // i
+    } // if (ivf->respectbdflag)
+
+    // Update the cavity by removing invisible faces until it is star-shaped.
+    for (i = 0; i < cavebdrylist->objects; i++) {
+      cavetet = (triface *) fastlookup(cavebdrylist, i);
+      // 'cavetet' is an exterior tet adjacent to the cavity.
+      // Check if its neighbor is inside C(p).
+      fsym(*cavetet, neightet);
+      if (infected(neightet)) {        
+        if (apex(*cavetet) != dummypoint) {
+          // It is a cavity boundary face. Check its visibility.
+          if (oppo(neightet) != dummypoint) {
+            ori = orient3d(org(*cavetet), dest(*cavetet), apex(*cavetet),
+                           insertpt); 
+            enqflag = (ori > 0);
+            // Comment: if ori == 0 (coplanar case), we also cut the tet.
+          } else {
+            // It is a hull face. And its adjacent tet (at inside of the 
+            //   domain) has been cut from the cavity. Cut it as well.
+            //assert(nonconvex);
+            enqflag = false;
+          }
+        } else {
+          enqflag = true; // A hull edge.
+        }
+        if (enqflag) {
+          // This face is valid, save it.
+          cavetetlist->newindex((void **) &parytet);
+          *parytet = *cavetet; 
+        } else {
+          uninfect(neightet);
+          unmarktest(neightet);
+          cutcount++;
+          // Add three new faces to find new boundaries.
+          for (j = 0; j < 3; j++) {
+            esym(neightet, neineitet);
+            neineitet.ver = epivot[neineitet.ver];
+            cavebdrylist->newindex((void **) &parytet);
+            *parytet = neineitet;
+            enextself(neightet);
+          }
+          // 'cavetet' is not on the cavity boundary anymore.
+          unmarktest(*cavetet);
+        }
+      } else {
+        // 'cavetet' is not on the cavity boundary anymore.
+        unmarktest(*cavetet);
+      }
+    } // i
+
+    if (cutcount > 0) {
+      // The cavity has been updated.
+      // Update the cavity boundary faces.
+      cavebdrylist->restart();
+      for (i = 0; i < cavetetlist->objects; i++) {
+        cavetet = (triface *) fastlookup(cavetetlist, i);
+        // 'cavetet' was an exterior tet adjacent to the cavity.
+        fsym(*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;
+        }
+      }
+      // Swap 'cavetetlist' and 'caveoldtetlist'.
+      swaplist = caveoldtetlist;
+      caveoldtetlist = cavetetlist;
+      cavetetlist = swaplist;
+
+      // The cavity should contain at least one tet.
+      if (caveoldtetlist->objects == 0l) {
+        insertpoint_abort(splitseg, ivf);
+        ivf->iloc = (int) BADELEMENT;
+        return 0;
+      }
+
+      if (ivf->splitbdflag) { 
+        int cutshcount = 0;
+        // Update the sub-cavity sC(p).
+        for (i = 0; i < caveshlist->objects; i++) {
+          parysh = (face *) fastlookup(caveshlist, i);
+          if (smarktested(*parysh)) {
+            enqflag = false;
+            stpivot(*parysh, neightet);
+            if (infected(neightet)) {
+              fsymself(neightet);
+              if (infected(neightet)) {
+                enqflag = true;
+              }
+            }
+            if (!enqflag) {
+              sunmarktest(*parysh);
+              // Use the last entry of this array to fill this entry.
+              j = caveshlist->objects - 1;
+              checksh = * (face *) fastlookup(caveshlist, j);
+              *parysh = checksh;
+              cutshcount++;
+              caveshlist->objects--; // The list is shrinked.
+              i--;
+            }
+          }
+        }
+
+        if (cutshcount > 0) {
+          i = 0; // Count the number of invalid subfaces/segments.
+          // Valid the updated sub-cavity sC(p).
+          if (loc == ONFACE) {
+            if ((splitsh != NULL) && (splitsh->sh != NULL)) {
+              // The to-be split subface should be in sC(p).
+              if (!smarktested(*splitsh)) i++;
+            }
+          } else if (loc == ONEDGE) {
+            if ((splitseg != NULL) && (splitseg->sh != NULL)) {
+              // The to-be split segment should be in sC(p).
+              if (!smarktested(*splitseg)) i++;
+            }
+            if ((splitsh != NULL) && (splitsh->sh != NULL)) {
+              // All subfaces at this edge should be in sC(p).
+              pa = sorg(*splitsh);
+              neighsh = *splitsh;
+              while (1) {
+                // Adjust the origin of its edge to be 'pa'.
+                if (sorg(neighsh) != pa) {
+                  sesymself(neighsh);
+                }
+                // Add this face into list (in B-W cavity).
+                if (!smarktested(neighsh)) i++;
+                // Go to the next face at the edge.
+                spivotself(neighsh);
+                // Stop if all faces at the edge have been visited.
+                if (neighsh.sh == splitsh->sh) break;
+                if (neighsh.sh == NULL) break;
+              } // while (1)
+            }
+          }
+
+          if (i > 0) {
+            // The updated sC(p) is invalid. Do not insert this vertex.
+            insertpoint_abort(splitseg, ivf);
+            ivf->iloc = (int) BADELEMENT;
+            return 0;
+          }
+        } // if (cutshcount > 0)
+      } // if (ivf->splitbdflag)
+    } // if (cutcount > 0)
+
+  } // if (ivf->validflag)
+
+  if (ivf->refineflag) {
+    // The new point is inserted by Delaunay refinement, i.e., it is the 
+    //   circumcenter of a tetrahedron, or a subface, or a segment.
+    //   Do not insert this point if the tetrahedron, or subface, or segment
+    //   is not inside the final cavity.
+    if (((ivf->refineflag == 1) && !infected(ivf->refinetet)) ||
+        ((ivf->refineflag == 2) && !smarktested(ivf->refinesh))) {
+      insertpoint_abort(splitseg, ivf);
+      ivf->iloc = (int) BADELEMENT;
+      return 0;
+    }
+  } // if (ivf->refineflag)
+
+  if (b->plc && (loc != INSTAR)) {
+    // Reject the new point if it lies too close to an existing point (b->plc),
+    // or it lies inside a protecting ball of near vertex (ivf->rejflag & 4).
+    // Collect the list of vertices of the initial cavity.
+    if (loc == OUTSIDE) {
+      pts = (point *) &(searchtet->tet[4]);
+      for (i = 0; i < 3; i++) {
+        cavetetvertlist->newindex((void **) &parypt);
+        *parypt = pts[i];
+      }
+    } else if (loc == INTETRAHEDRON) {
+      pts = (point *) &(searchtet->tet[4]);
+      for (i = 0; i < 4; i++) {
+        cavetetvertlist->newindex((void **) &parypt);
+        *parypt = pts[i];
+      } 
+    } else if (loc == ONFACE) {
+      pts = (point *) &(searchtet->tet[4]);
+      for (i = 0; i < 3; i++) {
+        cavetetvertlist->newindex((void **) &parypt);
+        *parypt = pts[i];
+      }
+      if (pts[3] != dummypoint) {
+        cavetetvertlist->newindex((void **) &parypt);
+        *parypt = pts[3];
+      }
+      fsym(*searchtet, spintet);
+      if (oppo(spintet) != dummypoint) {
+        cavetetvertlist->newindex((void **) &parypt);
+        *parypt = oppo(spintet);
+      }
+    } else if (loc == ONEDGE) {
+      spintet = *searchtet;
+      cavetetvertlist->newindex((void **) &parypt);
+      *parypt = org(spintet);
+      cavetetvertlist->newindex((void **) &parypt);
+      *parypt = dest(spintet);
+      while (1) {
+        if (apex(spintet) != dummypoint) {
+          cavetetvertlist->newindex((void **) &parypt);
+          *parypt = apex(spintet);
+        }
+        fnextself(spintet);
+        if (spintet.tet == searchtet->tet) break;
+      }
+    }
+
+    int rejptflag = (ivf->rejflag & 4);
+    REAL rd;
+    pts = NULL;
+
+    for (i = 0; i < cavetetvertlist->objects; i++) {
+      parypt = (point *) fastlookup(cavetetvertlist, i);
+      rd = distance(*parypt, insertpt);
+      // Is the point very close to an existing point?
+      if (rd < b->minedgelength) {
+        pts = parypt; 
+        loc = NEARVERTEX;
+        break;
+      }
+      if (rejptflag) {
+        // Is the point encroaches upon an existing point?
+        if (rd < (0.5 * (*parypt)[pointmtrindex])) {
+          pts = parypt;
+          loc = ENCVERTEX; 
+          break;
+        }
+      }
+    }
+    cavetetvertlist->restart(); // Clear the work list.
+
+    if (pts != NULL) {
+      // The point is either too close to an existing vertex (NEARVERTEX)
+      //   or encroaches upon (inside the protecting ball) of that vertex.
+      if (loc == NEARVERTEX) {
+        if (b->nomergevertex) { // -M0/1 option.
+          // In this case, we still insert this vertex. Although it is very
+          //   close to an existing vertex. Give a warning, anyway.
+          if (!b->quiet) {
+            printf("Warning:  Two points, %d and %d, are very close.\n",
+                   pointmark(insertpt), pointmark(*pts));
+            printf("  Creating a very short edge (len = %g) (< %g).\n",
+                   rd, b->minedgelength);
+            printf("  You may try a smaller tolerance (-T) (current is %g)\n", 
+                   b->epsilon);
+            printf("  to avoid this warning.\n");
+          }
+        } else {
+          insertpt[3] = rd; // Only for reporting.
+          setpoint2ppt(insertpt, *pts);
+          insertpoint_abort(splitseg, ivf);
+          ivf->iloc = (int) loc;
+          return 0;
+        }
+      } else { // loc == ENCVERTEX
+        // The point lies inside the protection ball.
+        setpoint2ppt(insertpt, *pts);
+        insertpoint_abort(splitseg, ivf);
+        ivf->iloc = (int) loc;
+        return 0;
+      }
+    }
+  } // if (b->plc && (loc != INSTAR))
+
+  if (b->weighted || ivf->cdtflag || ivf->smlenflag
+      ) {
+    // There may be other vertices inside C(p). We need to find them.
+    // Collect all vertices of C(p).
+    for (i = 0; i < caveoldtetlist->objects; i++) {
+      cavetet = (triface *) fastlookup(caveoldtetlist, i);
+      //assert(infected(*cavetet));
+      pts = (point *) &(cavetet->tet[4]);
+      for (j = 0; j < 4; j++) {
+        if (pts[j] != dummypoint) {
+          if (!pinfected(pts[j])) {
+            pinfect(pts[j]);
+            cavetetvertlist->newindex((void **) &parypt);
+            *parypt = pts[j];
+          }
+        }
+      } // j
+    } // i
+    // Uninfect all collected (cavity) vertices.
+    for (i = 0; i < cavetetvertlist->objects; i++) {
+      parypt = (point *) fastlookup(cavetetvertlist, i);
+      puninfect(*parypt);
+    }
+    if (ivf->smlenflag) {
+      REAL len;
+      // Get the length of the shortest edge connecting to 'newpt'.
+      parypt = (point *) fastlookup(cavetetvertlist, 0);
+      ivf->smlen = distance(*parypt, insertpt);
+      ivf->parentpt = *parypt;
+      for (i = 1; i < cavetetvertlist->objects; i++) {
+        parypt = (point *) fastlookup(cavetetvertlist, i);
+        len = distance(*parypt, insertpt);
+        if (len < ivf->smlen) {
+          ivf->smlen = len;
+          ivf->parentpt = *parypt;
+        }
+      } 
+    }
+  }
+
+
+  if (ivf->cdtflag) {
+    // Unmark tets.
+    for (i = 0; i < caveoldtetlist->objects; i++) {
+      cavetet = (triface *) fastlookup(caveoldtetlist, i);
+      unmarktest(*cavetet);
+    }
+    for (i = 0; i < cavebdrylist->objects; i++) {
+      cavetet = (triface *) fastlookup(cavebdrylist, i);
+      unmarktest(*cavetet);
+    }
+    // Clean up arrays which are not needed.
+    cavetetlist->restart();
+    if (checksubsegflag) {
+      cavetetseglist->restart();
+    }
+    if (checksubfaceflag) {
+      cavetetshlist->restart();
+    }
+    return 1;
+  }
+
+  // Before re-mesh C(p). Process the segments and subfaces which are on the
+  //   boundary of C(p). Make sure that each such segment or subface is
+  //   connecting to a tet outside C(p). So we can re-connect them to the
+  //   new tets inside the C(p) later.
+
+  if (checksubsegflag) {
+    for (i = 0; i < cavetetseglist->objects; i++) {
+      paryseg = (face *) fastlookup(cavetetseglist, i);
+      // Operate on it if it is not the splitting segment, i.e., in sC(p).
+      if (!smarktested(*paryseg)) {
+        // Check if the segment is inside the cavity.
+        //   'j' counts the num of adjacent tets of this seg.
+        //   'k' counts the num of adjacent tets which are 'sinfected'.
+        j = k = 0;
+        sstpivot1(*paryseg, neightet);
+        spintet = neightet;
+        while (1) {
+          j++;
+          if (!infected(spintet)) {
+            neineitet = spintet; // An outer tet. Remember it.
+          } else {
+            k++; // An in tet.
+          }
+          fnextself(spintet);
+          if (spintet.tet == neightet.tet) break;
+        }
+        // assert(j > 0);
+        if (k == 0) {
+          // The segment is not connect to C(p) anymore. Remove it by
+          //   Replacing it by the last entry of this list.
+          s = cavetetseglist->objects - 1;
+          checkseg = * (face *) fastlookup(cavetetseglist, s);
+          *paryseg = checkseg;
+          cavetetseglist->objects--;
+          i--;
+        } else if (k < j) {
+          // The segment is on the boundary of C(p).
+          sstbond1(*paryseg, neineitet);
+        } else { // k == j
+          // The segment is inside C(p).
+          if (!ivf->splitbdflag) {
+            checkseg = *paryseg;
+            sinfect(checkseg); // Flag it as an interior segment.
+            caveencseglist->newindex((void **) &paryseg);
+            *paryseg = checkseg;
+          } else {
+            assert(0); // Not possible.
+          }
+        }
+      } else { 
+        // assert(smarktested(*paryseg));
+        // Flag it as an interior segment. Do not queue it, since it will
+        //   be deleted after the segment splitting.
+        sinfect(*paryseg);
+      }
+    } // i
+  } // if (checksubsegflag)
+
+  if (checksubfaceflag) {
+    for (i = 0; i < cavetetshlist->objects; i++) {
+      parysh = (face *) fastlookup(cavetetshlist, i);
+      // Operate on it if it is not inside the sub-cavity sC(p).
+      if (!smarktested(*parysh)) {
+        // Check if this subface is inside the cavity.
+        k = 0;
+        for (j = 0; j < 2; j++) {
+          stpivot(*parysh, neightet);
+          if (!infected(neightet)) {
+            checksh = *parysh; // Remember this side.
+          } else {
+            k++;
+          }
+          sesymself(*parysh);
+        }
+        if (k == 0) {
+          // The subface is not connected to C(p). Remove it.
+          s = cavetetshlist->objects - 1;
+          checksh = * (face *) fastlookup(cavetetshlist, s);
+          *parysh = checksh;
+          cavetetshlist->objects--;
+          i--;
+        } else if (k == 1) {
+          // This side is the outer boundary of C(p).
+          *parysh = checksh;
+        } else { // k == 2
+          if (!ivf->splitbdflag) {
+            checksh = *parysh;
+            sinfect(checksh); // Flag it.
+            caveencshlist->newindex((void **) &parysh);
+            *parysh = checksh;
+          } else {
+            assert(0); // Not possible.
+          }
+        }
+      } else {
+        // assert(smarktested(*parysh));
+        // Flag it as an interior subface. Do not queue it. It will be
+        //   deleted after the facet point insertion.
+        sinfect(*parysh);
+      }
+    } // i
+  } // if (checksubfaceflag)
+
+  // Create new tetrahedra to fill the cavity.
+
+  for (i = 0; i < cavebdrylist->objects; i++) {
+    cavetet = (triface *) fastlookup(cavebdrylist, i);
+    neightet = *cavetet;
+    unmarktest(neightet); // Unmark it.
+    // Get the oldtet (inside the cavity).
+    fsym(neightet, oldtet);
+    if (apex(neightet) != dummypoint) {
+      // Create a new tet in the cavity.
+      maketetrahedron(&newtet);
+      setorg(newtet, dest(neightet));
+      setdest(newtet, org(neightet));
+      setapex(newtet, apex(neightet));
+      setoppo(newtet, insertpt);
+    } else {
+      // Create a new hull tet.
+      hullsize++; 
+      maketetrahedron(&newtet);
+      setorg(newtet, org(neightet));
+      setdest(newtet, dest(neightet));
+      setapex(newtet, insertpt);
+      setoppo(newtet, dummypoint); // It must opposite to face 3.
+      // Adjust back to the cavity bounday face.
+      esymself(newtet);
+    }
+    // The new tet inherits attribtes from the old tet.
+    for (j = 0; j < numelemattrib; j++) {
+      attrib = elemattribute(oldtet.tet, j);
+      setelemattribute(newtet.tet, j, attrib);
+    }
+    if (b->varvolume) {
+      volume = volumebound(oldtet.tet);
+      setvolumebound(newtet.tet, volume);
+    }
+    // Connect newtet <==> neightet, this also disconnect the old bond.
+    bond(newtet, neightet);
+    // oldtet still connects to neightet.
+    *cavetet = oldtet; // *cavetet = newtet;
+  } // i
+
+  // Set a handle for speeding point location.
+  recenttet = newtet;
+  //setpoint2tet(insertpt, encode(newtet));
+  setpoint2tet(insertpt, (tetrahedron) (newtet.tet));
+
+  // Re-use this list to save new interior cavity faces.
+  cavetetlist->restart();
+
+  // Connect adjacent new tetrahedra together.
+  for (i = 0; i < cavebdrylist->objects; i++) {
+    cavetet = (triface *) fastlookup(cavebdrylist, i);
+    // cavtet is an oldtet, get the newtet at this face.
+    oldtet = *cavetet;
+    fsym(oldtet, neightet);
+    fsym(neightet, newtet);
+    // Comment: oldtet and newtet must be at the same directed edge.
+    // Connect the three other faces of this newtet.
+    for (j = 0; j < 3; j++) {
+      esym(newtet, neightet); // Go to the face.
+      if (neightet.tet[neightet.ver & 3] == NULL) {
+        // Find the adjacent face of this newtet.
+        spintet = oldtet;
+        while (1) {
+          fnextself(spintet);
+          if (!infected(spintet)) break;
+        }
+        fsym(spintet, newneitet);
+        esymself(newneitet);
+        assert(newneitet.tet[newneitet.ver & 3] == NULL);
+        bond(neightet, newneitet);
+        if (ivf->lawson > 1) { 
+          cavetetlist->newindex((void **) &parytet);
+          *parytet = neightet;
+        }
+      }
+      //setpoint2tet(org(newtet), encode(newtet));
+      setpoint2tet(org(newtet), (tetrahedron) (newtet.tet));
+      enextself(newtet);
+      enextself(oldtet);
+    }
+    *cavetet = newtet; // Save the new tet.
+  } // i
+
+  if (checksubfaceflag) {
+    // Connect subfaces on the boundary of the cavity to the new tets.
+    for (i = 0; i < cavetetshlist->objects; i++) {
+      parysh = (face *) fastlookup(cavetetshlist, i);
+      // Connect it if it is not a missing subface.
+      if (!sinfected(*parysh)) {
+        stpivot(*parysh, neightet);
+        fsym(neightet, spintet);
+        sesymself(*parysh);
+        tsbond(spintet, *parysh);
+      }
+    }
+  }
+
+  if (checksubsegflag) {
+    // Connect segments on the boundary of the cavity to the new tets.
+    for (i = 0; i < cavetetseglist->objects; i++) {
+      paryseg = (face *) fastlookup(cavetetseglist, i);
+      // Connect it if it is not a missing segment.
+      if (!sinfected(*paryseg)) {
+        sstpivot1(*paryseg, neightet);
+        spintet = neightet;
+        while (1) {
+          tssbond1(spintet, *paryseg);
+          fnextself(spintet);
+          if (spintet.tet == neightet.tet) break;
+        }
+      }
+    }
+  }
+
+  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
+      ((splitseg != NULL) && (splitseg->sh != NULL))) {
+    // Split a subface or a segment.
+    sinsertvertex(insertpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat, 0);
+  }
+
+  if (checksubfaceflag) {
+    if (ivf->splitbdflag) {
+      // Recover new subfaces in C(p).
+      for (i = 0; i < caveshbdlist->objects; i++) {
+        // Get an old subface at edge [a, b].
+        parysh = (face *) fastlookup(caveshbdlist, i);
+        spivot(*parysh, checksh); // The new subface [a, b, p].
+        // Do not recover a deleted new face (degenerated).
+        if (checksh.sh[3] != NULL) {
+          // Note that the old subface still connects to adjacent old tets 
+          //   of C(p), which still connect to the tets outside C(p).
+          stpivot(*parysh, neightet);
+          assert(infected(neightet));
+          // Find the adjacent tet containing the edge [a,b] outside C(p).
+          spintet = neightet;
+          while (1) {
+            fnextself(spintet);
+            if (!infected(spintet)) break;
+            assert(spintet.tet != neightet.tet);
+          }
+          // The adjacent tet connects to a new tet in C(p).
+          fsym(spintet, neightet);
+          assert(!infected(neightet));
+          // Find the tet containing the face [a, b, p].
+          spintet = neightet;
+          while (1) {
+            fnextself(spintet);
+            if (apex(spintet) == insertpt) break;
+            assert(spintet.tet != neightet.tet);
+          }
+          // Adjust the edge direction in spintet and checksh.
+          if (sorg(checksh) != org(spintet)) {
+            sesymself(checksh);
+            assert(sorg(checksh) == org(spintet));
+          }
+          assert(sdest(checksh) == dest(spintet));
+          // Connect the subface to two adjacent tets.
+          tsbond(spintet, checksh);
+          fsymself(spintet);
+          sesymself(checksh);
+          tsbond(spintet, checksh);
+        } // if (checksh.sh[3] != NULL)
+      }
+      // There should be no missing interior subfaces in C(p).
+      assert(caveencshlist->objects == 0l);
+    } else { 
+      // The Boundary recovery phase.
+      // Put all new subfaces into stack for recovery.
+      for (i = 0; i < caveshbdlist->objects; i++) {
+        // Get an old subface at edge [a, b].
+        parysh = (face *) fastlookup(caveshbdlist, i);
+        spivot(*parysh, checksh); // The new subface [a, b, p].
+        // Do not recover a deleted new face (degenerated).
+        if (checksh.sh[3] != NULL) {
+          subfacstack->newindex((void **) &parysh);
+          *parysh = checksh;
+        }
+      }
+      // Put all interior subfaces into stack for recovery.
+      for (i = 0; i < caveencshlist->objects; i++) {
+        parysh = (face *) fastlookup(caveencshlist, i);
+        assert(sinfected(*parysh));
+        // Some subfaces inside C(p) might be split in sinsertvertex().
+        //   Only queue those faces which are not split.
+        if (!smarktested(*parysh)) {
+          checksh = *parysh;
+          suninfect(checksh);
+          stdissolve(checksh); // Detach connections to old tets.
+          subfacstack->newindex((void **) &parysh);
+          *parysh = checksh;
+        }
+      }
+    }
+  } // if (checksubfaceflag)
+
+  if (checksubsegflag) {
+    if (ivf->splitbdflag) {
+      if (splitseg != NULL) {
+        // Recover the two new subsegments in C(p).
+        for (i = 0; i < cavesegshlist->objects; i++) {
+          paryseg = (face *) fastlookup(cavesegshlist, i);
+          // Insert this subsegment into C(p).
+          checkseg = *paryseg;
+          // Get the adjacent new subface.
+          checkseg.shver = 0;
+          spivot(checkseg, checksh);
+          if (checksh.sh != NULL) {
+            // Get the adjacent new tetrahedron.
+            stpivot(checksh, neightet);
+          } else {
+            // It's a dangling segment.
+            point2tetorg(sorg(checkseg), neightet);
+            finddirection(&neightet, sdest(checkseg));
+            assert(dest(neightet) == sdest(checkseg));
+          }
+          assert(!infected(neightet));
+          sstbond1(checkseg, neightet);
+          spintet = neightet;
+          while (1) {
+            tssbond1(spintet, checkseg);
+            fnextself(spintet);
+            if (spintet.tet == neightet.tet) break;
+          }
+        }
+      } // if (splitseg != NULL)
+      // There should be no interior segment in C(p).
+      assert(caveencseglist->objects == 0l);
+    } else {
+      // The Boundary Recovery Phase.  
+      // Queue missing segments in C(p) for recovery.
+      if (splitseg != NULL) {
+        // Queue two new subsegments in C(p) for recovery.
+        for (i = 0; i < cavesegshlist->objects; i++) {
+          paryseg = (face *) fastlookup(cavesegshlist, i);
+          checkseg = *paryseg;
+          //sstdissolve1(checkseg); // It has not been connected yet.
+          s = randomnation(subsegstack->objects + 1);
+          subsegstack->newindex((void **) &paryseg);
+          *paryseg = * (face *) fastlookup(subsegstack, s); 
+          paryseg = (face *) fastlookup(subsegstack, s);
+          *paryseg = checkseg;
+        }
+      } // if (splitseg != NULL)
+      for (i = 0; i < caveencseglist->objects; i++) {
+        paryseg = (face *) fastlookup(caveencseglist, i);
+        assert(sinfected(*paryseg));
+        if (!smarktested(*paryseg)) { // It may be split.
+          checkseg = *paryseg;
+          suninfect(checkseg);
+          sstdissolve1(checkseg); // Detach connections to old tets.
+          s = randomnation(subsegstack->objects + 1);
+          subsegstack->newindex((void **) &paryseg);
+          *paryseg = * (face *) fastlookup(subsegstack, s); 
+          paryseg = (face *) fastlookup(subsegstack, s);
+          *paryseg = checkseg;
+        }
+      }
+    }
+  } // if (checksubsegflag)
+
+  if (b->weighted
+      ) {
+    // Some vertices may be completed inside the cavity. They must be
+    //   detected and added to recovering list.
+    // Since every "live" vertex must contain a pointer to a non-dead
+    //   tetrahedron, we can check for each vertex this pointer.
+    for (i = 0; i < cavetetvertlist->objects; i++) {
+      pts = (point *) fastlookup(cavetetvertlist, i);
+      decode(point2tet(*pts), *searchtet);
+      assert(searchtet->tet != NULL); // No tet has been deleted yet.
+      if (infected(*searchtet)) {
+        if (b->weighted) {
+          if (b->verbose > 1) {
+            printf("    Point #%d is non-regular after the insertion of #%d.\n",
+                   pointmark(*pts), pointmark(insertpt));
+          }
+          setpointtype(*pts, NREGULARVERTEX);
+          nonregularcount++;
+        }
+      }
+    }
+  }
+
+  if (ivf->chkencflag & 1) {
+    // Queue all segment outside C(p).
+    for (i = 0; i < cavetetseglist->objects; i++) {
+      paryseg = (face *) fastlookup(cavetetseglist, i);
+      // Skip if it is the split segment.
+      if (!sinfected(*paryseg)) {
+        enqueuesubface(badsubsegs, paryseg);
+      }
+    }
+    if (splitseg != NULL) {
+      // Queue the two new subsegments inside C(p).
+      for (i = 0; i < cavesegshlist->objects; i++) {
+        paryseg = (face *) fastlookup(cavesegshlist, i);
+        enqueuesubface(badsubsegs, paryseg);
+      }
+    }
+  } // if (chkencflag & 1)
+
+  if (ivf->chkencflag & 2) {
+    // Queue all subfaces outside C(p).
+    for (i = 0; i < cavetetshlist->objects; i++) {
+      parysh = (face *) fastlookup(cavetetshlist, i);
+      // Skip if it is a split subface.
+      if (!sinfected(*parysh)) {
+        enqueuesubface(badsubfacs, parysh);
+      }
+    }
+    // Queue all new subfaces inside C(p).
+    for (i = 0; i < caveshbdlist->objects; i++) {
+      // Get an old subface at edge [a, b].
+      parysh = (face *) fastlookup(caveshbdlist, i);
+      spivot(*parysh, checksh); // checksh is a new subface [a, b, p].
+      // Do not recover a deleted new face (degenerated).
+      if (checksh.sh[3] != NULL) {
+        enqueuesubface(badsubfacs, &checksh);
+      }
+    }
+  } // if (chkencflag & 2)
+
+  if (ivf->chkencflag & 4) {
+    // Queue all new tetrahedra in C(p).
+    for (i = 0; i < cavebdrylist->objects; i++) {
+      cavetet = (triface *) fastlookup(cavebdrylist, i);
+      enqueuetetrahedron(cavetet);
+    }
+  }
+
+  // C(p) is re-meshed successfully.
+
+  // Delete the old tets in C(p).
+  for (i = 0; i < caveoldtetlist->objects; i++) {
+    searchtet = (triface *) fastlookup(caveoldtetlist, i);
+    if (ishulltet(*searchtet)) {
+      hullsize--;
+    }
+    tetrahedrondealloc(searchtet->tet);
+  }
+
+  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
+      ((splitseg != NULL) && (splitseg->sh != NULL))) {
+    // Delete the old subfaces in sC(p).
+    for (i = 0; i < caveshlist->objects; i++) {
+      parysh = (face *) fastlookup(caveshlist, i);
+      if (checksubfaceflag) {//if (bowywat == 2) {
+        // It is possible that this subface still connects to adjacent
+        //   tets which are not in C(p). If so, clear connections in the
+        //   adjacent tets at this subface.
+        stpivot(*parysh, neightet);
+        if (neightet.tet != NULL) {
+          if (neightet.tet[4] != NULL) {
+            // Found an adjacent tet. It must be not in C(p).
+            assert(!infected(neightet));
+            tsdissolve(neightet);
+            fsymself(neightet);
+            assert(!infected(neightet));
+            tsdissolve(neightet);
+          }
+        }
+      }
+      shellfacedealloc(subfaces, parysh->sh);
+    }
+    if ((splitseg != NULL) && (splitseg->sh != NULL)) {
+      // Delete the old segment in sC(p).
+      shellfacedealloc(subsegs, splitseg->sh);
+    }
+  }
+
+  if (ivf->lawson) {
+    for (i = 0; i < cavebdrylist->objects; i++) {
+      searchtet = (triface *) fastlookup(cavebdrylist, i);
+      flippush(flipstack, searchtet);
+    }
+    if (ivf->lawson > 1) {
+      for (i = 0; i < cavetetlist->objects; i++) {
+        searchtet = (triface *) fastlookup(cavetetlist, i);
+        flippush(flipstack, searchtet);
+      }
+    }
+  }
+
+
+  // Clean the working lists.
+
+  caveoldtetlist->restart();
+  cavebdrylist->restart();
+  cavetetlist->restart();
+
+  if (checksubsegflag) {
+    cavetetseglist->restart();
+    caveencseglist->restart();
+  }
+
+  if (checksubfaceflag) {
+    cavetetshlist->restart();
+    caveencshlist->restart();
+  }
+  
+  if (b->weighted || ivf->validflag) {
+    cavetetvertlist->restart();
+  }
+  
+  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
+      ((splitseg != NULL) && (splitseg->sh != NULL))) {
+    caveshlist->restart();
+    caveshbdlist->restart();
+    cavesegshlist->restart();
+  }
+
+  return 1; // Point is inserted.
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertpoint_abort()    Abort the insertion of a new vertex.               //
+//                                                                           //
+// The cavity will be restored.  All working lists are cleared.              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::insertpoint_abort(face *splitseg, insertvertexflags *ivf)
+{
+  triface *cavetet;
+  face *parysh;
+  int i;
+
+  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); 
+  }
+  cavetetlist->restart();
+  cavebdrylist->restart();
+  caveoldtetlist->restart();
+  cavetetseglist->restart();
+  cavetetshlist->restart();
+  if (ivf->splitbdflag) { 
+    if ((splitseg != NULL) && (splitseg->sh != NULL)) {
+      sunmarktest(*splitseg);
+    }
+    for (i = 0; i < caveshlist->objects; i++) {
+      parysh = (face *) fastlookup(caveshlist, i);
+      assert(smarktested(*parysh));
+      sunmarktest(*parysh);
+    }
+    caveshlist->restart();
+    cavesegshlist->restart();
+  }
+}
+
+////                                                                       ////
+////                                                                       ////
+//// flip_cxx /////////////////////////////////////////////////////////////////
+
+//// delaunay_cxx /////////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// transfernodes()    Read the vertices from the input (tetgenio).           //
+//                                                                           //
+// Transferring all points from input ('in->pointlist') to TetGen's 'points'.//
+// All points are indexed (the first point index is 'in->firstnumber'). Each //
+// point's type is initialized as UNUSEDVERTEX. The bounding box (xmax, xmin,//
+// ...) and the diameter (longest) of the point set are calculated.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::transfernodes()
+{
+  point pointloop;
+  REAL x, y, z, w;
+  int coordindex;
+  int attribindex;
+  int mtrindex;
+  int i, j;
+
+  if (b->psc) {
+    assert(in->pointparamlist != NULL);
+  }
+
+  // Read the points.
+  coordindex = 0;
+  attribindex = 0;
+  mtrindex = 0;
+  for (i = 0; i < in->numberofpoints; i++) {
+    makepoint(&pointloop, UNUSEDVERTEX);
+    // 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. (Including point weights.)
+    for (j = 0; j < in->numberofpointattributes; j++) {
+      pointloop[3 + j] = in->pointattributelist[attribindex++];
+    }
+    // Read the point metric tensor.
+    for (j = 0; j < in->numberofpointmtrs; j++) {
+      pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++];
+    }
+    if (b->weighted) { // -w option
+      if (in->numberofpointattributes > 0) {
+        // The first point attribute is its weight.
+        //w = in->pointattributelist[in->numberofpointattributes * i];
+        w = pointloop[3];
+      } else {
+        // No given weight available. Default choose the maximum
+        //   absolute value among its coordinates.        
+        w = fabs(x);
+        if (w < fabs(y)) w = fabs(y);
+        if (w < fabs(z)) w = fabs(z);
+      }
+      if (b->weighted_param == 0) {
+        pointloop[3] = x * x + y * y + z * z - w; // Weighted DT.
+      } else { // -w1 option
+        pointloop[3] = w;  // Regular tetrahedralization.
+      }
+    }
+    // Determine the smallest and largest 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;
+    }
+    if (b->psc) {
+      // Read the geometry parameters.
+      setpointgeomuv(pointloop, 0, in->pointparamlist[i].uv[0]);
+      setpointgeomuv(pointloop, 1, in->pointparamlist[i].uv[1]);
+      setpointgeomtag(pointloop, in->pointparamlist[i].tag);
+      if (in->pointparamlist[i].type == 0) {
+        setpointtype(pointloop, RIDGEVERTEX);
+      } else if (in->pointparamlist[i].type == 1) {
+        setpointtype(pointloop, FREESEGVERTEX);
+      } else if (in->pointparamlist[i].type == 2) {
+        setpointtype(pointloop, FREEFACETVERTEX);
+      } else if (in->pointparamlist[i].type == 3) {
+        setpointtype(pointloop, FREEVOLVERTEX);
+      }
+    }
+  }
+
+  // 'longest' is the largest possible edge length formed by input vertices.
+  x = xmax - xmin;
+  y = ymax - ymin;
+  z = zmax - zmin;
+  longest = sqrt(x * x + y * y + z * z);
+  if (longest == 0.0) {
+    printf("Error:  The point set is trivial.\n");
+    terminatetetgen(this, 3);
+  }
+
+  // Two identical points are distinguished by 'lengthlimit'.
+  if (b->minedgelength == 0.0) {
+    b->minedgelength = longest * b->epsilon;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// hilbert_init()    Initialize the Gray code permutation table.             //
+//                                                                           //
+// The table 'transgc' has 8 x 3 x 8 entries. It contains all possible Gray  //
+// code sequences traveled by the 1st order Hilbert curve in 3 dimensions.   //
+// The first column is the Gray code of the entry point of the curve, and    //
+// the second column is the direction (0, 1, or 2, 0 means the x-axis) where //
+// the exit point of curve lies.                                             //
+//                                                                           //
+// The table 'tsb1mod3' contains the numbers of trailing set '1' bits of the //
+// indices from 0 to 7, modulo by '3'. The code for generating this table is //
+// from: http://graphics.stanford.edu/~seander/bithacks.html.                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::hilbert_init(int n)
+{
+  int gc[8], N, mask, travel_bit;
+  int e, d, f, k, g;
+  int v, c;
+  int i;
+
+  N = (n == 2) ? 4 : 8;
+  mask = (n == 2) ? 3 : 7;
+
+  // Generate the Gray code sequence.
+  for (i = 0; i < N; i++) {
+    gc[i] = i ^ (i >> 1);
+  }
+
+  for (e = 0; e < N; e++) {
+    for (d = 0; d < n; d++) {
+      // Calculate the end point (f).
+      f = e ^ (1 << d);  // Toggle the d-th bit of 'e'.
+      // travel_bit = 2**p, the bit we want to travel. 
+      travel_bit = e ^ f;
+      for (i = 0; i < N; i++) {
+        // // Rotate gc[i] left by (p + 1) % n bits.
+        k = gc[i] * (travel_bit * 2);
+        g = ((k | (k / N)) & mask);
+        // Calculate the permuted Gray code by xor with the start point (e).
+        transgc[e][d][i] = (g ^ e);
+      }
+      assert(transgc[e][d][0] == e);
+      assert(transgc[e][d][N - 1] == f);
+    } // d
+  } // e
+
+  // Count the consecutive '1' bits (trailing) on the right.
+  tsb1mod3[0] = 0;
+  for (i = 1; i < N; i++) {
+    v = ~i; // Count the 0s.
+    v = (v ^ (v - 1)) >> 1; // Set v's trailing 0s to 1s and zero rest
+    for (c = 0; v; c++) {
+      v >>= 1;
+    }
+    tsb1mod3[i] = c % n;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// hilbert_sort3()    Sort points using the 3d Hilbert curve.                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::hilbert_split(point* vertexarray,int arraysize,int gc0,int gc1,
+                              REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, 
+                              REAL bzmin, REAL bzmax)
+{
+  point swapvert;
+  int axis, d;
+  REAL split;
+  int i, j;
+
+
+  // Find the current splitting axis. 'axis' is a value 0, or 1, or 2, which 
+  //   correspoding to x-, or y- or z-axis.
+  axis = (gc0 ^ gc1) >> 1; 
+
+  // Calulate the split position along the axis.
+  if (axis == 0) {
+    split = 0.5 * (bxmin + bxmax);
+  } else if (axis == 1) {
+    split = 0.5 * (bymin + bymax);
+  } else { // == 2
+    split = 0.5 * (bzmin + bzmax);
+  }
+
+  // Find the direction (+1 or -1) of the axis. If 'd' is +1, the direction
+  //   of the axis is to the positive of the axis, otherwise, it is -1.
+  d = ((gc0 & (1<<axis)) == 0) ? 1 : -1;
+
+
+  // Partition the vertices into left- and right-arrays such that left points
+  //   have Hilbert indices lower than the right points.
+  i = 0;
+  j = arraysize - 1;
+
+  // Partition the vertices into left- and right-arrays.
+  if (d > 0) {
+    do {
+      for (; i < arraysize; i++) {      
+        if (vertexarray[i][axis] >= split) break;
+      }
+      for (; j >= 0; j--) {
+        if (vertexarray[j][axis] < split) break;
+      }
+      // Is the partition finished?
+      if (i == (j + 1)) break;
+      // Swap i-th and j-th vertices.
+      swapvert = vertexarray[i];
+      vertexarray[i] = vertexarray[j];
+      vertexarray[j] = swapvert;
+      // Continue patitioning the array;
+    } while (true);
+  } else {
+    do {
+      for (; i < arraysize; i++) {      
+        if (vertexarray[i][axis] <= split) break;
+      }
+      for (; j >= 0; j--) {
+        if (vertexarray[j][axis] > split) break;
+      }
+      // Is the partition finished?
+      if (i == (j + 1)) break;
+      // Swap i-th and j-th vertices.
+      swapvert = vertexarray[i];
+      vertexarray[i] = vertexarray[j];
+      vertexarray[j] = swapvert;
+      // Continue patitioning the array;
+    } while (true);
+  }
+
+  return i;
+}
+
+void tetgenmesh::hilbert_sort3(point* vertexarray, int arraysize, int e, int d, 
+                               REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, 
+                               REAL bzmin, REAL bzmax, int depth)
+{
+  REAL x1, x2, y1, y2, z1, z2;
+  int p[9], w, e_w, d_w, k, ei, di;
+  int n = 3, mask = 7;
+
+  p[0] = 0;
+  p[8] = arraysize;
+
+  // Sort the points according to the 1st order Hilbert curve in 3d.
+  p[4] = hilbert_split(vertexarray, p[8], transgc[e][d][3], transgc[e][d][4], 
+                       bxmin, bxmax, bymin, bymax, bzmin, bzmax);
+  p[2] = hilbert_split(vertexarray, p[4], transgc[e][d][1], transgc[e][d][2], 
+                       bxmin, bxmax, bymin, bymax, bzmin, bzmax);
+  p[1] = hilbert_split(vertexarray, p[2], transgc[e][d][0], transgc[e][d][1], 
+                       bxmin, bxmax, bymin, bymax, bzmin, bzmax);
+  p[3] = hilbert_split(&(vertexarray[p[2]]), p[4] - p[2], 
+                       transgc[e][d][2], transgc[e][d][3], 
+                       bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[2];
+  p[6] = hilbert_split(&(vertexarray[p[4]]), p[8] - p[4], 
+                       transgc[e][d][5], transgc[e][d][6], 
+                       bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4];
+  p[5] = hilbert_split(&(vertexarray[p[4]]), p[6] - p[4], 
+                       transgc[e][d][4], transgc[e][d][5], 
+                       bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4];
+  p[7] = hilbert_split(&(vertexarray[p[6]]), p[8] - p[6], 
+                       transgc[e][d][6], transgc[e][d][7], 
+                       bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[6];
+
+  if (b->hilbert_order > 0) {
+    // A maximum order is prescribed. 
+    if ((depth + 1) == b->hilbert_order) {
+      // The maximum prescribed order is reached.
+      return;
+    }
+  }
+
+  // Recursively sort the points in sub-boxes.
+  for (w = 0; w < 8; w++) {
+    // w is the local Hilbert index (NOT Gray code).
+    // Sort into the sub-box either there are more than 2 points in it, or
+    //   the prescribed order of the curve is not reached yet.
+    //if ((p[w+1] - p[w] > b->hilbert_limit) || (b->hilbert_order > 0)) {
+    if ((p[w+1] - p[w]) > b->hilbert_limit) {
+      // Calculcate the start point (ei) of the curve in this sub-box.
+      //   update e = e ^ (e(w) left_rotate (d+1)).
+      if (w == 0) {
+        e_w = 0;
+      } else {
+        //   calculate e(w) = gc(2 * floor((w - 1) / 2)).
+        k = 2 * ((w - 1) / 2); 
+        e_w = k ^ (k >> 1); // = gc(k).
+      }
+      k = e_w;
+      e_w = ((k << (d+1)) & mask) | ((k >> (n-d-1)) & mask);
+      ei = e ^ e_w;
+      // Calulcate the direction (di) of the curve in this sub-box.
+      //   update d = (d + d(w) + 1) % n
+      if (w == 0) {
+        d_w = 0;
+      } else {
+        d_w = ((w % 2) == 0) ? tsb1mod3[w - 1] : tsb1mod3[w];
+      }
+      di = (d + d_w + 1) % n;
+      // Calculate the bounding box of the sub-box.
+      if (transgc[e][d][w] & 1) { // x-axis
+        x1 = 0.5 * (bxmin + bxmax);
+        x2 = bxmax;
+      } else {
+        x1 = bxmin;
+        x2 = 0.5 * (bxmin + bxmax);
+      }
+      if (transgc[e][d][w] & 2) { // y-axis
+        y1 = 0.5 * (bymin + bymax);
+        y2 = bymax;
+      } else {
+        y1 = bymin;
+        y2 = 0.5 * (bymin + bymax);
+      }
+      if (transgc[e][d][w] & 4) { // z-axis
+        z1 = 0.5 * (bzmin + bzmax);
+        z2 = bzmax;
+      } else {
+        z1 = bzmin;
+        z2 = 0.5 * (bzmin + bzmax);
+      }
+      hilbert_sort3(&(vertexarray[p[w]]), p[w+1] - p[w], ei, di, 
+                    x1, x2, y1, y2, z1, z2, depth+1);
+    } // if (p[w+1] - p[w] > 1)
+  } // w
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// brio_multiscale_sort()    Sort the points using BRIO and Hilbert curve.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::brio_multiscale_sort(point* vertexarray, int arraysize, 
+                                      int threshold, REAL ratio, int *depth)
+{
+  int middle;
+
+  middle = 0;
+  if (arraysize >= threshold) {
+    (*depth)++;
+    middle = arraysize * ratio;
+    brio_multiscale_sort(vertexarray, middle, threshold, ratio, depth);
+  }
+  // Sort the right-array (rnd-th round) using the Hilbert curve.
+  hilbert_sort3(&(vertexarray[middle]), arraysize - middle, 0, 0, // e, d
+                xmin, xmax, ymin, ymax, zmin, zmax, 0); // depth.
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// randomnation()    Generate a random number between 0 and 'choices' - 1.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+unsigned long tetgenmesh::randomnation(unsigned int choices)
+{
+  unsigned long newrandom;
+
+  if (choices >= 714025l) {
+    newrandom = (randomseed * 1366l + 150889l) % 714025l;
+    randomseed = (newrandom * 1366l + 150889l) % 714025l;
+    newrandom = newrandom * (choices / 714025l) + randomseed;
+    if (newrandom >= choices) {
+      return newrandom - choices;
+    } else {
+      return newrandom;
+    }
+  } else {
+    randomseed = (randomseed * 1366l + 150889l) % 714025l;
+    return randomseed % choices;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// randomsample()    Randomly sample the tetrahedra for point loation.       //
+//                                                                           //
+// 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 searching for.                                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::randomsample(point searchpt,triface *searchtet)
+{
+  tetrahedron *firsttet, *tetptr;
+  point torg;
+  void **sampleblock;
+  uintptr_t alignptr;
+  long sampleblocks, samplesperblock, samplenum;
+  long tetblocks, i, j;
+  REAL searchdist, dist;
+
+  if (b->verbose > 2) {
+    printf("      Random sampling tetrahedra for searching point %d.\n",
+           pointmark(searchpt));
+  }
+
+  if (!nonconvex) {
+    if (searchtet->tet == NULL) {
+      // A null tet. Choose the recenttet as the starting tet.
+      *searchtet = recenttet;
+      // Recenttet should not be dead.
+      assert(recenttet.tet[4] != NULL);
+    }
+
+    // 'searchtet' should be a valid tetrahedron. Choose the base face
+    //   whose vertices must not be 'dummypoint'.
+    searchtet->ver = 3;
+    // Record the distance from its origin to the searching point.
+    torg = org(*searchtet);
+    searchdist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
+                 (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
+                 (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
+
+    // If a recently encountered tetrahedron has been recorded and has not
+    //   been deallocated, test it as a good starting point.
+    if (recenttet.tet != searchtet->tet) {
+      recenttet.ver = 3;
+      torg = org(recenttet);
+      dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
+             (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
+             (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
+      if (dist < searchdist) {
+        *searchtet = recenttet;
+        searchdist = dist;
+      }
+    }
+  } else {
+    // The mesh is non-convex. Do not use 'recenttet'.
+    assert(samples >= 1l); // Make sure at least 1 sample.
+    searchdist = longest;
+  }
+
+  // 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 < tetrahedrons->items) {
+    samples++;
+  }
+  // Find how much blocks in current tet pool.
+  tetblocks = (tetrahedrons->maxitems + b->tetrahedraperblock - 1) 
+            / b->tetrahedraperblock;
+  // Find the average samples per block. Each block at least have 1 sample.
+  samplesperblock = 1 + (samples / tetblocks);
+  sampleblocks = samples / samplesperblock;
+  sampleblock = tetrahedrons->firstblock;
+  for (i = 0; i < sampleblocks; i++) {
+    alignptr = (uintptr_t) (sampleblock + 1);
+    firsttet = (tetrahedron *)
+               (alignptr + (uintptr_t) tetrahedrons->alignbytes
+               - (alignptr % (uintptr_t) tetrahedrons->alignbytes));
+    for (j = 0; j < samplesperblock; j++) {
+      if (i == tetblocks - 1) {
+        // This is the last block.
+        samplenum = randomnation((int)
+                      (tetrahedrons->maxitems - (i * b->tetrahedraperblock)));
+      } else {
+        samplenum = randomnation(b->tetrahedraperblock);
+      }
+      tetptr = (tetrahedron *)
+               (firsttet + (samplenum * tetrahedrons->itemwords));
+      torg = (point) tetptr[4];
+      if (torg != (point) NULL) {
+        dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
+               (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
+               (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
+        if (dist < searchdist) {
+          searchtet->tet = tetptr;
+          searchtet->ver = 11; // torg = org(t);
+          searchdist = dist;
+        }
+      } else {
+        // A dead tet. Re-sample it.
+        if (i != tetblocks - 1) j--;
+      }
+    }
+    sampleblock = (void **) *sampleblock;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// locate()    Find a tetrahedron containing a given point.                  //
+//                                                                           //
+// Begins its search from 'searchtet', assume there is a line segment L from //
+// a vertex 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 face which 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::locateresult tetgenmesh::locate(point searchpt, 
+                                                 triface* searchtet)
+{
+  point torg, tdest, tapex, toppo;
+  enum {ORGMOVE, DESTMOVE, APEXMOVE} nextmove;
+  REAL ori, oriorg, oridest, oriapex;
+  enum locateresult loc = OUTSIDE;
+  int t1ver;
+  int s;
+
+  if (searchtet->tet == NULL) {
+    // A null tet. Choose the recenttet as the starting tet.
+    searchtet->tet = recenttet.tet;
+  }
+
+  // Check if we are in the outside of the convex hull.
+  if (ishulltet(*searchtet)) {
+    // Get its adjacent tet (inside the hull).
+    searchtet->ver = 3;
+    fsymself(*searchtet);
+  }
+
+  // Let searchtet be the face such that 'searchpt' lies above to it.
+  for (searchtet->ver = 0; searchtet->ver < 4; searchtet->ver++) {
+    torg = org(*searchtet);
+    tdest = dest(*searchtet);
+    tapex = apex(*searchtet);
+    ori = orient3d(torg, tdest, tapex, searchpt); 
+    if (ori < 0.0) break;
+  }
+  assert(searchtet->ver != 4);
+
+  // Walk through tetrahedra to locate the point.
+  while (true) {
+
+    toppo = oppo(*searchtet);
+    
+    // Check if the vertex is we seek.
+    if (toppo == searchpt) {
+      // Adjust the origin of searchtet to be searchpt.
+      esymself(*searchtet);
+      eprevself(*searchtet);
+      loc = ONVERTEX; // return ONVERTEX;
+      break;
+    }
+
+    // We enter from one of serarchtet's faces, which face do we exit?
+    oriorg = orient3d(tdest, tapex, toppo, searchpt); 
+    oridest = orient3d(tapex, torg, toppo, searchpt);
+    oriapex = orient3d(torg, tdest, toppo, searchpt);
+
+    // Now decide which face to move. It is possible there are more than one
+    //   faces are viable moves. If so, randomly choose one.
+    if (oriorg < 0) {
+      if (oridest < 0) {
+        if (oriapex < 0) {
+          // All three faces are possible.
+          s = randomnation(3); // 's' is in {0,1,2}.
+          if (s == 0) {
+            nextmove = ORGMOVE;
+          } else if (s == 1) {
+            nextmove = DESTMOVE;
+          } else {
+            nextmove = APEXMOVE;
+          }
+        } else {
+          // Two faces, opposite to origin and destination, are viable.
+          //s = randomnation(2); // 's' is in {0,1}.
+          if (randomnation(2)) {
+            nextmove = ORGMOVE;
+          } else {
+            nextmove = DESTMOVE;
+          }
+        }
+      } else {
+        if (oriapex < 0) {
+          // Two faces, opposite to origin and apex, are viable.
+          //s = randomnation(2); // 's' is in {0,1}.
+          if (randomnation(2)) {
+            nextmove = ORGMOVE;
+          } else {
+            nextmove = APEXMOVE;
+          }
+        } 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.
+          //s = randomnation(2); // 's' is in {0,1}.
+          if (randomnation(2)) {
+            nextmove = DESTMOVE;
+          } else {
+            nextmove = APEXMOVE;
+          }
+        } 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.
+            enextesymself(*searchtet);
+            if (oridest == 0) {
+              eprevself(*searchtet); // edge oppo->apex
+              if (oriapex == 0) {
+                // oppo is duplicated with p.
+                loc = ONVERTEX; // return ONVERTEX;
+                break;
+              }
+              loc = ONEDGE; // return ONEDGE;
+              break;
+            }
+            if (oriapex == 0) {
+              enextself(*searchtet); // edge dest->oppo
+              loc = ONEDGE; // return ONEDGE;
+              break;
+            }
+            loc = ONFACE; // return ONFACE;
+            break;
+          }
+          if (oridest == 0) {
+            // Go to the face opposite to destination.
+            eprevesymself(*searchtet);
+            if (oriapex == 0) {
+              eprevself(*searchtet); // edge oppo->org
+              loc = ONEDGE; // return ONEDGE;
+              break;
+            }
+            loc = ONFACE; // return ONFACE;
+            break;
+          }
+          if (oriapex == 0) {
+            // Go to the face opposite to apex
+            esymself(*searchtet);
+            loc = ONFACE; // return ONFACE;
+            break;
+          }
+          loc = INTETRAHEDRON; // return INTETRAHEDRON;
+          break;
+        }
+      }
+    }
+    
+    // Move to the selected face.
+    if (nextmove == ORGMOVE) {
+      enextesymself(*searchtet);
+    } else if (nextmove == DESTMOVE) {
+      eprevesymself(*searchtet);
+    } else {
+      esymself(*searchtet);
+    }
+    // Move to the adjacent tetrahedron (maybe a hull tetrahedron).
+    fsymself(*searchtet);
+    if (oppo(*searchtet) == dummypoint) {
+      loc = OUTSIDE; // return OUTSIDE;
+      break;
+    }
+
+    // Retreat the three vertices of the base face.
+    torg = org(*searchtet);
+    tdest = dest(*searchtet);
+    tapex = apex(*searchtet);
+
+  } // while (true)
+
+  return loc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flippush()    Push a face (possibly will be flipped) into flipstack.      //
+//                                                                           //
+// The face is marked. The flag is used to check the validity of the face on //
+// its popup.  Some other flips may change it already.                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flippush(badface*& fstack, triface* flipface)
+{
+  if (!facemarked(*flipface)) {
+    badface *newflipface = (badface *) flippool->alloc();
+    newflipface->tt = *flipface;
+    markface(newflipface->tt);
+    // Push this face into stack.
+    newflipface->nextitem = fstack;
+    fstack = newflipface;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// incrementalflip()    Incrementally flipping to construct DT.              //
+//                                                                           //
+// Faces need to be checked for flipping are already queued in 'flipstack'.  //
+// Return the total number of performed flips.                               //
+//                                                                           //
+// Comment:  This routine should be only used in the incremental Delaunay    //
+// construction.  In other cases, lawsonflip3d() should be used.             // 
+//                                                                           //
+// If the new point lies outside of the convex hull ('hullflag' is set). The //
+// incremental flip algorithm still works as usual.  However, we must ensure //
+// that every flip (2-to-3 or 3-to-2) does not create a duplicated (existing)//
+// edge or face. Otherwise, the underlying space of the triangulation becomes//
+// non-manifold and it is not possible to flip further.                      //
+// Thanks to Joerg Rambau and Frank Lutz for helping in this issue.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::incrementalflip(point newpt, int hullflag, flipconstraints *fc)
+{
+  badface *popface;
+  triface fliptets[5], *parytet;
+  point *pts, *parypt, pe;
+  REAL sign, ori;
+  int flipcount = 0;
+  int t1ver;
+  int i;
+
+  if (b->verbose > 2) {
+    printf("      Lawson flip (%ld faces).\n", flippool->items);
+  }
+
+  if (hullflag) {
+    // 'newpt' lies in the outside of the convex hull. 
+    // Mark all hull vertices which are connecting to it.
+    popface = flipstack;
+    while (popface != NULL) {
+      pts = (point *) popface->tt.tet;
+      for (i = 4; i < 8; i++) {
+        if ((pts[i] != newpt) && (pts[i] != dummypoint)) {
+          if (!pinfected(pts[i])) {
+            pinfect(pts[i]);
+            cavetetvertlist->newindex((void **) &parypt);
+            *parypt = pts[i];
+          }
+        } 
+      }
+      popface = popface->nextitem;
+    }
+  }
+
+  // Loop until the queue is empty.
+  while (flipstack != NULL) {
+
+    // Pop a face from the stack.
+    popface = flipstack;
+    fliptets[0] = popface->tt;
+    flipstack = flipstack->nextitem; // The next top item in stack.
+    flippool->dealloc((void *) popface);
+
+    // Skip it if it is a dead tet (destroyed by previous flips).
+    if (isdeadtet(fliptets[0])) continue;
+    // Skip it if it is not the same tet as we saved.
+    if (!facemarked(fliptets[0])) continue;
+
+    unmarkface(fliptets[0]);    
+
+    if ((point) fliptets[0].tet[7] == dummypoint) {
+      // It must be a hull edge.
+      fliptets[0].ver = epivot[fliptets[0].ver];
+      // A hull edge. The current convex hull may be enlarged.
+      fsym(fliptets[0], fliptets[1]);
+      pts = (point *) fliptets[1].tet;
+      ori = orient3d(pts[4], pts[5], pts[6], newpt);
+      if (ori < 0) {
+        // Visible. The convex hull will be enlarged.
+        // Decide which flip (2-to-3, 3-to-2, or 4-to-1) to use.
+        // Check if the tet [a,c,e,d] or [c,b,e,d] exists.
+        enext(fliptets[1], fliptets[2]); 
+        eprev(fliptets[1], fliptets[3]); 
+        fnextself(fliptets[2]); // [a,c,e,*]
+        fnextself(fliptets[3]); // [c,b,e,*]
+        if (oppo(fliptets[2]) == newpt) {
+          if (oppo(fliptets[3]) == newpt) {
+            // Both tets exist! A 4-to-1 flip is found.
+            terminatetetgen(this, 2); // Report a bug.
+          } else {
+            esym(fliptets[2], fliptets[0]);
+            fnext(fliptets[0], fliptets[1]); 
+            fnext(fliptets[1], fliptets[2]); 
+            // Perform a 3-to-2 flip. Replace edge [c,a] by face [d,e,b].
+            // This corresponds to my standard labels, where edge [e,d] is
+            //   repalced by face [a,b,c], and a is the new vertex. 
+            //   [0] [c,a,d,e] (d = newpt)
+            //   [1] [c,a,e,b] (c = dummypoint)
+            //   [2] [c,a,b,d]
+            flip32(fliptets, 1, fc);
+          }
+        } else {
+          if (oppo(fliptets[3]) == newpt) {
+            fnext(fliptets[3], fliptets[0]);
+            fnext(fliptets[0], fliptets[1]); 
+            fnext(fliptets[1], fliptets[2]); 
+            // Perform a 3-to-2 flip. Replace edge [c,b] by face [d,a,e].
+            //   [0] [c,b,d,a] (d = newpt)
+            //   [1] [c,b,a,e] (c = dummypoint)
+            //   [2] [c,b,e,d]
+            flip32(fliptets, 1, fc);
+          } else {
+            if (hullflag) {
+              // Reject this flip if pe is already marked.
+              pe = oppo(fliptets[1]);
+              if (!pinfected(pe)) {
+                pinfect(pe);
+                cavetetvertlist->newindex((void **) &parypt);
+                *parypt = pe;
+                // Perform a 2-to-3 flip.
+                flip23(fliptets, 1, fc);
+              } else {
+                // Reject this flip.
+                flipcount--;
+              }
+            } else {
+              // Perform a 2-to-3 flip. Replace face [a,b,c] by edge [e,d].
+              //   [0] [a,b,c,d], d = newpt.
+              //   [1] [b,a,c,e], c = dummypoint.
+              flip23(fliptets, 1, fc);
+            }
+          }
+        }
+        flipcount++;
+      } 
+      continue;
+    } // if (dummypoint)
+
+    fsym(fliptets[0], fliptets[1]);
+    if ((point) fliptets[1].tet[7] == dummypoint) {
+      // A hull face is locally Delaunay.
+      continue;
+    }
+    // Check if the adjacent tet has already been tested.
+    if (marktested(fliptets[1])) {
+      // It has been tested and it is Delaunay.
+      continue;
+    }
+
+    // Test whether the face is locally Delaunay or not.
+    pts = (point *) fliptets[1].tet; 
+    if (b->weighted) {
+      sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], newpt,
+                        pts[4][3], pts[5][3], pts[6][3], pts[7][3],
+                        newpt[3]);
+    } else {
+      sign = insphere_s(pts[4], pts[5], pts[6], pts[7], newpt);
+    }
+
+
+    if (sign < 0) {
+      point pd = newpt;
+      point pe = oppo(fliptets[1]);
+      // Check the convexity of its three edges. Stop checking either a
+      //   locally non-convex edge (ori < 0) or a flat edge (ori = 0) is
+      //   encountered, and 'fliptet' represents that edge.
+      for (i = 0; i < 3; i++) {
+        ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe);
+        if (ori <= 0) break;
+        enextself(fliptets[0]);
+      }
+      if (ori > 0) {
+        // A 2-to-3 flip is found.
+        //   [0] [a,b,c,d], 
+        //   [1] [b,a,c,e]. no dummypoint.
+        flip23(fliptets, 0, fc);
+        flipcount++;
+      } else { // ori <= 0
+        // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat,
+        //   where the edge [a',b'] is one of [a,b], [b,c], and [c,a].
+        // Check if there are three or four tets sharing at this edge.        
+        esymself(fliptets[0]); // [b,a,d,c]
+        for (i = 0; i < 3; i++) {
+          fnext(fliptets[i], fliptets[i+1]);
+        }
+        if (fliptets[3].tet == fliptets[0].tet) {
+          // A 3-to-2 flip is found. (No hull tet.)
+          flip32(fliptets, 0, fc); 
+          flipcount++;
+        } else {
+          // There are more than 3 tets at this edge.
+          fnext(fliptets[3], fliptets[4]);
+          if (fliptets[4].tet == fliptets[0].tet) {
+            if (ori == 0) {
+              // A 4-to-4 flip is found. (Two hull tets may be involved.)
+              // Current tets in 'fliptets':
+              //   [0] [b,a,d,c] (d may be newpt)
+              //   [1] [b,a,c,e]
+              //   [2] [b,a,e,f] (f may be dummypoint)
+              //   [3] [b,a,f,d]
+              esymself(fliptets[0]); // [a,b,c,d] 
+              // A 2-to-3 flip replaces face [a,b,c] by edge [e,d].
+              //   This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]).
+              //   It will be removed by the followed 3-to-2 flip.
+              flip23(fliptets, 0, fc); // No hull tet.
+              fnext(fliptets[3], fliptets[1]);
+              fnext(fliptets[1], fliptets[2]);
+              // Current tets in 'fliptets':
+              //   [0] [...]
+              //   [1] [b,a,d,e] (degenerated, d may be new point).
+              //   [2] [b,a,e,f] (f may be dummypoint)
+              //   [3] [b,a,f,d]
+              // A 3-to-2 flip replaces edge [b,a] by face [d,e,f].
+              //   Hull tets may be involved (f may be dummypoint).
+              flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc);
+              flipcount++;
+            }
+          }
+        }
+      } // ori
+    } else {
+      // The adjacent tet is Delaunay. Mark it to avoid testing it again.
+      marktest(fliptets[1]);
+      // Save it for unmarking it later.
+      cavebdrylist->newindex((void **) &parytet);
+      *parytet = fliptets[1];
+    }
+
+  } // while (flipstack)
+
+  // Unmark saved tetrahedra.
+  for (i = 0; i < cavebdrylist->objects; i++) {
+    parytet = (triface *) fastlookup(cavebdrylist, i);
+    unmarktest(*parytet);
+  }
+  cavebdrylist->restart();
+
+  if (hullflag) {
+    // Unmark infected vertices.
+    for (i = 0; i < cavetetvertlist->objects; i++) {
+      parypt = (point *) fastlookup(cavetetvertlist, i);
+      puninfect(*parypt);
+    }
+    cavetetvertlist->restart();
+  }
+
+
+  return flipcount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// initialdelaunay()    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::initialdelaunay(point pa, point pb, point pc, point pd)
+{
+  triface firsttet, tetopa, tetopb, tetopc, tetopd;
+  triface worktet, worktet1;
+
+  if (b->verbose > 2) {
+    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);
+  esym(firsttet, worktet);
+  bond(worktet, tetopc); // ab
+  enextesym(firsttet, worktet);
+  bond(worktet, tetopa); // bc 
+  eprevesym(firsttet, worktet);
+  bond(worktet, tetopb); // ca
+
+  // Connect hull tetrahedra together (at six edges of firsttet).
+  esym(tetopc, worktet); 
+  esym(tetopd, worktet1);
+  bond(worktet, worktet1); // ab
+  esym(tetopa, worktet);
+  eprevesym(tetopd, worktet1);
+  bond(worktet, worktet1); // bc
+  esym(tetopb, worktet);
+  enextesym(tetopd, worktet1);
+  bond(worktet, worktet1); // ca
+  eprevesym(tetopc, worktet);
+  enextesym(tetopb, worktet1);
+  bond(worktet, worktet1); // da
+  eprevesym(tetopa, worktet);
+  enextesym(tetopc, worktet1);
+  bond(worktet, worktet1); // db
+  eprevesym(tetopb, worktet);
+  enextesym(tetopa, worktet1);
+  bond(worktet, worktet1); // dc
+
+  // Set the vertex type.
+  if (pointtype(pa) == UNUSEDVERTEX) {
+    setpointtype(pa, VOLVERTEX);
+  }
+  if (pointtype(pb) == UNUSEDVERTEX) {
+    setpointtype(pb, VOLVERTEX);
+  }
+  if (pointtype(pc) == UNUSEDVERTEX) {
+    setpointtype(pc, VOLVERTEX);
+  }
+  if (pointtype(pd) == UNUSEDVERTEX) {
+    setpointtype(pd, VOLVERTEX);
+  }
+
+  setpoint2tet(pa, encode(firsttet));
+  setpoint2tet(pb, encode(firsttet));
+  setpoint2tet(pc, encode(firsttet));
+  setpoint2tet(pd, encode(firsttet));
+
+  // Remember the first tetrahedron.
+  recenttet = firsttet;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// incrementaldelaunay()    Create a Delaunay tetrahedralization by          //
+//                          the incremental approach.                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+
+void tetgenmesh::incrementaldelaunay(clock_t& tv)
+{
+  triface searchtet;
+  point *permutarray, swapvertex;
+  REAL v1[3], v2[3], n[3];
+  REAL bboxsize, bboxsize2, bboxsize3, ori;
+  int randindex; 
+  int ngroup = 0;
+  int 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];
+  points->traversalinit();
+
+  if (b->no_sort) {
+    if (b->verbose) {
+      printf("  Using the input order.\n"); 
+    }
+    for (i = 0; i < in->numberofpoints; i++) {
+      permutarray[i] = (point) points->traverse();
+    }
+  } else {
+    if (b->verbose) {
+      printf("  Permuting vertices.\n"); 
+    }
+    srand(in->numberofpoints);
+    for (i = 0; i < in->numberofpoints; i++) {
+      randindex = rand() % (i + 1); // randomnation(i + 1);
+      permutarray[i] = permutarray[randindex];
+      permutarray[randindex] = (point) points->traverse();
+    }
+    if (b->brio_hilbert) { // -b option
+      if (b->verbose) {
+        printf("  Sorting vertices.\n"); 
+      }
+      hilbert_init(in->mesh_dim);
+      brio_multiscale_sort(permutarray, in->numberofpoints, b->brio_threshold, 
+                           b->brio_ratio, &ngroup);
+    }
+  }
+
+  tv = clock(); // Remember the time for sorting points.
+
+  // 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 ((distance(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(this, 10);
+    }
+  }
+  if (i > 1) {
+    // Swap to move the non-identical 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.
+  // Acknowledgement:  Thanks Jan Pomplun for his correction by using 
+  //   epsilon^2 and epsilon^3 (instead of epsilon). 2013-08-15.
+  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 * b->epsilon)) {
+    i++;
+    if (i == in->numberofpoints - 1) {
+      printf("Exception:  All vertices are (nearly) collinear (Tol = %g).\n",
+             b->epsilon);
+      terminatetetgen(this, 10);
+    }
+    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-identical 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 = orient3dfast(permutarray[0], permutarray[1], permutarray[2], 
+                     permutarray[i]);
+  while ((fabs(ori) / bboxsize3) < (b->epsilon * b->epsilon * b->epsilon)) {
+    i++;
+    if (i == in->numberofpoints) {
+      printf("Exception:  All vertices are coplanar (Tol = %g).\n",
+             b->epsilon);
+      terminatetetgen(this, 10);
+    }
+    ori = orient3dfast(permutarray[0], permutarray[1], permutarray[2], 
+                       permutarray[i]);
+  }
+  if (i > 3) {
+    // Swap to move the non-identical 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.
+  initialdelaunay(permutarray[0], permutarray[1], permutarray[2],
+                  permutarray[3]);
+
+  if (b->verbose) {
+    printf("  Incrementally inserting vertices.\n");
+  }
+  insertvertexflags ivf;
+  flipconstraints fc;
+
+  // Choose algorithm: Bowyer-Watson (default) or Incremental Flip
+  if (b->incrflip) {
+    ivf.bowywat = 0;
+    ivf.lawson = 1;
+    fc.enqflag = 1;
+  } else {
+    ivf.bowywat = 1;
+    ivf.lawson = 0;
+  }
+
+
+  for (i = 4; i < in->numberofpoints; i++) {
+    if (pointtype(permutarray[i]) == UNUSEDVERTEX) {
+      setpointtype(permutarray[i], VOLVERTEX);
+    }
+    if (b->brio_hilbert || b->no_sort) { // -b or -b/1
+      // Start the last updated tet.
+      searchtet.tet = recenttet.tet;
+    } else { // -b0
+      // Randomly choose the starting tet for point location.
+      searchtet.tet = NULL;
+    }
+    ivf.iloc = (int) OUTSIDE;
+    // Insert the vertex.
+    if (insertpoint(permutarray[i], &searchtet, NULL, NULL, &ivf)) {
+      if (flipstack != NULL) {
+        // Perform flip to recover Delaunayness.
+        incrementalflip(permutarray[i], (ivf.iloc == (int) OUTSIDE), &fc);
+      }
+    } else {
+      if (ivf.iloc == (int) ONVERTEX) {
+        // The point already exists. Mark it and do nothing on it.
+        swapvertex = org(searchtet);
+        assert(swapvertex != permutarray[i]); // SELF_CHECK
+        if (b->object != tetgenbehavior::STL) {
+          if (!b->quiet) {
+            printf("Warning:  Point #%d is coincident with #%d. Ignored!\n",
+                   pointmark(permutarray[i]), pointmark(swapvertex));
+          }
+        }
+        setpoint2ppt(permutarray[i], swapvertex);
+        setpointtype(permutarray[i], DUPLICATEDVERTEX);
+        dupverts++;
+      } else if (ivf.iloc == (int) NEARVERTEX) {
+        swapvertex = point2ppt(permutarray[i]);
+        if (!b->quiet) {
+          printf("Warning:  Point %d is replaced by point %d.\n",
+                 pointmark(permutarray[i]), pointmark(swapvertex));
+          printf("  Avoid creating a very short edge (len = %g) (< %g).\n",
+                 permutarray[i][3], b->minedgelength);
+          printf("  You may try a smaller tolerance (-T) (current is %g)\n", 
+                 b->epsilon);
+          printf("  or use the option -M0/1 to avoid such replacement.\n");
+        }
+        // Remember it is a duplicated point.
+        setpointtype(permutarray[i], DUPLICATEDVERTEX);
+        // Count the number of duplicated points.
+        dupverts++;
+      }
+    }
+  }
+
+
+
+  delete [] permutarray;
+}
+
+////                                                                       ////
+////                                                                       ////
+//// delaunay_cxx /////////////////////////////////////////////////////////////
+
+//// surface_cxx //////////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flipshpush()    Push a facet edge into flip stack.                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flipshpush(face* flipedge)
+{
+  badface *newflipface;
+
+  newflipface = (badface *) flippool->alloc();
+  newflipface->ss = *flipedge;
+  newflipface->forg = sorg(*flipedge);
+  newflipface->fdest = sdest(*flipedge);
+  newflipface->nextitem = flipstack;
+  flipstack = newflipface;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip22()    Perform a 2-to-2 flip in surface mesh.                        //
+//                                                                           //
+// 'flipfaces' is an array of two subfaces. On input, they are [a,b,c] and   //
+// [b,a,d]. On output, they are [c,d,b] and [d,c,a]. As a result, edge [a,b] //
+// is replaced by edge [c,d].                                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flip22(face* flipfaces, int flipflag, int chkencflag)
+{
+  face bdedges[4], outfaces[4], infaces[4];
+  face bdsegs[4];
+  face checkface;
+  point pa, pb, pc, pd;
+  int i;
+
+  pa = sorg(flipfaces[0]);
+  pb = sdest(flipfaces[0]);
+  pc = sapex(flipfaces[0]);
+  pd = sapex(flipfaces[1]);
+
+  if (sorg(flipfaces[1]) != pb) {
+    sesymself(flipfaces[1]);
+  }
+
+  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) {
+      if (isshsubseg(bdedges[i])) {
+        spivot(infaces[i], checkface);
+        while (checkface.sh != bdedges[i].sh) {
+          infaces[i] = checkface;
+          spivot(infaces[i], checkface);
+        }
+      }
+    }
+  }
+
+  // The flags set in these two subfaces do not change.
+  // Shellmark does not change.
+  // area constraint does not change.
+
+  // Transform [a,b,c] -> [c,d,b].
+  setshvertices(flipfaces[0], pc, pd, pb);
+  // Transform [b,a,d] -> [d,c,a].
+  setshvertices(flipfaces[1], pd, pc, pa);
+
+  // Update the point-to-subface map.
+  if (pointtype(pa) == FREEFACETVERTEX) {
+    setpoint2sh(pa, sencode(flipfaces[1]));
+  }
+  if (pointtype(pb) == FREEFACETVERTEX) {
+    setpoint2sh(pb, sencode(flipfaces[0]));
+  }
+  if (pointtype(pc) == FREEFACETVERTEX) {
+    setpoint2sh(pc, sencode(flipfaces[0]));
+  }
+  if (pointtype(pd) == FREEFACETVERTEX) {
+    setpoint2sh(pd, sencode(flipfaces[0]));
+  }
+
+  // Reconnect boundary edges to outer boundary faces.
+  for (i = 0; i < 4; i++) {
+    if (outfaces[(3 + i) % 4].sh != NULL) {
+      // Make sure that the subface has the ori as the segment.
+      if (bdsegs[(3 + i) % 4].sh != NULL) {
+        bdsegs[(3 + i) % 4].shver = 0;
+        if (sorg(bdedges[i]) != sorg(bdsegs[(3 + i) % 4])) {
+          sesymself(bdedges[i]);
+        }
+      }
+      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]);
+      if (chkencflag & 1) {
+        // Queue this segment for encroaching check.
+        enqueuesubface(badsubsegs, &(bdsegs[(3 + i) % 4]));
+      }
+    } else {
+      ssdissolve(bdedges[i]);
+    }
+  }
+
+  if (chkencflag & 2) {
+    // Queue the flipped subfaces for quality/encroaching checks.
+    for (i = 0; i < 2; i++) {
+      enqueuesubface(badsubfacs, &(flipfaces[i]));
+    }
+  }
+
+  recentsh = flipfaces[0];
+
+  if (flipflag) {
+    // Put the boundary edges into flip stack.
+    for (i = 0; i < 4; i++) {
+      flipshpush(&(bdedges[i]));
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip31()    Remove a vertex by transforming 3-to-1 subfaces.              //
+//                                                                           //
+// 'flipfaces' is an array of subfaces. Its length is at least 4.  On input, //
+// the first three faces are: [p,a,b], [p,b,c], and [p,c,a]. This routine    //
+// replaces them by one face [a,b,c], it is returned in flipfaces[3].        //
+//                                                                           //
+// NOTE: The three old subfaces are not deleted within this routine.  They   //
+// still hold pointers to their adjacent subfaces. These informations are    //
+// needed by the routine 'sremovevertex()' for recovering a segment.         //
+// The caller of this routine must delete the old subfaces after their uses. //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flip31(face* flipfaces, int flipflag)
+{
+  face bdedges[3], outfaces[3], infaces[3];
+  face bdsegs[3];
+  face checkface;
+  point pa, pb, pc;
+  int i;
+
+  pa = sdest(flipfaces[0]);
+  pb = sdest(flipfaces[1]);
+  pc = sdest(flipfaces[2]);
+
+  flip31count++;
+
+  // Collect all infos at the three boundary edges.
+  for (i = 0; i < 3; i++) {
+    senext(flipfaces[i], bdedges[i]);
+    spivot(bdedges[i], outfaces[i]);
+    infaces[i] = outfaces[i];
+    sspivot(bdedges[i], bdsegs[i]);
+    if (outfaces[i].sh != NULL) {
+      if (isshsubseg(bdedges[i])) {
+        spivot(infaces[i], checkface);
+        while (checkface.sh != bdedges[i].sh) {
+          infaces[i] = checkface;
+          spivot(infaces[i], checkface);
+        }
+      }
+    }
+  } // i
+
+  // Create a new subface.
+  makeshellface(subfaces, &(flipfaces[3]));
+  setshvertices(flipfaces[3], pa, pb,pc);
+  setshellmark(flipfaces[3], shellmark(flipfaces[0]));
+  if (checkconstraints) {
+    //area = areabound(flipfaces[0]);
+    setareabound(flipfaces[3], areabound(flipfaces[0]));
+  }
+  if (useinsertradius) {
+    setfacetindex(flipfaces[3], getfacetindex(flipfaces[0]));
+  }
+
+  // Update the point-to-subface map.
+  if (pointtype(pa) == FREEFACETVERTEX) {
+    setpoint2sh(pa, sencode(flipfaces[3]));
+  }
+  if (pointtype(pb) == FREEFACETVERTEX) {
+    setpoint2sh(pb, sencode(flipfaces[3]));
+  }
+  if (pointtype(pc) == FREEFACETVERTEX) {
+    setpoint2sh(pc, sencode(flipfaces[3]));
+  }
+
+  // Update the three new boundary edges.
+  bdedges[0] = flipfaces[3];         // [a,b]
+  senext(flipfaces[3], bdedges[1]);  // [b,c]
+  senext2(flipfaces[3], bdedges[2]); // [c,a]
+
+  // Reconnect boundary edges to outer boundary faces.
+  for (i = 0; i < 3; i++) {
+    if (outfaces[i].sh != NULL) {
+      // Make sure that the subface has the ori as the segment.
+      if (bdsegs[i].sh != NULL) {
+        bdsegs[i].shver = 0;
+        if (sorg(bdedges[i]) != sorg(bdsegs[i])) {
+          sesymself(bdedges[i]);
+        }
+      }
+      sbond1(bdedges[i], outfaces[i]);
+      sbond1(infaces[i], bdedges[i]);
+    }
+    if (bdsegs[i].sh != NULL) {
+      ssbond(bdedges[i], bdsegs[i]);
+    }
+  }
+
+  recentsh = flipfaces[3];
+
+  if (flipflag) {
+    // Put the boundary edges into flip stack.
+    for (i = 0; i < 3; i++) {
+      flipshpush(&(bdedges[i]));
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// lawsonflip()    Flip non-locally Delaunay edges.                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+long tetgenmesh::lawsonflip()
+{
+  badface *popface;
+  face flipfaces[2];
+  point pa, pb, pc, pd;
+  REAL sign;
+  long flipcount = 0;
+
+  if (b->verbose > 2) {
+    printf("      Lawson flip %ld edges.\n", flippool->items);
+  }
+
+  while (flipstack != (badface *) NULL) {
+
+    // Pop an edge from the stack.
+    popface = flipstack;
+    flipfaces[0] = popface->ss;
+    pa = popface->forg;
+    pb = popface->fdest;
+    flipstack = popface->nextitem; // The next top item in stack.
+    flippool->dealloc((void *) popface);
+
+    // 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.
+    if (isshsubseg(flipfaces[0])) 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, 0);
+      flipcount++;
+    }
+  }
+
+  if (b->verbose > 2) {
+    printf("      Performed %ld flips.\n", flipcount);
+  }
+
+  return flipcount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// sinsertvertex()    Insert a vertex into a triangulation of a facet.       //
+//                                                                           //
+// This function uses three global arrays: 'caveshlist', 'caveshbdlist', and //
+// 'caveshseglist'. On return, 'caveshlist' contains old subfaces in C(p),   //
+// 'caveshbdlist' contains new subfaces in C(p). If the new point lies on a  //
+// segment, 'cavesegshlist' returns the two new subsegments.                 //
+//                                                                           //
+// 'iloc' suggests the location of the point. If it is OUTSIDE, this routine //
+// will first locate the point. It starts searching from 'searchsh' or 'rec- //
+// entsh' if 'searchsh' is NULL.                                             //
+//                                                                           //
+// If 'bowywat' is set (1), the Bowyer-Watson algorithm is used to insert    //
+// the vertex. Otherwise, only insert the vertex in the initial cavity.      // 
+//                                                                           //
+// If 'iloc' is 'INSTAR', this means the cavity of this vertex was already   //
+// provided in the list 'caveshlist'.                                        //
+//                                                                           //
+// If 'splitseg' is not NULL, the new vertex lies on the segment and it will //
+// be split. 'iloc' must be either 'ONEDGE' or 'INSTAR'.                     //
+//                                                                           //
+// 'rflag' (rounding) is a parameter passed to slocate() function.  If it is //
+// set, after the location of the point is found, either ONEDGE or ONFACE,   //
+// round the result using an epsilon.                                        //
+//                                                                           //
+// NOTE: the old subfaces in C(p) are not deleted. They're needed in case we //
+// want to remove the new point immediately.                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::sinsertvertex(point insertpt, face *searchsh, face *splitseg,
+                              int iloc, int bowywat, int rflag)
+{
+  face cavesh, neighsh, *parysh;
+  face newsh, casout, casin;
+  face checkseg;
+  point pa, pb;
+  enum locateresult loc = OUTSIDE;
+  REAL sign, ori;
+  int i, j;
+
+  if (b->verbose > 2) {
+    printf("      Insert facet point %d.\n", pointmark(insertpt));
+  }
+
+  if (bowywat == 3) {
+    loc = INSTAR;
+  }
+
+  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
+    // A segment is going to be split, no point location.
+    spivot(*splitseg, *searchsh);
+    if (loc != INSTAR) loc = ONEDGE;
+  } else {
+    if (loc != INSTAR) loc = (enum locateresult) iloc;
+    if (loc == OUTSIDE) {
+      // Do point location in surface mesh.
+      if (searchsh->sh == NULL) {
+        *searchsh = recentsh;
+      }
+      // Search the vertex. An above point must be provided ('aflag' = 1).
+      loc = slocate(insertpt, searchsh, 1, 1, rflag);
+    }
+  }
+
+
+  // Form the initial sC(p).
+  if (loc == ONFACE) {
+    // Add the face into list (in B-W cavity).
+    smarktest(*searchsh);
+    caveshlist->newindex((void **) &parysh);
+    *parysh = *searchsh;
+  } else if (loc == ONEDGE) {
+    if ((splitseg != NULL) && (splitseg->sh != NULL)) {
+      splitseg->shver = 0;
+      pa = sorg(*splitseg);
+    } else {
+      pa = sorg(*searchsh);
+    }
+    if (searchsh->sh != NULL) {
+      // Collect all subfaces share at this edge.
+      neighsh = *searchsh;
+      while (1) {
+        // Adjust the origin of its edge to be 'pa'.
+        if (sorg(neighsh) != pa) sesymself(neighsh);
+        // Add this face into list (in B-W cavity).
+        smarktest(neighsh);
+        caveshlist->newindex((void **) &parysh);
+        *parysh = neighsh;
+        // Add this face into face-at-splitedge list.
+        cavesegshlist->newindex((void **) &parysh);
+        *parysh = neighsh;
+        // Go to the next face at the edge.
+        spivotself(neighsh);
+        // Stop if all faces at the edge have been visited.
+        if (neighsh.sh == searchsh->sh) break;
+        if (neighsh.sh == NULL) break;
+      }
+    } // If (not a non-dangling segment).
+  } else if (loc == ONVERTEX) {
+    return (int) loc;
+  } else if (loc == OUTSIDE) {
+    // Comment: This should only happen during the surface meshing step.
+    // Enlarge the convex hull of the triangulation by including p.
+    // An above point of the facet is set in 'dummypoint' to replace
+    // orient2d tests by orient3d tests.
+    // Imagine that the current edge a->b (in 'searchsh') is horizontal in a
+    //   plane, and a->b is directed from left to right, p lies above a->b.  
+    //   Find the right-most edge of the triangulation which is visible by p.
+    neighsh = *searchsh;
+    while (1) {
+      senext2self(neighsh);
+      spivot(neighsh, casout);
+      if (casout.sh == NULL) {
+        // A convex hull edge. Is it visible by p.
+        ori = orient3d(sorg(neighsh), sdest(neighsh), dummypoint, insertpt);
+        if (ori < 0) {
+          *searchsh = neighsh; // Visible, update 'searchsh'.
+        } else {
+          break; // 'searchsh' 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(*searchsh);
+    pb = sdest(*searchsh);
+    while (1) {
+      // Create a new subface on top of the (visible) edge.
+      makeshellface(subfaces, &newsh); 
+      setshvertices(newsh, pb, pa, insertpt);
+      setshellmark(newsh, shellmark(*searchsh));
+      if (checkconstraints) {
+        //area = areabound(*searchsh);
+        setareabound(newsh, areabound(*searchsh));
+      }
+      if (useinsertradius) {
+        setfacetindex(newsh, getfacetindex(*searchsh));
+      }
+      // Connect the new subface to the bottom subfaces.
+      sbond1(newsh, *searchsh);
+      sbond1(*searchsh, 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 (inside the B-W cavity).
+      smarktest(newsh);
+      caveshlist->newindex((void **) &parysh);
+      *parysh = newsh;
+      // Move to the convex hull edge at the left of 'searchsh'.
+      neighsh = *searchsh;
+      while (1) {
+        senextself(neighsh);
+        spivot(neighsh, casout);
+        if (casout.sh == NULL) {
+          *searchsh = neighsh;
+          break;
+        }
+        if (sorg(casout) != sdest(neighsh)) sesymself(casout);
+        neighsh = casout;
+      }
+      // A convex hull edge. Is it visible by p.
+      pa = sorg(*searchsh);
+      pb = sdest(*searchsh);
+      ori = orient3d(pa, pb, dummypoint, insertpt);
+      // Finish the process if p is not visible by the hull edge.
+      if (ori >= 0) break;
+    }
+  } else if (loc == INSTAR) {
+    // Under this case, the sub-cavity sC(p) has already been formed in
+    //   insertvertex().
+  }
+
+  // Form the Bowyer-Watson cavity sC(p).
+  for (i = 0; i < caveshlist->objects; i++) {
+    cavesh = * (face *) fastlookup(caveshlist, i);
+    for (j = 0; j < 3; j++) {
+      if (!isshsubseg(cavesh)) {
+        spivot(cavesh, neighsh);
+        if (neighsh.sh != NULL) {
+          // The adjacent face exists.
+          if (!smarktested(neighsh)) {
+            if (bowywat) {
+              if (loc == INSTAR) { // if (bowywat > 2) {
+                // It must be a boundary edge.
+                sign = 1;
+              } else {
+                // Check if this subface is connected to adjacent tet(s).
+                if (!isshtet(neighsh)) {
+                  // Check if the subface is non-Delaunay wrt. the new pt.
+                  sign = incircle3d(sorg(neighsh), sdest(neighsh), 
+                                    sapex(neighsh), insertpt);
+                } else {
+                  // It is connected to an adjacent tet. A boundary edge.
+                  sign = 1;
+                }
+              }
+              if (sign < 0) {
+                // Add the adjacent face in list (in B-W cavity).
+                smarktest(neighsh);
+                caveshlist->newindex((void **) &parysh);
+                *parysh = neighsh;
+              }
+            } else {
+              sign = 1; // A boundary edge.
+            }
+          } else {
+            sign = -1; // Not a boundary edge.
+          }
+        } else {
+          // No adjacent face. It is a hull edge.
+          if (loc == OUTSIDE) {
+            // It is a boundary edge if it does not contain p.
+            if ((sorg(cavesh) == insertpt) || (sdest(cavesh) == insertpt)) {
+              sign = -1; // Not a boundary edge.
+            } else {
+              sign = 1; // A boundary edge.
+            }
+          } else {
+            sign = 1; // A boundary edge.
+          }
+        }
+      } else {
+        // Do not across a segment. It is a boundary edge.
+        sign = 1;
+      }
+      if (sign >= 0) {
+        // Add a boundary edge.
+        caveshbdlist->newindex((void **) &parysh);
+        *parysh = cavesh;
+      }
+      senextself(cavesh);
+    } // j
+  } // i
+
+
+  // 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(subfaces, &newsh); 
+    setshvertices(newsh, pa, pb, insertpt);
+    setshellmark(newsh, shellmark(*parysh));
+    if (checkconstraints) {
+      //area = areabound(*parysh);
+      setareabound(newsh, areabound(*parysh));
+    }
+    if (useinsertradius) {
+      setfacetindex(newsh, getfacetindex(*parysh));
+    }
+    // Update the point-to-subface map.
+    if (pointtype(pa) == FREEFACETVERTEX) {
+      setpoint2sh(pa, sencode(newsh));
+    }
+    if (pointtype(pb) == FREEFACETVERTEX) {
+      setpoint2sh(pb, sencode(newsh));
+    }
+    // Connect newsh to outer subfaces.
+    spivot(*parysh, casout);
+    if (casout.sh != NULL) {
+      casin = casout;
+      if (checkseg.sh != NULL) {
+        // Make sure that newsh has the right ori at this segment.
+        checkseg.shver = 0;
+        if (sorg(newsh) != sorg(checkseg)) {
+          sesymself(newsh);
+          sesymself(*parysh); // This side should also be inverse.
+        }
+        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).
+    //   *parysh and newsh point to the same edge and the same ori.
+    sbond1(*parysh, newsh);
+  }
+
+  if (newsh.sh != NULL) {
+    // Set a handle for searching.
+    recentsh = newsh;
+  }
+
+  // Update the point-to-subface map.
+  if (pointtype(insertpt) == FREEFACETVERTEX) {
+    setpoint2sh(insertpt, sencode(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);
+    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);
+        senext2self(neighsh); // Go to the open edge [p, b].
+        sbond(newsh, neighsh);
+      } else {
+        // There is no adjacent new face at this side.
+        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);
+        senextself(neighsh); // Go to the open edge [a, p].
+        sbond(newsh, neighsh);
+      } else {
+        // There is no adjacent new face at this side.
+        assert(loc == OUTSIDE); // SELF_CHECK
+      }
+    }
+  }
+
+  if ((loc == ONEDGE) || ((splitseg != NULL) && (splitseg->sh != NULL))
+      || (cavesegshlist->objects > 0l)) {
+    // An edge is being split. We distinguish two cases:
+    //   (1) the edge is not on the boundary of the cavity;
+    //   (2) the edge is on the boundary of the cavity.
+    // In case (2), the edge is either a segment or a hull edge. There are
+    //   degenerated new faces in the cavity. They must be removed.
+    face aseg, bseg, aoutseg, boutseg;
+
+    for (i = 0; i < cavesegshlist->objects; i++) {
+      // Get the saved old subface.
+      parysh = (face *) fastlookup(cavesegshlist, i);
+      // Get a possible new degenerated subface.
+      spivot(*parysh, cavesh);
+      if (sapex(cavesh) == insertpt) {
+        // Found a degenerated new subface, i.e., case (2).
+        if (cavesegshlist->objects > 1) {
+          // There are more than one subface share at this edge.
+          j = (i + 1) % (int) cavesegshlist->objects;
+          parysh = (face *) fastlookup(cavesegshlist, j);
+          spivot(*parysh, neighsh);
+          // Adjust cavesh and neighsh both at edge a->b, and has p as apex.
+          if (sorg(neighsh) != sorg(cavesh)) {
+            sesymself(neighsh);
+            assert(sorg(neighsh) == sorg(cavesh)); // SELF_CHECK
+          }
+          assert(sapex(neighsh) == insertpt); // SELF_CHECK
+          // Connect adjacent faces at two other edges of cavesh and neighsh.
+          //   As a result, the two degenerated new faces are squeezed from the
+          //   new triangulation of the cavity. Note that the squeezed faces
+          //   still hold the adjacent informations which will be used in 
+          //   re-connecting subsegments (if they exist). 
+          for (j = 0; j < 2; j++) { 
+            senextself(cavesh);
+            senextself(neighsh);
+            spivot(cavesh, newsh);
+            spivot(neighsh, casout);
+            sbond1(newsh, casout); // newsh <- casout.
+          }
+        } else {
+          // There is only one subface containing this edge [a,b]. Squeeze the
+          //   degenerated new face [a,b,c] by disconnecting it from its two 
+          //   adjacent subfaces at edges [b,c] and [c,a]. Note that the face
+          //   [a,b,c] still hold the connection to them.
+          for (j = 0; j < 2; j++) {
+            senextself(cavesh);
+            spivot(cavesh, newsh);
+            sdissolve(newsh);
+          }
+        }
+        //recentsh = newsh;
+        // Update the point-to-subface map.
+        if (pointtype(insertpt) == FREEFACETVERTEX) {
+          setpoint2sh(insertpt, sencode(newsh));
+        }
+      }
+    }
+
+    if ((splitseg != NULL) && (splitseg->sh != NULL)) {
+      if (loc != INSTAR) { // if (bowywat < 3) {
+        smarktest(*splitseg); // Mark it as being processed.
+      }
+      
+      aseg = *splitseg;
+      pa = sorg(*splitseg);
+      pb = sdest(*splitseg);
+
+      // Insert the new point p.
+      makeshellface(subsegs, &aseg);
+      makeshellface(subsegs, &bseg);
+
+      setshvertices(aseg, pa, insertpt, NULL);
+      setshvertices(bseg, insertpt, pb, NULL);
+      setshellmark(aseg, shellmark(*splitseg));
+      setshellmark(bseg, shellmark(*splitseg));
+      if (checkconstraints) {
+        setareabound(aseg, areabound(*splitseg));
+        setareabound(bseg, areabound(*splitseg));
+      }
+      if (useinsertradius) {
+        setfacetindex(aseg, getfacetindex(*splitseg));
+        setfacetindex(bseg, getfacetindex(*splitseg));
+      }
+
+      // Connect [#, a]<->[a, p].
+      senext2(*splitseg, boutseg); // Temporarily use boutseg.
+      spivotself(boutseg);
+      if (boutseg.sh != NULL) {
+        senext2(aseg, aoutseg);
+        sbond(boutseg, aoutseg);
+      }
+      // Connect [p, b]<->[b, #].
+      senext(*splitseg, aoutseg);
+      spivotself(aoutseg);
+      if (aoutseg.sh != NULL) {
+        senext(bseg, boutseg);
+        sbond(boutseg, aoutseg);
+      }
+      // Connect [a, p] <-> [p, b].
+      senext(aseg, aoutseg);
+      senext2(bseg, boutseg);
+      sbond(aoutseg, boutseg);
+
+      // Connect subsegs [a, p] and [p, b] to adjacent new subfaces.
+      // Although the degenerated new faces have been squeezed. They still
+      //   hold the connections to the actual new faces. 
+      for (i = 0; i < cavesegshlist->objects; i++) {        
+        parysh = (face *) fastlookup(cavesegshlist, i);
+        spivot(*parysh, neighsh);
+        // neighsh is a degenerated new face.
+        if (sorg(neighsh) != pa) {
+          sesymself(neighsh);
+        }
+        senext2(neighsh, newsh);
+        spivotself(newsh); // The edge [p, a] in newsh
+        ssbond(newsh, aseg);
+        senext(neighsh, newsh);
+        spivotself(newsh); // The edge [b, p] in newsh
+        ssbond(newsh, bseg);
+      }
+
+
+      // Let the point remember the segment it lies on.
+      if (pointtype(insertpt) == FREESEGVERTEX) {
+        setpoint2sh(insertpt, sencode(aseg));
+      }
+      // Update the point-to-seg map.
+      if (pointtype(pa) == FREESEGVERTEX) {
+        setpoint2sh(pa, sencode(aseg));
+      }
+      if (pointtype(pb) == FREESEGVERTEX) {
+        setpoint2sh(pb, sencode(bseg));
+      }
+    } // if ((splitseg != NULL) && (splitseg->sh != NULL)) 
+
+    // Delete all degenerated new faces.
+    for (i = 0; i < cavesegshlist->objects; i++) {
+      parysh = (face *) fastlookup(cavesegshlist, i);
+      spivotself(*parysh);
+      if (sapex(*parysh) == insertpt) {
+        shellfacedealloc(subfaces, parysh->sh);
+      }
+    }
+    cavesegshlist->restart();
+
+    if ((splitseg != NULL) && (splitseg->sh != NULL)) {
+      // Return the two new subsegments (for further process).
+      //   Re-use 'cavesegshlist'.
+      cavesegshlist->newindex((void **) &parysh);
+      *parysh = aseg;
+      cavesegshlist->newindex((void **) &parysh);
+      *parysh = bseg;
+    }
+  } // if (loc == ONEDGE)
+
+
+  return (int) loc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// sremovevertex()    Remove a vertex from the surface mesh.                 //
+//                                                                           //
+// 'delpt' (p) is the vertex to be removed. If 'parentseg' is not NULL, p is //
+// a segment vertex, and the origin of 'parentseg' is p. Otherwise, p is a   //
+// facet vertex, and the origin of 'parentsh' is p.                          //
+//                                                                           //
+// Within each facet, we first use a sequence of 2-to-2 flips to flip any    //
+// edge at p, finally use a 3-to-1 flip to remove p.                         //
+//                                                                           //
+// All new created subfaces are returned in the global array 'caveshbdlist'. //
+// The new segment (when p is on segment) is returned in 'parentseg'.        //
+//                                                                           //
+// If 'lawson' > 0, the Lawson flip algorithm is used to recover Delaunay-   //
+// ness after p is removed.                                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
+                              int lawson)
+{
+  face flipfaces[4], spinsh, *parysh;
+  point pa, pb, pc, pd;
+  REAL ori1, ori2;
+  int it, i, j;
+
+  if (parentseg != NULL) {
+    // 'delpt' (p) should be a Steiner point inserted in a segment [a,b],
+    //   where 'parentseg' should be [p,b]. Find the segment [a,p].
+    face startsh, neighsh, nextsh;
+    face abseg, prevseg, checkseg;
+    face adjseg1, adjseg2;
+    face fakesh;
+    senext2(*parentseg, prevseg);
+    spivotself(prevseg);
+    prevseg.shver = 0;
+    assert(sdest(prevseg) == delpt);
+    // Restore the original segment [a,b].
+    pa = sorg(prevseg);
+    pb = sdest(*parentseg);
+    if (b->verbose > 2) {
+      printf("      Remove vertex %d from segment [%d, %d].\n", 
+             pointmark(delpt), pointmark(pa), pointmark(pb));
+    }
+    makeshellface(subsegs, &abseg);
+    setshvertices(abseg, pa, pb, NULL);
+    setshellmark(abseg, shellmark(*parentseg));
+    if (checkconstraints) {
+      setareabound(abseg, areabound(*parentseg));
+    }
+    if (useinsertradius) {
+      setfacetindex(abseg, getfacetindex(*parentseg));
+    }
+    // Connect [#, a]<->[a, b].
+    senext2(prevseg, adjseg1);
+    spivotself(adjseg1);
+    if (adjseg1.sh != NULL) {
+      adjseg1.shver = 0;
+      assert(sdest(adjseg1) == pa);
+      senextself(adjseg1);
+      senext2(abseg, adjseg2);
+      sbond(adjseg1, adjseg2);
+    }
+    // Connect [a, b]<->[b, #].
+    senext(*parentseg, adjseg1);
+    spivotself(adjseg1);
+    if (adjseg1.sh != NULL) {
+      adjseg1.shver = 0;
+      assert(sorg(adjseg1) == pb);
+      senext2self(adjseg1);
+      senext(abseg, adjseg2);
+      sbond(adjseg1, adjseg2);
+    }
+    // Update the point-to-segment map.
+    setpoint2sh(pa, sencode(abseg));
+    setpoint2sh(pb, sencode(abseg));
+
+    // Get the faces in face ring at segment [p, b].
+    //   Re-use array 'caveshlist'.
+    spivot(*parentseg, *parentsh);
+    if (parentsh->sh != NULL) {
+      spinsh = *parentsh;
+      while (1) {
+        // Save this face in list.
+        caveshlist->newindex((void **) &parysh);
+        *parysh = spinsh;
+        // Go to the next face in the ring.
+        spivotself(spinsh);
+        if (spinsh.sh == parentsh->sh) break;
+      }
+    }
+
+    // Create the face ring of the new segment [a,b]. Each face in the ring
+    //   is [a,b,p] (degenerated!). It will be removed (automatically).
+    for (i = 0; i < caveshlist->objects; i++) {
+      parysh = (face *) fastlookup(caveshlist, i);
+      startsh = *parysh;
+      if (sorg(startsh) != delpt) {
+        sesymself(startsh);
+        assert(sorg(startsh) == delpt);
+      }      
+      // startsh is [p, b, #1], find the subface [a, p, #2].
+      neighsh = startsh;
+      while (1) {
+        senext2self(neighsh);
+        sspivot(neighsh, checkseg);
+        if (checkseg.sh != NULL) {
+          // It must be the segment [a, p].
+          assert(checkseg.sh == prevseg.sh);
+          break;
+        }
+        spivotself(neighsh);
+        assert(neighsh.sh != NULL);
+        if (sorg(neighsh) != delpt) sesymself(neighsh);
+      }
+      // Now neighsh is [a, p, #2].
+      if (neighsh.sh != startsh.sh) {
+        // Detach the two subsegments [a,p] and [p,b] from subfaces.
+        ssdissolve(startsh);
+        ssdissolve(neighsh);
+        // Create a degenerated subface [a,b,p]. It is used to: (1) hold the
+        //   new segment [a,b]; (2) connect to the two adjacent subfaces
+        //   [p,b,#] and [a,p,#].
+        makeshellface(subfaces, &fakesh);
+        setshvertices(fakesh, pa, pb, delpt);
+        setshellmark(fakesh, shellmark(startsh));
+        // Connect fakesh to the segment [a,b].
+        ssbond(fakesh, abseg);
+        // Connect fakesh to adjacent subfaces: [p,b,#1] and [a,p,#2].
+        senext(fakesh, nextsh);
+        sbond(nextsh, startsh);
+        senext2(fakesh, nextsh);
+        sbond(nextsh, neighsh);
+        smarktest(fakesh); // Mark it as faked.
+      } else {
+        // Special case. There exists already a degenerated face [a,b,p]!
+        //   There is no need to create a faked subface here.
+        senext2self(neighsh); // [a,b,p]
+        assert(sapex(neighsh) == delpt);
+        // Since we will re-connect the face ring using the faked subfaces.
+        //   We put the adjacent face of [a,b,p] to the list.
+        spivot(neighsh, startsh); // The original adjacent subface.
+        if (sorg(startsh) != pa) sesymself(startsh);
+        sdissolve(startsh);
+        // Connect fakesh to the segment [a,b].
+        ssbond(startsh, abseg);
+        fakesh = startsh; // Do not mark it!
+        // Delete the degenerated subface.
+        shellfacedealloc(subfaces, neighsh.sh);
+      }
+      // Save the fakesh in list (for re-creating the face ring).
+      cavesegshlist->newindex((void **) &parysh);
+      *parysh = fakesh;
+    } // i
+    caveshlist->restart();
+
+    // Re-create the face ring.
+    if (cavesegshlist->objects > 1) {
+      for (i = 0; i < cavesegshlist->objects; i++) {
+        parysh = (face *) fastlookup(cavesegshlist, i);
+        fakesh = *parysh;
+        // Get the next face in the ring.
+        j = (i + 1) % cavesegshlist->objects;
+        parysh = (face *) fastlookup(cavesegshlist, j);
+        nextsh = *parysh;
+        sbond1(fakesh, nextsh);
+      }
+    }
+
+    // Delete the two subsegments containing p.
+    shellfacedealloc(subsegs, parentseg->sh);
+    shellfacedealloc(subsegs, prevseg.sh);
+    // Return the new segment.
+    *parentseg = abseg;
+  } else {
+    // p is inside the surface.
+    if (b->verbose > 2) {
+      printf("      Remove vertex %d from surface.\n", pointmark(delpt));
+    }
+    assert(sorg(*parentsh) == delpt);
+    // Let 'delpt' be its apex.
+    senextself(*parentsh);
+    // For unifying the code, we add parentsh to list.
+    cavesegshlist->newindex((void **) &parysh);
+    *parysh = *parentsh;
+  }
+
+  // Remove the point (p).
+
+  for (it = 0; it < cavesegshlist->objects; it++) {
+    parentsh = (face *) fastlookup(cavesegshlist, it); // [a,b,p]
+    senextself(*parentsh); // [b,p,a].
+    spivotself(*parentsh);
+    if (sorg(*parentsh) != delpt) sesymself(*parentsh);
+    // now parentsh is [p,b,#].
+    if (sorg(*parentsh) != delpt) {
+      // The vertex has already been removed in above special case.
+      assert(!smarktested(*parentsh));
+      continue;
+    }
+
+    while (1) {      
+      // Initialize the flip edge list. Re-use 'caveshlist'.
+      spinsh = *parentsh; // [p, b, #]
+      while (1) {
+        caveshlist->newindex((void **) &parysh);
+        *parysh = spinsh;
+        senext2self(spinsh);
+        spivotself(spinsh);
+        assert(spinsh.sh != NULL);
+        if (spinsh.sh == parentsh->sh) break;
+        if (sorg(spinsh) != delpt) sesymself(spinsh);
+        assert(sorg(spinsh) == delpt);
+      } // while (1)
+
+      if (caveshlist->objects == 3) {
+        // Delete the point by a 3-to-1 flip.
+        for (i = 0; i < 3; i++) {
+          parysh = (face *) fastlookup(caveshlist, i);
+          flipfaces[i] = *parysh;
+        }
+        flip31(flipfaces, lawson);
+        for (i = 0; i < 3; i++) { 
+          shellfacedealloc(subfaces, flipfaces[i].sh);
+        }
+        caveshlist->restart();
+        // Save the new subface.
+        caveshbdlist->newindex((void **) &parysh);
+        *parysh = flipfaces[3];
+        // The vertex is removed.
+        break;
+      }
+
+      // Search an edge to flip.
+      for (i = 0; i < caveshlist->objects; i++) {
+        parysh = (face *) fastlookup(caveshlist, i);
+        flipfaces[0] = *parysh;
+        spivot(flipfaces[0], flipfaces[1]);
+        if (sorg(flipfaces[0]) != sdest(flipfaces[1])) 
+          sesymself(flipfaces[1]);
+        // Skip this edge if it belongs to a faked subface.
+        if (!smarktested(flipfaces[0]) && !smarktested(flipfaces[1])) {
+          pa = sorg(flipfaces[0]);
+          pb = sdest(flipfaces[0]);
+          pc = sapex(flipfaces[0]);
+          pd = sapex(flipfaces[1]);
+          calculateabovepoint4(pa, pb, pc, pd);
+          // Check if a 2-to-2 flip is possible.
+          ori1 = orient3d(pc, pd, dummypoint, pa);
+          ori2 = orient3d(pc, pd, dummypoint, pb);
+          if (ori1 * ori2 < 0) {
+            // A 2-to-2 flip is found.
+            flip22(flipfaces, lawson, 0);
+            // The i-th edge is flipped. The i-th and (i-1)-th subfaces are
+            //   changed. The 'flipfaces[1]' contains p as its apex.
+            senext2(flipfaces[1], *parentsh);
+            // Save the new subface.
+            caveshbdlist->newindex((void **) &parysh);
+            *parysh = flipfaces[0];
+            break;
+          }
+        } //
+      } // i
+
+      if (i == caveshlist->objects) {
+        // This can happen only if there are 4 edges at p, and they are
+        //   orthogonal to each other, see Fig. 2010-11-01.
+        assert(caveshlist->objects == 4);
+        // Do a flip22 and a flip31 to remove p.
+        parysh = (face *) fastlookup(caveshlist, 0);
+        flipfaces[0] = *parysh;
+        spivot(flipfaces[0], flipfaces[1]);
+        if (sorg(flipfaces[0]) != sdest(flipfaces[1])) {
+          sesymself(flipfaces[1]);
+        }
+        flip22(flipfaces, lawson, 0);
+        senext2(flipfaces[1], *parentsh);
+        // Save the new subface.
+        caveshbdlist->newindex((void **) &parysh);
+        *parysh = flipfaces[0];
+      }
+
+      // The edge list at p are changed.
+      caveshlist->restart();
+    } // while (1)
+
+  } // it
+
+  cavesegshlist->restart();
+
+  if (b->verbose > 2) {
+    printf("      Created %ld new subfaces.\n", caveshbdlist->objects);
+  }
+
+
+  if (lawson) {
+    lawsonflip();
+  }
+
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// slocate()    Locate a point in a surface triangulation.                   //
+//                                                                           //
+// Staring the search from 'searchsh'(it should not be NULL). Perform a line //
+// walk search for a subface containing the point (p).                       //
+//                                                                           //
+// If 'aflag' is set, the 'dummypoint' is pre-calculated so that it lies     //
+// above the 'searchsh' in its current orientation. The test if c is CCW to  //
+// the line a->b can be done by the test if c is below the oriented plane    //
+// a->b->dummypoint.                                                         //
+//                                                                           //
+// If 'cflag' is not TRUE, the triangulation may not be convex.  Stop search //
+// when a segment is met and return OUTSIDE.                                 //
+//                                                                           //
+// If 'rflag' (rounding) is set, after the location of the point is found,   //
+// either ONEDGE or ONFACE, round the result using an epsilon.               //
+//                                                                           //
+// The returned value indicates 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.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::locateresult tetgenmesh::slocate(point searchpt, 
+  face* searchsh, int aflag, int cflag, int rflag)
+{
+  face neighsh;
+  point pa, pb, pc;
+  enum locateresult loc;
+  enum {MOVE_BC, MOVE_CA} nextmove;
+  REAL ori, ori_bc, ori_ca;
+  int i;
+
+  pa = sorg(*searchsh);
+  pb = sdest(*searchsh);
+  pc = sapex(*searchsh);
+
+  if (!aflag) {
+    // No above point is given. Calculate an above point for this facet.
+    calculateabovepoint4(pa, pb, pc, searchpt);
+  }
+
+  // 'dummypoint' is given. Make sure it is above [a,b,c]
+  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
+
+  pc = sapex(*searchsh);
+
+  if (pc == searchpt) {
+    senext2self(*searchsh);
+    return ONVERTEX;
+  }
+
+  while (1) {
+
+    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.
+        if (randomnation(2)) {
+          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) { // (++)
+            loc = ONFACE;  // Inside [a, b, c].
+            break;
+          } else { // (+0)
+            senext2self(*searchsh); // On edge [c, a].
+            loc = ONEDGE;
+            break;
+          }
+        } else { // ori_bc == 0
+          if (ori_ca > 0) { // (0+)
+            senextself(*searchsh); // On edge [b, c].
+            loc = ONEDGE;
+            break;
+          } else { // (00)
+            // p is coincident with vertex c. 
+            senext2self(*searchsh);
+            return ONVERTEX;
+          }
+        }
+      }
+    }
+
+    // Move to the next face.
+    if (nextmove == MOVE_BC) {
+      senextself(*searchsh);
+    } else {
+      senext2self(*searchsh);
+    }
+    if (!cflag) {
+      // NON-convex case. Check if we will cross a boundary.
+      if (isshsubseg(*searchsh)) {
+        return ENCSEGMENT;
+      }
+    }
+    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);
+    pc = sapex(*searchsh);
+
+    if (pc == searchpt) {
+      senext2self(*searchsh);
+      return ONVERTEX;
+    }
+
+  } // while (1)
+
+  // assert(loc == ONFACE || loc == ONEDGE);
+
+
+  if (rflag) {
+    // Round the locate result before return.
+    REAL n[3], area_abc, area_abp, area_bcp, area_cap;
+
+    pa = sorg(*searchsh);
+    pb = sdest(*searchsh);
+    pc = sapex(*searchsh);
+
+    facenormal(pa, pb, pc, n, 1, NULL);
+    area_abc = sqrt(dot(n, n));
+
+    facenormal(pb, pc, searchpt, n, 1, NULL);
+    area_bcp = sqrt(dot(n, n));
+    if ((area_bcp / area_abc) < b->epsilon) {
+      area_bcp = 0; // Rounding.
+    }
+
+    facenormal(pc, pa, searchpt, n, 1, NULL);
+    area_cap = sqrt(dot(n, n));
+    if ((area_cap / area_abc) < b->epsilon) {
+      area_cap = 0; // Rounding
+    }
+
+    if ((loc == ONFACE) || (loc == OUTSIDE)) {
+      facenormal(pa, pb, searchpt, n, 1, NULL);
+      area_abp = sqrt(dot(n, n));
+      if ((area_abp / area_abc) < b->epsilon) {
+        area_abp = 0; // Rounding
+      }
+    } else { // loc == ONEDGE
+      area_abp = 0;
+    }
+
+    if (area_abp == 0) {
+      if (area_bcp == 0) {
+        assert(area_cap != 0);
+        senextself(*searchsh); 
+        loc = ONVERTEX; // p is close to b.
+      } else {
+        if (area_cap == 0) {
+          loc = ONVERTEX; // p is close to a.
+        } else {
+          loc = ONEDGE; // p is on edge [a,b].
+        }
+      }
+    } else if (area_bcp == 0) {
+      if (area_cap == 0) {
+        senext2self(*searchsh); 
+        loc = ONVERTEX; // p is close to c.
+      } else {
+        senextself(*searchsh);
+        loc = ONEDGE; // p is on edge [b,c].
+      }
+    } else if (area_cap == 0) {
+      senext2self(*searchsh);
+      loc = ONEDGE; // p is on edge [c,a].
+    } else {
+      loc = ONFACE; // p is on face [a,b,c].
+    }
+  } // if (rflag)
+
+  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 "locked"   //
+// 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::interresult tetgenmesh::sscoutsegment(face *searchsh, 
+  point endpt)
+{
+  face flipshs[2], neighsh;
+  face newseg;
+  point startpt, pa, pb, pc, pd;
+  enum interresult dir;
+  enum {MOVE_AB, MOVE_CA} nextmove;
+  REAL ori_ab, ori_ca, len;
+
+  // The origin of 'searchsh' is fixed.
+  startpt = sorg(*searchsh); // pa = startpt;
+  nextmove = MOVE_AB; // Avoid compiler warning.
+
+  if (b->verbose > 2) {
+    printf("      Scout segment (%d, %d).\n", pointmark(startpt),
+           pointmark(endpt));
+  }
+  len = distance(startpt, 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;
+    }
+
+    // Round the results.
+    if ((sqrt(triarea(startpt, pb, endpt)) / len) < b->epsilon) {
+      ori_ab = 0.0;
+    } else {
+      ori_ab = orient3d(startpt, pb, dummypoint, endpt);
+    }
+    if ((sqrt(triarea(pc, startpt, endpt)) / len) < b->epsilon) {
+      ori_ca = 0.0;
+    } else {
+      ori_ca = orient3d(pc, startpt, dummypoint, endpt);
+    }
+
+    if (ori_ab < 0) {
+      if (ori_ca < 0) { // (--)
+        // Both sides are viable moves.
+        if (randomnation(2)) {
+          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 (neighsh.sh != NULL) {
+        if (sorg(neighsh) != pb) sesymself(neighsh);
+        senext(neighsh, *searchsh);
+      } else {
+        // This side (startpt->pb) is outside. It is caused by rounding error.
+        // Try the next side, i.e., (pc->startpt).
+        senext2(*searchsh, neighsh);
+        spivotself(neighsh);
+        assert(neighsh.sh != NULL);
+        if (sdest(neighsh) != pc) sesymself(neighsh);
+        *searchsh = neighsh;
+      }
+    } else {
+      senext2(*searchsh, neighsh);
+      spivotself(neighsh);
+      if (neighsh.sh != NULL) {
+        if (sdest(neighsh) != pc) sesymself(neighsh);
+        *searchsh = neighsh;
+      } else {
+        // The same reason as above. 
+        // Try the next side, i.e., (startpt->pb).
+        spivot(*searchsh, neighsh);
+        assert(neighsh.sh != NULL);
+        if (sorg(neighsh) != pb) sesymself(neighsh);
+        senext(neighsh, *searchsh);
+      }
+    }
+    assert(sorg(*searchsh) == startpt); // SELF_CHECK
+
+  } // while
+
+  if (dir == SHAREEDGE) {
+    // Insert the segment into the triangulation.
+    makeshellface(subsegs, &newseg);
+    setshvertices(newseg, startpt, endpt, NULL);
+    // Set the default segment marker.
+    setshellmark(newseg, 1);
+    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]);
+    if (isshsubseg(flipshs[0])) {
+      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(this, 3);
+    }
+    // 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, 0);
+    // The flip may create an inverted 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) {
+      flipshpush(&(flipshs[0]));  // push it to 'flipstack'
+    } else if (ori_ca < 0) {
+      flipshpush(&(flipshs[1])); // // push it to 'flipstack'
+    }
+    // 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;
+  enum locateresult 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.
+        if (!isshsubseg(searchsh)) {
+          // 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, 1, 1, 0);
+    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) {
+        if (!isshsubseg(searchsh)) {
+          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(subfaces, parysh->sh);
+    } else {
+      sunmarktest(*parysh);
+    }
+  }
+
+  caveshlist->restart();
+  caveshbdlist->restart();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// triangulate()    Create a CDT for the facet.                              //
+//                                                                           //
+// All vertices of the triangulation have type FACETVERTEX.  The actual type //
+// of boundary vertices are set by the routine unifysements().               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist,
+                             int holes, REAL* holelist)
+{
+  face searchsh, newsh, *parysh; 
+  face newseg;
+  point pa, pb, pc, *ppt, *cons;
+  int iloc;
+  int i, j;
+
+  if (b->verbose > 2) {
+    printf("      f%d:  %ld vertices, %ld segments", shmark, ptlist->objects,
+           conlist->objects);
+    if (holes > 0) {
+      printf(", %d holes", holes);
+    }
+    printf(".\n");
+  }
+
+  if (ptlist->objects < 2l) {
+    // Not a segment or a facet.
+    return;
+  }
+
+  if (ptlist->objects == 2l) {
+    pa = * (point *) fastlookup(ptlist, 0);
+    pb = * (point *) fastlookup(ptlist, 1);
+    if (distance(pa, pb) > 0) {
+      // It is a single segment.
+      makeshellface(subsegs, &newseg);
+      setshvertices(newseg, pa, pb, NULL);
+      // Set the default segment marker '1'.
+      setshellmark(newseg, 1);
+    }
+    if (pointtype(pa) == VOLVERTEX) {
+      setpointtype(pa, FACETVERTEX);
+    }
+    if (pointtype(pb) == VOLVERTEX) {
+      setpointtype(pb, FACETVERTEX);
+    }
+    return;
+  } 
+
+
+  if (ptlist->objects == 3) {
+    pa = * (point *) fastlookup(ptlist, 0);
+    pb = * (point *) fastlookup(ptlist, 1);
+    pc = * (point *) fastlookup(ptlist, 2);
+  } else {
+    // Calculate an above point of this facet.
+    if (!calculateabovepoint(ptlist, &pa, &pb, &pc)) {
+      return; // The point set is degenerate.
+    }
+  }
+
+  // Create an initial triangulation.
+  makeshellface(subfaces, &newsh);
+  setshvertices(newsh, pa, pb, pc);
+  setshellmark(newsh, shmark);
+  recentsh = newsh;
+
+  if (pointtype(pa) == VOLVERTEX) {
+    setpointtype(pa, FACETVERTEX);
+  }
+  if (pointtype(pb) == VOLVERTEX) {
+    setpointtype(pb, FACETVERTEX);
+  }
+  if (pointtype(pc) == VOLVERTEX) {
+    setpointtype(pc, FACETVERTEX);
+  }
+
+  // Are there area constraints?
+  if (b->quality && (in->facetconstraintlist != (REAL *) NULL)) {
+    int idx, fmarker;
+    REAL area;
+    idx = in->facetmarkerlist[shmark - 1]; // The actual facet marker.
+    for (i = 0; i < in->numberoffacetconstraints; i++) {
+      fmarker = (int) in->facetconstraintlist[i * 2];
+      if (fmarker == idx) {
+        area = in->facetconstraintlist[i * 2 + 1];
+        setareabound(newsh, area);
+        break;
+      }
+    }
+  }
+
+  if (ptlist->objects == 3) {
+    // The triangulation only has one element.
+    for (i = 0; i < 3; i++) {
+      makeshellface(subsegs, &newseg);
+      setshvertices(newseg, sorg(newsh), sdest(newsh), NULL);
+      // Set the default segment marker '1'.
+      setshellmark(newseg, 1);
+      ssbond(newsh, newseg);
+      senextself(newsh);
+    }
+    return;
+  }
+
+  // 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; // Start from 'recentsh'.
+      iloc = (int) OUTSIDE;
+      // Insert the vertex. Use Bowyer-Watson algo. Round the location.
+      iloc = sinsertvertex(*ppt, &searchsh, NULL, iloc, 1, 1);
+      if (pointtype(*ppt) == VOLVERTEX) {
+        setpointtype(*ppt, FACETVERTEX);
+      }
+      // Delete all removed subfaces.
+      for (j = 0; j < caveshlist->objects; j++) {
+        parysh = (face *) fastlookup(caveshlist, j);
+        shellfacedealloc(subfaces, parysh->sh);
+      }
+      // Clear the global lists.
+      caveshbdlist->restart();
+      caveshlist->restart();
+      cavesegshlist->restart();
+    } else {
+      puninfect(*ppt); // This point has inserted.
+    }
+  }
+
+  // Insert the segments.
+  for (i = 0; i < conlist->objects; i++) {
+    cons = (point *) fastlookup(conlist, i);
+    searchsh = recentsh;
+    iloc = (int) slocate(cons[0], &searchsh, 1, 1, 0);
+    if (iloc != (enum locateresult) ONVERTEX) {
+      // Not found due to roundoff errors. Do a brute-force search.
+      subfaces->traversalinit();
+      searchsh.sh = shellfacetraverse(subfaces);
+      while (searchsh.sh != NULL) {
+        // Only search the subface in the same facet.
+        if (shellmark(searchsh) == shmark) {
+          if ((point) searchsh.sh[3] == cons[0]) {
+            searchsh.shver = 0; break;
+          } else if ((point) searchsh.sh[4] == cons[0]) {
+            searchsh.shver = 2; break;
+          } else if ((point) searchsh.sh[5] == cons[0]) {
+            searchsh.shver = 4; break;
+          }
+        }
+        searchsh.sh = shellfacetraverse(subfaces);
+	  }
+      assert(searchsh.sh != NULL);
+    }
+    // Recover the segment. Some edges may be flipped.
+    sscoutsegment(&searchsh, cons[1]);
+    if (flipstack != 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. Otherwise, these two subfaces     //
+// intersect, and the mesher is stopped.                                     //
+//                                                                           //
+// If the two subfaces are identical, we try to replace f2 by f1, i.e, all   //
+// neighbors of f2 are re-connected to f1.                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::unifysubfaces(face *f1, face *f2)
+{
+  if (b->psc) {
+    // In this case, it is possible that two subfaces are identical.
+    // While they must belong to two different surfaces.
+    return;
+  }
+
+  point pa, pb, pc, pd;
+
+  pa = sorg(*f1);
+  pb = sdest(*f1);
+  pc = sapex(*f1);
+  pd = sapex(*f2);
+
+  if (pc != pd) {
+    printf("Found two facets intersect each other.\n");
+    printf("  1st: [%d, %d, %d] #%d\n", 
+	       pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
+    printf("  2nd: [%d, %d, %d] #%d\n",
+	       pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
+    terminatetetgen(this, 3);
+  } else {
+    printf("Found two duplicated facets.\n");
+    printf("  1st: [%d, %d, %d] #%d\n", 
+	       pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
+    printf("  2nd: [%d, %d, %d] #%d\n",
+	       pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
+    terminatetetgen(this, 3);
+  }
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// unifysegments()    Remove redundant segments and create face links.       //
+//                                                                           //
+// After this routine, although segments are unique, but some of them may be //
+// removed later by mergefacet().  All vertices still have type FACETVERTEX. //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::unifysegments()
+{
+  badface *facelink = NULL, *newlinkitem, *f1, *f2;
+  face *facperverlist, sface;
+  face subsegloop, testseg;
+  point torg, tdest;
+  REAL ori1, ori2, ori3;
+  REAL n1[3], n2[3];
+  int *idx2faclist;
+  int idx, k, m;
+
+  if (b->verbose > 1) {
+    printf("  Unifying segments.\n");
+  }
+
+  // Create a mapping from vertices to subfaces.
+  makepoint2submap(subfaces, idx2faclist, facperverlist);
+
+  if (b->psc) {
+    face sface1;
+    face seg, seg1;
+    int fmarker, fmarker1;
+    // First only connect subfaces which belong to the same surfaces.
+    subsegloop.shver = 0;
+    subsegs->traversalinit();
+    subsegloop.sh = shellfacetraverse(subsegs);
+    while (subsegloop.sh != (shellface *) NULL) {
+      torg = sorg(subsegloop);
+      tdest = sdest(subsegloop);
+
+      idx = pointmark(torg) - in->firstnumber;
+      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;
+
+        sspivot(sface, seg);
+        if (seg.sh == NULL) continue;
+        // assert(seg.sh != NULL); It may or may not be subsegloop.
+
+        // Find the adjacent subface on the same facet.
+        fmarker = in->facetmarkerlist[shellmark(sface) - 1];
+        sface1.sh = NULL;
+        k++;
+        for (; k < idx2faclist[idx + 1]; k++) {
+          sface1 = facperverlist[k];
+          // The face may be deleted if it is a duplicated face.
+          if (sface1.sh[3] == NULL) continue;
+          // Search the edge torg->tdest.
+          assert(sorg(sface1) == torg); // SELF_CHECK
+          if (sdest(sface1) != tdest) {
+            senext2self(sface1);
+            sesymself(sface1);
+          }
+          if (sdest(sface1) != tdest) continue;
+          // Found a subface sharing at the same edge.
+          fmarker1 = in->facetmarkerlist[shellmark(sface1) - 1];
+          if (fmarker1 == fmarker) {
+            // Found a pair of adjacent subfaces. Connect them.
+            // Delete a redundent segment.
+            sspivot(sface1, seg1); 
+            assert(seg1.sh != NULL); // SELF_CHECK
+            shellfacedealloc(subsegs, seg.sh);
+            shellfacedealloc(subsegs, seg1.sh);
+            ssdissolve(sface);
+            ssdissolve(sface1);
+            // Connect them.
+            sbond(sface, sface1);
+            // Set Steiner point -to- subface map.
+            if (pointtype(torg) == FREEFACETVERTEX) {
+              setpoint2sh(torg, sencode(sface));
+            }
+            if (pointtype(tdest) == FREEFACETVERTEX) {
+              setpoint2sh(tdest, sencode(sface));
+            }
+            break;
+          }
+        }
+        break;
+      }
+      subsegloop.sh = shellfacetraverse(subsegs);
+    }
+  } // if (b->psc)
+
+  subsegloop.shver = 0;
+  subsegs->traversalinit();
+  subsegloop.sh = shellfacetraverse(subsegs);
+  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, NULL);
+              facenormal(torg, tdest, sapex(sface), n2, 1, NULL);
+              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, NULL);
+          facenormal(torg, tdest, sapex(sface), n2, 1, NULL);
+          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->psc) {
+      // Set Steiner point -to- segment map.
+      if (pointtype(torg) == FREESEGVERTEX) {
+        setpoint2sh(torg, sencode(subsegloop));
+      }
+      if (pointtype(tdest) == FREESEGVERTEX) {
+        setpoint2sh(tdest, sencode(subsegloop));
+      }
+    }
+
+    // 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(subsegs, 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;
+        sbond1(f1->ss, f2->ss);
+        f1 = f2;
+      }
+    }
+
+    // All identified segments has an init marker "0".
+    flippool->restart();
+
+    // Are there length constraints?
+    if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
+      int e1, e2;
+      REAL len;
+      for (k = 0; k < in->numberofsegmentconstraints; k++) {
+        e1 = (int) in->segmentconstraintlist[k * 3];
+        e2 = (int) in->segmentconstraintlist[k * 3 + 1];
+        if (((pointmark(torg) == e1) && (pointmark(tdest) == e2)) ||
+            ((pointmark(torg) == e2) && (pointmark(tdest) == e1))) {
+          len = in->segmentconstraintlist[k * 3 + 2];
+          setareabound(subsegloop, len);
+          break;
+        }
+      }
+    }
+
+    subsegloop.sh = shellfacetraverse(subsegs);
+  }
+
+  delete [] idx2faclist;
+  delete [] facperverlist;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// mergefacets()    Merge adjacent facets.                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::mergefacets()
+{
+  face parentsh, neighsh, neineish;
+  face segloop;
+  point pa, pb, pc, pd;
+  REAL ang_tol, ang;
+  int remsegcount;
+  int fidx1, fidx2;
+  int fmrk1, fmrk2;
+
+  if (b->verbose > 1) {
+    printf("    Merging adjacent facets.\n");
+  }
+
+  // The dihedral angle bound for two different facets.
+  //   Set by -p option. Default is 179 degree.
+  ang_tol = b->facet_ang_tol / 180.0 * PI;
+  remsegcount = 0;
+
+  // Loop all segments, merge adjacent coplanar facets.
+  subsegs->traversalinit();
+  segloop.sh = shellfacetraverse(subsegs);
+  while (segloop.sh != (shellface *) NULL) {
+    spivot(segloop, parentsh);
+    if (parentsh.sh != NULL) {
+      spivot(parentsh, neighsh);
+      if (neighsh.sh != NULL) {
+        spivot(neighsh, neineish);
+        if (neineish.sh == parentsh.sh) {
+          // Exactly two subfaces at this segment.
+          fidx1 = shellmark(parentsh) - 1;
+          fidx2 = shellmark(neighsh) - 1;
+          // Only merge them if they are in different facet.
+          if (fidx1 != fidx2) {
+            // The two subfaces are not in the same facet.
+            if (in->facetmarkerlist != NULL) { 
+              fmrk1 = in->facetmarkerlist[fidx1];
+              fmrk2 = in->facetmarkerlist[fidx2];
+            } else {
+              fmrk1 = fmrk2 = 0;
+            }
+            // Only merge them if they have the same boundary marker.
+            if (fmrk1 == fmrk2) {
+              pa = sorg(segloop);
+              pb = sdest(segloop);
+              pc = sapex(parentsh);
+              pd = sapex(neighsh);
+              // Calculate the dihedral angle at the segment [a,b].
+              ang = facedihedral(pa, pb, pc, pd);
+              if (ang > PI) ang = (2 * PI - ang);
+              if (ang > ang_tol) {
+                remsegcount++;
+                ssdissolve(parentsh);
+                ssdissolve(neighsh);
+                shellfacedealloc(subsegs, segloop.sh);
+                // Add the edge to flip stack.
+                flipshpush(&parentsh);
+              } // if (ang > ang_tol)
+            } // if (fmrk1 == fmrk2)
+          } // if (fidx1 != fidx2)
+        } // if (neineish.sh == parentsh.sh)
+      }
+    }
+    segloop.sh = shellfacetraverse(subsegs);
+  }
+
+  if (flipstack != NULL) {
+    lawsonflip(); // Recover Delaunayness.
+  }
+
+  if (b->verbose > 1) {
+    printf("    %d segments are removed.\n", remsegcount);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// identifypscedges()    Identify PSC edges.                                 //
+//                                                                           //
+// The set of PSC edges are provided in the 'in->edgelist'. Each edge should //
+// also be an edge in the surface mesh.  We find the corresponding edges in  //
+// the surface mesh and make them segments of the mesh.                      //
+//                                                                           //
+// It is possible to give an edge which is not in any facet, i.e., it is a   //
+// dangling edge inside the volume.                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::identifypscedges(point *idx2verlist)
+{
+  face* shperverlist;
+  int* idx2shlist;
+  face searchsh, neighsh;
+  face segloop, checkseg, newseg;
+  point checkpt, pa = NULL, pb = NULL;
+  int *endpts;
+  int edgemarker;
+  int idx, i, j;
+
+  int e1, e2;
+  REAL len;
+
+  if (!b->quiet) {
+    printf("Inserting edges ...\n");
+  }
+
+  // All identified segments have the initial marker '1'.
+  // All segments inserted here should have a marker 'k >= 0'.
+
+  if (b->psc) {
+    // First mark all segments of the mesh with a marker '-1'.
+    subsegs->traversalinit();
+    segloop.sh = shellfacetraverse(subsegs);
+    while (segloop.sh != NULL) {
+      setshellmark(segloop, -1);
+      segloop.sh = shellfacetraverse(subsegs);
+    }
+  }
+
+  // Construct a map from points to subfaces.
+  makepoint2submap(subfaces, idx2shlist, shperverlist);
+
+  // Process the set of PSC edges.
+  for (i = 0; i < in->numberofedges; i++) {
+    endpts = &(in->edgelist[(i << 1)]);
+    edgemarker = in->edgemarkerlist ? in->edgemarkerlist[i] : 0;
+
+    // Find a face contains the edge.
+    newseg.sh = NULL;
+    searchsh.sh = NULL;
+    idx = endpts[0] - in->firstnumber;
+    for (j = idx2shlist[idx]; j < idx2shlist[idx + 1]; j++) {
+      checkpt = sdest(shperverlist[j]);
+      if (pointmark(checkpt) == endpts[1]) {
+        searchsh = shperverlist[j];
+        break; // Found.
+      } else {
+        checkpt = sapex(shperverlist[j]);
+        if (pointmark(checkpt) == endpts[1]) {
+          senext2(shperverlist[j], searchsh);
+          sesymself(searchsh);
+          break;
+        }
+      }
+    } // j
+
+    if (searchsh.sh != NULL) {
+      // Check if this edge is already a segment of the mesh.
+      sspivot(searchsh, checkseg);
+      if (checkseg.sh != NULL) {
+        // This segment already exist.
+        newseg = checkseg;
+      } else {
+        // Create a new segment at this edge.
+        pa = sorg(searchsh);
+        pb = sdest(searchsh);
+        makeshellface(subsegs, &newseg);
+        setshvertices(newseg, pa, pb, NULL);
+        ssbond(searchsh, newseg);
+        spivot(searchsh, neighsh);
+        if (neighsh.sh != NULL) {
+          ssbond(neighsh, newseg);
+        }
+        if (b->psc) {
+          if (pointtype(pa) == FREESEGVERTEX) {
+            setpoint2sh(pa, sencode(newseg));
+          }
+          if (pointtype(pb) == FREESEGVERTEX) {
+            setpoint2sh(pb, sencode(newseg));
+          }
+        }
+      }
+    } else {
+      // It is a dangling segment (not belong to any facets).
+      // Get the two endpoints of this segment.
+      pa = idx2verlist[endpts[0]];
+      pb = idx2verlist[endpts[1]];
+      // Check if segment [a,b] already exists.
+      // TODO: Change the brute-force search. Slow!
+      point *ppt;
+      subsegs->traversalinit();
+      segloop.sh = shellfacetraverse(subsegs);
+      while (segloop.sh != NULL) {
+        ppt = (point *) &(segloop.sh[3]);
+        if (((ppt[0] == pa) && (ppt[1] == pb)) ||
+            ((ppt[0] == pb) && (ppt[1] == pa))) {
+          // Found!
+          newseg = segloop; 
+          break;
+        }
+        segloop.sh = shellfacetraverse(subsegs);
+      }
+      if (newseg.sh == NULL) {
+        makeshellface(subsegs, &newseg);
+        setshvertices(newseg, pa, pb, NULL);
+        if (b->psc) {
+          if (pointtype(pa) == FREESEGVERTEX) {
+            setpoint2sh(pa, sencode(newseg));
+          }
+          if (pointtype(pb) == FREESEGVERTEX) {
+            setpoint2sh(pb, sencode(newseg));
+          }
+        }
+      }
+    }
+
+    setshellmark(newseg, edgemarker);
+
+    if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
+      for (i = 0; i < in->numberofsegmentconstraints; i++) {
+        e1 = (int) in->segmentconstraintlist[i * 3];
+        e2 = (int) in->segmentconstraintlist[i * 3 + 1];
+        if (((pointmark(pa) == e1) && (pointmark(pb) == e2)) ||
+            ((pointmark(pa) == e2) && (pointmark(pb) == e1))) {
+          len = in->segmentconstraintlist[i * 3 + 2];
+          setareabound(newseg, len);
+          break;
+        }
+      }
+    }
+  } // i
+
+
+  delete [] shperverlist;
+  delete [] idx2shlist;
+
+  if (b->psc) {
+    // Removing all segments with a marker '-1'.
+    subsegs->traversalinit();
+    segloop.sh = shellfacetraverse(subsegs);
+    while (segloop.sh != NULL) {
+      if (shellmark(segloop) == -1) {
+        shellfacedealloc(subsegs, segloop.sh);
+      }
+      segloop.sh = shellfacetraverse(subsegs);
+    }
+  
+    // Connecting subsegments at Steiner points.
+    face seg1, seg2;
+    // Re-use 'idx2shlist' and 'shperverlist'.
+    makepoint2submap(subsegs, idx2shlist, shperverlist);
+
+    points->traversalinit();
+    pa = pointtraverse();
+    while (pa != NULL) {
+      if (pointtype(pa) == FREESEGVERTEX) {
+        idx = pointmark(pa) - in->firstnumber;
+        // There must be only two segments containing this vertex.
+        assert((idx2shlist[idx + 1] - idx2shlist[idx]) == 2);
+        i = idx2shlist[idx];
+        seg1 = shperverlist[i];
+        seg2 = shperverlist[i+1];
+        senextself(seg1);
+        senextself(seg2);
+        sbond(seg1, seg2);
+      }
+      pa = pointtraverse();
+    }
+
+    delete [] shperverlist;
+    delete [] idx2shlist;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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 (pointtype(tstart) == DUPLICATEDVERTEX) {
+            // Reset the index of vertex-j.
+            tend = point2ppt(tstart);
+            end2 = pointmark(tend);
+            p->vertexlist[j] = end2;
+          }
+        }
+      }
+    }
+
+    // Loop polygons of F, get the set 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();
+  }
+
+  if (!b->diagnose) {
+    // Remove redundant segments and build the face links.
+    unifysegments();
+    if (!b->psc && !b->nomergefacet && !b->nobisect) {
+      // Merge adjacent coplanar facets.
+      mergefacets();
+    }
+    if (in->numberofedges > 0) { // if (b->psc)
+      // There are segments specified by the user. Read and create them.
+      identifypscedges(idx2verlist);
+    }
+    if (!b->psc) {
+      // Mark all segment vertices to be RIDGEVERTEX.
+      face segloop;
+      point *ppt;
+      subsegs->traversalinit();
+      segloop.sh = shellfacetraverse(subsegs);
+      while (segloop.sh != NULL) {
+        ppt = (point *) &(segloop.sh[3]);
+        setpointtype(ppt[0], RIDGEVERTEX);
+        setpointtype(ppt[1], RIDGEVERTEX);
+        segloop.sh = shellfacetraverse(subsegs);
+      }
+    }
+  }
+
+  if (b->object == tetgenbehavior::STL) {
+    // Remove redundant vertices (for .stl input mesh).
+    jettisonnodes();
+  }
+
+  if (b->verbose) {
+    printf("  %ld (%ld) subfaces (segments).\n", subfaces->items, 
+           subsegs->items);
+  }
+
+  // The total number of iunput segments.
+  insegments = subsegs->items;
+
+  delete [] idx2verlist;
+  delete ptlist;
+  delete conlist;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// interecursive()    Recursively do intersection test on a set of triangles.//
+//                                                                           //
+// Recursively split the set 'subfacearray' of subfaces into two sets using  //
+// a cut plane parallel to x-, or, y-, or z-axis.  The split criteria are    //
+// follows. Assume the cut plane is H, and H+ denotes the left halfspace of  //
+// H, and H- denotes the right halfspace of H; and s be a subface:           //
+//                                                                           //
+//    (1) If all points of s lie at H+, put it into left array;              //
+//    (2) If all points of s lie at H-, put it into right array;             //
+//    (3) If some points of s lie at H+ and some of lie at H-, or some       //
+//        points lie on H, put it into both arraies.                         //
+//                                                                           //
+// Partitions by x-axis if axis == '0'; by y-axis if axis == '1'; by z-axis  //
+// if axis == '2'. If current cut plane is parallel to the x-axis, the next  //
+// one will be parallel to y-axis, and the next one after the next is z-axis,//
+// and then alternately return back to x-axis.                               //
+//                                                                           //
+// Stop splitting when the number of triangles of the input array is not     //
+// decreased anymore. Do tests on the current set.                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::interecursive(shellface** subfacearray, int arraysize, 
+                               int axis, REAL bxmin, REAL bxmax, REAL bymin, 
+                               REAL bymax, REAL bzmin, REAL bzmax, 
+                               int* internum)
+{
+  shellface **leftarray, **rightarray;
+  face sface1, sface2;
+  point p1, p2, p3;
+  point p4, p5, p6;
+  enum interresult intersect;
+  REAL split;
+  bool toleft, toright;
+  int leftsize, rightsize;
+  int i, j;
+
+  if (b->verbose > 2) {
+    printf("      Recur %d faces. Bbox (%g, %g, %g),(%g, %g, %g). %s-axis\n",
+           arraysize, bxmin, bymin, bzmin, bxmax, bymax, bzmax,
+           axis == 0 ? "x" : (axis == 1 ? "y" : "z"));
+  }
+    
+  leftarray = new shellface*[arraysize];
+  if (leftarray == NULL) {
+    terminatetetgen(this, 1);
+  }
+  rightarray = new shellface*[arraysize];
+  if (rightarray == NULL) {
+    terminatetetgen(this, 1);
+  }
+  leftsize = rightsize = 0;
+
+  if (axis == 0) {
+    // Split along x-axis.
+    split = 0.5 * (bxmin + bxmax);
+  } else if (axis == 1) {
+    // Split along y-axis.
+    split = 0.5 * (bymin + bymax);
+  } else {
+    // Split along z-axis.
+    split = 0.5 * (bzmin + bzmax);
+  }
+
+  for (i = 0; i < arraysize; i++) {
+    sface1.sh = subfacearray[i];
+    p1 = (point) sface1.sh[3];
+    p2 = (point) sface1.sh[4];
+    p3 = (point) sface1.sh[5];
+    toleft = toright = false;
+    if (p1[axis] < split) {
+      toleft = true;
+      if (p2[axis] >= split || p3[axis] >= split) {
+        toright = true;
+      } 
+    } else if (p1[axis] > split) {
+      toright = true;
+      if (p2[axis] <= split || p3[axis] <= split) {
+        toleft = true;
+      } 
+    } else {
+      // p1[axis] == split;
+      toleft = true;
+      toright = true;
+    }
+    // At least one is true;
+    assert(!(toleft == false && toright == false));
+    if (toleft) {
+      leftarray[leftsize] = sface1.sh;
+      leftsize++;
+    }
+    if (toright) {
+      rightarray[rightsize] = sface1.sh;
+      rightsize++;
+    }
+  }
+
+  if (leftsize < arraysize && rightsize < arraysize) {
+    // Continue to partition the input set. Now 'subfacearray' has been
+    //   split into two sets, it's memory can be freed. 'leftarray' and
+    //   'rightarray' will be freed in the next recursive (after they're
+    //   partitioned again or performing tests).
+    delete [] subfacearray;
+    // Continue to split these two sets.
+    if (axis == 0) {
+      interecursive(leftarray, leftsize, 1, bxmin, split, bymin, bymax,
+                    bzmin, bzmax, internum);
+      interecursive(rightarray, rightsize, 1, split, bxmax, bymin, bymax,
+                    bzmin, bzmax, internum);
+    } else if (axis == 1) {
+      interecursive(leftarray, leftsize, 2, bxmin, bxmax, bymin, split,
+                    bzmin, bzmax, internum);
+      interecursive(rightarray, rightsize, 2, bxmin, bxmax, split, bymax,
+                    bzmin, bzmax, internum);
+    } else {
+      interecursive(leftarray, leftsize, 0, bxmin, bxmax, bymin, bymax,
+                    bzmin, split, internum);
+      interecursive(rightarray, rightsize, 0, bxmin, bxmax, bymin, bymax,
+                    split, bzmax, internum);
+    }
+  } else {
+    if (b->verbose > 1) {
+      printf("  Checking intersecting faces.\n");
+    }
+    // Perform a brute-force compare on the set.
+    for (i = 0; i < arraysize; i++) {
+      sface1.sh = subfacearray[i];
+      p1 = (point) sface1.sh[3];
+      p2 = (point) sface1.sh[4];
+      p3 = (point) sface1.sh[5];
+      for (j = i + 1; j < arraysize; j++) {
+        sface2.sh = subfacearray[j];
+        p4 = (point) sface2.sh[3];
+        p5 = (point) sface2.sh[4];
+        p6 = (point) sface2.sh[5];
+        intersect = (enum interresult) tri_tri_inter(p1, p2, p3, p4, p5, p6);
+        if (intersect == INTERSECT || intersect == SHAREFACE) {
+          if (!b->quiet) {
+            if (intersect == INTERSECT) {
+              printf("  Facet #%d intersects facet #%d at triangles:\n",
+                     shellmark(sface1), shellmark(sface2));
+              printf("    (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
+                     pointmark(p1), pointmark(p2), pointmark(p3),
+                     pointmark(p4), pointmark(p5), pointmark(p6));
+            } else {
+              printf("  Facet #%d duplicates facet #%d at triangle:\n",
+                     shellmark(sface1), shellmark(sface2));
+              printf("    (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
+                     pointmark(p1), pointmark(p2), pointmark(p3),
+                     pointmark(p4), pointmark(p5), pointmark(p6));
+            }
+          }
+          // Increase the number of intersecting pairs.
+          (*internum)++; 
+          // Infect these two faces (although they may already be infected).
+          sinfect(sface1);
+          sinfect(sface2);
+        }
+      }
+    }
+    // Don't forget to free all three arrays. No further partition.
+    delete [] leftarray;
+    delete [] rightarray;  
+    delete [] subfacearray;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// detectinterfaces()    Detect intersecting triangles.                      //
+//                                                                           //
+// Given a set of triangles,  find the pairs of intersecting triangles from  //
+// them.  Here the set of triangles is in 'subfaces' which is a surface mesh //
+// of a PLC (.poly or .smesh).                                               //
+//                                                                           //
+// To detect whether two triangles are intersecting is done by the routine   //
+// 'tri_tri_inter()'.  The algorithm for the test is very simple and stable. //
+// It is based on geometric orientation test which uses exact arithmetics.   //
+//                                                                           //
+// Use divide-and-conquer algorithm for reducing the number of intersection  //
+// tests.  Start from the bounding box of the input point set, recursively   //
+// partition the box into smaller boxes, until the number of triangles in a  //
+// box is not decreased anymore. Then perform triangle-triangle tests on the //
+// remaining set of triangles.  The memory allocated in the input set is     //
+// freed immediately after it has been partitioned into two arrays.  So it   //
+// can be re-used for the consequent partitions.                             //
+//                                                                           //
+// On return, the pool 'subfaces' will be cleared, and only the intersecting //
+// triangles remain for output (to a .face file).                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::detectinterfaces()
+{
+  shellface **subfacearray;
+  face shloop;
+  int internum;
+  int i;
+
+  if (!b->quiet) {
+    printf("Detecting self-intersecting facets...\n");
+  }
+
+  // Construct a map from indices to subfaces;
+  subfacearray = new shellface*[subfaces->items];
+  subfaces->traversalinit();
+  shloop.sh = shellfacetraverse(subfaces);
+  i = 0;
+  while (shloop.sh != (shellface *) NULL) {
+    subfacearray[i] = shloop.sh;
+    shloop.sh = shellfacetraverse(subfaces);
+    i++;
+  }
+
+  internum = 0;
+  // Recursively split the set of triangles into two sets using a cut plane
+  //   parallel to x-, or, y-, or z-axis.  Stop splitting when the number
+  //   of subfaces is not decreasing anymore. Do tests on the current set.
+  interecursive(subfacearray, subfaces->items, 0, xmin, xmax, ymin, ymax,
+                zmin, zmax, &internum);
+
+  if (!b->quiet) {
+    if (internum > 0) {
+      printf("\n!! Found %d pairs of faces are intersecting.\n\n", internum);
+    } else {
+      printf("\nNo faces are intersecting.\n\n");
+    }
+  }
+
+  if (internum > 0) {
+    // Traverse all subfaces, deallocate those have not been infected (they
+    //   are not intersecting faces). Uninfect those have been infected.
+    //   After this loop, only intersecting faces remain.
+    subfaces->traversalinit();
+    shloop.sh = shellfacetraverse(subfaces);
+    while (shloop.sh != (shellface *) NULL) {
+      if (sinfected(shloop)) {
+        suninfect(shloop);
+      } else {
+        shellfacedealloc(subfaces, shloop.sh);
+      }
+      shloop.sh = shellfacetraverse(subfaces);
+    }
+  } else {
+    // Deallocate all subfaces.
+    subfaces->restart();
+  }
+}
+
+////                                                                       ////
+////                                                                       ////
+//// surface_cxx //////////////////////////////////////////////////////////////
+
+//// constrained_cxx //////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// makesegmentendpointsmap()    Create a map from a segment to its endpoints.//
+//                                                                           //
+// The map is saved in the array 'segmentendpointslist'. The length of this  //
+// array is twice the number of segments.  Each segment is assigned a unique //
+// index (starting from 0).                                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::makesegmentendpointsmap()
+{
+  arraypool *segptlist;
+  face segloop, prevseg, nextseg;
+  point eorg, edest, *parypt;
+  int segindex = 0, idx = 0;
+  int i;
+
+  if (b->verbose > 0) {
+    printf("  Creating the segment-endpoints map.\n");
+  }
+
+  segptlist = new arraypool(2 * sizeof(point), 10);
+
+  // A segment s may have been split into many subsegments. Operate the one
+  //   which contains the origin of s. Then mark the rest of subsegments.
+  subsegs->traversalinit();
+  segloop.sh = shellfacetraverse(subsegs);
+  segloop.shver = 0;
+  while (segloop.sh != NULL) {
+    senext2(segloop, prevseg);
+    spivotself(prevseg);
+    if (prevseg.sh == NULL) {
+      eorg = sorg(segloop);
+      edest = sdest(segloop);
+      setfacetindex(segloop, segindex);
+      senext(segloop, nextseg);
+      spivotself(nextseg);
+      while (nextseg.sh != NULL) {
+        setfacetindex(nextseg, segindex);
+        nextseg.shver = 0;
+        if (sorg(nextseg) != edest) sesymself(nextseg);
+        assert(sorg(nextseg) == edest);
+        edest = sdest(nextseg);
+        // Go the next connected subsegment at edest.
+        senextself(nextseg);
+        spivotself(nextseg);
+      }
+      segptlist->newindex((void **) &parypt);
+      parypt[0] = eorg;
+      parypt[1] = edest;
+      segindex++;
+    }
+    segloop.sh = shellfacetraverse(subsegs);
+  }
+
+  if (b->verbose) {
+    printf("  Found %ld segments.\n", segptlist->objects);
+  }
+
+  segmentendpointslist = new point[segptlist->objects * 2];
+
+  totalworkmemory += (segptlist->objects * 2) * sizeof(point *);
+
+  for (i = 0; i < segptlist->objects; i++) {
+    parypt = (point *) fastlookup(segptlist, i);
+    segmentendpointslist[idx++] = parypt[0];
+    segmentendpointslist[idx++] = parypt[1];
+  }
+
+  delete segptlist;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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::interresult 
+  tetgenmesh::finddirection(triface* searchtet, point endpt)
+{
+  triface neightet;
+  point pa, pb, pc, pd;
+  enum {HMOVE, RMOVE, LMOVE} nextmove;
+  REAL hori, rori, lori;
+  int t1ver;
+  int s;
+
+  // The origin is fixed.
+  pa = org(*searchtet);
+  if ((point) searchtet->tet[7] == dummypoint) {
+    // A hull tet. Choose the neighbor of its base face.
+    decode(searchtet->tet[3], *searchtet);
+    // Reset the origin to be pa.
+    if ((point) searchtet->tet[4] == pa) {
+      searchtet->ver = 11;
+    } else if ((point) searchtet->tet[5] == pa) {
+      searchtet->ver = 3;
+    } else if ((point) searchtet->tet[6] == pa) {
+      searchtet->ver = 7;
+    } else {
+      assert((point) searchtet->tet[7] == pa); 
+      searchtet->ver = 0;
+    }
+  }
+
+  pb = dest(*searchtet);
+  // Check whether the destination or apex is 'endpt'.
+  if (pb == endpt) {
+    // pa->pb is the search edge.
+    return ACROSSVERT;
+  }
+
+  pc = apex(*searchtet);
+  if (pc == endpt) {
+    // pa->pc is the search edge.
+    eprevesymself(*searchtet);
+    return ACROSSVERT;
+  }
+
+  // Walk through tets around pa until the right one is found.
+  while (1) {
+
+    pd = oppo(*searchtet);
+    // Check whether the opposite vertex is 'endpt'.
+    if (pd == endpt) {
+      // pa->pd is the search edge.
+      esymself(*searchtet);
+      enextself(*searchtet);
+      return ACROSSVERT;
+    }
+    // Check if we have entered outside of the domain.
+    if (pd == dummypoint) {
+      // This is possible when the mesh is non-convex.
+      assert(nonconvex);
+      return ACROSSSUB; // Hit a bounday.
+    }
+
+    // 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);
+
+    // Now decide the tet to move.  It is possible there are more than one
+    //   tets are viable moves. Is so, randomly choose one. 
+    if (hori > 0) {
+      if (rori > 0) {
+        if (lori > 0) {
+          // Any of the three neighbors is a viable move.
+          s = randomnation(3); 
+          if (s == 0) {
+            nextmove = HMOVE;
+          } else if (s == 1) {
+            nextmove = RMOVE;
+          } else {
+            nextmove = LMOVE;
+          }
+        } else {
+          // Two tets, below horizon and below right, are viable.
+          //s = randomnation(2); 
+          if (randomnation(2)) {
+            nextmove = HMOVE;
+          } else {
+            nextmove = RMOVE;
+          }
+        }
+      } else {
+        if (lori > 0) {
+          // Two tets, below horizon and below left, are viable.
+          //s = randomnation(2); 
+          if (randomnation(2)) {
+            nextmove = HMOVE;
+          } else {
+            nextmove = LMOVE;
+          }
+        } 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.
+          //s = randomnation(2); 
+          if (randomnation(2)) {
+            nextmove = RMOVE;
+          } else {
+            nextmove = LMOVE;
+          }
+        } 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.
+              eprevesymself(*searchtet); // // [a,c,d]
+              return ACROSSVERT;
+            }
+            // pa->'endpt' crosses the edge pb->pc.
+            return ACROSSEDGE;
+          }
+          if (rori == 0) {
+            if (lori == 0) {
+              // pa->'endpt' is COLLINEAR with pa->pd.
+              esymself(*searchtet); // face bad.
+              enextself(*searchtet); // face [a,d,b]
+              return ACROSSVERT;
+            }
+            // pa->'endpt' crosses the edge pb->pd.
+            esymself(*searchtet); // face bad.
+            enextself(*searchtet); // face adb
+            return ACROSSEDGE;
+          }
+          if (lori == 0) {
+            // pa->'endpt' crosses the edge pc->pd.
+            eprevesymself(*searchtet); // [a,c,d]
+            return ACROSSEDGE;
+          }
+          // pa->'endpt' crosses the face bcd.
+          return ACROSSFACE;
+        }
+      }
+    }
+
+    // Move to the next tet, fix pa as its origin.
+    if (nextmove == RMOVE) {
+      fnextself(*searchtet);
+    } else if (nextmove == LMOVE) {
+      eprevself(*searchtet);
+      fnextself(*searchtet);
+      enextself(*searchtet);
+    } else { // HMOVE
+      fsymself(*searchtet);
+      enextself(*searchtet);
+    }
+    assert(org(*searchtet) == pa); 
+    pb = dest(*searchtet);
+    pc = apex(*searchtet);
+
+  } // while (1)
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// scoutsegment()    Search an edge in the tetrahedralization.               //
+//                                                                           //
+// If the edge is found, it returns SHAREEDGE, and 'searchtet' returns the   //
+// edge from startpt to endpt.                                               //
+//                                                                           //
+// If the edge is missing, it returns either ACROSSEDGE or ACROSSFACE, which //
+// indicates that the edge intersects an edge or a face.  If 'refpt' is NULL,//
+// 'searchtet' returns the edge or face. If 'refpt' is not NULL, it returns  //
+// a vertex which encroaches upon this edge, and 'searchtet' returns a tet   //
+// which containing 'refpt'.                                                 // 
+//                                                                           //
+// The following cases can happen when the input PLC is not valid.           //
+//   - ACROSSVERT, the edge intersects a vertex return by the origin of      //
+//                 'searchtet'.                                              //
+//   - ACROSSSEG, the edge intersects a segment returned by 'searchtet'.     //
+//   - ACROSSSUB, the edge intersects a subface returned by 'searchtet'.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::interresult 
+  tetgenmesh::scoutsegment(point startpt, point endpt, triface* searchtet, 
+                           point* refpt, arraypool* intfacelist)
+{
+  point pd;
+  enum interresult dir;
+  int t1ver;
+
+  if (b->verbose > 2) {
+    printf("      Scout seg (%d, %d).\n",pointmark(startpt),pointmark(endpt));
+  }
+
+  point2tetorg(startpt, *searchtet);
+  dir = finddirection(searchtet, endpt);
+
+  if (dir == ACROSSVERT) {
+    pd = dest(*searchtet);
+    if (pd == endpt) {
+      // The job is done. 
+      return SHAREEDGE;
+    } else {
+      // A point is on the path.
+      // Let the origin of the searchtet be the vertex.
+      enextself(*searchtet);
+      if (refpt) *refpt = pd;
+      return ACROSSVERT;
+    }
+  } // if (dir == ACROSSVERT)
+
+  // dir is either ACROSSEDGE or ACROSSFACE.
+
+  enextesymself(*searchtet); // Go to the opposite face.
+  fsymself(*searchtet); // Enter the adjacent tet.
+
+  if (dir == ACROSSEDGE) {
+    // Check whether two segments are intersecting.
+    if (issubseg(*searchtet)) {
+      return ACROSSSEG;
+    }
+  } else if (dir == ACROSSFACE) {
+    if (checksubfaceflag) {
+      // Check whether a segment and a subface are intersecting.
+      if (issubface(*searchtet)) {
+        return ACROSSSUB;
+      }
+    }
+  }
+
+  if (refpt == NULL) {
+    // Do not need a reference point. Return.
+    return dir;
+  }
+
+  triface neightet, reftet;
+  point pa, pb, pc;
+  REAL angmax, ang;
+  int types[2], poss[4];
+  int pos = 0, i, j;
+
+  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;
+  }
+  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
+
+
+    // 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 = *searchtet;
+      j = (neightet.ver & 3); // j is the current face number.
+      for (i = j + 1; i < j + 4; i++) {
+        neightet.ver = (i % 4);
+        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 interresult) 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'.      
+      for (i = 0; i < 2; i++) {
+        if (i == 0) {
+          enextesym(*searchtet, neightet);
+        } else {
+          eprevesym(*searchtet, neightet);
+        }
+        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 interresult) types[0];
+          pos = poss[0];
+          break;
+        } else {
+          dir = DISJOINT;
+          pos = 0;
+        }
+      }
+      if (dir == DISJOINT) {
+        // No intersection. Rotate to the next tet at the edge.
+        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);
+      *refpt = pd;
+      // break;
+      return ACROSSVERT;
+    } else if (dir == ACROSSEDGE) {
+      // Get the edge intersects with the segment.
+      for (i = 0; i < pos; i++) {
+        enextself(neightet);
+      }
+    }
+    // Go to the next tet.
+    fsym(neightet, *searchtet);
+
+    if (dir == ACROSSEDGE) {
+      // Check whether two segments are intersecting.
+      if (issubseg(*searchtet)) {
+        return ACROSSSEG;
+      }
+    } else if (dir == ACROSSFACE) {
+      if (checksubfaceflag) {
+        // Check whether a segment and a subface are intersecting.
+        if (issubface(*searchtet)) {
+          return ACROSSSUB;
+        }
+      }
+    }
+
+  } // while (1)
+
+  // A valid reference point should inside the diametrial circumsphere of
+  //   the missing segment, i.e., it encroaches upon it.
+  if (2.0 * angmax < PI) {
+    *refpt = NULL;
+  }
+
+
+  *searchtet = reftet;
+  return dir;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// getsteinerpointonsegment()    Get a Steiner point on a segment.           //
+//                                                                           //
+// Return '1' if 'refpt' lies on an adjacent segment of this segment. Other- //
+// wise, return '0'.                                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::getsteinerptonsegment(face* seg, point refpt, point steinpt)
+{
+  point ei = sorg(*seg);
+  point ej = sdest(*seg);
+  int adjflag = 0, i;
+
+  if (refpt != NULL) {
+    REAL L, L1, t;
+  
+    if (pointtype(refpt) == FREESEGVERTEX) {
+      face parentseg;
+      sdecode(point2sh(refpt), parentseg);
+      int sidx1 = getfacetindex(parentseg);
+      point far_pi = segmentendpointslist[sidx1 * 2];
+      point far_pj = segmentendpointslist[sidx1 * 2 + 1];
+      int sidx2 = getfacetindex(*seg);
+      point far_ei = segmentendpointslist[sidx2 * 2];
+      point far_ej = segmentendpointslist[sidx2 * 2 + 1];
+      if ((far_pi == far_ei) || (far_pj == far_ei)) {
+        // Create a Steiner point at the intersection of the segment
+        //   [far_ei, far_ej] and the sphere centered at far_ei with 
+        //   radius |far_ei - refpt|.
+        L = distance(far_ei, far_ej);
+        L1 = distance(far_ei, refpt);
+        t = L1 / L;
+        for (i = 0; i < 3; i++) {
+          steinpt[i] = far_ei[i] + t * (far_ej[i] - far_ei[i]);
+        }
+        adjflag = 1;
+      } else if ((far_pi == far_ej) || (far_pj == far_ej)) {
+        L = distance(far_ei, far_ej);
+        L1 = distance(far_ej, refpt);
+        t = L1 / L;
+        for (i = 0; i < 3; i++) {
+          steinpt[i] = far_ej[i] + t * (far_ei[i] - far_ej[i]);
+        }
+        adjflag = 1;
+      } else {
+        // Cut the segment by the projection point of refpt.
+        projpt2edge(refpt, ei, ej, steinpt);
+      }
+    } else {
+      // Cut the segment by the projection point of refpt.
+      projpt2edge(refpt, ei, ej, steinpt);
+    }
+
+    // Make sure that steinpt is not too close to ei and ej.
+    L = distance(ei, ej);
+    L1 = distance(steinpt, ei);
+    t = L1 / L;
+    if ((t < 0.2) || (t > 0.8)) {
+      // Split the point at the middle.
+      for (i = 0; i < 3; i++) {
+        steinpt[i] = ei[i] + 0.5 * (ej[i] - ei[i]);
+      }
+    }
+  } else {
+    // Split the point at the middle.
+    for (i = 0; i < 3; i++) {
+      steinpt[i] = ei[i] + 0.5 * (ej[i] - ei[i]);
+    }
+  }
+
+
+  return adjflag;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// delaunizesegments()    Recover segments in a DT.                          //
+//                                                                           //
+// All segments need to be recovered are in 'subsegstack' (Q).  They will be //
+// be recovered one by one (in a random order).                              //
+//                                                                           //
+// Given a segment s in the Q, this routine first queries s in the DT, if s  //
+// matches an edge in DT, it is 'locked' at the edge. Otherwise, s is split  //
+// by inserting a new point p in both the DT and itself. The two new subseg- //
+// ments of s are queued in Q.  The process continues until Q is empty.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::delaunizesegments()
+{
+  triface searchtet, spintet;
+  face searchsh;
+  face sseg, *psseg;
+  point refpt, newpt;
+  enum interresult dir;
+  insertvertexflags ivf;
+  int t1ver; 
+
+
+  ivf.bowywat = 1; // Use Bowyer-Watson insertion.
+  ivf.assignmeshsize = b->metric;
+  ivf.sloc = (int) ONEDGE; // on 'sseg'.
+  ivf.sbowywat = 1; // Use Bowyer-Watson insertion.
+
+  // 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;
+
+    // Check if this segment has been recovered.
+    sstpivot1(sseg, searchtet);
+    if (searchtet.tet != NULL) {
+      continue; // Not a missing segment.
+    }
+
+    // Search the segment.
+    dir = scoutsegment(sorg(sseg), sdest(sseg), &searchtet, &refpt, NULL);
+
+    if (dir == SHAREEDGE) {
+      // Found this segment, insert it.
+      if (!issubseg(searchtet)) {
+        // Let the segment remember an adjacent tet.
+        sstbond1(sseg, searchtet);
+        // Bond the segment to all tets containing it.
+        spintet = searchtet;
+        do {
+          tssbond1(spintet, sseg);
+          fnextself(spintet);
+        } while (spintet.tet != searchtet.tet);
+      } else {
+        // Collision! Maybe a bug.
+        assert(0);
+      }
+    } else {
+      if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
+        // The segment is missing. Split it.
+        // Create a new point.
+        makepoint(&newpt, FREESEGVERTEX);
+        //setpointtype(newpt, FREESEGVERTEX);
+        getsteinerptonsegment(&sseg, refpt, newpt);
+
+        // Start searching from 'searchtet'.
+        ivf.iloc = (int) OUTSIDE;
+        // Insert the new point into the tetrahedralization T.
+        //   Missing segments and subfaces are queued for recovery.
+        //   Note that T is convex (nonconvex = 0).
+        if (insertpoint(newpt, &searchtet, &searchsh, &sseg, &ivf)) {
+          // The new point has been inserted.
+          st_segref_count++;
+          if (steinerleft > 0) steinerleft--;
+        } else {
+          assert (ivf.iloc == (enum locateresult) NEARVERTEX);
+          terminatetetgen(this, 4);
+        }
+      } else {
+        // Indicate it is an input problem.
+        terminatetetgen(this, 3);
+      }
+    }
+  } // while
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// scoutsubface()    Search subface in the tetrahedralization.               //
+//                                                                           //
+// 'searchsh' is searched in T. If it exists, it is 'locked' at the face in  //
+// T. 'searchtet' refers to the face. Otherwise, it is missing.              //
+//                                                                           //
+// The return value indicates one of the following cases:                    //
+//   - SHAREFACE, 'searchsh' exists and is inserted in T.                    //
+//   - COLLISIONFACE, 'searchsh' exists in T, but it conflicts with another  //
+//     subface which was inserted earlier. It is not inserted.               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+enum tetgenmesh::interresult 
+  tetgenmesh::scoutsubface(face* searchsh, triface* searchtet)
+{
+  triface spintet;
+  point pa, pb, pc;
+  enum interresult dir;
+  int t1ver; 
+
+  pa = sorg(*searchsh);
+  pb = sdest(*searchsh);
+
+
+  // Get a tet whose origin is a.
+  point2tetorg(pa, *searchtet);
+  // Search the edge [a,b].
+  dir = finddirection(searchtet, pb);
+  if (dir == ACROSSVERT) {
+    // Check validity of a PLC.
+    if (dest(*searchtet) != pb) {
+      // A vertex lies on the search edge. 
+      enextself(*searchtet);
+      // It is possible a PLC self-intersection problem.
+      terminatetetgen(this, 3);
+      return TOUCHEDGE;
+    }
+    // The edge exists. Check if the face exists.
+    pc = sapex(*searchsh);
+    // Searchtet holds edge [a,b]. Search a face with apex c.
+    spintet = *searchtet;
+    while (1) {
+      if (apex(spintet) == pc) {
+        // Found a face matching to 'searchsh'!
+        if (!issubface(spintet)) {
+          // Insert 'searchsh'.
+          tsbond(spintet, *searchsh);
+          fsymself(spintet);
+          sesymself(*searchsh);
+          tsbond(spintet, *searchsh);
+          *searchtet = spintet;
+          return SHAREFACE;
+        } else {
+          // Another subface is already inserted.
+          face checksh;
+          tspivot(spintet, checksh);
+          assert(checksh.sh != searchsh->sh); // SELF_CHECK
+          // This is possibly an input problem, i.e., two facets overlap.
+          // Report this problem and exit.
+          printf("Warning:  Found two facets nearly overlap.\n");
+          terminatetetgen(this, 5);
+          // unifysubfaces(&checksh, searchsh);
+          *searchtet = spintet;
+          return COLLISIONFACE;
+        }
+      }
+      fnextself(spintet);
+      if (spintet.tet == searchtet->tet) break;
+    }
+  }
+
+  // dir is either ACROSSEDGE or ACROSSFACE.
+  return dir; 
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// formregion()    Form the missing region of a missing subface.             //
+//                                                                           //
+// 'missh' is a missing subface. From it we form a missing region R which is //
+// a connected region formed by a set of missing subfaces of a facet.        //
+// Comment: There should be no segment inside R.                             //
+//                                                                           //
+// 'missingshs' returns the list of subfaces in R. All subfaces in this list //
+// are oriented as the 'missh'.  'missingshbds' returns the list of boundary //
+// edges (tetrahedral handles) of R.  'missingshverts' returns all vertices  //
+// of R. They are all pmarktested.                                           //
+//                                                                           //
+// Except the first one (which is 'missh') in 'missingshs', each subface in  //
+// this list represents an internal edge of R, i.e., it is missing in the    //
+// tetrahedralization. Since R may contain interior vertices, not all miss-  //
+// ing edges can be found by this way.                                       //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::formregion(face* missh, arraypool* missingshs,  
+                            arraypool* missingshbds, arraypool* missingshverts)
+{
+  triface searchtet, spintet;
+  face neighsh, *parysh;
+  face neighseg, fakeseg;
+  point pa, pb, *parypt;
+  enum interresult dir;
+  int t1ver;
+  int i, j;
+
+  smarktest(*missh);
+  missingshs->newindex((void **) &parysh);
+  *parysh = *missh;
+
+  // Incrementally find other missing subfaces.
+  for (i = 0; i < missingshs->objects; i++) {
+    missh = (face *) fastlookup(missingshs, i);
+    for (j = 0; j < 3; j++) {
+      pa = sorg(*missh);
+      pb = sdest(*missh);
+      point2tetorg(pa, searchtet);
+      dir = finddirection(&searchtet, pb);
+      if (dir != ACROSSVERT) {
+        // This edge is missing. Its neighbor is a missing subface.
+        spivot(*missh, neighsh);
+        if (!smarktested(neighsh)) {
+          // Adjust the face orientation.
+          if (sorg(neighsh) != pb) sesymself(neighsh);
+          smarktest(neighsh);
+          missingshs->newindex((void **) &parysh);
+          *parysh = neighsh;
+        }
+      } else {
+        if (dest(searchtet) != pb) {
+          // This might be a self-intersection problem.
+          terminatetetgen(this, 3); 
+        }
+      }
+      // Collect the vertices of R.
+      if (!pmarktested(pa)) {
+        pmarktest(pa);
+        missingshverts->newindex((void **) &parypt);
+        *parypt = pa;
+      }
+      senextself(*missh);
+    } // j
+  } // i
+
+  // Get the boundary edges of R.
+  for (i = 0; i < missingshs->objects; i++) {
+    missh = (face *) fastlookup(missingshs, i);
+    for (j = 0; j < 3; j++) {
+      spivot(*missh, neighsh);
+      if ((neighsh.sh == NULL) || !smarktested(neighsh)) {
+        // A boundary edge of R.
+        // Let the segment point to the adjacent tet.
+        point2tetorg(sorg(*missh), searchtet);
+        finddirection(&searchtet, sdest(*missh));
+        missingshbds->newindex((void **) &parysh);
+        *parysh = *missh;
+        // Check if this edge is a segment.
+        sspivot(*missh, neighseg); 
+        if (neighseg.sh == NULL) {
+          // Temporarily create a segment at this edge.
+          makeshellface(subsegs, &fakeseg);
+          setsorg(fakeseg, sorg(*missh));
+          setsdest(fakeseg, sdest(*missh));
+          sinfect(fakeseg); // Mark it as faked.
+          // Connect it to all tets at this edge.
+          spintet = searchtet;
+          while (1) {
+            tssbond1(spintet, fakeseg);
+            fnextself(spintet);
+            if (spintet.tet == searchtet.tet) break;
+          }
+          neighseg = fakeseg;
+        }
+        // Let the segment and the boundary edge point to each other.
+        ssbond(*missh, neighseg);
+        sstbond1(neighseg, searchtet);
+      }
+      senextself(*missh);
+    } // j
+  } // i
+
+
+  // Unmarktest collected missing subfaces.
+  for (i = 0; i < missingshs->objects; i++) {
+    parysh = (face *) fastlookup(missingshs, i);
+    sunmarktest(*parysh);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// scoutcrossedge()    Search an edge that crosses the missing region.       //
+//                                                                           //
+// Return 1 if a crossing edge is found. It is returned by 'crosstet'. More- //
+// over, the edge is oriented such that its origin lies below R.  Return 0   //
+// if no such edge is found.                                                 //
+//                                                                           //
+// Assumption: All vertices of the missing region are marktested.            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::scoutcrossedge(triface& crosstet, arraypool* missingshbds, 
+                               arraypool* missingshs)
+{
+  triface searchtet, spintet;
+  face *parysh;
+  face neighseg;
+  point pa, pb, pc, pd, pe;
+  enum interresult dir;
+  REAL ori;
+  int types[2], poss[4];
+  int searchflag, interflag;
+  int t1ver;
+  int i, j;
+
+  searchflag = 0;
+
+  for (j = 0; j < missingshbds->objects && !searchflag; j++) {
+    parysh = (face *) fastlookup(missingshbds, j);
+    sspivot(*parysh, neighseg);
+    sstpivot1(neighseg, searchtet);
+    interflag = 0;
+    // Let 'spintet' be [#,#,d,e] where [#,#] is the boundary edge of R.
+    spintet = searchtet;
+    while (1) {
+      pd = apex(spintet);
+      pe = oppo(spintet);
+      // Skip a hull edge.
+      if ((pd != dummypoint) && (pe != dummypoint)) {
+        // Skip an edge containing a vertex of R.
+        if (!pmarktested(pd) && !pmarktested(pe)) {
+          // Check if [d,e] intersects R.
+          for (i = 0; i < missingshs->objects && !interflag; i++) {
+            parysh = (face *) fastlookup(missingshs, i);
+            pa = sorg(*parysh);
+            pb = sdest(*parysh);
+            pc = sapex(*parysh);
+            interflag=tri_edge_test(pa, pb, pc, pd, pe, NULL, 1, types, poss);
+            if (interflag > 0) { 
+              if (interflag == 2) {
+                // They intersect at a single point.
+                dir = (enum interresult) types[0];
+                if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
+                  //pos = poss[0];
+                  // Go to the crossing edge [d,e,#,#].
+                  edestoppo(spintet, crosstet); // // [d,e,#,#].
+                  // Check if it is a segment.
+                  if (issubseg(crosstet)) {
+                    //face checkseg;
+                    //tsspivot1(crosstet, checkseg);
+                    //reportselfintersect(&checkseg, parysh);
+                    terminatetetgen(this, 3);
+                  }
+                  // Adjust the edge such that d lies below [a,b,c].
+                  ori = orient3d(pa, pb, pc, pd);
+                  assert(ori != 0);
+                  if (ori < 0) {
+                    esymself(crosstet);
+                  }
+                  searchflag = 1;                  
+                }
+              }
+              break;
+            } // if (interflag > 0)
+          }
+        } 
+      }
+      // Leave search at this bdry edge if an intersection is found.
+      if (interflag > 0) break;
+      // Go to the next tetrahedron.
+      fnextself(spintet);
+      if (spintet.tet == searchtet.tet) break; 
+    } // while (1)
+  } // j
+
+  return searchflag;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// formcavity()    Form the cavity of a missing region.                      //
+//                                                                           //
+// The missing region R is formed by a set of missing subfaces 'missingshs'. //
+// In the following, we assume R is horizontal and oriented. (All subfaces   //
+// of R are oriented in the same way.)  'searchtet' is a tetrahedron [d,e,#, //
+// #] which intersects R in its interior, where the edge [d,e] intersects R, //
+// and d lies below R.                                                       //
+//                                                                           //
+// 'crosstets' returns the set of crossing tets. Every tet in it has the     //
+// form [d,e,#,#] where [d,e] is a crossing edge, and d lies below R.  The   //
+// set of tets form the cavity C, which 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.                                        //
+//                                                                           //
+// Important: This routine assumes all vertices of the facet containing this //
+// subface are marked, i.e., pmarktested(p) returns true.                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
+                            arraypool* crosstets, arraypool* topfaces, 
+                            arraypool* botfaces, arraypool* toppoints, 
+                            arraypool* botpoints)
+{
+  arraypool *crossedges;
+  triface spintet, neightet, *parytet;
+  face *parysh = NULL;
+  point pa, pd, pe, *parypt;
+  enum interresult dir; 
+  bool testflag, invalidflag;
+  int types[2], poss[4];
+  int t1ver;
+  int i, j, k;
+
+  // Temporarily re-use 'topfaces' for all crossing edges.
+  crossedges = topfaces;
+
+  if (b->verbose > 2) {
+    printf("      Form the cavity of a missing region.\n"); 
+  }
+  // Mark this edge to avoid testing it later.
+  markedge(*searchtet);
+  crossedges->newindex((void **) &parytet);
+  *parytet = *searchtet;
+
+  invalidflag = 0; 
+
+  // Collect all crossing tets.  Each cross tet is saved in the standard
+  //   form [d,e,#,#], where [d,e] is a crossing edge, d lies below R.
+  //   NEITHER d NOR e is a vertex of R (!pmarktested). 
+  for (i = 0; i < crossedges->objects; i++) {
+    // Get a crossing edge [d,e,#,#].
+    searchtet = (triface *) fastlookup(crossedges, i);
+
+    // Sort vertices into the bottom and top arrays.
+    pd = org(*searchtet);
+    if (!pinfected(pd)) {
+      pinfect(pd);
+      botpoints->newindex((void **) &parypt);
+      *parypt = pd;
+    }
+    pe = dest(*searchtet);
+    if (!pinfected(pe)) {
+      pinfect(pe);
+      toppoints->newindex((void **) &parypt);
+      *parypt = pe;
+    }
+
+    // All tets sharing this edge are crossing tets.
+    spintet = *searchtet;
+    while (1) {
+      if (!infected(spintet)) {
+        infect(spintet);
+        crosstets->newindex((void **) &parytet);
+        *parytet = spintet;
+      }
+      // Go to the next crossing tet.
+      fnextself(spintet);
+      if (spintet.tet == searchtet->tet) break;
+    } // while (1)
+
+    // Detect new crossing edges.
+    spintet = *searchtet;
+    while (1) {
+      // spintet is [d,e,a,#], where d lies below R, and e lies above R. 
+      pa = apex(spintet);
+      if (pa != dummypoint) {
+        if (!pmarktested(pa)) {
+	      // There exists a crossing edge, either [e,a] or [a,d]. First check
+          //   if the crossing edge has already be added, i.e., check if a
+          //   tetrahedron at this edge is marked.
+          testflag = true;
+          for (j = 0; j < 2 && testflag; j++) {
+            if (j == 0) {
+              enext(spintet, neightet);
+            } else {
+              eprev(spintet, neightet);
+            }
+            while (1) {
+              if (edgemarked(neightet)) {
+                // This crossing edge has already been tested. Skip it.
+                testflag = false;
+                break;
+              }
+              fnextself(neightet);
+              if (neightet.tet == spintet.tet) break;
+            }
+          } // j
+          if (testflag) {
+            // Test if [e,a] or [a,d] intersects R.
+            // Do a brute-force search in the set of subfaces of R. Slow!
+            //   Need to be improved!
+            pd = org(spintet);
+            pe = dest(spintet);
+            for (k = 0; k < missingshs->objects; k++) {
+              parysh = (face *) fastlookup(missingshs, k);
+              if (tri_edge_test(sorg(*parysh), sdest(*parysh), sapex(*parysh),
+                                pe, pa, NULL, 1, types, poss)) {
+                // Found intersection. 'a' lies below R.
+                enext(spintet, neightet);
+                dir = (enum interresult) types[0];
+                if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
+                  // A valid intersection.
+                } else {
+                  // A non-valid intersection. Maybe a PLC problem.
+                  invalidflag = 1;
+                }
+                break;
+              }
+              if (tri_edge_test(sorg(*parysh), sdest(*parysh), sapex(*parysh),
+                                pa, pd, NULL, 1, types, poss)) {
+                // Found intersection. 'a' lies above R.
+                eprev(spintet, neightet);
+                dir = (enum interresult) types[0];
+                if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
+                  // A valid intersection.
+                } else {
+                  // A non-valid intersection. Maybe a PLC problem.
+                  invalidflag = 1;
+                }
+                break;
+              }
+            } // k
+            if (k < missingshs->objects) {
+              // Found a pair of triangle - edge intersection.
+              if (invalidflag) {
+                if (!b->quiet) {
+                  printf("Warning:  A non-valid facet - edge intersection\n");
+                  printf("      subface: (%d, %d, %d) edge: (%d, %d)\n",
+                         pointmark(sorg(*parysh)), pointmark(sdest(*parysh)), 
+                         pointmark(sapex(*parysh)), pointmark(org(neightet)),
+                         pointmark(dest(neightet)));
+                }
+                // It may be a PLC problem.
+                terminatetetgen(this, 3);
+              }
+              // Adjust the edge direction, so that its origin lies below R,
+              //   and its destination lies above R.
+              esymself(neightet);
+              // Check if this edge is a segment.
+              if (issubseg(neightet)) {
+                // Invalid PLC!
+                //face checkseg;
+                //tsspivot1(neightet, checkseg);
+                //reportselfintersect(&checkseg, parysh);
+                terminatetetgen(this, 3);
+              }
+              // Mark this edge to avoid testing it again.
+              markedge(neightet);
+              crossedges->newindex((void **) &parytet);
+              *parytet = neightet;            
+            } else {
+              // No intersection is found. It may be a PLC problem.
+              invalidflag = 1;
+              // Split the subface intersecting [d,e].
+              for (k = 0; k < missingshs->objects; k++) {
+                parysh = (face *) fastlookup(missingshs, k);
+                // Test if this face intersects [e,a].
+                if (tri_edge_test(sorg(*parysh),sdest(*parysh),sapex(*parysh),
+                                  pd, pe, NULL, 1, types, poss)) {
+                  break;
+                }
+              } // k
+              if (k == missingshs->objects) {
+                // Not found such an edge. 
+                // Arbitrarily choose an edge (except the first) to split.
+                k = randomnation(missingshs->objects - 1);
+                parysh = (face *) fastlookup(missingshs, k + 1);
+              }
+              recentsh = *parysh;
+              recenttet = spintet; // For point location.
+              break; // the while (1) loop
+            } // if (k == missingshs->objects)
+          } // if (testflag)
+	    } // if (!pmarktested(pa) || b->psc)
+      } // if (pa != dummypoint)
+      // Go to the next crossing tet.
+      fnextself(spintet);
+      if (spintet.tet == searchtet->tet) break;
+    } // while (1)
+
+    //if (b->psc) {
+      if (invalidflag) break;
+    //}
+  } // i
+
+  if (b->verbose > 2) {
+    printf("      Formed cavity: %ld (%ld) cross tets (edges).\n", 
+           crosstets->objects, crossedges->objects);
+  }
+
+  // Unmark all marked edges.
+  for (i = 0; i < crossedges->objects; i++) {
+    searchtet = (triface *) fastlookup(crossedges, i);
+    assert(edgemarked(*searchtet)); // SELF_CHECK
+    unmarkedge(*searchtet);
+  }
+  crossedges->restart();
+
+
+  if (invalidflag) {
+    // Unmark all collected tets.
+    for (i = 0; i < crosstets->objects; i++) {
+      searchtet = (triface *) fastlookup(crosstets, i);
+      uninfect(*searchtet);
+    }
+    // Unmark all collected vertices.
+    for (i = 0; i < botpoints->objects; i++) {
+      parypt = (point *) fastlookup(botpoints, i);
+      puninfect(*parypt);
+    }
+    for (i = 0; i < toppoints->objects; i++) {
+      parypt = (point *) fastlookup(toppoints, i);
+      puninfect(*parypt);
+    }
+    crosstets->restart();
+    botpoints->restart();
+    toppoints->restart();
+
+    // Randomly split an interior edge of R.
+    i = randomnation(missingshs->objects - 1);
+    recentsh = * (face *) fastlookup(missingshs, i);
+    return false;
+  }
+
+
+  // Collect the top and bottom faces and the middle vertices. Since all top
+  //   and bottom vertices have been infected. Uninfected vertices must be
+  //   middle vertices (i.e., the vertices of R).
+  // NOTE 1: Hull tets may be collected. Process them as a normal one.
+  // NOTE 2: Some previously recovered subfaces may be completely inside the
+  //   cavity. In such case, we remove these subfaces from the cavity and put
+  //   them into 'subfacstack'. They will be recovered later.
+  // NOTE 3: Some segments may be completely inside the cavity, e.g., they
+  //   attached to a subface which is inside the cavity. Such segments are
+  //   put in 'subsegstack'. They will be recovered later. 
+  // NOTE4 : The interior subfaces and segments mentioned in NOTE 2 and 3
+  //   are identified in the routine "carvecavity()". 
+
+  for (i = 0; i < crosstets->objects; i++) {
+    searchtet = (triface *) fastlookup(crosstets, i);
+    // searchtet is [d,e,a,b].
+    eorgoppo(*searchtet, spintet);
+    fsym(spintet, neightet); // neightet is [a,b,e,#]
+    if (!infected(neightet)) {
+      // A top face.
+      topfaces->newindex((void **) &parytet);
+      *parytet = neightet;
+    }
+    edestoppo(*searchtet, spintet);
+    fsym(spintet, neightet); // neightet is [b,a,d,#]
+    if (!infected(neightet)) {
+      // A bottom face.
+      botfaces->newindex((void **) &parytet);
+      *parytet = neightet;
+    }
+    // Add middle vertices if there are (skip dummypoint).
+    pa = org(neightet);
+    if (!pinfected(pa)) {
+      if (pa != dummypoint) {
+        pinfect(pa);
+        botpoints->newindex((void **) &parypt);
+        *parypt = pa;
+        toppoints->newindex((void **) &parypt);
+        *parypt = pa;
+      }
+    }
+    pa = dest(neightet);
+    if (!pinfected(pa)) {
+      if (pa != dummypoint) {
+        pinfect(pa);
+        botpoints->newindex((void **) &parypt);
+        *parypt = pa;
+        toppoints->newindex((void **) &parypt);
+        *parypt = pa;
+      }
+    }
+  } // i
+
+  // Uninfect all collected top, bottom, and middle vertices.
+  for (i = 0; i < toppoints->objects; i++) {
+    parypt = (point *) fastlookup(toppoints, i);
+    puninfect(*parypt);
+  }
+  for (i = 0; i < botpoints->objects; i++) {
+    parypt = (point *) fastlookup(botpoints, i);
+    puninfect(*parypt);
+  }
+  cavitycount++;
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// delaunizecavity()    Fill a cavity by Delaunay tetrahedra.                //
+//                                                                           //
+// The cavity C to be tetrahedralized is the top or bottom part of a whole   //
+// cavity. 'cavfaces' contains the boundary faces of C. NOTE: faces in 'cav- //
+// faces' do not form a closed polyhedron.  The "open" side are subfaces of  //
+// the missing facet. These faces will be recovered later in fillcavity().   //
+//                                                                           //
+// This routine first constructs the DT of the vertices. Then it identifies  //
+// the half boundary faces of the cavity in DT. Possiblely the cavity C will //
+// be enlarged.                                                              //
+//                                                                           //
+// The DT is returned in 'newtets'.                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces, 
+                                 arraypool *cavshells, arraypool *newtets, 
+                                 arraypool *crosstets, arraypool *misfaces)
+{
+  triface searchtet, neightet, *parytet, *parytet1;
+  face tmpsh, *parysh;
+  point pa, pb, pc, pd, pt[3], *parypt;
+  enum interresult dir;
+  insertvertexflags ivf;
+  REAL ori;
+  long baknum, bakhullsize;
+  int bakchecksubsegflag, bakchecksubfaceflag;
+  int t1ver; 
+  int i, j;
+
+  if (b->verbose > 2) {
+    printf("      Delaunizing cavity: %ld points, %ld faces.\n", 
+           cavpoints->objects, cavfaces->objects);
+  }
+  // Remember the current number of crossing tets. It may be enlarged later.
+  baknum = crosstets->objects;
+  bakhullsize = hullsize;
+  bakchecksubsegflag = checksubsegflag;
+  bakchecksubfaceflag = checksubfaceflag;
+  hullsize = 0l;
+  checksubsegflag = 0;
+  checksubfaceflag = 0;
+  b->verbose--;  // Suppress informations for creating Delaunay tetra.
+  b->plc = 0; // Do not check near vertices.
+
+  ivf.bowywat = 1; // Use Bowyer-Watson algorithm.
+
+  // Get four non-coplanar points (no dummypoint).
+  pa = pb = pc = NULL;
+  for (i = 0; i < cavfaces->objects; i++) {
+    parytet = (triface *) fastlookup(cavfaces, i);
+    parytet->ver = epivot[parytet->ver];
+    if (apex(*parytet) != dummypoint) {
+      pa = org(*parytet);
+      pb = dest(*parytet);
+      pc = apex(*parytet);
+      break;
+    }
+  }
+  pd = NULL;
+  for (; 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.
+        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
+
+  // Create an init DT.
+  initialdelaunay(pa, pb, pc, pd);
+
+  // Incrementally insert the vertices (duplicated vertices are ignored).
+  for (i = 0; i < cavpoints->objects; i++) {
+    pt[0] = * (point *) fastlookup(cavpoints, i);
+    searchtet = recenttet;
+    ivf.iloc = (int) OUTSIDE;
+    insertpoint(pt[0], &searchtet, NULL, NULL, &ivf);
+  }
+
+  if (b->verbose > 2) {
+    printf("      Identifying %ld boundary faces of the cavity.\n", 
+           cavfaces->objects);
+  }
+
+  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;
+      parytet->ver = epivot[parytet->ver];
+      pt[0] = org(*parytet);
+      pt[1] = dest(*parytet);
+      pt[2] = apex(*parytet);
+      // Create a temp subface.
+      makeshellface(subfaces, &tmpsh);
+      setshvertices(tmpsh, pt[0], pt[1], pt[2]);
+      // Insert tmpsh in DT.
+      searchtet.tet = NULL; 
+      dir = scoutsubface(&tmpsh, &searchtet);
+      if (dir == SHAREFACE) {
+        // Inserted! 'tmpsh' must face toward the inside of the cavity.
+        // Remember the boundary tet (outside the cavity) in tmpsh 
+        //   (use the adjacent tet slot). 
+        tmpsh.sh[0] = (shellface) encode(*parytet);
+        // Save this subface.
+        cavshells->newindex((void **) &parysh);
+        *parysh = tmpsh;
+      } 
+      else {
+        // This boundary face is missing.
+        shellfacedealloc(subfaces, tmpsh.sh);
+        // Save this face in list.
+        misfaces->newindex((void **) &parytet1);
+        *parytet1 = *parytet;
+      }
+    } // i
+
+    if (misfaces->objects > 0) {
+      if (b->verbose > 2) {
+        printf("      Enlarging the cavity. %ld missing bdry faces\n", 
+               misfaces->objects);
+      }
+
+      // Removing all temporary subfaces.
+      for (i = 0; i < cavshells->objects; i++) {
+        parysh = (face *) fastlookup(cavshells, i);
+        stpivot(*parysh, neightet);
+        tsdissolve(neightet); // Detach it from adj. tets.
+        fsymself(neightet);
+        tsdissolve(neightet);
+        shellfacedealloc(subfaces, 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)) {
+            searchtet = recenttet;
+            ivf.iloc = (int) OUTSIDE;
+            insertpoint(pd, &searchtet, NULL, NULL, &ivf);
+            pinfect(pd);
+            cavpoints->newindex((void **) &parypt);
+            *parypt = pd;
+          }
+          // Add three opposite faces into the boundary list.
+          for (j = 0; j < 3; j++) {
+            esym(*parytet, neightet);
+            fsymself(neightet);
+            if (!infected(neightet)) {
+              cavfaces->newindex((void **) &parytet1);
+              *parytet1 = neightet;
+            } 
+            enextself(*parytet);
+          } // j
+        } // if (!infected(parytet))
+      } // i
+
+      // 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();
+      continue;
+    } // if (misfaces->objects > 0)
+
+    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 (j = 0; j < 4; j++) {
+      decode(searchtet.tet[j], neightet);
+      if (!marktested(neightet)) {
+        marktest(neightet);
+        newtets->newindex((void **) &parytet);
+        *parytet = neightet;
+      }
+    }
+  }
+
+  cavpoints->restart();
+  cavfaces->restart();
+
+  if (crosstets->objects > baknum) {
+    // The cavity has been enlarged.
+    cavityexpcount++;
+  }
+
+  // Restore the original values.
+  hullsize = bakhullsize;
+  checksubsegflag = bakchecksubsegflag;
+  checksubfaceflag = bakchecksubfaceflag;
+  b->verbose++;
+  b->plc = 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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.   //
+//                                                                           //
+// Important: This routine assumes all vertices of the missing region R are  //
+// marktested, i.e., pmarktested(p) returns true.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::fillcavity(arraypool* topshells, arraypool* botshells,
+                            arraypool* midfaces, arraypool* missingshs,
+                            arraypool* topnewtets, arraypool* botnewtets,
+                            triface* crossedge)
+{
+  arraypool *cavshells;
+  triface bdrytet, neightet, *parytet;
+  triface searchtet, spintet;
+  face *parysh;
+  face checkseg;
+  point pa, pb, pc;
+  bool mflag;
+  int t1ver;
+  int i, j;
+
+  // Connect newtets to tets outside the cavity.  These connections are needed
+  //   for identifying the middle faces (which belong to R).
+  for (j = 0; j < 2; j++) {
+    cavshells = (j == 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 outside the cavity (saved in sh[0]).
+        decode(parysh->sh[0], bdrytet);
+        pa = org(bdrytet);
+        pb = dest(bdrytet);
+        pc = apex(bdrytet);
+        // Get the adjacent new tet inside the cavity.
+        stpivot(*parysh, neightet);
+        // Mark neightet as an interior tet of this cavity.
+        infect(neightet);
+        // Connect the two tets (the old connections are replaced).
+        bond(bdrytet, neightet); 
+        tsdissolve(neightet); // Clear the pointer to tmpsh.
+        // Update the point-to-tets map.
+        setpoint2tet(pa, (tetrahedron) neightet.tet);
+        setpoint2tet(pb, (tetrahedron) neightet.tet);
+        setpoint2tet(pc, (tetrahedron) neightet.tet);
+      } // i
+    } // if (cavshells != NULL)
+  } // j
+
+  if (crossedge != NULL) {
+    // Glue top and bottom tets at their common facet.
+    triface toptet, bottet, spintet, *midface;
+    point pd, pe;
+    REAL ori;
+    int types[2], poss[4];
+    int interflag;
+    int bflag;
+
+    mflag = false;
+    pd = org(*crossedge);
+    pe = dest(*crossedge);
+
+    // Search the first (middle) face in R. 
+    // Since R may be non-convex, we must make sure that the face is in the
+    //   interior of R.  We search a face in 'topnewtets' whose three vertices
+    //   are on R and it intersects 'crossedge' in its interior. Then search
+    //   a matching face in 'botnewtets'.
+    for (i = 0; i < topnewtets->objects && !mflag; i++) {
+      searchtet = * (triface *) fastlookup(topnewtets, i);
+      for (searchtet.ver = 0; searchtet.ver < 4 && !mflag; searchtet.ver++) {
+        pa = org(searchtet);
+        if (pmarktested(pa)) {
+          pb = dest(searchtet);
+          if (pmarktested(pb)) {
+            pc = apex(searchtet);
+            if (pmarktested(pc)) {
+              // Check if this face intersects [d,e].
+              interflag = tri_edge_test(pa,pb,pc,pd,pe,NULL,1,types,poss);
+              if (interflag == 2) {
+                // They intersect at a single point. Found.
+                toptet = searchtet;
+                // The face lies in the interior of R.
+                // Get the tet (in topnewtets) which lies above R.
+                ori = orient3d(pa, pb, pc, pd);
+                assert(ori != 0);
+                if (ori < 0) {
+                  fsymself(toptet);
+                  pa = org(toptet);
+                  pb = dest(toptet);
+                }
+                // Search the face [b,a,c] in 'botnewtets'.
+                for (j = 0; j < botnewtets->objects; j++) {
+                  neightet = * (triface *) fastlookup(botnewtets, j);                  
+                  // Is neightet contains 'b'.
+                  if ((point) neightet.tet[4] == pb) {
+                    neightet.ver = 11;
+                  } else if ((point) neightet.tet[5] == pb) {
+                    neightet.ver = 3;
+                  } else if ((point) neightet.tet[6] == pb) {
+                    neightet.ver = 7;
+                  } else if ((point) neightet.tet[7] == pb) {
+                    neightet.ver = 0;
+                  } else {
+                    continue;
+                  }
+                  // Is the 'neightet' contains edge [b,a].
+                  if (dest(neightet) == pa) {
+                    // 'neightet' is just the edge.
+                  } else if (apex(neightet) == pa) {
+                    eprevesymself(neightet);
+                  } else if (oppo(neightet) == pa) {
+                    esymself(neightet);
+                    enextself(neightet);
+                  } else {
+                    continue;
+                  }
+                  // Is 'neightet' the face [b,a,c]. 
+                  if (apex(neightet) == pc) {
+                    bottet = neightet;
+                    mflag = true;
+                    break;
+                  }
+                } // j
+              } // if (interflag == 2)
+            } // pc
+          } // pb
+        } // pa
+      } // toptet.ver
+    } // i
+
+    if (mflag) {
+      // Found a pair of matched faces in 'toptet' and 'bottet'.
+      bond(toptet, bottet);
+      // Both are interior tets.
+      infect(toptet);
+      infect(bottet);
+      // Add this face into search list.
+      markface(toptet);
+      midfaces->newindex((void **) &parytet);
+      *parytet = toptet;
+    } else {
+      // No pair of 'toptet' and 'bottet'.
+      toptet.tet = NULL;
+      // Randomly split an interior edge of R.
+      i = randomnation(missingshs->objects - 1);
+      recentsh = * (face *) fastlookup(missingshs, i);
+    }
+
+    // Find other 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);
+      // The tet must be a new created tet (marktested).
+      assert(marktested(*midface)); // SELF_CHECK
+      // Check the neighbors at the edges of this face. 
+      for (j = 0; j < 3 && mflag; j++) {
+        toptet = *midface;
+        bflag = false;
+        while (1) {
+          // Go to the next face in the same tet.
+          esymself(toptet);
+          pc = apex(toptet);
+          if (pmarktested(pc)) {
+            break; // Find a subface.
+          }
+          if (pc == dummypoint) {
+            assert(0); // Check this case.
+            break; // Find a subface.
+          }
+          // Go to the adjacent tet.
+          fsymself(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)) {
+            fsym(*midface, bottet);
+            spintet = bottet;
+            while (1) {
+              esymself(bottet);
+              pd = apex(bottet);
+              if (pd == pc) break; // Face matched.
+              fsymself(bottet);
+              if (bottet.tet == spintet.tet) {
+                // Not found a matched bottom face.
+                mflag = false;
+                break;
+              }
+            } // while (1)
+            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.
+                markface(toptet);
+                midfaces->newindex((void **) &parytet);
+                *parytet = toptet;
+              }
+            } else { // mflag == false
+              // Adjust 'toptet' and 'bottet' to be the crossing edges.
+              fsym(*midface, bottet);
+              spintet = bottet;
+              while (1) {
+                esymself(bottet);
+                pd = apex(bottet);
+                if (pmarktested(pd)) {
+                  // assert(pd != pc);
+                  // Let 'toptet' be [a,b,c,#], and 'bottet' be [b,a,d,*].
+                  // Adjust 'toptet' and 'bottet' to be the crossing edges.
+                  // Test orient3d(b,c,#,d).
+                  ori = orient3d(dest(toptet), pc, oppo(toptet), pd);
+                  if (ori < 0) {
+                    // Edges [a,d] and [b,c] cross each other.
+                    enextself(toptet); // [b,c]
+                    enextself(bottet); // [a,d]
+                  } else if (ori > 0) {
+                    // Edges [a,c] and [b,d] cross each other. 
+                    eprevself(toptet); // [c,a]
+                    eprevself(bottet); // [d,b]
+                  } else {
+                    // b,c,#,and d are coplanar!.
+                    assert(0);
+                  }
+                  break; // Not matched
+                }
+                fsymself(bottet);
+                assert (bottet.tet != spintet.tet);
+              }
+            } // if (!mflag)
+          } // if (!facemarked(toptet))
+        } // if (!bflag)
+        enextself(*midface);
+      } // j
+    } // i
+
+    if (mflag) {
+      if (b->verbose > 2) {
+        printf("      Found %ld middle subfaces.\n", midfaces->objects);
+      }
+      face oldsh, newsh, casout, casin, neighsh;
+
+      oldsh = * (face *) fastlookup(missingshs, 0);
+
+      // Create new subfaces to fill the region R.
+      for (i = 0; i < midfaces->objects; i++) {
+        // Get a matched middle face [a, b, c]
+        midface = (triface *) fastlookup(midfaces, i);
+        unmarkface(*midface);
+        makeshellface(subfaces, &newsh);
+        setsorg(newsh, org(*midface));
+        setsdest(newsh, dest(*midface));
+        setsapex(newsh, apex(*midface));
+        // The new subface gets its markers from the old one.
+        setshellmark(newsh, shellmark(oldsh));
+        if (checkconstraints) {
+          setareabound(newsh, areabound(oldsh));
+        }
+        // Connect the new subface to adjacent tets.
+        tsbond(*midface, newsh);
+        fsym(*midface, neightet);
+        sesymself(newsh);
+        tsbond(neightet, newsh);
+      }
+
+      // Connect new subfaces together and to the bdry of R.
+      // Delete faked segments.
+      for (i = 0; i < midfaces->objects; i++) {
+        // Get a matched middle face [a, b, c]
+        midface = (triface *) fastlookup(midfaces, i);
+        for (j = 0; j < 3; j++) {
+          tspivot(*midface, newsh);
+          spivot(newsh, casout);
+          if (casout.sh == NULL) {
+            // Search its neighbor.
+            fnext(*midface, searchtet);
+            while (1) {
+              // (1) First check if this side is a bdry edge of R.
+              tsspivot1(searchtet, checkseg);
+              if (checkseg.sh != NULL) {
+                // It's a bdry edge of R.
+                assert(!infected(searchtet)); // It must not be a cavity tet.
+                // Get the old subface.
+                checkseg.shver = 0;
+                spivot(checkseg, oldsh);
+                if (sinfected(checkseg)) {
+                  // It's a faked segment. Delete it.
+                  spintet = searchtet;
+                  while (1) {
+                    tssdissolve1(spintet);
+                    fnextself(spintet);
+                    if (spintet.tet == searchtet.tet) break;
+                  }
+                  shellfacedealloc(subsegs, checkseg.sh);
+                  ssdissolve(oldsh);
+                  checkseg.sh = NULL;
+                }
+                spivot(oldsh, casout);
+                if (casout.sh != NULL) {
+                  casin = casout;
+                  if (checkseg.sh != NULL) {
+                    // Make sure that the subface has the right ori at the 
+                    //   segment.
+                    checkseg.shver = 0;
+                    if (sorg(newsh) != sorg(checkseg)) {
+                      sesymself(newsh);
+                    }
+                    spivot(casin, neighsh);
+                    while (neighsh.sh != oldsh.sh) {
+                      casin = neighsh;
+                      spivot(casin, neighsh);
+                    }
+                  }
+                  sbond1(newsh, casout);
+                  sbond1(casin, newsh);
+                }
+                if (checkseg.sh != NULL) {
+                  ssbond(newsh, checkseg);
+                }
+                break;
+              } // if (checkseg.sh != NULL)
+              // (2) Second check if this side is an interior edge of R.
+              tspivot(searchtet, neighsh);
+              if (neighsh.sh != NULL) {
+                // Found an adjacent subface of newsh (an interior edge).
+                sbond(newsh, neighsh);
+                break;
+              }
+              fnextself(searchtet);
+              assert(searchtet.tet != midface->tet);
+            } // while (1)
+          } // if (casout.sh == NULL)
+          enextself(*midface);
+        } // j
+      } // i
+
+      // Delete old subfaces.
+      for (i = 0; i < missingshs->objects; i++) {
+        parysh = (face *) fastlookup(missingshs, i);
+        shellfacedealloc(subfaces, parysh->sh);
+      }
+    } else {
+      if (toptet.tet != NULL) {
+        // Faces at top and bottom are not matched. 
+        // Choose a Steiner point in R.
+        // Split one of the crossing edges.
+        pa = org(toptet);
+        pb = dest(toptet);
+        pc = org(bottet);
+        pd = dest(bottet);
+        // Search an edge in R which is either [a,b] or [c,d].
+        // Reminder:  Subfaces in this list 'missingshs', except the first
+        //   one, represents an interior edge of R. 
+        for (i = 1; i < missingshs->objects; i++) {
+          parysh = (face *) fastlookup(missingshs, i);
+          if (((sorg(*parysh) == pa) && (sdest(*parysh) == pb)) ||
+              ((sorg(*parysh) == pb) && (sdest(*parysh) == pa))) break;
+          if (((sorg(*parysh) == pc) && (sdest(*parysh) == pd)) ||
+              ((sorg(*parysh) == pd) && (sdest(*parysh) == pc))) break;
+        }
+        if (i < missingshs->objects) {
+          // Found. Return it.
+          recentsh = *parysh;
+        } else {
+          assert(0);
+        }
+      }
+    }
+
+    midfaces->restart();
+  } else {
+    mflag = true;
+  } 
+
+  // Delete the temp subfaces.
+  for (j = 0; j < 2; j++) {
+    cavshells = (j == 0 ? topshells : botshells);
+    if (cavshells != NULL) {
+      for (i = 0; i < cavshells->objects; i++) {
+        parysh = (face *) fastlookup(cavshells, i);
+        shellfacedealloc(subfaces, parysh->sh);
+      }
+    }
+  }
+
+  topshells->restart();
+  if (botshells != NULL) {
+    botshells->restart();
+  }
+
+  return mflag;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// carvecavity()    Delete old tets and outer new tets of the cavity.        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
+                             arraypool *botnewtets)
+{
+  arraypool *newtets;
+  shellface *sptr, *ssptr;
+  triface *parytet, *pnewtet, newtet, neightet, spintet;
+  face checksh, *parysh;
+  face checkseg, *paryseg;
+  int t1ver;
+  int i, j;
+
+  if (b->verbose > 2) {
+    printf("      Carve cavity: %ld old tets.\n", crosstets->objects);
+  }
+
+  // First process subfaces and segments which are adjacent to the cavity.
+  //   They must be re-connected to new tets in the cavity.
+  // Comment: It is possible that some subfaces and segments are completely
+  //   inside the cavity. This can happen even if the cavity is not enlarged. 
+  //   Before deleting the old tets, find and queue all interior subfaces
+  //   and segments. They will be recovered later. 2010-05-06.
+
+  // Collect all subfaces and segments which attached to the old tets.
+  for (i = 0; i < crosstets->objects; i++) {
+    parytet = (triface *) fastlookup(crosstets, i);
+    if ((sptr = (shellface*) parytet->tet[9]) != NULL) {
+      for (j = 0; j < 4; j++) {
+        if (sptr[j]) {
+          sdecode(sptr[j], checksh);
+          if (!sinfected(checksh)) {
+            sinfect(checksh);
+            cavetetshlist->newindex((void **) &parysh);
+            *parysh = checksh;
+          }
+        }
+      } // j
+    }
+    if ((ssptr = (shellface*) parytet->tet[8]) != NULL) {
+      for (j = 0; j < 6; j++) {
+        if (ssptr[j]) {
+          sdecode(ssptr[j], checkseg);
+          // Skip a deleted segment (was a faked segment)
+          if (checkseg.sh[3] != NULL) {
+            if (!sinfected(checkseg)) {
+              sinfect(checkseg);
+              cavetetseglist->newindex((void **) &paryseg);
+              *paryseg = checkseg;
+            }
+          }
+        }
+      } // j
+    }
+  } // i
+
+  // Uninfect collected subfaces.
+  for (i = 0; i < cavetetshlist->objects; i++) {
+    parysh = (face *) fastlookup(cavetetshlist, i);
+    suninfect(*parysh);
+  }
+  // Uninfect collected segments.
+  for (i = 0; i < cavetetseglist->objects; i++) {
+    paryseg = (face *) fastlookup(cavetetseglist, i);
+    suninfect(*paryseg);
+  }
+
+  // Connect subfaces to new tets.
+  for (i = 0; i < cavetetshlist->objects; i++) {
+    parysh = (face *) fastlookup(cavetetshlist, i);
+    // Get an adjacent tet at this subface.
+    stpivot(*parysh, neightet);
+    // Does this tet lie inside the cavity.
+    if (infected(neightet)) {
+      // Yes. Get the other adjacent tet at this subface.
+      sesymself(*parysh);
+      stpivot(*parysh, neightet);
+      // Does this tet lie inside the cavity.
+      if (infected(neightet)) {
+        checksh = *parysh;
+        stdissolve(checksh);
+        caveencshlist->newindex((void **) &parysh);
+        *parysh = checksh;
+      }
+    }
+    if (!infected(neightet)) {
+      // Found an outside tet. Re-connect this subface to a new tet.
+      fsym(neightet, newtet);
+      assert(marktested(newtet)); // It's a new tet.
+      sesymself(*parysh);
+      tsbond(newtet, *parysh);
+    }
+  } // i
+
+
+  for (i = 0; i < cavetetseglist->objects; i++) {
+    checkseg = * (face *) fastlookup(cavetetseglist, i);
+    // Check if the segment is inside the cavity.
+    sstpivot1(checkseg, neightet);
+    spintet = neightet;
+    while (1) {
+      if (!infected(spintet)) {
+        // This segment is on the boundary of the cavity.
+        break;
+      }
+      fnextself(spintet);
+      if (spintet.tet == neightet.tet) {
+        sstdissolve1(checkseg);
+        caveencseglist->newindex((void **) &paryseg);
+        *paryseg = checkseg;
+        break;
+      }
+    }
+    if (!infected(spintet)) {
+      // A boundary segment. Connect this segment to the new tets.
+      sstbond1(checkseg, spintet);
+      neightet = spintet;
+      while (1) {
+        tssbond1(spintet, checkseg);
+        fnextself(spintet);
+        if (spintet.tet == neightet.tet) break;
+      }
+    }
+  } // i
+
+
+  cavetetshlist->restart();
+  cavetetseglist->restart();
+
+  // Delete the old tets in cavity.
+  for (i = 0; i < crosstets->objects; i++) {
+    parytet = (triface *) fastlookup(crosstets, i);
+    if (ishulltet(*parytet)) {
+      hullsize--;
+    }
+    tetrahedrondealloc(parytet->tet);
+  }
+
+  crosstets->restart(); // crosstets will be re-used.
+
+  // Collect new tets in cavity.  Some new tets have already been found 
+  //   (and infected) in the fillcavity(). We first collect them.
+  for (j = 0; j < 2; j++) {
+    newtets = (j == 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;
+        }
+      } // i
+    }
+  } // j
+
+  // Now we collect all new tets in cavity.
+  for (i = 0; i < crosstets->objects; i++) {
+    parytet = (triface *) fastlookup(crosstets, i);
+    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;
+        }
+      }
+    } // j
+  } // i
+
+  parytet = (triface *) fastlookup(crosstets, 0);
+  recenttet = *parytet; // Remember a live handle.
+
+  // Delete outer new tets.
+  for (j = 0; j < 2; j++) {
+    newtets = (j == 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);
+          if (ishulltet(*parytet)) {
+            hullsize++;
+          }
+        } 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, arraypool *missingshbds)
+{
+  triface *parytet, neightet, spintet;
+  face *parysh;
+  face checkseg;
+  point *ppt;
+  int t1ver;
+  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
+    parytet->ver = 0;
+    for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
+      fsym(*parytet, neightet);
+      if (!infected(neightet)) {
+        // Restore the old connections of tets.
+        bond(*parytet, neightet);
+      }
+    }
+    // Update the point-to-tet map.
+    parytet->ver = 0;
+    ppt = (point *) &(parytet->tet[4]);
+    for (j = 0; j < 4; j++) {
+      setpoint2tet(ppt[j], encode(*parytet));
+    }
+  }
+
+  // Uninfect all crossing tets.
+  for (i = 0; i < crosstets->objects; i++) {
+    parytet = (triface *) fastlookup(crosstets, i);
+    uninfect(*parytet);
+  }
+
+  // Remember a live handle.
+  recenttet = * (triface *) fastlookup(crosstets, 0);
+
+  // Delete faked segments.
+  for (i = 0; i < missingshbds->objects; i++) {
+    parysh = (face *) fastlookup(missingshbds, i);
+    sspivot(*parysh, checkseg);
+    assert(checkseg.sh != NULL);
+    if (checkseg.sh[3] != NULL) {
+      if (sinfected(checkseg)) {
+            // It's a faked segment. Delete it.
+        sstpivot1(checkseg, neightet);
+        spintet = neightet;
+        while (1) {
+          tssdissolve1(spintet);
+          fnextself(spintet);
+          if (spintet.tet == neightet.tet) break;
+        }
+        shellfacedealloc(subsegs, checkseg.sh);
+        ssdissolve(*parysh);
+        //checkseg.sh = NULL;
+      }
+    }
+  } // i
+
+  // 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();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flipcertify()    Insert a crossing face into priority queue.              //
+//                                                                           //
+// A crossing face of a facet must have at least one top and one bottom ver- //
+// tex of the facet.                                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flipcertify(triface *chkface,badface **pqueue,point plane_pa,
+                             point plane_pb, point plane_pc)
+{
+  badface *parybf, *prevbf, *nextbf;
+  triface neightet;
+  face checksh;
+  point p[5];
+  REAL w[5];
+  REAL insph, ori4;
+  int topi, boti;
+  int i;
+
+  // Compute the flip time \tau.
+  fsym(*chkface, neightet);
+
+  p[0] = org(*chkface);
+  p[1] = dest(*chkface);
+  p[2] = apex(*chkface);
+  p[3] = oppo(*chkface);
+  p[4] = oppo(neightet);
+
+  // Check if the face is a crossing face.
+  topi = boti = 0;
+  for (i = 0; i < 3; i++) {
+    if (pmarktest2ed(p[i])) topi++;
+    if (pmarktest3ed(p[i])) boti++;
+  }
+  if ((topi == 0) || (boti == 0)) {
+    // It is not a crossing face.
+    // return;
+    for (i = 3; i < 5; i++) {
+      if (pmarktest2ed(p[i])) topi++;
+      if (pmarktest3ed(p[i])) boti++;
+    }
+    if ((topi == 0) || (boti == 0)) {
+      // The two tets sharing at this face are on one side of the facet.
+      // Check if this face is locally Delaunay (due to rounding error).
+      if ((p[3] != dummypoint) && (p[4] != dummypoint)) {
+        // Do not check it if it is a subface.
+        tspivot(*chkface, checksh);
+        if (checksh.sh == NULL) {
+          insph = insphere_s(p[1], p[0], p[2], p[3], p[4]);
+          assert(insph != 0);
+          if (insph > 0) {
+            // Add the face into queue.
+            if (b->verbose > 2) {
+              printf("      A locally non-Delanay face (%d, %d, %d)-%d,%d\n", 
+                     pointmark(p[0]), pointmark(p[1]), pointmark(p[2]), 
+                     pointmark(p[3]), pointmark(p[4]));
+            }
+            parybf = (badface *) flippool->alloc();
+            parybf->key = 0.;  // tau = 0, do immediately.
+            parybf->tt = *chkface;
+            parybf->forg = p[0];
+            parybf->fdest = p[1];
+            parybf->fapex = p[2];
+            parybf->foppo = p[3];
+            parybf->noppo = p[4];
+            // Add it at the top of the priority queue.
+            if (*pqueue == NULL) {
+              *pqueue = parybf;
+              parybf->nextitem = NULL;
+            } else {
+              parybf->nextitem = *pqueue;
+              *pqueue = parybf;
+            }
+          } // if (insph > 0)
+        } // if (checksh.sh == NULL)
+      }
+      //return;
+    }
+    return; // Test: omit this face.
+  }
+
+  // Decide the "height" for each point.
+  for (i = 0; i < 5; i++) {
+    if (pmarktest2ed(p[i])) {
+      // A top point has a positive weight.
+      w[i] = orient3dfast(plane_pa, plane_pb, plane_pc, p[i]);      
+      if (w[i] < 0) w[i] = -w[i];
+      assert(w[i] != 0);
+    } else {
+      w[i] = 0;
+    }
+  }
+
+  // Make sure orient3d(p[1], p[0], p[2], p[3]) > 0;
+  //   Hence if (insphere(p[1], p[0], p[2], p[3], p[4]) > 0) means that
+  //     p[4] lies inside the circumsphere of p[1], p[0], p[2], p[3].
+  //   The same if orient4d(p[1], p[0], p[2], p[3], p[4]) > 0 means that
+  //     p[4] lies below the oriented hyperplane passing through 
+  //     p[1], p[0], p[2], p[3].
+
+  insph = insphere(p[1], p[0], p[2], p[3], p[4]);
+  ori4 = orient4d(p[1], p[0], p[2], p[3], p[4], w[1], w[0], w[2], w[3], w[4]);
+
+  if (b->verbose > 2) {
+    printf("      Heights: (%g, %g, %g, %g, %g)\n", w[0],w[1],w[2],w[3],w[4]);
+    printf("      Insph: %g, ori4: %g, tau = %g\n", insph, ori4, -insph/ori4);
+  }
+
+  if (ori4 > 0) {
+    // Add the face into queue.
+    if (b->verbose > 2) {
+      printf("      Insert face (%d, %d, %d) - %d, %d\n", pointmark(p[0]),
+        pointmark(p[1]), pointmark(p[2]), pointmark(p[3]), pointmark(p[4]));
+    }
+    
+    parybf = (badface *) flippool->alloc();
+
+    parybf->key = -insph / ori4;
+    parybf->tt = *chkface;
+    parybf->forg = p[0];
+    parybf->fdest = p[1];
+    parybf->fapex = p[2];
+    parybf->foppo = p[3];
+    parybf->noppo = p[4];
+
+    // Push the face into priority queue.
+    //pq.push(bface);
+    if (*pqueue == NULL) {
+      *pqueue = parybf;
+      parybf->nextitem = NULL;
+    } else {
+      // Search an item whose key is larger or equal to current key.
+      prevbf = NULL;
+      nextbf = *pqueue;
+      //if (!b->flipinsert_random) { // Default use a priority queue.
+        // Insert the item into priority queue.
+        while (nextbf != NULL) {
+          if (nextbf->key < parybf->key) {
+            prevbf = nextbf;
+            nextbf = nextbf->nextitem;
+          } else {
+            break;
+          }
+        }
+      //} // if (!b->flipinsert_random)
+      // Insert the new item between prev and next items.
+      if (prevbf == NULL) {
+        *pqueue = parybf;
+      } else {
+        prevbf->nextitem = parybf;
+      }
+      parybf->nextitem = nextbf;
+    }
+  } else if (ori4 == 0) {
+    
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flipinsertfacet()    Insert a facet into a CDT by flips.                  //
+//                                                                           //
+// The algorithm is described in Shewchuk's paper "Updating and Constructing //
+// Constrained Delaunay and Constrained Regular Triangulations by Flips", in //
+// Proc. 19th Ann. Symp. on Comput. Geom., 86--95, 2003.                     //
+//                                                                           //
+// 'crosstets' contains the set of crossing tetrahedra (infected) of the     //
+// facet.  'toppoints' and 'botpoints' are points lies above and below the   //
+// facet, not on the facet.                                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
+                                 arraypool *botpoints, arraypool *midpoints)
+{
+  arraypool *crossfaces, *bfacearray;
+  triface fliptets[6], baktets[2], fliptet, newface;
+  triface neightet, *parytet;
+  face checksh;
+  face checkseg;
+  badface *pqueue;
+  badface *popbf, bface;
+  point plane_pa, plane_pb, plane_pc;
+  point p1, p2, pd, pe;
+  point *parypt;
+  flipconstraints fc;
+  REAL ori[3];
+  int convcount, copcount;
+  int flipflag, fcount;
+  int n, i;
+  long f23count, f32count, f44count;
+  long totalfcount;
+
+  f23count = flip23count;
+  f32count = flip32count;
+  f44count = flip44count;
+
+  // Get three affinely independent vertices in the missing region R.
+  calculateabovepoint(midpoints, &plane_pa, &plane_pb, &plane_pc);
+
+  // Mark top and bottom points. Do not mark midpoints.
+  for (i = 0; i < toppoints->objects; i++) {
+    parypt = (point *) fastlookup(toppoints, i);
+    if (!pmarktested(*parypt)) {
+      pmarktest2(*parypt);
+    }
+  }
+  for (i = 0; i < botpoints->objects; i++) {
+    parypt = (point *) fastlookup(botpoints, i);
+    if (!pmarktested(*parypt)) {
+      pmarktest3(*parypt);
+    }
+  }
+
+  // Collect crossing faces. 
+  crossfaces = cavetetlist;  // Re-use array 'cavetetlist'.
+
+  // Each crossing face contains at least one bottom vertex and
+  //   one top vertex.
+  for (i = 0; i < crosstets->objects; i++) {
+    parytet = (triface *) fastlookup(crosstets, i);
+    fliptet = *parytet;
+    for (fliptet.ver = 0; fliptet.ver < 4; fliptet.ver++) {
+      fsym(fliptet, neightet);
+      if (infected(neightet)) { // It is an interior face.
+        if (!marktested(neightet)) { // It is an unprocessed face.
+          crossfaces->newindex((void **) &parytet);
+          *parytet = fliptet;
+        }
+      }
+    }
+    marktest(fliptet);
+  }
+
+  if (b->verbose > 1) {
+    printf("    Found %ld crossing faces.\n", crossfaces->objects);
+  }
+
+  for (i = 0; i < crosstets->objects; i++) {
+    parytet = (triface *) fastlookup(crosstets, i);
+    unmarktest(*parytet);
+    uninfect(*parytet);
+  }
+
+  // Initialize the priority queue.
+  pqueue = NULL;
+
+  for (i = 0; i < crossfaces->objects; i++) {
+    parytet = (triface *) fastlookup(crossfaces, i);
+    flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
+  }
+  crossfaces->restart();
+
+  // The list for temporarily storing unflipable faces.
+  bfacearray = new arraypool(sizeof(triface), 4);
+
+
+  fcount = 0;  // Count the number of flips.
+
+  // Flip insert the facet.
+  while (pqueue != NULL) {
+
+    // Pop a face from the priority queue.
+    popbf = pqueue;
+    bface = *popbf;
+
+    // Update the queue.
+    pqueue = pqueue->nextitem;
+
+    // Delete the popped item from the pool.
+    flippool->dealloc((void *) popbf);
+
+    if (!isdeadtet(bface.tt)) {
+      if ((org(bface.tt) == bface.forg) && (dest(bface.tt) == bface.fdest) &&
+          (apex(bface.tt) == bface.fapex) && (oppo(bface.tt) == bface.foppo)) {
+        // It is still a crossing face of R.
+        fliptet = bface.tt;
+        fsym(fliptet, neightet);
+        assert(!isdeadtet(neightet));
+        if (oppo(neightet) == bface.noppo) {
+          pd = oppo(fliptet);
+          pe = oppo(neightet);
+
+          if (b->verbose > 2) {
+            printf("      Get face (%d, %d, %d) - %d, %d, tau = %.17g\n",
+                   pointmark(bface.forg), pointmark(bface.fdest),
+                   pointmark(bface.fapex), pointmark(bface.foppo),
+                   pointmark(bface.noppo), bface.key);
+          }
+          flipflag = 0;
+
+          // Check for which type of flip can we do.
+          convcount = 3;
+          copcount = 0;
+          for (i = 0; i < 3; i++) {
+            p1 = org(fliptet);
+            p2 = dest(fliptet);
+            ori[i] = orient3d(p1, p2, pd, pe);
+            if (ori[i] < 0) {
+              convcount--;
+              //break;
+            } else if (ori[i] == 0) {
+              convcount--; // Possible 4-to-4 flip.
+              copcount++;
+              //break;
+            }
+            enextself(fliptet);
+          }
+
+          if (convcount == 3) {
+            // A 2-to-3 flip is found.
+            // The face should not be a subface.
+            tspivot(fliptet, checksh);
+            assert(checksh.sh == NULL);
+
+            fliptets[0] = fliptet; // abcd, d may be the new vertex.
+            fliptets[1] = neightet; // bace.
+            flip23(fliptets, 1, &fc);
+            // Put the link faces into check list.
+            for (i = 0; i < 3; i++) {
+              eprevesym(fliptets[i], newface);
+              crossfaces->newindex((void **) &parytet);
+              *parytet = newface;
+            }
+            for (i = 0; i < 3; i++) {
+              enextesym(fliptets[i], newface);
+              crossfaces->newindex((void **) &parytet);
+              *parytet = newface;
+            }
+            flipflag = 1;
+          } else if (convcount == 2) {
+            assert(copcount <= 1);
+            //if (copcount <= 1) {
+            // A 3-to-2 or 4-to-4 may be possible.
+            // Get the edge which is locally non-convex or flat. 
+            for (i = 0; i < 3; i++) {
+              if (ori[i] <= 0) break;
+              enextself(fliptet);
+            }
+            // The edge should not be a segment.
+            tsspivot1(fliptet, checkseg);
+            assert(checkseg.sh == NULL);
+
+            // Collect tets sharing at this edge.
+            // NOTE: This operation may collect tets which lie outside the
+            //   cavity, e.g., when the edge lies on the boundary of the
+            //   cavity. Do not flip if there are outside tets at this edge.
+            //   2012-07-27.
+            esym(fliptet, fliptets[0]); // [b,a,d,c]
+            n = 0;
+            do {
+              p1 = apex(fliptets[n]);
+              if (!(pmarktested(p1) || pmarktest2ed(p1) || pmarktest3ed(p1))) {
+                // This apex is not on the cavity. Hence the face does not
+                //   lie inside the cavity. Do not flip this edge.
+                n = 1000; break;
+              }
+              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, 1, &fc);
+              // Put the link faces into check list.
+              for (i = 0; i < 3; i++) {
+                esym(fliptets[0], newface);
+                crossfaces->newindex((void **) &parytet);
+                *parytet = newface;
+                enextself(fliptets[0]);
+              }
+              for (i = 0; i < 3; i++) {
+                esym(fliptets[1], newface);
+                crossfaces->newindex((void **) &parytet);
+                *parytet = newface;
+                enextself(fliptets[1]);
+              }
+              flipflag = 1;
+            } else if (n == 4) {
+              if (copcount == 1) {                
+                // Found a 4-to-4 flip. 
+                // Let the six vertices are: a,b,c,d,e,f, where
+                //   fliptets[0] = [b,a,d,c]
+                //           [1] = [b,a,c,e]
+                //           [2] = [b,a,e,f]
+                //           [3] = [b,a,f,d]
+                // After the 4-to-4 flip, edge [a,b] is flipped, edge [e,d]
+                //   is created.
+                // First do a 2-to-3 flip.
+                // Comment: This flip temporarily creates a degenerated
+                //   tet (whose volume is zero). It will be removed by the 
+                //   followed 3-to-2 flip.
+                fliptets[0] = fliptet; // = [a,b,c,d], d is the new vertex.
+                // fliptets[1];        // = [b,a,c,e].
+                baktets[0] = fliptets[2]; // = [b,a,e,f]
+                baktets[1] = fliptets[3]; // = [b,a,f,d]
+                // The flip may involve hull tets.
+                flip23(fliptets, 1, &fc);
+                // Put the "outer" link faces into check list.
+                //   fliptets[0] = [e,d,a,b] => will be flipped, so 
+                //   [a,b,d] and [a,b,e] are not "outer" link faces.
+                for (i = 1; i < 3; i++) {
+                  eprevesym(fliptets[i], newface);
+                  crossfaces->newindex((void **) &parytet);
+                  *parytet = newface;
+                }
+                for (i = 1; i < 3; i++) {
+                  enextesym(fliptets[i], newface);
+                  crossfaces->newindex((void **) &parytet);
+                  *parytet = newface;
+                }
+                // Then do a 3-to-2 flip.
+                enextesymself(fliptets[0]);  // fliptets[0] is [e,d,a,b].
+                eprevself(fliptets[0]); // = [b,a,d,c], d is the new vertex.
+                fliptets[1] = baktets[0]; // = [b,a,e,f]
+                fliptets[2] = baktets[1]; // = [b,a,f,d]
+                flip32(fliptets, 1, &fc);
+                // Put the "outer" link faces into check list.
+                //   fliptets[0] = [d,e,f,a]
+                //   fliptets[1] = [e,d,f,b]
+                //   Faces [a,b,d] and [a,b,e] are not "outer" link faces.
+                enextself(fliptets[0]);
+                for (i = 1; i < 3; i++) {
+                  esym(fliptets[0], newface);
+                  crossfaces->newindex((void **) &parytet);
+                  *parytet = newface;
+                  enextself(fliptets[0]);
+                }
+                enextself(fliptets[1]);
+                for (i = 1; i < 3; i++) {
+                  esym(fliptets[1], newface);
+                  crossfaces->newindex((void **) &parytet);
+                  *parytet = newface;
+                  enextself(fliptets[1]);
+                }
+                flip23count--;
+                flip32count--;
+                flip44count++;
+                flipflag = 1;
+              } else {
+                //n == 4, convflag != 0; assert(0);
+              }
+            } else { 
+              // n > 4 => unflipable. //assert(0);
+            }
+          } else {
+            // There are more than 1 non-convex or coplanar cases.
+            flipflag = -1; // Ignore this face.
+            if (b->verbose > 2) {
+              printf("        Ignore face (%d, %d, %d) - %d, %d, tau = %.17g\n",
+                     pointmark(bface.forg), pointmark(bface.fdest),
+                     pointmark(bface.fapex), pointmark(bface.foppo),
+                     pointmark(bface.noppo), bface.key);
+            }
+          } // if (convcount == 1)
+
+          if (flipflag == 1) {
+            // Update the priority queue.
+            for (i = 0; i < crossfaces->objects; i++) {
+              parytet = (triface *) fastlookup(crossfaces, i);
+              flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
+            }
+            crossfaces->restart();
+            if (1) { // if (!b->flipinsert_random) {
+              // Insert all queued unflipped faces.
+              for (i = 0; i < bfacearray->objects; i++) {
+                parytet = (triface *) fastlookup(bfacearray, i);
+                // This face may be changed.
+                if (!isdeadtet(*parytet)) {
+                  flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
+                }
+              }
+              bfacearray->restart();
+            }
+            fcount++;
+          } else if (flipflag == 0) {
+            // Queue an unflippable face. To process it later.
+            bfacearray->newindex((void **) &parytet);
+            *parytet = fliptet;
+          }
+        } // if (pe == bface.noppo)  
+      } // if ((pa == bface.forg) && ...)
+    } // if (bface.tt != NULL)
+
+  } // while (pqueue != NULL)
+
+  if (bfacearray->objects > 0) {
+    if (fcount == 0) {
+      printf("!! No flip is found in %ld faces.\n", bfacearray->objects);
+      assert(0);
+    }
+  }
+
+  // 'bfacearray' may be not empty (for what reason ??).
+  //dbg_unflip_facecount += bfacearray->objects;
+
+  assert(flippool->items == 0l);
+  delete bfacearray;
+
+  // Un-mark top and bottom points.
+  for (i = 0; i < toppoints->objects; i++) {
+    parypt = (point *) fastlookup(toppoints, i);
+    punmarktest2(*parypt);
+  }
+  for (i = 0; i < botpoints->objects; i++) {
+    parypt = (point *) fastlookup(botpoints, i);
+    punmarktest3(*parypt);
+  }
+
+  f23count = flip23count - f23count;
+  f32count = flip32count - f32count;
+  f44count = flip44count - f44count;
+  totalfcount = f23count + f32count + f44count;
+  if (b->verbose > 2) {
+    printf("      Total %ld flips. f23(%ld), f32(%ld), f44(%ld).\n",
+           totalfcount, f23count, f32count, f44count);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// fillregion()    Fill the missing region by a set of new subfaces.         //
+//                                                                           //
+// 'missingshs' contains the list of subfaces in R.  Moreover, each subface  //
+// (except the first one) in this list represents an interior edge of R.     //
+//                                                                           //
+// Note: We assume that all vertices of R are marktested so we can detect    //
+// new subface by checking the flag in apexes.                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::fillregion(arraypool* missingshs, arraypool* missingshbds,
+                            arraypool* newshs)
+{
+  badface *newflipface, *popface;
+  triface searchtet, spintet, neightet;
+  face oldsh, newsh, opensh, *parysh;
+  face casout, casin, neighsh, checksh;
+  face neighseg, checkseg;
+  point pc;
+  int success;
+  int t1ver;
+  int i, j;
+
+
+  // Search the first new subface to fill the region.
+  for (i = 0; i < missingshbds->objects; i++) {
+    parysh = (face *) fastlookup(missingshbds, i);
+    sspivot(*parysh, neighseg);
+    sstpivot1(neighseg, searchtet);
+    j = 0; // Count the number of passes of R.
+    spintet = searchtet;
+    while (1) {
+      pc = apex(spintet);
+      if (pmarktested(pc)) {
+        neightet = spintet;
+        j++;
+      }
+      fnextself(spintet);
+      if (spintet.tet == searchtet.tet) break;
+    }
+    assert(j >= 1);
+    if (j == 1) {
+      // Found an interior new subface.
+      searchtet = neightet;
+      oldsh = *parysh;
+      break;
+    }
+  } // i
+
+  if (i == missingshbds->objects) {
+    // Failed to find any interior subface.
+    // Need Steiner points.
+    return false;
+  }
+
+  makeshellface(subfaces, &newsh);
+  setsorg(newsh, org(searchtet));
+  setsdest(newsh, dest(searchtet));
+  setsapex(newsh, apex(searchtet));
+  // The new subface gets its markers from the old one.
+  setshellmark(newsh, shellmark(oldsh));
+  if (checkconstraints) {
+    setareabound(newsh, areabound(oldsh));
+  }
+  // Connect the new subface to adjacent tets.
+  tsbond(searchtet, newsh);
+  fsymself(searchtet);
+  sesymself(newsh);
+  tsbond(searchtet, newsh);
+  // Connect newsh to outer subfaces.
+  sspivot(oldsh, checkseg);
+  if (sinfected(checkseg)) {
+    // It's a faked segment. Delete it.
+    spintet = searchtet;
+    while (1) {
+      tssdissolve1(spintet);
+      fnextself(spintet);
+      if (spintet.tet == searchtet.tet) break;
+    }
+    shellfacedealloc(subsegs, checkseg.sh);
+    ssdissolve(oldsh);
+    checkseg.sh = NULL;
+  }
+  spivot(oldsh, casout);
+  if (casout.sh != NULL) {
+    casin = casout;
+    if (checkseg.sh != NULL) {
+      // Make sure that the subface has the right ori at the segment.
+      checkseg.shver = 0;
+      if (sorg(newsh) != sorg(checkseg)) {
+        sesymself(newsh);
+      }
+      spivot(casin, neighsh);
+      while (neighsh.sh != oldsh.sh) {
+        casin = neighsh;
+        spivot(casin, neighsh);
+      }
+    }
+    sbond1(newsh, casout);
+    sbond1(casin, newsh);
+  }
+  if (checkseg.sh != NULL) {
+    ssbond(newsh, checkseg);
+  }
+  // Add this new subface into list.
+  sinfect(newsh);
+  newshs->newindex((void **) &parysh);
+  *parysh = newsh;
+
+  // Push two "open" side of the new subface into stack.
+  for (i = 0; i < 2; i++) {
+    senextself(newsh);
+    newflipface = (badface *) flippool->alloc();
+    newflipface->ss = newsh;
+    newflipface->nextitem = flipstack;
+    flipstack = newflipface;
+  }
+
+  success = 1;
+
+  // Loop until 'flipstack' is empty.
+  while ((flipstack != NULL) && success) {
+    // Pop an "open" side from the stack.
+    popface = flipstack;
+    opensh = popface->ss;
+    flipstack = popface->nextitem; // The next top item in stack.
+    flippool->dealloc((void *) popface);
+
+    // opensh is either (1) an interior edge or (2) a bdry edge.
+    stpivot(opensh, searchtet);
+    tsspivot1(searchtet, checkseg);
+    if (checkseg.sh == NULL) {
+      // No segment. It is an interior edge of R. 
+      // Search for a new face in R.
+      spintet = searchtet;
+      fnextself(spintet); // Skip the current face.
+      while (1) {
+        pc = apex(spintet);
+        if (pmarktested(pc)) {
+          // 'opensh' is an interior edge.
+          if (!issubface(spintet)) {
+            // Create a new subface.
+            makeshellface(subfaces, &newsh);
+            setsorg(newsh, org(spintet));
+            setsdest(newsh, dest(spintet));
+            setsapex(newsh, pc);
+            // The new subface gets its markers from its neighbor.
+            setshellmark(newsh, shellmark(opensh));
+            if (checkconstraints) {
+              setareabound(newsh, areabound(opensh));
+            }
+            // Connect the new subface to adjacent tets.
+            tsbond(spintet, newsh);
+            fsymself(spintet);
+            sesymself(newsh);
+            tsbond(spintet, newsh);
+            // Connect newsh to its adjacent subface.
+            sbond(newsh, opensh);
+            // Add this new subface into list.
+            sinfect(newsh);
+            newshs->newindex((void **) &parysh);
+            *parysh = newsh;
+            // Push two "open" side of the new subface into stack.
+            for (i = 0; i < 2; i++) {
+              senextself(newsh);
+              newflipface = (badface *) flippool->alloc();
+              newflipface->ss = newsh;
+              newflipface->nextitem = flipstack;
+              flipstack = newflipface;
+            }
+          } else {
+            // Connect to another open edge.
+            tspivot(spintet, checksh);
+            sbond(opensh, checksh); 
+          }
+          break;
+        } // if (pmarktested(pc))
+        fnextself(spintet);
+        if (spintet.tet == searchtet.tet) {
+          // Not find any face to fill in R at this side.
+          // Suggest a point to split the edge.
+          success = 0;
+          break;
+        }
+      } // while (1)
+    } else {
+      // This side coincident with a boundary edge of R.
+      checkseg.shver = 0;
+      spivot(checkseg, oldsh);
+      if (sinfected(checkseg)) {
+        // It's a faked segment. Delete it.
+        spintet = searchtet;
+        while (1) {
+          tssdissolve1(spintet);
+          fnextself(spintet);
+          if (spintet.tet == searchtet.tet) break;
+        }
+        shellfacedealloc(subsegs, checkseg.sh);
+        ssdissolve(oldsh);
+        checkseg.sh = NULL;
+      }
+      spivot(oldsh, casout);
+      if (casout.sh != NULL) {
+        casin = casout;
+        if (checkseg.sh != NULL) {
+          // Make sure that the subface has the right ori at the segment.
+          checkseg.shver = 0;
+          if (sorg(opensh) != sorg(checkseg)) {
+            sesymself(opensh);
+	      }
+          spivot(casin, neighsh);
+          while (neighsh.sh != oldsh.sh) {
+            casin = neighsh;
+            spivot(casin, neighsh);
+          }
+        }
+        sbond1(opensh, casout);
+        sbond1(casin, opensh);
+      }
+      if (checkseg.sh != NULL) {
+        ssbond(opensh, checkseg);
+      }
+    } // if (checkseg.sh != NULL)
+  } // while ((flipstack != NULL) && success)
+
+  if (success) {
+    // Uninfect all new subfaces.
+    for (i = 0; i < newshs->objects; i++) {
+      parysh = (face *) fastlookup(newshs, i);
+      suninfect(*parysh);
+    }
+    // Delete old subfaces.
+    for (i = 0; i < missingshs->objects; i++) {
+      parysh = (face *) fastlookup(missingshs, i);
+      shellfacedealloc(subfaces, parysh->sh);
+    }
+    fillregioncount++;
+  } else {
+    // Failed to fill the region. 
+    // Re-connect old subfaces at boundaries of R.
+    // Also delete fake segments.
+    for (i = 0; i < missingshbds->objects; i++) {
+      parysh = (face *) fastlookup(missingshbds, i);
+      // It still connect to 'casout'. 
+      // Re-connect 'casin' to it.
+      spivot(*parysh, casout);
+      casin = casout;
+      spivot(casin, neighsh);
+      while (1) {
+        if (sinfected(neighsh)) break;
+        if (neighsh.sh == parysh->sh) break;
+        casin = neighsh;
+        spivot(casin, neighsh);
+      }
+      if (sinfected(neighsh)) {
+        sbond1(casin, *parysh);
+      }
+      sspivot(*parysh, checkseg);
+      if (checkseg.sh != NULL) {
+        if (checkseg.sh[3] != NULL) {
+          if (sinfected(checkseg)) {
+            sstpivot1(checkseg, searchtet);
+            spintet = searchtet;
+            while (1) {
+              tssdissolve1(spintet);
+              fnextself(spintet);
+              if (spintet.tet == searchtet.tet) break;
+            }
+            ssdissolve(*parysh);
+            shellfacedealloc(subsegs, checkseg.sh);
+          }
+        }
+      }
+    }
+    // Delete all new subfaces.
+    for (i = 0; i < newshs->objects; i++) {
+      parysh = (face *) fastlookup(newshs, i);
+      shellfacedealloc(subfaces, parysh->sh);
+    }
+    // Clear the flip pool.    
+    flippool->restart();
+    flipstack = NULL;
+
+    // Choose an interior edge of R to split.
+    assert(missingshs->objects > 1);
+    // Skip the first subface in 'missingshs'.
+    i = randomnation(missingshs->objects - 1) + 1;
+    parysh = (face *) fastlookup(missingshs, i);
+    recentsh = *parysh;
+  }
+
+  newshs->restart();
+
+  return success;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertpoint_cdt()    Insert a new point into a CDT.                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::insertpoint_cdt(point newpt, triface *searchtet, face *splitsh, 
+                                face *splitseg, insertvertexflags *ivf,
+                                arraypool *cavpoints, arraypool *cavfaces,
+                                arraypool *cavshells, arraypool *newtets,
+                                arraypool *crosstets, arraypool *misfaces)
+{
+  triface neightet, *parytet;
+  face checksh, *parysh, *parysh1;
+  face *paryseg, *paryseg1;
+  point *parypt;
+  int t1ver;
+  int i;
+
+  if (b->verbose > 2) {
+    printf("      Insert point %d into CDT\n", pointmark(newpt));
+  }
+
+  if (!insertpoint(newpt, searchtet, NULL, NULL, ivf)) {
+    // Point is not inserted. Check ivf->iloc for reason.
+    return 0;
+  }
+
+
+  for (i = 0; i < cavetetvertlist->objects; i++) {
+    cavpoints->newindex((void **) &parypt);
+    *parypt = * (point *) fastlookup(cavetetvertlist, i);
+  }
+  // Add the new point into the point list.
+  cavpoints->newindex((void **) &parypt);
+  *parypt = newpt;
+
+  for (i = 0; i < cavebdrylist->objects; i++) {
+    cavfaces->newindex((void **) &parytet);
+    *parytet = * (triface *) fastlookup(cavebdrylist, i);
+  }
+
+  for (i = 0; i < caveoldtetlist->objects; i++) {
+    crosstets->newindex((void **) &parytet);
+    *parytet = * (triface *) fastlookup(caveoldtetlist, i);
+  }
+
+  cavetetvertlist->restart();
+  cavebdrylist->restart();
+  caveoldtetlist->restart();
+
+  // Insert the point using the cavity algorithm.
+  delaunizecavity(cavpoints, cavfaces, cavshells, newtets, crosstets, 
+                  misfaces);
+  fillcavity(cavshells, NULL, NULL, NULL, NULL, NULL, NULL);
+  carvecavity(crosstets, newtets, NULL);
+
+  if ((splitsh != NULL) || (splitseg != NULL)) {
+    // Insert the point into the surface mesh.
+    sinsertvertex(newpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat, 0);
+
+    // Put all new subfaces into stack.
+    for (i = 0; i < caveshbdlist->objects; i++) { 
+      // Get an old subface at edge [a, b].
+      parysh = (face *) fastlookup(caveshbdlist, i);
+      spivot(*parysh, checksh); // The new subface [a, b, p].
+      // Do not recover a deleted new face (degenerated).
+      if (checksh.sh[3] != NULL) {
+        subfacstack->newindex((void **) &parysh);
+        *parysh = checksh;
+      }
+    }
+
+    if (splitseg != NULL) {
+      // Queue two new subsegments in C(p) for recovery.
+      for (i = 0; i < cavesegshlist->objects; i++) {
+        paryseg = (face *) fastlookup(cavesegshlist, i);
+        subsegstack->newindex((void **) &paryseg1);
+        *paryseg1 = *paryseg;
+      }
+    } // if (splitseg != NULL)
+
+    // Delete the old subfaces in sC(p).
+    for (i = 0; i < caveshlist->objects; i++) {
+      parysh = (face *) fastlookup(caveshlist, i);
+      if (checksubfaceflag) {
+        // It is possible that this subface still connects to adjacent
+        //   tets which are not in C(p). If so, clear connections in the
+        //   adjacent tets at this subface.
+        stpivot(*parysh, neightet);
+        if (neightet.tet != NULL) {
+          if (neightet.tet[4] != NULL) {
+            // Found an adjacent tet. It must be not in C(p).
+            assert(!infected(neightet));
+            tsdissolve(neightet);
+            fsymself(neightet);
+            assert(!infected(neightet));
+            tsdissolve(neightet);
+          }
+        }
+      }
+      shellfacedealloc(subfaces, parysh->sh);
+    }
+    if (splitseg != NULL) {
+      // Delete the old segment in sC(p).
+      shellfacedealloc(subsegs, splitseg->sh);
+    }
+
+    // Clear working lists.
+    caveshlist->restart();
+    caveshbdlist->restart();
+    cavesegshlist->restart();
+  } // if ((splitsh != NULL) || (splitseg != NULL)) 
+
+  // Put all interior subfaces into stack for recovery.
+  // They were collected in carvecavity().
+  // Note: Some collected subfaces may be deleted by sinsertvertex().
+  for (i = 0; i < caveencshlist->objects; i++) {
+    parysh = (face *) fastlookup(caveencshlist, i);
+    if (parysh->sh[3] != NULL) {
+      subfacstack->newindex((void **) &parysh1);
+      *parysh1 = *parysh;
+    }
+  }
+
+  // Put all interior segments into stack for recovery.
+  // They were collected in carvecavity().
+  // Note: Some collected segments may be deleted by sinsertvertex().
+  for (i = 0; i < caveencseglist->objects; i++) {
+    paryseg = (face *) fastlookup(caveencseglist, i);
+    if (paryseg->sh[3] != NULL) {
+      subsegstack->newindex((void **) &paryseg1);
+      *paryseg1 = *paryseg;
+    }
+  }
+
+  caveencshlist->restart();
+  caveencseglist->restart();
+
+  return 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// refineregion()    Refine a missing region by inserting points.            //
+//                                                                           //
+// 'splitsh' represents an edge of the facet to be split. It must be not a   //
+// segment. 
+//                                                                           //
+// Assumption: The current mesh is a CDT and is convex.                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::refineregion(face &splitsh, arraypool *cavpoints, 
+                              arraypool *cavfaces, arraypool *cavshells,
+                              arraypool *newtets, arraypool *crosstets,
+                              arraypool *misfaces)
+{
+  triface searchtet, spintet;
+  face splitseg, *paryseg;
+  point steinpt, pa, pb, refpt;
+  insertvertexflags ivf;
+  enum interresult dir;
+  long baknum = points->items;
+  int t1ver;
+  int i;
+
+  if (b->verbose > 2) {
+    printf("      Refining region at edge (%d, %d, %d).\n",
+           pointmark(sorg(splitsh)), pointmark(sdest(splitsh)),
+           pointmark(sapex(splitsh)));
+  }
+
+  // Add the Steiner point at the barycenter of the face.
+  pa = sorg(splitsh);
+  pb = sdest(splitsh);
+  // Create a new point.
+  makepoint(&steinpt, FREEFACETVERTEX);
+  for (i = 0; i < 3; i++) {
+    steinpt[i] = 0.5 * (pa[i] + pb[i]);
+  }
+
+  ivf.bowywat = 1; // Use the Bowyer-Watson algorrithm.
+  ivf.cdtflag = 1; // Only create the initial cavity.
+  ivf.sloc = (int) ONEDGE;
+  ivf.sbowywat = 1;
+  ivf.assignmeshsize = b->metric;
+
+  point2tetorg(pa, searchtet); // Start location from it.
+  ivf.iloc = (int) OUTSIDE;
+
+  ivf.rejflag = 1; // Reject it if it encroaches upon any segment.
+  if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, NULL, &ivf, cavpoints,
+                       cavfaces, cavshells, newtets, crosstets, misfaces)) {
+    if (ivf.iloc == (int) ENCSEGMENT) {
+      pointdealloc(steinpt);
+      // Split an encroached segment.
+      assert(encseglist->objects > 0);
+      i = randomnation(encseglist->objects);
+      paryseg = (face *) fastlookup(encseglist, i);
+      splitseg = *paryseg;
+      encseglist->restart();
+
+      // Split the segment.
+      pa = sorg(splitseg);
+      pb = sdest(splitseg);
+      // Create a new point.
+      makepoint(&steinpt, FREESEGVERTEX);
+      for (i = 0; i < 3; i++) {
+        steinpt[i] = 0.5 * (pa[i] + pb[i]);
+      }
+      point2tetorg(pa, searchtet);
+      ivf.iloc = (int) OUTSIDE;
+      ivf.rejflag = 0;
+      if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, &splitseg, &ivf,
+                           cavpoints, cavfaces, cavshells, newtets, 
+                           crosstets, misfaces)) {
+        assert(0);
+      }
+      st_segref_count++;
+      if (steinerleft > 0) steinerleft--;
+    } else {
+      assert(0);
+    }
+  } else {
+    st_facref_count++;
+    if (steinerleft > 0) steinerleft--;
+  }
+
+  while (subsegstack->objects > 0l) {
+    // seglist is used as a stack.
+    subsegstack->objects--;
+    paryseg = (face *) fastlookup(subsegstack, subsegstack->objects);
+    splitseg = *paryseg;
+
+    // Check if this segment has been recovered.
+    sstpivot1(splitseg, searchtet);
+    if (searchtet.tet != NULL) continue;
+
+    // Search the segment.
+    dir = scoutsegment(sorg(splitseg), sdest(splitseg), &searchtet, &refpt, 
+                       NULL);
+    if (dir == SHAREEDGE) {
+      // Found this segment, insert it.
+      if (!issubseg(searchtet)) {
+        // Let the segment remember an adjacent tet.
+        sstbond1(splitseg, searchtet);
+        // Bond the segment to all tets containing it.
+        spintet = searchtet;
+        do {
+          tssbond1(spintet, splitseg);
+          fnextself(spintet);
+        } while (spintet.tet != searchtet.tet);
+      } else {
+        // Collision! Should not happen.
+        assert(0);
+      }
+    } else { 
+      if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
+        // Split the segment.
+        // Create a new point.
+        makepoint(&steinpt, FREESEGVERTEX);
+        //setpointtype(newpt, FREESEGVERTEX);
+        getsteinerptonsegment(&splitseg, refpt, steinpt);
+        ivf.iloc = (int) OUTSIDE;
+        ivf.rejflag = 0;
+        if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, &splitseg, &ivf,
+                             cavpoints, cavfaces, cavshells, newtets, 
+                             crosstets, misfaces)) {
+          assert(0);
+        }
+        st_segref_count++;
+        if (steinerleft > 0) steinerleft--;
+      } else {
+        // Maybe a PLC problem.
+        assert(0);
+      }
+    }
+  } // while
+
+  if (b->verbose > 2) {
+    printf("      Added %ld Steiner points.\n", points->items - baknum);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// constrainedfacets()    Recover constrained facets in a CDT.               //
+//                                                                           //
+// All unrecovered subfaces are queued in 'subfacestack'.                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::constrainedfacets()
+{
+  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;
+  arraypool *tg_missingshs, *tg_missingshbds, *tg_missingshverts;
+  triface searchtet, neightet, crossedge;
+  face searchsh, *parysh, *parysh1;
+  face *paryseg;
+  point *parypt;
+  enum interresult dir;
+  int facetcount;
+  int success;
+  int t1ver;
+  int i, j;
+
+  // 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_facfaces       = new arraypool(sizeof(face), 10);
+  tg_topshells      = new arraypool(sizeof(face), 10);
+  tg_botshells      = new arraypool(sizeof(face), 10);
+  tg_missingshs     = new arraypool(sizeof(face), 10);
+  tg_missingshbds   = new arraypool(sizeof(face), 10);
+  tg_missingshverts = new arraypool(sizeof(point), 8);
+  // This is a global array used by refineregion().
+  encseglist        = new arraypool(sizeof(face), 4);
+
+  facetcount = 0;
+
+  while (subfacstack->objects > 0l) {
+
+    subfacstack->objects--;
+    parysh = (face *) fastlookup(subfacstack, subfacstack->objects);
+    searchsh = *parysh;
+
+    if (searchsh.sh[3] == NULL) continue; // It is dead.
+    if (isshtet(searchsh)) continue; // It is recovered.
+
+    // Collect all unrecovered subfaces which are co-facet.
+    smarktest(searchsh);
+    tg_facfaces->newindex((void **) &parysh);
+    *parysh = searchsh;
+    for (i = 0; i < tg_facfaces->objects; i++) {
+      parysh = (face *) fastlookup(tg_facfaces, i);
+      for (j = 0; j < 3; j++) {
+        if (!isshsubseg(*parysh)) {
+          spivot(*parysh, searchsh);
+          assert(searchsh.sh != NULL); // SELF_CHECK
+          if (!smarktested(searchsh)) {
+            if (!isshtet(searchsh)) {
+              smarktest(searchsh);
+              tg_facfaces->newindex((void **) &parysh1);
+              *parysh1 = searchsh;
+            }
+          }
+        }
+        senextself(*parysh);
+      } // j
+    } // i
+    // Have found all facet subfaces. Unmark them.
+    for (i = 0; i < tg_facfaces->objects; i++) {
+      parysh = (face *) fastlookup(tg_facfaces, i);
+      sunmarktest(*parysh);
+    }
+
+    if (b->verbose > 2) {
+      printf("    Recovering facet #%d: %ld subfaces.\n", facetcount + 1, 
+             tg_facfaces->objects);
+    }
+    facetcount++;
+
+    while (tg_facfaces->objects > 0l) {
+
+      tg_facfaces->objects--;
+      parysh = (face *) fastlookup(tg_facfaces, tg_facfaces->objects);
+      searchsh = *parysh;
+
+      if (searchsh.sh[3] == NULL) continue; // It is dead.
+      if (isshtet(searchsh)) continue; // It is recovered.
+
+      searchtet.tet = NULL;
+      dir = scoutsubface(&searchsh, &searchtet);
+      if (dir == SHAREFACE) continue; // The subface is inserted.
+
+      // The subface is missing. Form the missing region.
+      //   Re-use 'tg_crosstets' for 'adjtets'.
+      formregion(&searchsh, tg_missingshs, tg_missingshbds, tg_missingshverts);
+
+      if (scoutcrossedge(searchtet, tg_missingshbds, tg_missingshs)) {
+        // Save this crossing edge, will be used by fillcavity().
+        crossedge = searchtet;
+        // Form a cavity of crossing tets.
+        success = formcavity(&searchtet, tg_missingshs, tg_crosstets,
+                             tg_topfaces, tg_botfaces, tg_toppoints,
+                             tg_botpoints);
+        if (success) {
+          if (!b->flipinsert) {
+            // Tetrahedralize the top part. Re-use 'tg_midfaces'.
+            delaunizecavity(tg_toppoints, tg_topfaces, tg_topshells,
+                            tg_topnewtets, tg_crosstets, tg_midfaces);
+            // Tetrahedralize the bottom part. Re-use 'tg_midfaces'.
+            delaunizecavity(tg_botpoints, tg_botfaces, tg_botshells,
+                            tg_botnewtets, tg_crosstets, tg_midfaces);
+            // Fill the cavity with new tets.
+            success = fillcavity(tg_topshells, tg_botshells, tg_midfaces,
+                                 tg_missingshs, tg_topnewtets, tg_botnewtets,
+                                 &crossedge);
+            if (success) {
+              // Cavity is remeshed. Delete old tets and outer new tets.
+              carvecavity(tg_crosstets, tg_topnewtets, tg_botnewtets);
+            } else {
+              restorecavity(tg_crosstets, tg_topnewtets, tg_botnewtets,
+                            tg_missingshbds);
+            }
+          } else {
+            // Use the flip algorithm of Shewchuk to recover the subfaces.
+            flipinsertfacet(tg_crosstets, tg_toppoints, tg_botpoints, 
+                            tg_missingshverts);
+            // Recover the missing region.
+            success = fillregion(tg_missingshs, tg_missingshbds, tg_topshells);
+            assert(success);
+            // Clear working lists.
+            tg_crosstets->restart();
+            tg_topfaces->restart();
+            tg_botfaces->restart();
+            tg_toppoints->restart();
+            tg_botpoints->restart();
+          } // b->flipinsert
+
+          if (success) {
+            // Recover interior subfaces.
+            for (i = 0; i < caveencshlist->objects; i++) {
+              parysh = (face *) fastlookup(caveencshlist, i);
+              dir = scoutsubface(parysh, &searchtet);
+              if (dir != SHAREFACE) {
+                // Add this face at the end of the list, so it will be
+                //   processed immediately.
+                tg_facfaces->newindex((void **) &parysh1);
+                *parysh1 = *parysh;
+              }
+            }
+            caveencshlist->restart();
+            // Recover interior segments. This should always be recovered.
+            for (i = 0; i < caveencseglist->objects; i++) {
+              paryseg = (face *) fastlookup(caveencseglist, i);
+              dir = scoutsegment(sorg(*paryseg),sdest(*paryseg),&searchtet,
+                                 NULL, NULL);
+              assert(dir == SHAREEDGE);
+              // Insert this segment.
+              if (!issubseg(searchtet)) {
+                // Let the segment remember an adjacent tet.
+                sstbond1(*paryseg, searchtet);
+                // Bond the segment to all tets containing it.
+                neightet = searchtet;
+                do {
+                  tssbond1(neightet, *paryseg);
+                  fnextself(neightet);
+                } while (neightet.tet != searchtet.tet);
+              } else {
+                // Collision! Should not happen.
+                assert(0);
+              }
+            }
+            caveencseglist->restart();
+          } // success - remesh cavity
+        } // success - form cavity
+      } else {
+        // Recover subfaces by retriangulate the surface mesh.
+        //   Re-use tg_topshells for newshs.
+        success = fillregion(tg_missingshs, tg_missingshbds, tg_topshells);
+      }
+
+      // Unmarktest all points of the missing region.
+      for (i = 0; i < tg_missingshverts->objects; i++) {
+        parypt = (point *) fastlookup(tg_missingshverts, i);
+        punmarktest(*parypt);
+      }
+      tg_missingshverts->restart();
+      tg_missingshbds->restart();
+      tg_missingshs->restart();
+
+      if (!success) {
+        // The missing region can not be recovered. Refine it.
+        refineregion(recentsh, tg_toppoints, tg_topfaces, tg_topshells,
+                     tg_topnewtets, tg_crosstets, tg_midfaces);
+        // Clean the current list of facet subfaces.
+        // tg_facfaces->restart();
+      }
+    } // while (tg_facfaces->objects)
+
+  } // while ((subfacstack->objects)
+
+  // Accumulate the dynamic memory.
+  totalworkmemory += (tg_crosstets->totalmemory + tg_topnewtets->totalmemory +
+                      tg_botnewtets->totalmemory + tg_topfaces->totalmemory +
+                      tg_botfaces->totalmemory + tg_midfaces->totalmemory +
+                      tg_toppoints->totalmemory + tg_botpoints->totalmemory +
+                      tg_facfaces->totalmemory + tg_topshells->totalmemory +
+                      tg_botshells->totalmemory + tg_missingshs->totalmemory +
+                      tg_missingshbds->totalmemory + 
+                      tg_missingshverts->totalmemory + 
+                      encseglist->totalmemory);
+
+  // 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_facfaces;
+  delete tg_topshells;
+  delete tg_botshells;
+  delete tg_missingshs;
+  delete tg_missingshbds;
+  delete tg_missingshverts;
+  delete encseglist;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// constraineddelaunay()    Create a constrained Delaunay tetrahedralization.//
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::constraineddelaunay(clock_t& tv)
+{
+  face searchsh, *parysh;
+  face searchseg, *paryseg;
+  int s, i;
+
+  // Statistics.
+  long bakfillregioncount;
+  long bakcavitycount, bakcavityexpcount;
+  long bakseg_ref_count;
+
+  if (!b->quiet) {
+    printf("Constrained Delaunay...\n");
+  }
+
+  makesegmentendpointsmap();
+
+  if (b->verbose) {
+    printf("  Delaunizing segments.\n");
+  }
+
+  checksubsegflag = 1;
+
+  // Put all segments into the list (in random order).
+  subsegs->traversalinit();
+  for (i = 0; i < subsegs->items; i++) {
+    s = randomnation(i + 1);
+    // Move the s-th seg to the i-th.
+    subsegstack->newindex((void **) &paryseg);
+    *paryseg = * (face *) fastlookup(subsegstack, s);
+    // Put i-th seg to be the s-th.
+    searchseg.sh = shellfacetraverse(subsegs);
+    //sinfect(searchseg);  // Only save it once.
+    paryseg = (face *) fastlookup(subsegstack, s);
+    *paryseg = searchseg;
+  }
+
+  // Recover non-Delaunay segments.
+  delaunizesegments();
+
+  if (b->verbose) {
+    printf("  Inserted %ld Steiner points.\n", st_segref_count); 
+  }
+
+  tv = clock();
+
+  if (b->verbose) {
+    printf("  Constraining facets.\n");
+  }
+
+  // Subfaces will be introduced.
+  checksubfaceflag = 1;
+
+  bakfillregioncount = fillregioncount;
+  bakcavitycount = cavitycount;
+  bakcavityexpcount = cavityexpcount;
+  bakseg_ref_count = st_segref_count;
+
+  // Randomly order the subfaces.
+  subfaces->traversalinit();
+  for (i = 0; i < subfaces->items; i++) {
+    s = randomnation(i + 1);
+    // Move the s-th subface to the i-th.
+    subfacstack->newindex((void **) &parysh);
+    *parysh = * (face *) fastlookup(subfacstack, s);
+    // Put i-th subface to be the s-th.
+    searchsh.sh = shellfacetraverse(subfaces);
+    parysh = (face *) fastlookup(subfacstack, s);
+    *parysh = searchsh;
+  }
+
+  // Recover facets.
+  constrainedfacets();
+
+  if (b->verbose) {
+    if (fillregioncount > bakfillregioncount) {
+      printf("  Remeshed %ld regions.\n", fillregioncount-bakfillregioncount);
+    }
+    if (cavitycount > bakcavitycount) {
+      printf("  Remeshed %ld cavities", cavitycount - bakcavitycount);
+      if (cavityexpcount - bakcavityexpcount) {
+        printf(" (%ld enlarged)", cavityexpcount - bakcavityexpcount);
+      }
+      printf(".\n");
+    }
+    if (st_segref_count + st_facref_count - bakseg_ref_count > 0) {
+      printf("  Inserted %ld (%ld, %ld) refine points.\n", 
+             st_segref_count + st_facref_count - bakseg_ref_count,
+             st_segref_count - bakseg_ref_count, st_facref_count);
+    }
+  }
+}
+
+////                                                                       ////
+////                                                                       ////
+//// constrained_cxx //////////////////////////////////////////////////////////
+
+//// steiner_cxx //////////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkflipeligibility()    A call back function for boundary recovery.     //
+//                                                                           //
+// 'fliptype' indicates which elementary flip will be performed: 1 : 2-to-3, //
+// and 2 : 3-to-2, respectively.                                             //
+//                                                                           //
+// 'pa, ..., pe' are the vertices involved in this flip, where [a,b,c] is    //
+// the flip face, and [d,e] is the flip edge. NOTE: 'pc' may be 'dummypoint',//
+// other points must not be 'dummypoint'.                                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb, 
+                                     point pc, point pd, point pe,
+                                     int level, int edgepivot,
+                                     flipconstraints* fc)
+{
+  point tmppts[3];
+  enum interresult dir;
+  int types[2], poss[4];
+  int intflag;
+  int rejflag = 0;
+  int i;
+
+  if (fc->seg[0] != NULL) {
+    // A constraining edge is given (e.g., for edge recovery).
+    if (fliptype == 1) {
+      // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c].
+      tmppts[0] = pa;
+      tmppts[1] = pb;
+      tmppts[2] = pc;
+      for (i = 0; i < 3 && !rejflag; i++) {
+        if (tmppts[i] != dummypoint) {
+          // Test if the face [e,d,#] intersects the edge.
+          intflag = tri_edge_test(pe, pd, tmppts[i], fc->seg[0], fc->seg[1], 
+                                  NULL, 1, types, poss);
+          if (intflag == 2) {
+            // They intersect at a single point.
+            dir = (enum interresult) types[0];
+            if (dir == ACROSSFACE) {
+              // The interior of [e,d,#] intersect the segment.
+              rejflag = 1;
+            } else if (dir == ACROSSEDGE) {
+              if (poss[0] == 0) {
+                // The interior of [e,d] intersect the segment.
+                // Since [e,d] is the newly created edge. Reject this flip.
+                rejflag = 1; 
+              }
+            }
+          } else if (intflag == 4) {
+            // They may intersect at either a point or a line segment.
+            dir = (enum interresult) types[0];
+            if (dir == ACROSSEDGE) {
+              if (poss[0] == 0) {
+                // The interior of [e,d] intersect the segment.
+                // Since [e,d] is the newly created edge. Reject this flip.
+                rejflag = 1;
+              }
+            }
+          }
+        } // if (tmppts[0] != dummypoint)
+      } // i
+    } else if (fliptype == 2) {
+      // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c]
+      if (pc != dummypoint) {
+        // Check if the new face [a,b,c] intersect the edge in its interior.
+        intflag = tri_edge_test(pa, pb, pc, fc->seg[0], fc->seg[1], NULL, 
+                                1, types, poss);
+        if (intflag == 2) {
+          // They intersect at a single point.
+          dir = (enum interresult) types[0];
+          if (dir == ACROSSFACE) {
+            // The interior of [a,b,c] intersect the segment.
+            rejflag = 1; // Do not flip.
+          }
+        } else if (intflag == 4) {
+          // [a,b,c] is coplanar with the edge. 
+          dir = (enum interresult) types[0];
+          if (dir == ACROSSEDGE) {
+            // The boundary of [a,b,c] intersect the segment.            
+            rejflag = 1; // Do not flip.
+          }
+        }
+      } // if (pc != dummypoint)
+    }
+  } // if (fc->seg[0] != NULL)
+
+  if ((fc->fac[0] != NULL) && !rejflag) {
+    // A constraining face is given (e.g., for face recovery).
+    if (fliptype == 1) {
+      // A 2-to-3 flip.
+      // Test if the new edge [e,d] intersects the face.
+      intflag = tri_edge_test(fc->fac[0], fc->fac[1], fc->fac[2], pe, pd, 
+                              NULL, 1, types, poss);
+      if (intflag == 2) {
+        // They intersect at a single point.
+        dir = (enum interresult) types[0];
+        if (dir == ACROSSFACE) {
+          rejflag = 1;
+        } else if (dir == ACROSSEDGE) {
+          rejflag = 1;
+        } 
+      } else if (intflag == 4) {
+        // The edge [e,d] is coplanar with the face.
+        // There may be two intersections.
+        for (i = 0; i < 2 && !rejflag; i++) {
+          dir = (enum interresult) types[i];
+          if (dir == ACROSSFACE) {
+            rejflag = 1;
+          } else if (dir == ACROSSEDGE) {
+            rejflag = 1;
+          }
+        }
+      }
+    } // if (fliptype == 1)
+  } // if (fc->fac[0] != NULL)
+
+  if ((fc->remvert != NULL) && !rejflag) {
+    // The vertex is going to be removed. Do not create a new edge which
+    //   contains this vertex.
+    if (fliptype == 1) {
+      // A 2-to-3 flip.
+      if ((pd == fc->remvert) || (pe == fc->remvert)) {
+        rejflag = 1;
+      }
+    }
+  }
+
+  if (fc->remove_large_angle && !rejflag) {
+    // Remove a large dihedral angle. Do not create a new small angle.
+    REAL cosmaxd = 0, diff;
+    if (fliptype == 1) {
+      // We assume that neither 'a' nor 'b' is dummypoint.
+      assert((pa != dummypoint) && (pb != dummypoint)); // SELF_CHECK
+      // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c].
+      // The new tet [e,d,a,b] will be flipped later. Only two new tets:
+      //   [e,d,b,c] and [e,d,c,a] need to be checked.
+      if ((pc != dummypoint) && (pe != dummypoint) && (pd != dummypoint)) {
+        // Get the largest dihedral angle of [e,d,b,c].
+        tetalldihedral(pe, pd, pb, pc, NULL, &cosmaxd, NULL);
+        diff = cosmaxd - fc->cosdihed_in;
+        if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding.
+        if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
+          rejflag = 1;
+        } else {
+          // Record the largest new angle.
+          if (cosmaxd < fc->cosdihed_out) {
+            fc->cosdihed_out = cosmaxd; 
+          }
+          // Get the largest dihedral angle of [e,d,c,a].
+          tetalldihedral(pe, pd, pc, pa, NULL, &cosmaxd, NULL);
+          diff = cosmaxd - fc->cosdihed_in;
+          if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding.
+          if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
+            rejflag = 1;
+          } else {
+            // Record the largest new angle.
+            if (cosmaxd < fc->cosdihed_out) {
+              fc->cosdihed_out = cosmaxd; 
+            }
+          }
+        }
+      } // if (pc != dummypoint && ...)
+    } else if (fliptype == 2) {
+      // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c]
+      // We assume that neither 'e' nor 'd' is dummypoint.
+      assert((pe != dummypoint) && (pd != dummypoint)); // SELF_CHECK
+      if (level == 0) {
+        // Both new tets [a,b,c,d] and [b,a,c,e] are new tets.
+        if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
+          // Get the largest dihedral angle of [a,b,c,d].
+          tetalldihedral(pa, pb, pc, pd, NULL, &cosmaxd, NULL);
+          diff = cosmaxd - fc->cosdihed_in;
+          if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding
+          if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
+            rejflag = 1;
+          } else {
+            // Record the largest new angle.
+            if (cosmaxd < fc->cosdihed_out) {
+              fc->cosdihed_out = cosmaxd; 
+            }
+            // Get the largest dihedral angle of [b,a,c,e].
+            tetalldihedral(pb, pa, pc, pe, NULL, &cosmaxd, NULL);
+            diff = cosmaxd - fc->cosdihed_in;
+            if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
+            if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
+              rejflag = 1;
+            } else {
+              // Record the largest new angle.
+              if (cosmaxd < fc->cosdihed_out) {
+                fc->cosdihed_out = cosmaxd; 
+              }
+            }
+          }
+        }
+      } else { // level > 0
+        assert(edgepivot != 0);
+        if (edgepivot == 1) {
+          // The new tet [a,b,c,d] will be flipped. Only check [b,a,c,e].
+          if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
+            // Get the largest dihedral angle of [b,a,c,e].
+            tetalldihedral(pb, pa, pc, pe, NULL, &cosmaxd, NULL);
+            diff = cosmaxd - fc->cosdihed_in;
+            if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
+            if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
+              rejflag = 1;
+            } else {
+              // Record the largest new angle.
+              if (cosmaxd < fc->cosdihed_out) {
+                fc->cosdihed_out = cosmaxd; 
+              }
+            }
+          }
+        } else {
+          assert(edgepivot == 2);
+          // The new tet [b,a,c,e] will be flipped. Only check [a,b,c,d].
+          if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
+            // Get the largest dihedral angle of [b,a,c,e].
+            tetalldihedral(pa, pb, pc, pd, NULL, &cosmaxd, NULL);
+            diff = cosmaxd - fc->cosdihed_in;
+            if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
+            if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
+              rejflag = 1;
+            } else {
+              // Record the largest new angle.
+              if (cosmaxd < fc->cosdihed_out) {
+                fc->cosdihed_out = cosmaxd; 
+              }
+            }
+          }
+        } // edgepivot
+      } // level
+    }
+  }
+
+  return rejflag;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// removeedgebyflips()    Remove an edge by flips.                           //
+//                                                                           //
+// 'flipedge' is a non-convex or flat edge [a,b,#,#] to be removed.          //
+//                                                                           //
+// The return value is a positive integer, it indicates whether the edge is  //
+// removed or not.  A value "2" means the edge is removed, otherwise, the    //
+// edge is not removed and the value (must >= 3) is the current number of    //
+// tets in the edge star.                                                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc)
+{
+  triface *abtets, spintet;
+  int t1ver; 
+  int n, nn, i;
+
+
+  if (checksubsegflag) {
+    // Do not flip a segment.
+    if (issubseg(*flipedge)) {
+      if (fc->collectencsegflag) {
+        face checkseg, *paryseg;
+        tsspivot1(*flipedge, checkseg);
+        if (!sinfected(checkseg)) {
+          // Queue this segment in list.
+          sinfect(checkseg);                
+          caveencseglist->newindex((void **) &paryseg);
+          *paryseg = checkseg;
+        }
+      }
+      return 0;
+    }
+  }
+
+  // Count the number of tets at edge [a,b].
+  n = 0;
+  spintet = *flipedge;
+  while (1) {
+    n++;
+    fnextself(spintet);
+    if (spintet.tet == flipedge->tet) break;
+  }
+  assert(n >= 3);
+
+  if ((b->flipstarsize > 0) && (n > b->flipstarsize)) {
+    // The star size exceeds the limit.
+    return 0; // Do not flip it.
+  }
+
+  // Allocate spaces.
+  abtets = new triface[n];
+  // Collect the tets at edge [a,b].
+  spintet = *flipedge;
+  i = 0;
+  while (1) {
+    abtets[i] = spintet;
+    setelemcounter(abtets[i], 1); 
+    i++;
+    fnextself(spintet);
+    if (spintet.tet == flipedge->tet) break;
+  }
+
+
+  // Try to flip the edge (level = 0, edgepivot = 0).
+  nn = flipnm(abtets, n, 0, 0, fc);
+
+
+  if (nn > 2) {
+    // Edge is not flipped. Unmarktest the remaining tets in Star(ab).
+    for (i = 0; i < nn; i++) {
+      setelemcounter(abtets[i], 0);
+    }
+    // Restore the input edge (needed by Lawson's flip).
+    *flipedge = abtets[0];
+  }
+
+  // Release the temporary allocated spaces.
+  // NOTE: fc->unflip must be 0.
+  int bakunflip = fc->unflip;
+  fc->unflip = 0;
+  flipnm_post(abtets, n, nn, 0, fc);
+  fc->unflip = bakunflip;
+
+  delete [] abtets;
+
+  return nn; 
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// removefacebyflips()    Remove a face by flips.                            //
+//                                                                           //
+// Return 1 if the face is removed. Otherwise, return 0.                     //
+//                                                                           //
+// ASSUMPTIONS:                                                              //
+//   - 'flipface' must not be a hull face.                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::removefacebyflips(triface *flipface, flipconstraints* fc)
+{
+  if (checksubfaceflag) {
+    if (issubface(*flipface)) {
+      return 0;
+    }
+  }
+
+  triface fliptets[3], flipedge;
+  point pa, pb, pc, pd, pe;
+  REAL ori;
+  int reducflag = 0;
+
+  fliptets[0] = *flipface;
+  fsym(*flipface, fliptets[1]);
+  pa = org(fliptets[0]);
+  pb = dest(fliptets[0]);
+  pc = apex(fliptets[0]);
+  pd = oppo(fliptets[0]);
+  pe = oppo(fliptets[1]);
+
+  ori = orient3d(pa, pb, pd, pe);
+  if (ori > 0) {
+    ori = orient3d(pb, pc, pd, pe);
+    if (ori > 0) {
+      ori = orient3d(pc, pa, pd, pe);
+      if (ori > 0) {
+        // Found a 2-to-3 flip.
+        reducflag = 1;
+      } else {
+        eprev(*flipface, flipedge); // [c,a]
+      }
+    } else {
+      enext(*flipface, flipedge); // [b,c]
+    }
+  } else {
+    flipedge = *flipface; // [a,b]
+  }
+
+  if (reducflag) {
+    // A 2-to-3 flip is found.
+    flip23(fliptets, 0, fc);
+    return 1;
+  } else {
+    // Try to flip the selected edge of this face.
+    if (removeedgebyflips(&flipedge, fc) == 2) {
+      return 1;
+    }
+  }
+
+  // Face is not removed.
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// recoveredge()    Recover an edge in current tetrahedralization.           //
+//                                                                           //
+// If the edge is recovered, 'searchtet' returns a tet containing the edge.  //
+//                                                                           //
+// This edge may intersect a set of faces and edges in the mesh.  All these  //
+// faces or edges are needed to be removed.                                  //
+//                                                                           //
+// If the parameter 'fullsearch' is set, it tries to flip any face or edge   //
+// that intersects the recovering edge.  Otherwise, only the face or edge    //
+// which is visible by 'startpt' is tried.                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::recoveredgebyflips(point startpt, point endpt, 
+                                   triface* searchtet, int fullsearch)
+{
+  flipconstraints fc;
+  enum interresult dir;
+
+  fc.seg[0] = startpt;
+  fc.seg[1] = endpt;
+  fc.checkflipeligibility = 1;
+
+  // The mainloop of the edge reocvery.
+  while (1) { // Loop I
+
+    // Search the edge from 'startpt'.
+    point2tetorg(startpt, *searchtet);
+    dir = finddirection(searchtet, endpt);
+    if (dir == ACROSSVERT) {
+      if (dest(*searchtet) == endpt) {
+        return 1; // Edge is recovered.
+      } else {
+        terminatetetgen(this, 3); // // It may be a PLC problem. 
+      }
+    }
+
+    // The edge is missing. 
+
+    // Try to flip the first intersecting face/edge.
+    enextesymself(*searchtet); // Go to the opposite face.
+    if (dir == ACROSSFACE) {
+      // A face is intersected with the segment. Try to flip it.
+      if (removefacebyflips(searchtet, &fc)) {
+        continue;
+      }
+    } else if (dir == ACROSSEDGE) {
+      // An edge is intersected with the segment. Try to flip it.
+      if (removeedgebyflips(searchtet, &fc) == 2) {
+        continue;
+      }
+    } else {
+      terminatetetgen(this, 3); // It may be a PLC problem.
+    }
+
+    // The edge is missing.
+
+    if (fullsearch) {
+      // Try to flip one of the faces/edges which intersects the edge.
+      triface neightet, spintet;
+      point pa, pb, pc, pd;
+      badface bakface;
+      enum interresult dir1;
+      int types[2], poss[4], pos = 0;
+      int success = 0;
+      int t1ver; 
+      int i, j;
+
+      // Loop through the sequence of intersecting faces/edges from
+      //   'startpt' to 'endpt'.
+      point2tetorg(startpt, *searchtet);
+      dir = finddirection(searchtet, endpt);
+      //assert(dir != ACROSSVERT);
+
+      // Go to the face/edge intersecting the searching edge.
+      enextesymself(*searchtet); // Go to the opposite face.
+      // This face/edge has been tried in previous step.
+
+      while (1) { // Loop I-I
+
+        // Find the next intersecting face/edge.
+        fsymself(*searchtet);
+        if (dir == ACROSSFACE) {
+          neightet = *searchtet;
+          j = (neightet.ver & 3); // j is the current face number.
+          for (i = j + 1; i < j + 4; i++) {
+            neightet.ver = (i % 4);
+            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 interresult) types[0];
+              pos = poss[0];
+              break;
+            } else {
+              dir = DISJOINT;
+              pos = 0;
+            }
+          } // i
+          // There must be an intersection face/edge.
+          assert(dir != DISJOINT);  // SELF_CHECK
+        } else {
+          assert(dir == ACROSSEDGE);
+          while (1) { // Loop I-I-I
+            // Check the two opposite faces (of the edge) in 'searchtet'.  
+            for (i = 0; i < 2; i++) {
+              if (i == 0) {
+                enextesym(*searchtet, neightet);
+              } else {
+                eprevesym(*searchtet, neightet);
+              }
+              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 interresult) types[0];
+                pos = poss[0];
+                break; // for loop
+              } else {
+                dir = DISJOINT;
+                pos = 0;
+              }
+            } // i
+            if (dir != DISJOINT) {
+              // Find an intersection face/edge.
+              break;  // Loop I-I-I
+            }
+            // No intersection. Rotate to the next tet at the edge.
+            fnextself(*searchtet);
+          } // while (1) // Loop I-I-I
+        }
+
+        // Adjust to the intersecting edge/vertex.
+        for (i = 0; i < pos; i++) {
+          enextself(neightet);
+        }
+
+        if (dir == SHAREVERT) {
+          // Check if we have reached the 'endpt'.
+          pd = org(neightet);
+          if (pd == endpt) {
+            // Failed to recover the edge.
+            break; // Loop I-I
+          } else {
+            // We need to further check this case. It might be a PLC problem
+            //   or a Steiner point that was added at a bad location.
+            assert(0);
+          }
+        }
+
+        // The next to be flipped face/edge.
+        *searchtet = neightet;
+
+        // Bakup this face (tetrahedron).
+        bakface.forg = org(*searchtet);
+        bakface.fdest = dest(*searchtet);
+        bakface.fapex = apex(*searchtet);
+        bakface.foppo = oppo(*searchtet);
+
+        // Try to flip this intersecting face/edge.
+        if (dir == ACROSSFACE) {
+          if (removefacebyflips(searchtet, &fc)) {
+            success = 1;
+            break; // Loop I-I 
+          }
+        } else if (dir == ACROSSEDGE) {
+          if (removeedgebyflips(searchtet, &fc) == 2) {
+            success = 1;
+            break; // Loop I-I
+          }
+        } else {
+          assert(0); // A PLC problem.
+        }
+
+        // The face/edge is not flipped.
+        if ((searchtet->tet == NULL) ||
+            (org(*searchtet) != bakface.forg) ||
+            (dest(*searchtet) != bakface.fdest) ||
+            (apex(*searchtet) != bakface.fapex) ||
+            (oppo(*searchtet) != bakface.foppo)) {
+          // 'searchtet' was flipped. We must restore it.
+          point2tetorg(bakface.forg, *searchtet);
+          dir1 = finddirection(searchtet, bakface.fdest);
+          if (dir1 == ACROSSVERT) {
+            assert(dest(*searchtet) == bakface.fdest);
+            spintet = *searchtet;
+            while (1) {
+              if (apex(spintet) == bakface.fapex) {
+                // Found the face.
+                *searchtet = spintet;
+                break;
+              }
+              fnextself(spintet);
+              if (spintet.tet == searchtet->tet) {
+                searchtet->tet = NULL;
+                break; // Not find.
+              }
+	        } // while (1)
+            if (searchtet->tet != NULL) {
+              if (oppo(*searchtet) != bakface.foppo) {
+                fsymself(*searchtet);
+                if (oppo(*searchtet) != bakface.foppo) {
+                  assert(0); // Check this case.
+                  searchtet->tet = NULL;
+                  break; // Not find.
+                }
+              }
+            }
+          } else {
+            searchtet->tet = NULL; // Not find.
+          }
+          if (searchtet->tet == NULL) {
+            success = 0; // This face/edge has been destroyed.
+            break; // Loop I-I 
+          }
+        }
+      } // while (1) // Loop I-I
+
+      if (success) {
+        // One of intersecting faces/edges is flipped.
+        continue;
+      }
+
+    } // if (fullsearch)
+
+    // The edge is missing.
+    break; // Loop I
+
+  } // while (1) // Loop I
+
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// add_steinerpt_in_schoenhardtpoly()    Insert a Steiner point in a Schoen- //
+//                                       hardt polyhedron.                   //
+//                                                                           //
+// 'abtets' is an array of n tets which all share at the edge [a,b]. Let the //
+// tets are [a,b,p0,p1], [a,b,p1,p2], ..., [a,b,p_(n-2),p_(n-1)].  Moreover, //
+// the edge [p0,p_(n-1)] intersects all of the tets in 'abtets'.  A special  //
+// case is that the edge [p0,p_(n-1)] is coplanar with the edge [a,b].       //
+// Such set of tets arises when we want to recover an edge from 'p0' to 'p_  //
+// (n-1)', and the number of tets at [a,b] can not be reduced by any flip.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::add_steinerpt_in_schoenhardtpoly(triface *abtets, int n,
+                                                 int chkencflag)
+{
+  triface worktet, *parytet;
+  triface faketet1, faketet2;
+  point pc, pd, steinerpt;
+  insertvertexflags ivf;
+  optparameters opm;
+  REAL vcd[3], sampt[3], smtpt[3];
+  REAL maxminvol = 0.0, minvol = 0.0, ori;
+  int success, maxidx = 0;
+  int it, i;
+
+
+  pc = apex(abtets[0]);   // pc = p0
+  pd = oppo(abtets[n-1]); // pd = p_(n-1)
+
+
+  // Find an optimial point in edge [c,d]. It is visible by all outer faces
+  //   of 'abtets', and it maxmizes the min volume.
+
+  // initialize the list of 2n boundary faces.
+  for (i = 0; i < n; i++) {    
+    edestoppo(abtets[i], worktet); // [p_i,p_i+1,a]
+    cavetetlist->newindex((void **) &parytet);
+    *parytet = worktet;
+    eorgoppo(abtets[i], worktet);  // [p_i+1,p_i,b]
+    cavetetlist->newindex((void **) &parytet);
+    *parytet = worktet;
+  }
+
+  int N = 100;
+  REAL stepi = 0.01;
+
+  // Search the point along the edge [c,d].
+  for (i = 0; i < 3; i++) vcd[i] = pd[i] - pc[i];
+
+  // Sample N points in edge [c,d].
+  for (it = 1; it < N; it++) {
+    for (i = 0; i < 3; i++) {
+      sampt[i] = pc[i] + (stepi * (double) it) * vcd[i];
+    }
+    for (i = 0; i < cavetetlist->objects; i++) {
+      parytet = (triface *) fastlookup(cavetetlist, i);
+      ori = orient3d(dest(*parytet), org(*parytet), apex(*parytet), sampt);
+      if (i == 0) {
+        minvol = ori;
+      } else {
+        if (minvol > ori) minvol = ori;
+      }
+    } // i
+    if (it == 1) {
+      maxminvol = minvol;
+      maxidx = it;
+    } else {
+      if (maxminvol < minvol) {
+        maxminvol = minvol;
+        maxidx = it;
+      } 
+    }
+  } // it
+
+  if (maxminvol <= 0) {
+    cavetetlist->restart();
+    return 0;
+  }
+
+  for (i = 0; i < 3; i++) {
+    smtpt[i] = pc[i] + (stepi * (double) maxidx) * vcd[i];
+  }
+
+  // Create two faked tets to hold the two non-existing boundary faces:
+  //   [d,c,a] and [c,d,b].
+  maketetrahedron(&faketet1);
+  setvertices(faketet1, pd, pc, org(abtets[0]), dummypoint);
+  cavetetlist->newindex((void **) &parytet);
+  *parytet = faketet1;
+  maketetrahedron(&faketet2);
+  setvertices(faketet2, pc, pd, dest(abtets[0]), dummypoint);
+  cavetetlist->newindex((void **) &parytet);
+  *parytet = faketet2;
+
+  // Point smooth options.
+  opm.max_min_volume = 1;
+  opm.numofsearchdirs = 20;
+  opm.searchstep = 0.001;  
+  opm.maxiter = 100; // Limit the maximum iterations.
+  opm.initval = 0.0; // Initial volume is zero.
+
+  // Try to relocate the point into the inside of the polyhedron.
+  success = smoothpoint(smtpt, cavetetlist, 1, &opm);
+
+  if (success) {
+    while (opm.smthiter == 100) {
+      // It was relocated and the prescribed maximum iteration reached. 
+      // Try to increase the search stepsize.
+      opm.searchstep *= 10.0;
+      //opm.maxiter = 100; // Limit the maximum iterations.
+      opm.initval = opm.imprval;
+      opm.smthiter = 0; // Init.
+      smoothpoint(smtpt, cavetetlist, 1, &opm);  
+    }
+  } // if (success)
+
+  // Delete the two faked tets.
+  tetrahedrondealloc(faketet1.tet);
+  tetrahedrondealloc(faketet2.tet);
+
+  cavetetlist->restart();
+
+  if (!success) {
+    return 0;
+  }
+
+
+  // Insert the Steiner point.
+  makepoint(&steinerpt, FREEVOLVERTEX);
+  for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i];
+
+  // Insert the created Steiner point.
+  for (i = 0; i < n; i++) {
+    infect(abtets[i]);
+    caveoldtetlist->newindex((void **) &parytet);
+    *parytet = abtets[i];
+  }
+  worktet = abtets[0]; // No need point location.
+  ivf.iloc = (int) INSTAR;
+  ivf.chkencflag = chkencflag;
+  ivf.assignmeshsize = b->metric; 
+  if (ivf.assignmeshsize) {
+    // Search the tet containing 'steinerpt' for size interpolation.
+    locate(steinerpt, &(abtets[0]));
+    worktet = abtets[0];
+  }
+
+  // Insert the new point into the tetrahedralization T.
+  // Note that T is convex (nonconvex = 0).
+  if (insertpoint(steinerpt, &worktet, NULL, NULL, &ivf)) {
+    // The vertex has been inserted.
+    st_volref_count++; 
+    if (steinerleft > 0) steinerleft--;
+    return 1;
+  } else {
+    // Not inserted. 
+    pointdealloc(steinerpt);
+    return 0;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// add_steinerpt_in_segment()    Add a Steiner point inside a segment.       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::add_steinerpt_in_segment(face* misseg, int searchlevel)
+{
+  triface searchtet;
+  face *paryseg, candseg;
+  point startpt, endpt, pc, pd;
+  flipconstraints fc;
+  enum interresult dir;
+  REAL P[3], Q[3], tp, tq;
+  REAL len, smlen = 0, split = 0, split_q = 0;
+  int success;
+  int i;
+
+  startpt = sorg(*misseg);
+  endpt = sdest(*misseg);
+
+  fc.seg[0] = startpt;
+  fc.seg[1] = endpt;
+  fc.checkflipeligibility = 1;
+  fc.collectencsegflag = 1;
+
+  point2tetorg(startpt, searchtet);
+  dir = finddirection(&searchtet, endpt);
+  //assert(dir != ACROSSVERT);
+
+  // Try to flip the first intersecting face/edge.
+  enextesymself(searchtet); // Go to the opposite face.
+
+  int bak_fliplinklevel = b->fliplinklevel;
+  b->fliplinklevel = searchlevel;
+
+  if (dir == ACROSSFACE) {
+    // A face is intersected with the segment. Try to flip it.
+    success = removefacebyflips(&searchtet, &fc);
+    assert(success == 0);
+  } else if (dir == ACROSSEDGE) {
+    // An edge is intersected with the segment. Try to flip it.
+    success = removeedgebyflips(&searchtet, &fc);
+    assert(success != 2);
+  } else {
+    terminatetetgen(this, 3); // It may be a PLC problem.
+  }
+
+  split = 0;
+  for (i = 0; i < caveencseglist->objects; i++) {
+    paryseg = (face *) fastlookup(caveencseglist, i);
+    suninfect(*paryseg);
+    // Calculate the shortest edge between the two lines.
+    pc = sorg(*paryseg);
+    pd = sdest(*paryseg);
+    tp = tq = 0;
+    if (linelineint(startpt, endpt, pc, pd, P, Q, &tp, &tq)) {
+      // Does the shortest edge lie between the two segments? 
+      // Round tp and tq.
+      if ((tp > 0) && (tq < 1)) {
+        if (tp < 0.5) {
+          if (tp < (b->epsilon * 1e+3)) tp = 0.0;
+        } else {
+          if ((1.0 - tp) < (b->epsilon * 1e+3)) tp = 1.0;
+        }
+      }
+      if ((tp <= 0) || (tp >= 1)) continue; 
+      if ((tq > 0) && (tq < 1)) {
+        if (tq < 0.5) {
+          if (tq < (b->epsilon * 1e+3)) tq = 0.0;
+        } else {
+          if ((1.0 - tq) < (b->epsilon * 1e+3)) tq = 1.0;
+        }
+      }
+      if ((tq <= 0) || (tq >= 1)) continue;
+      // It is a valid shortest edge. Calculate its length.
+      len = distance(P, Q);
+      if (split == 0) {
+        smlen = len;
+        split = tp;
+        split_q = tq;
+        candseg = *paryseg;
+      } else {
+        if (len < smlen) {
+          smlen = len;
+          split = tp;
+          split_q = tq;
+          candseg = *paryseg;
+        }
+      }
+    }
+  }
+
+  caveencseglist->restart();
+  b->fliplinklevel = bak_fliplinklevel;
+
+  if (split == 0) {
+    // Found no crossing segment. 
+    return 0;
+  }
+
+  face splitsh;
+  face splitseg;
+  point steinerpt, *parypt;
+  insertvertexflags ivf;
+
+  if (b->addsteiner_algo == 1) {
+    // Split the segment at the closest point to a near segment.
+    makepoint(&steinerpt, FREESEGVERTEX);
+    for (i = 0; i < 3; i++) {
+      steinerpt[i] = startpt[i] + split * (endpt[i] - startpt[i]);
+    }
+  } else { // b->addsteiner_algo == 2
+    for (i = 0; i < 3; i++) {
+      P[i] = startpt[i] + split * (endpt[i] - startpt[i]);
+    }
+    pc = sorg(candseg);
+    pd = sdest(candseg);
+    for (i = 0; i < 3; i++) {
+      Q[i] = pc[i] + split_q * (pd[i] - pc[i]);
+    }
+    makepoint(&steinerpt, FREEVOLVERTEX);
+    for (i = 0; i < 3; i++) {
+      steinerpt[i] = 0.5 * (P[i] + Q[i]);
+    }
+  }
+
+  // We need to locate the point. Start searching from 'searchtet'.
+  if (split < 0.5) {
+    point2tetorg(startpt, searchtet);
+  } else {
+    point2tetorg(endpt, searchtet);
+  }
+  if (b->addsteiner_algo == 1) {
+    splitseg = *misseg;
+    spivot(*misseg, splitsh);
+  } else {
+    splitsh.sh = NULL;
+    splitseg.sh = NULL;
+  }
+  ivf.iloc = (int) OUTSIDE;
+  ivf.bowywat = 1;
+  ivf.lawson = 0;
+  ivf.rejflag = 0;
+  ivf.chkencflag = 0;
+  ivf.sloc = (int) ONEDGE;
+  ivf.sbowywat = 1;
+  ivf.splitbdflag = 0;
+  ivf.validflag = 1;
+  ivf.respectbdflag = 1;
+  ivf.assignmeshsize = b->metric; 
+
+  if (!insertpoint(steinerpt, &searchtet, &splitsh, &splitseg, &ivf)) {
+    pointdealloc(steinerpt);
+    return 0;
+  }
+
+  if (b->addsteiner_algo == 1) {
+    // Save this Steiner point (for removal).
+    //   Re-use the array 'subvertstack'.
+    subvertstack->newindex((void **) &parypt);
+    *parypt = steinerpt;
+    st_segref_count++;
+  } else { // b->addsteiner_algo == 2
+    // Queue the segment for recovery.
+    subsegstack->newindex((void **) &paryseg);
+    *paryseg = *misseg; 
+    st_volref_count++;
+  }
+  if (steinerleft > 0) steinerleft--;
+
+  return 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// addsteiner4recoversegment()    Add a Steiner point for recovering a seg.  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
+{
+  triface *abtets, searchtet, spintet;
+  face splitsh;
+  face *paryseg;
+  point startpt, endpt;
+  point pa, pb, pd, steinerpt, *parypt;
+  enum interresult dir;
+  insertvertexflags ivf;
+  int types[2], poss[4];
+  int n, endi, success;
+  int t1ver;
+  int i;
+
+  startpt = sorg(*misseg);
+  if (pointtype(startpt) == FREESEGVERTEX) {
+    sesymself(*misseg);
+    startpt = sorg(*misseg);
+  }
+  endpt = sdest(*misseg);
+
+  // Try to recover the edge by adding Steiner points.
+  point2tetorg(startpt, searchtet);
+  dir = finddirection(&searchtet, endpt);
+  enextself(searchtet); 
+  //assert(apex(searchtet) == startpt);
+
+  if (dir == ACROSSFACE) {
+    // The segment is crossing at least 3 faces. Find the common edge of 
+    //   the first 3 crossing faces.
+    esymself(searchtet);
+    fsym(searchtet, spintet);
+    pd = oppo(spintet);
+    for (i = 0; i < 3; i++) {
+      pa = org(spintet);
+      pb = dest(spintet);
+      //pc = apex(neightet);
+      if (tri_edge_test(pa, pb, pd, startpt, endpt, NULL, 1, types, poss)) {
+        break; // Found the edge.
+      }
+      enextself(spintet);
+      eprevself(searchtet);
+    }
+    assert(i < 3);
+    esymself(searchtet);        
+  } else {
+    assert(dir == ACROSSEDGE);
+    // PLC check.
+    if (issubseg(searchtet)) {
+      face checkseg;
+      tsspivot1(searchtet, checkseg);
+      printf("Found two segments intersect each other.\n");
+      pa = farsorg(*misseg);
+      pb = farsdest(*misseg);
+      printf("  1st: [%d,%d] %d.\n", pointmark(pa), pointmark(pb), 
+             shellmark(*misseg));
+      pa = farsorg(checkseg);
+      pb = farsdest(checkseg);
+      printf("  2nd: [%d,%d] %d.\n", pointmark(pa), pointmark(pb), 
+             shellmark(checkseg));
+      terminatetetgen(this, 3);
+    }
+  }
+  assert(apex(searchtet) == startpt);
+
+  spintet = searchtet;
+  n = 0; endi = -1;
+  while (1) {
+    // Check if the endpt appears in the star.
+    if (apex(spintet) == endpt) {
+      endi = n; // Remember the position of endpt.
+    }
+    n++; // Count a tet in the star.
+    fnextself(spintet);
+    if (spintet.tet == searchtet.tet) break;
+  }
+  assert(n >= 3);
+
+  if (endi > 0) {
+    // endpt is also in the edge star
+    // Get all tets in the edge star.
+    abtets = new triface[n];
+    spintet = searchtet;
+    for (i = 0; i < n; i++) {
+      abtets[i] = spintet;
+      fnextself(spintet);
+    }
+
+    success = 0;
+
+    if (dir == ACROSSFACE) {
+      // Find a Steiner points inside the polyhedron.
+      if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) {
+        success = 1;
+      }
+    } else if (dir == ACROSSEDGE) {
+      if (n > 4) {
+        // In this case, 'abtets' is separated by the plane (containing the
+        //   two intersecting edges) into two parts, P1 and P2, where P1
+        //   consists of 'endi' tets: abtets[0], abtets[1], ..., 
+        //   abtets[endi-1], and P2 consists of 'n - endi' tets: 
+        //   abtets[endi], abtets[endi+1], abtets[n-1].
+        if (endi > 2) { // P1
+          // There are at least 3 tets in the first part.
+          if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) {
+            success++;
+          }
+        }
+        if ((n - endi) > 2) { // P2
+          // There are at least 3 tets in the first part.
+          if (add_steinerpt_in_schoenhardtpoly(&(abtets[endi]), n - endi, 0)) {
+            success++;
+          }
+        }
+      } else {
+        // In this case, a 4-to-4 flip should be re-cover the edge [c,d].
+        //   However, there will be invalid tets (either zero or negtive 
+        //   volume). Otherwise, [c,d] should already be recovered by the 
+        //   recoveredge() function.
+        terminatetetgen(this, 2); // Report a bug.
+      }
+    } else {
+      terminatetetgen(this, 10); // A PLC problem.
+    }
+
+    delete [] abtets;
+
+    if (success) {
+      // Add the missing segment back to the recovering list.
+      subsegstack->newindex((void **) &paryseg);
+      *paryseg = *misseg;
+      return 1;
+    }
+  } // if (endi > 0)
+
+  if (!splitsegflag) {
+    return 0;
+  }
+
+  if (b->verbose > 2) {
+    printf("      Splitting segment (%d, %d)\n", pointmark(startpt), 
+           pointmark(endpt));
+  }
+  steinerpt = NULL;
+
+  if (b->addsteiner_algo > 0) { // -Y/1 or -Y/2
+    if (add_steinerpt_in_segment(misseg, 3)) {
+      return 1;
+    }
+    sesymself(*misseg);
+    if (add_steinerpt_in_segment(misseg, 3)) {
+      return 1;
+    }
+    sesymself(*misseg);
+  }
+
+
+
+
+  if (steinerpt == NULL) {
+    // Split the segment at its midpoint.
+    makepoint(&steinerpt, FREESEGVERTEX);
+    for (i = 0; i < 3; i++) {
+      steinerpt[i] = 0.5 * (startpt[i] + endpt[i]);
+    }
+
+    // We need to locate the point.
+    assert(searchtet.tet != NULL); // Start searching from 'searchtet'.
+    spivot(*misseg, splitsh);
+    ivf.iloc = (int) OUTSIDE;
+    ivf.bowywat = 1;
+    ivf.lawson = 0;
+    ivf.rejflag = 0;
+    ivf.chkencflag = 0;
+    ivf.sloc = (int) ONEDGE;
+    ivf.sbowywat = 1;
+    ivf.splitbdflag = 0;
+    ivf.validflag = 1;
+    ivf.respectbdflag = 1;
+    ivf.assignmeshsize = b->metric; 
+    if (!insertpoint(steinerpt, &searchtet, &splitsh, misseg, &ivf)) {
+      assert(0);
+    }
+  } // if (endi > 0)
+
+  // Save this Steiner point (for removal).
+  //   Re-use the array 'subvertstack'.
+  subvertstack->newindex((void **) &parypt);
+  *parypt = steinerpt;
+
+  st_segref_count++;
+  if (steinerleft > 0) steinerleft--;
+
+  return 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// recoversegments()    Recover all segments.                                //
+//                                                                           //
+// All segments need to be recovered are in 'subsegstack'.                   //
+//                                                                           //
+// This routine first tries to recover each segment by only using flips. If  //
+// no flip is possible, and the flag 'steinerflag' is set, it then tries to  //
+// insert Steiner points near or in the segment.                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::recoversegments(arraypool *misseglist, int fullsearch,
+                                int steinerflag)
+{
+  triface searchtet, spintet;
+  face sseg, *paryseg;
+  point startpt, endpt;
+  int success;
+  int t1ver;
+  long bak_inpoly_count = st_volref_count; 
+  long bak_segref_count = st_segref_count;
+
+  if (b->verbose > 1) {
+    printf("    Recover segments [%s level = %2d] #:  %ld.\n",
+           (b->fliplinklevel > 0) ? "fixed" : "auto",
+           (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
+           subsegstack->objects);
+  }
+
+  // Loop until 'subsegstack' is empty.
+  while (subsegstack->objects > 0l) {
+    // seglist is used as a stack.
+    subsegstack->objects--;
+    paryseg = (face *) fastlookup(subsegstack, subsegstack->objects);
+    sseg = *paryseg;
+
+    // Check if this segment has been recovered.
+    sstpivot1(sseg, searchtet);
+    if (searchtet.tet != NULL) {
+      continue; // Not a missing segment.
+    }
+
+    startpt = sorg(sseg);
+    endpt = sdest(sseg);
+
+    if (b->verbose > 2) {
+      printf("      Recover segment (%d, %d).\n", pointmark(startpt), 
+             pointmark(endpt));
+    }
+
+    success = 0;
+
+    if (recoveredgebyflips(startpt, endpt, &searchtet, 0)) {
+      success = 1;
+    } else {
+      // Try to recover it from the other direction.
+      if (recoveredgebyflips(endpt, startpt, &searchtet, 0)) {
+        success = 1;
+      }
+    }
+
+    if (!success && fullsearch) {
+      if (recoveredgebyflips(startpt, endpt, &searchtet, fullsearch)) {
+        success = 1;
+      }
+    }
+
+    if (success) {
+      // Segment is recovered. Insert it.
+      // Let the segment remember an adjacent tet.
+      sstbond1(sseg, searchtet);
+      // Bond the segment to all tets containing it.
+      spintet = searchtet;
+      do {
+        tssbond1(spintet, sseg);
+        fnextself(spintet);
+      } while (spintet.tet != searchtet.tet);
+    } else {
+      if (steinerflag > 0) {
+        // Try to recover the segment but do not split it.
+        if (addsteiner4recoversegment(&sseg, 0)) {
+          success = 1;
+        }
+        if (!success && (steinerflag > 1)) {
+          // Split the segment.
+          addsteiner4recoversegment(&sseg, 1);
+          success = 1;
+        }
+      }
+      if (!success) {
+        if (misseglist != NULL) {
+          // Save this segment.
+          misseglist->newindex((void **) &paryseg);
+          *paryseg = sseg;
+        }
+      }
+    }
+
+  } // while (subsegstack->objects > 0l)
+
+  if (steinerflag) {
+    if (b->verbose > 1) {
+      // Report the number of added Steiner points.
+      if (st_volref_count > bak_inpoly_count) {
+        printf("    Add %ld Steiner points in volume.\n", 
+               st_volref_count - bak_inpoly_count);
+      }
+      if (st_segref_count > bak_segref_count) {
+        printf("    Add %ld Steiner points in segments.\n", 
+               st_segref_count - bak_segref_count);
+      }
+    }
+  }
+
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// recoverfacebyflips()    Recover a face by flips.                          //
+//                                                                           //
+// If 'searchsh' is not NULL, it is a subface to be recovered.  It is only   //
+// used for checking self-intersections.                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::recoverfacebyflips(point pa, point pb, point pc, 
+                                   face *searchsh, triface* searchtet)
+{
+  triface spintet, flipedge;
+  point pd, pe;
+  enum interresult dir;
+  flipconstraints fc;
+  int types[2], poss[4], intflag;
+  int success, success1;
+  int t1ver; 
+  int i, j;
+
+
+  fc.fac[0] = pa;
+  fc.fac[1] = pb;
+  fc.fac[2] = pc;
+  fc.checkflipeligibility = 1;
+  success = 0;
+
+  for (i = 0; i < 3 && !success; i++) {
+    while (1) {
+      // Get a tet containing the edge [a,b].
+      point2tetorg(fc.fac[i], *searchtet);
+      dir = finddirection(searchtet, fc.fac[(i+1)%3]);
+      //assert(dir == ACROSSVERT);
+      assert(dest(*searchtet) == fc.fac[(i+1)%3]);
+      // Search the face [a,b,c]
+      spintet = *searchtet;
+      while (1) {
+        if (apex(spintet) == fc.fac[(i+2)%3]) {
+          // Found the face.
+          *searchtet = spintet;
+          // Return the face [a,b,c].
+          for (j = i; j > 0; j--) {
+            eprevself(*searchtet);
+          }
+          success = 1;
+          break;
+        }
+        fnextself(spintet);
+        if (spintet.tet == searchtet->tet) break;
+      } // while (1)
+      if (success) break;
+      // The face is missing. Try to recover it.
+      success1 = 0;
+      // Find a crossing edge of this face.
+      spintet = *searchtet;
+      while (1) {
+        pd = apex(spintet);
+        pe = oppo(spintet);
+        if ((pd != dummypoint) && (pe != dummypoint)) {
+          // Check if [d,e] intersects [a,b,c]
+          intflag = tri_edge_test(pa, pb, pc, pd, pe, NULL, 1, types, poss);
+          if (intflag > 0) {
+            // By our assumptions, they can only intersect at a single point.
+            if (intflag == 2) {
+              // Check the intersection type.
+              dir = (enum interresult) types[0];
+              if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
+                // Go to the edge [d,e].
+                edestoppo(spintet, flipedge); // [d,e,a,b]
+                if (searchsh != NULL) {
+                  // Check if [e,d] is a segment.
+                  if (issubseg(flipedge)) {
+                    if (!b->quiet) {
+                      face checkseg;
+                      tsspivot1(flipedge, checkseg);
+                      printf("Found a segment and a subface intersect.\n");
+                      pd = farsorg(checkseg);
+                      pe = farsdest(checkseg);
+                      printf("  1st: [%d, %d] %d.\n",  pointmark(pd), 
+                             pointmark(pe), shellmark(checkseg)); 
+                      printf("  2nd: [%d,%d,%d] %d\n", pointmark(pa), 
+                        pointmark(pb), pointmark(pc), shellmark(*searchsh));
+	                }
+                    terminatetetgen(this, 3);
+		          }
+                }
+                // Try to flip the edge [d,e].
+                success1 = (removeedgebyflips(&flipedge, &fc) == 2);
+              } else {
+                if (dir == TOUCHFACE) {
+                  point touchpt, *parypt;
+                  if (poss[1] == 0) {
+                    touchpt = pd; // pd is a coplanar vertex.
+                  } else {
+                    touchpt = pe; // pe is a coplanar vertex.
+                  }
+                  if (pointtype(touchpt) == FREEVOLVERTEX) {
+                    // A volume Steiner point was added in this subface.
+                    // Split this subface by this point.
+                    face checksh, *parysh;
+                    int siloc = (int) ONFACE;
+                    int sbowat = 0; // Only split this subface.
+                    setpointtype(touchpt, FREEFACETVERTEX);
+                    sinsertvertex(touchpt, searchsh, NULL, siloc, sbowat, 0);
+                    st_volref_count--;
+                    st_facref_count++;
+                    // Queue this vertex for removal.
+                    subvertstack->newindex((void **) &parypt);
+                    *parypt = touchpt;
+                    // Queue new subfaces for recovery.
+                    // Put all new subfaces into stack for recovery.
+                    for (i = 0; i < caveshbdlist->objects; i++) {
+                      // Get an old subface at edge [a, b].
+                      parysh = (face *) fastlookup(caveshbdlist, i);
+                      spivot(*parysh, checksh); // The new subface [a, b, p].
+                      // Do not recover a deleted new face (degenerated).
+                      if (checksh.sh[3] != NULL) {
+                        subfacstack->newindex((void **) &parysh);
+                        *parysh = checksh;
+                      }
+                    }
+                    // Delete the old subfaces in sC(p).
+                    assert(caveshlist->objects == 1);
+                    for (i = 0; i < caveshlist->objects; i++) {
+                      parysh = (face *) fastlookup(caveshlist, i);
+                      shellfacedealloc(subfaces, parysh->sh);
+                    }
+                    // Clear working lists.
+                    caveshlist->restart();
+                    caveshbdlist->restart();
+                    cavesegshlist->restart();
+                    // We can return this function.
+                    searchsh->sh = NULL; // It has been split.
+                    success1 = 0;
+                    success = 1; 
+                  } else {
+                    // It should be a PLC problem.
+                    if (pointtype(touchpt) == FREESEGVERTEX) {
+                      // A segment and a subface intersect. 
+                    } else if (pointtype(touchpt) == FREEFACETVERTEX) {
+                      // Two facets self-intersect.
+                    }
+                    terminatetetgen(this, 3);
+                  }
+                } else {
+                  assert(0); // Unknown cases. Debug.
+                }
+              }
+              break;
+            } else { // intflag == 4. Coplanar case.
+              // This may be an input PLC error.
+              assert(0);
+            }
+          } // if (intflag > 0)
+        }
+        fnextself(spintet);
+        assert(spintet.tet != searchtet->tet);
+      } // while (1)
+      if (!success1) break;
+    } // while (1)
+  } // i
+
+  return success;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// recoversubfaces()    Recover all subfaces.                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
+{
+  triface searchtet, neightet, spintet;
+  face searchsh, neighsh, neineish, *parysh;
+  face bdsegs[3];
+  point startpt, endpt, apexpt, *parypt;
+  point steinerpt;
+  enum interresult dir;
+  insertvertexflags ivf;
+  int success;
+  int t1ver;
+  int i, j;
+
+  if (b->verbose > 1) {
+    printf("    Recover subfaces [%s level = %2d] #:  %ld.\n",
+           (b->fliplinklevel > 0) ? "fixed" : "auto",
+           (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
+           subfacstack->objects);
+  }
+
+  // Loop until 'subfacstack' is empty.
+  while (subfacstack->objects > 0l) {
+
+    subfacstack->objects--;
+    parysh = (face *) fastlookup(subfacstack, subfacstack->objects);
+    searchsh = *parysh;
+
+    if (searchsh.sh[3] == NULL) continue; // Skip a dead subface.
+
+    stpivot(searchsh, neightet);
+    if (neightet.tet != NULL) continue; // Skip a recovered subface.
+
+
+    if (b->verbose > 2) {
+      printf("      Recover subface (%d, %d, %d).\n",pointmark(sorg(searchsh)),
+             pointmark(sdest(searchsh)), pointmark(sapex(searchsh)));
+    }
+
+    // The three edges of the face need to be existed first.
+    for (i = 0; i < 3; i++) {
+      sspivot(searchsh, bdsegs[i]);   
+      if (bdsegs[i].sh != NULL) {
+        // The segment must exist.
+        sstpivot1(bdsegs[i], searchtet);
+        if (searchtet.tet == NULL) {
+          assert(0);
+        }
+      } else {
+        // This edge is not a segment (due to a Steiner point).
+        // Check whether it exists or not.
+        success = 0;
+        startpt = sorg(searchsh);
+        endpt = sdest(searchsh);
+        point2tetorg(startpt, searchtet);
+        dir = finddirection(&searchtet, endpt);
+        if (dir == ACROSSVERT) {
+          if (dest(searchtet) == endpt) {
+            success = 1;  
+          } else {
+            //assert(0); // A PLC problem.
+            terminatetetgen(this, 3);
+          }
+        } else {
+          // The edge is missing. Try to recover it.
+          if (recoveredgebyflips(startpt, endpt, &searchtet, 0)) {
+            success = 1;
+          } else {
+            if (recoveredgebyflips(endpt, startpt, &searchtet, 0)) {
+              success = 1;
+            }
+          }
+        }
+        if (success) {
+          // Insert a temporary segment to protect this edge.
+          makeshellface(subsegs, &(bdsegs[i]));
+          setshvertices(bdsegs[i], startpt, endpt, NULL);
+          smarktest2(bdsegs[i]); // It's a temporary segment.
+          // Insert this segment into surface mesh.
+          ssbond(searchsh, bdsegs[i]);
+          spivot(searchsh, neighsh);
+          if (neighsh.sh != NULL) {
+            ssbond(neighsh, bdsegs[i]);
+          }
+          // Insert this segment into tetrahedralization.
+          sstbond1(bdsegs[i], searchtet);
+          // Bond the segment to all tets containing it.
+          spintet = searchtet;
+          do {
+            tssbond1(spintet, bdsegs[i]);
+            fnextself(spintet);
+          } while (spintet.tet != searchtet.tet);
+        } else {
+          // An edge of this subface is missing. Can't recover this subface.
+          // Delete any temporary segment that has been created.
+          for (j = (i - 1); j >= 0; j--) {
+            if (smarktest2ed(bdsegs[j])) { 
+              spivot(bdsegs[j], neineish);
+              assert(neineish.sh != NULL);
+              //if (neineish.sh != NULL) {
+                ssdissolve(neineish);
+                spivot(neineish, neighsh);
+                if (neighsh.sh != NULL) {
+                  ssdissolve(neighsh);
+                  // There should be only two subfaces at this segment.
+                  spivotself(neighsh); // SELF_CHECK
+                  assert(neighsh.sh == neineish.sh);
+                }
+	          //}
+              sstpivot1(bdsegs[j], searchtet);
+              assert(searchtet.tet != NULL);
+              //if (searchtet.tet != NULL) {
+                spintet = searchtet;
+                while (1) {
+                  tssdissolve1(spintet);
+                  fnextself(spintet);
+                  if (spintet.tet == searchtet.tet) break;
+                }
+	          //}
+              shellfacedealloc(subsegs, bdsegs[j].sh);
+            }
+          } // j
+          if (steinerflag) {
+            // Add a Steiner point at the midpoint of this edge.
+            if (b->verbose > 2) {
+              printf("      Add a Steiner point in subedge (%d, %d).\n",
+                     pointmark(startpt), pointmark(endpt));
+            }
+            makepoint(&steinerpt, FREEFACETVERTEX);
+            for (j = 0; j < 3; j++) {
+              steinerpt[j] = 0.5 * (startpt[j] + endpt[j]);
+            }
+
+            point2tetorg(startpt, searchtet); // Start from 'searchtet'.
+            ivf.iloc = (int) OUTSIDE; // Need point location.
+            ivf.bowywat = 1;
+            ivf.lawson = 0;
+            ivf.rejflag = 0;
+            ivf.chkencflag = 0;
+            ivf.sloc = (int) ONEDGE;            
+            ivf.sbowywat = 1; // Allow flips in facet.
+            ivf.splitbdflag = 0;
+            ivf.validflag = 1;
+            ivf.respectbdflag = 1;
+            ivf.assignmeshsize = b->metric;
+            if (!insertpoint(steinerpt, &searchtet, &searchsh, NULL, &ivf)) {
+              assert(0);
+            }
+            // Save this Steiner point (for removal).
+            //   Re-use the array 'subvertstack'.
+            subvertstack->newindex((void **) &parypt);
+            *parypt = steinerpt;
+
+            st_facref_count++;
+            if (steinerleft > 0) steinerleft--;
+          } // if (steinerflag)
+          break;
+        }
+      }
+      senextself(searchsh);
+    } // i
+
+    if (i == 3) {
+      // Recover the subface.
+      startpt = sorg(searchsh);
+      endpt   = sdest(searchsh);
+      apexpt  = sapex(searchsh);
+
+      success = recoverfacebyflips(startpt,endpt,apexpt,&searchsh,&searchtet);
+
+      // Delete any temporary segment that has been created.
+      for (j = 0; j < 3; j++) {
+        if (smarktest2ed(bdsegs[j])) { 
+          spivot(bdsegs[j], neineish);
+          assert(neineish.sh != NULL);
+          //if (neineish.sh != NULL) {
+            ssdissolve(neineish);
+            spivot(neineish, neighsh);
+            if (neighsh.sh != NULL) {
+              ssdissolve(neighsh);
+              // There should be only two subfaces at this segment.
+              spivotself(neighsh); // SELF_CHECK
+              assert(neighsh.sh == neineish.sh);
+            }
+	      //}
+          sstpivot1(bdsegs[j], neightet);
+          assert(neightet.tet != NULL);
+          //if (neightet.tet != NULL) {
+            spintet = neightet;
+            while (1) {
+              tssdissolve1(spintet);
+              fnextself(spintet);
+              if (spintet.tet == neightet.tet) break;
+            }
+	      //}
+          shellfacedealloc(subsegs, bdsegs[j].sh);
+        }
+      } // j
+
+      if (success) {
+        if (searchsh.sh != NULL) {
+          // Face is recovered. Insert it.
+          tsbond(searchtet, searchsh);
+          fsymself(searchtet);
+          sesymself(searchsh);
+          tsbond(searchtet, searchsh);
+        }
+      } else {
+        if (steinerflag) {
+          // Add a Steiner point at the barycenter of this subface.
+          if (b->verbose > 2) {
+            printf("      Add a Steiner point in subface (%d, %d, %d).\n",
+                   pointmark(startpt), pointmark(endpt), pointmark(apexpt));
+          }
+          makepoint(&steinerpt, FREEFACETVERTEX);
+          for (j = 0; j < 3; j++) {
+            steinerpt[j] = (startpt[j] + endpt[j] + apexpt[j]) / 3.0;
+          }
+
+          point2tetorg(startpt, searchtet); // Start from 'searchtet'.
+          ivf.iloc = (int) OUTSIDE; // Need point location.
+          ivf.bowywat = 1;
+          ivf.lawson = 0;
+          ivf.rejflag = 0;
+          ivf.chkencflag = 0;
+          ivf.sloc = (int) ONFACE;          
+          ivf.sbowywat = 1; // Allow flips in facet.
+          ivf.splitbdflag = 0;
+          ivf.validflag = 1;
+          ivf.respectbdflag = 1;
+          ivf.assignmeshsize = b->metric; 
+          if (!insertpoint(steinerpt, &searchtet, &searchsh, NULL, &ivf)) {
+            assert(0);
+          }
+          // Save this Steiner point (for removal).
+          //   Re-use the array 'subvertstack'.
+          subvertstack->newindex((void **) &parypt);
+          *parypt = steinerpt;
+
+          st_facref_count++;
+          if (steinerleft > 0) steinerleft--;
+        } // if (steinerflag)
+      }
+    } else {
+      success = 0;      
+    }
+
+    if (!success) {
+      if (misshlist != NULL) {
+        // Save this subface.
+        misshlist->newindex((void **) &parysh);
+        *parysh = searchsh;
+      }
+    }
+
+  } // while (subfacstack->objects > 0l)
+
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// getvertexstar()    Return the star of a vertex.                           //
+//                                                                           //
+// If the flag 'fullstar' is set, return the complete star of this vertex.   //
+// Otherwise, only a part of the star which is bounded by facets is returned.// 
+//                                                                           //
+// 'tetlist' returns the list of tets in the star of the vertex 'searchpt'.  //
+// Every tet in 'tetlist' is at the face opposing to 'searchpt'.             //
+//                                                                           //
+// 'vertlist' returns the list of vertices in the star (exclude 'searchpt'). //
+//                                                                           //
+// 'shlist' returns the list of subfaces in the star. Each subface must face //
+// to the interior of this star.                                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::getvertexstar(int fullstar, point searchpt, arraypool* tetlist, 
+                              arraypool* vertlist, arraypool* shlist)
+{
+  triface searchtet, neightet, *parytet;
+  face checksh, *parysh;
+  point pt, *parypt;
+  int collectflag;
+  int t1ver;
+  int i, j;
+
+  point2tetorg(searchpt, searchtet);
+
+  // Go to the opposite face (the link face) of the vertex.
+  enextesymself(searchtet);
+  //assert(oppo(searchtet) == searchpt);
+  infect(searchtet); // Collect this tet (link face).
+  tetlist->newindex((void **) &parytet);
+  *parytet = searchtet;
+  if (vertlist != NULL) {
+    // Collect three (link) vertices.
+    j = (searchtet.ver & 3); // The current vertex index.
+    for (i = 1; i < 4; i++) {
+      pt = (point) searchtet.tet[4 + ((j + i) % 4)];
+      pinfect(pt);
+      vertlist->newindex((void **) &parypt);
+      *parypt = pt;
+    }
+  }
+
+  collectflag = 1;
+  esym(searchtet, neightet);
+  if (issubface(neightet)) {
+    if (shlist != NULL) {
+      tspivot(neightet, checksh);
+      if (!sinfected(checksh)) {
+        // Collect this subface (link edge).
+        sinfected(checksh);
+        shlist->newindex((void **) &parysh);
+        *parysh = checksh;
+      }
+    } 
+    if (!fullstar) {
+      collectflag = 0;
+    }
+  }
+  if (collectflag) {
+    fsymself(neightet); // Goto the adj tet of this face.
+    esymself(neightet); // Goto the oppo face of this vertex.
+    // assert(oppo(neightet) == searchpt);
+    infect(neightet); // Collect this tet (link face).
+    tetlist->newindex((void **) &parytet);
+    *parytet = neightet;
+    if (vertlist != NULL) {
+      // Collect its apex.
+      pt = apex(neightet);
+      pinfect(pt);
+      vertlist->newindex((void **) &parypt);
+      *parypt = pt;
+    }
+  } // if (collectflag)
+
+  // Continue to collect all tets in the star.
+  for (i = 0; i < tetlist->objects; i++) {
+    searchtet = * (triface *) fastlookup(tetlist, i);
+    // Note that 'searchtet' is a face opposite to 'searchpt', and the neighbor
+    //   tet at the current edge is already collected.
+    // Check the neighbors at the other two edges of this face.
+    for (j = 0; j < 2; j++) {
+      collectflag = 1;
+      enextself(searchtet);
+      esym(searchtet, neightet);
+      if (issubface(neightet)) {
+        if (shlist != NULL) {
+          tspivot(neightet, checksh);
+          if (!sinfected(checksh)) {
+            // Collect this subface (link edge).
+            sinfected(checksh);
+            shlist->newindex((void **) &parysh);
+            *parysh = checksh;
+          }
+        }
+        if (!fullstar) {
+          collectflag = 0;
+        }
+      }
+      if (collectflag) {
+        fsymself(neightet);
+        if (!infected(neightet)) {
+          esymself(neightet); // Go to the face opposite to 'searchpt'.
+          infect(neightet);
+          tetlist->newindex((void **) &parytet);
+          *parytet = neightet;
+          if (vertlist != NULL) {
+            // Check if a vertex is collected.
+            pt = apex(neightet);
+            if (!pinfected(pt)) {
+              pinfect(pt);
+              vertlist->newindex((void **) &parypt);
+              *parypt = pt;
+            }
+          }
+        } // if (!infected(neightet))
+      } // if (collectflag)
+    } // j
+  } // i
+
+
+  // Uninfect the list of tets and vertices.
+  for (i = 0; i < tetlist->objects; i++) {
+    parytet = (triface *) fastlookup(tetlist, i);
+    uninfect(*parytet);
+  }
+
+  if (vertlist != NULL) {
+    for (i = 0; i < vertlist->objects; i++) {
+      parypt = (point *) fastlookup(vertlist, i);
+      puninfect(*parypt);
+    }
+  }
+
+  if (shlist != NULL) {
+    for (i = 0; i < shlist->objects; i++) {
+      parysh = (face *) fastlookup(shlist, i);
+      suninfect(*parysh);
+    }
+  }
+
+  return (int) tetlist->objects;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// getedge()    Get a tetrahedron having the two endpoints.                  //
+//                                                                           //
+// The method here is to search the second vertex in the link faces of the   //
+// first vertex. The global array 'cavetetlist' is re-used for searching.    //
+//                                                                           //
+// This function is used for the case when the mesh is non-convex. Otherwise,//
+// the function finddirection() should be faster than this.                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::getedge(point e1, point e2, triface *tedge)
+{
+  triface searchtet, neightet, *parytet;
+  point pt;
+  int done;
+  int i, j;
+
+  if (b->verbose > 2) {
+    printf("      Get edge from %d to %d.\n", pointmark(e1), pointmark(e2));
+  }
+
+  // Quickly check if 'tedge' is just this edge.
+  if (!isdeadtet(*tedge)) {
+    if (org(*tedge) == e1) {
+      if (dest(*tedge) == e2) {
+        return 1;
+      }
+    } else if (org(*tedge) == e2) {
+      if (dest(*tedge) == e1) {
+        esymself(*tedge);
+        return 1;
+      }
+    }
+  }
+
+  // Search for the edge [e1, e2].
+  point2tetorg(e1, *tedge);
+  finddirection(tedge, e2);
+  if (dest(*tedge) == e2) {
+    return 1;
+  } else {
+    // Search for the edge [e2, e1].
+    point2tetorg(e2, *tedge);
+    finddirection(tedge, e1);
+    if (dest(*tedge) == e1) {
+      esymself(*tedge);
+      return 1;
+    }
+  }
+
+
+  // Go to the link face of e1.
+  point2tetorg(e1, searchtet);
+  enextesymself(searchtet);
+  //assert(oppo(searchtet) == e1);
+
+  assert(cavebdrylist->objects == 0l); // It will re-use this list.
+  arraypool *tetlist = cavebdrylist;
+
+  // Search e2.
+  for (i = 0; i < 3; i++) {
+    pt = apex(searchtet);
+    if (pt == e2) {
+      // Found. 'searchtet' is [#,#,e2,e1].
+      eorgoppo(searchtet, *tedge); // [e1,e2,#,#].
+      return 1;
+    }
+    enextself(searchtet);
+  }
+
+  // Get the adjacent link face at 'searchtet'.
+  fnext(searchtet, neightet);
+  esymself(neightet);
+  // assert(oppo(neightet) == e1);
+  pt = apex(neightet);
+  if (pt == e2) {
+    // Found. 'neightet' is [#,#,e2,e1].
+    eorgoppo(neightet, *tedge); // [e1,e2,#,#].
+    return 1;
+  }
+
+  // Continue searching in the link face of e1.
+  infect(searchtet);
+  tetlist->newindex((void **) &parytet);
+  *parytet = searchtet;
+  infect(neightet);
+  tetlist->newindex((void **) &parytet);
+  *parytet = neightet;
+
+  done = 0;
+
+  for (i = 0; (i < tetlist->objects) && !done; i++) {
+    parytet = (triface *) fastlookup(tetlist, i);
+    searchtet = *parytet;
+    for (j = 0; (j < 2) && !done; j++) {
+      enextself(searchtet);
+      fnext(searchtet, neightet);
+      if (!infected(neightet)) {        
+        esymself(neightet);
+        pt = apex(neightet);
+        if (pt == e2) {
+          // Found. 'neightet' is [#,#,e2,e1].
+          eorgoppo(neightet, *tedge);
+          done = 1;
+        } else {
+          infect(neightet);
+          tetlist->newindex((void **) &parytet);
+          *parytet = neightet;
+        }
+      }
+    } // j
+  } // i 
+
+  // Uninfect the list of visited tets.
+  for (i = 0; i < tetlist->objects; i++) {
+    parytet = (triface *) fastlookup(tetlist, i);
+    uninfect(*parytet);
+  }
+  tetlist->restart();
+
+  return done;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// reduceedgesatvertex()    Reduce the number of edges at a given vertex.    //
+//                                                                           //
+// 'endptlist' contains the endpoints of edges connecting at the vertex.     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::reduceedgesatvertex(point startpt, arraypool* endptlist)
+{
+  triface searchtet;
+  point *pendpt, *parypt;
+  enum interresult dir;
+  flipconstraints fc;
+  int reduceflag;
+  int count;
+  int n, i, j;
+
+
+  fc.remvert = startpt;
+  fc.checkflipeligibility = 1;
+
+  while (1) {
+
+    count = 0;
+
+    for (i = 0; i < endptlist->objects; i++) {
+      pendpt = (point *) fastlookup(endptlist, i);
+      if (*pendpt == dummypoint) {
+        continue; // Do not reduce a virtual edge.
+      }
+      reduceflag = 0;
+      // Find the edge.
+      if (nonconvex) {
+        if (getedge(startpt, *pendpt, &searchtet)) {
+          dir = ACROSSVERT;
+        } else {
+          // The edge does not exist (was flipped).
+          dir = INTERSECT;
+        }
+      } else {
+        point2tetorg(startpt, searchtet);
+        dir = finddirection(&searchtet, *pendpt);
+      }
+      if (dir == ACROSSVERT) {
+        if (dest(searchtet) == *pendpt) {
+          // Do not flip a segment.
+          if (!issubseg(searchtet)) {
+            n = removeedgebyflips(&searchtet, &fc);
+            if (n == 2) {
+              reduceflag = 1;
+            }
+          }
+        } else {
+          assert(0); // A plc problem.
+        }
+      } else {
+        // The edge has been flipped.
+        reduceflag = 1;
+      }
+      if (reduceflag) {
+        count++;
+        // Move the last vertex into this slot.
+        j = endptlist->objects - 1;
+        parypt = (point *) fastlookup(endptlist, j);
+        *pendpt = *parypt;
+        endptlist->objects--;
+        i--;
+      }
+    } // i
+
+    if (count == 0) {
+      // No edge is reduced.
+      break;
+    }
+
+  } // while (1)
+
+  return (int) endptlist->objects;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// removevertexbyflips()    Remove a vertex by flips.                        //
+//                                                                           //
+// This routine attempts to remove the given vertex 'rempt' (p) from the     //
+// tetrahedralization (T) by a sequence of flips.                            //
+//                                                                           //
+// The algorithm used here is a simple edge reduce method. Suppose there are //
+// n edges connected at p. We try to reduce the number of edges by flipping  //
+// any edge (not a segment) that is connecting at p.                         //
+//                                                                           //
+// Unless T is a Delaunay tetrahedralization, there is no guarantee that 'p' //
+// can be successfully removed.                                              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::removevertexbyflips(point steinerpt)
+{
+  triface *fliptets = NULL, wrktets[4];
+  triface searchtet, spintet, neightet;
+  face parentsh, spinsh, checksh;
+  face leftseg, rightseg, checkseg;
+  point lpt = NULL, rpt = NULL, apexpt; //, *parypt;
+  flipconstraints fc;
+  enum verttype vt;
+  enum locateresult loc;
+  int valence, removeflag;
+  int slawson;
+  int t1ver;
+  int n, i;
+
+  vt = pointtype(steinerpt);
+
+  if (vt == FREESEGVERTEX) {
+    sdecode(point2sh(steinerpt), leftseg);
+    assert(leftseg.sh != NULL);
+    leftseg.shver = 0;
+    if (sdest(leftseg) == steinerpt) {
+      senext(leftseg, rightseg);
+      spivotself(rightseg);
+      assert(rightseg.sh != NULL);
+      rightseg.shver = 0;
+      assert(sorg(rightseg) == steinerpt);
+    } else {
+      assert(sorg(leftseg) == steinerpt);
+      rightseg = leftseg;
+      senext2(rightseg, leftseg);
+      spivotself(leftseg);
+      assert(leftseg.sh != NULL);
+      leftseg.shver = 0;
+      assert(sdest(leftseg) == steinerpt);
+    }
+    lpt = sorg(leftseg);
+    rpt = sdest(rightseg);
+    if (b->verbose > 2) {
+      printf("      Removing Steiner point %d in segment (%d, %d).\n",
+             pointmark(steinerpt), pointmark(lpt), pointmark(rpt));
+
+    }
+  } else if (vt == FREEFACETVERTEX) {
+    if (b->verbose > 2) {
+      printf("      Removing Steiner point %d in facet.\n",
+             pointmark(steinerpt));
+    }
+  } else if (vt == FREEVOLVERTEX) {
+    if (b->verbose > 2) {
+      printf("      Removing Steiner point %d in volume.\n",
+             pointmark(steinerpt));
+    }
+  } else if (vt == VOLVERTEX) {
+    if (b->verbose > 2) {
+      printf("      Removing a point %d in volume.\n",
+             pointmark(steinerpt));
+    }
+  } else {
+    // It is not a Steiner point.
+    return 0;
+  }
+
+  // Try to reduce the number of edges at 'p' by flips.
+  getvertexstar(1, steinerpt, cavetetlist, cavetetvertlist, NULL);
+  cavetetlist->restart(); // This list may be re-used.
+  if (cavetetvertlist->objects > 3l) {
+    valence = reduceedgesatvertex(steinerpt, cavetetvertlist);
+  } else {
+    valence = cavetetvertlist->objects;
+  }
+  assert(cavetetlist->objects == 0l);
+  cavetetvertlist->restart();
+
+  removeflag = 0;
+
+  if (valence == 4) {
+    // Only 4 vertices (4 tets) left! 'p' is inside the convex hull of the 4
+    //   vertices. This case is due to that 'p' is not exactly on the segment.
+    point2tetorg(steinerpt, searchtet);
+    loc = INTETRAHEDRON;
+    removeflag = 1;
+  } else if (valence == 5) {
+    // There are 5 edges.
+    if (vt == FREESEGVERTEX) {
+      sstpivot1(leftseg, searchtet);
+      if (org(searchtet) != steinerpt) {
+        esymself(searchtet);
+      }
+      assert(org(searchtet) == steinerpt);
+      assert(dest(searchtet) == lpt);
+      i = 0; // Count the numbe of tet at the edge [p,lpt].
+      neightet.tet = NULL; // Init the face.
+      spintet = searchtet;
+      while (1) {
+        i++;
+        if (apex(spintet) == rpt) {
+          // Remember the face containing the edge [lpt, rpt].
+          neightet = spintet;
+        }
+        fnextself(spintet);
+        if (spintet.tet == searchtet.tet) break;
+      }
+      if (i == 3) {
+        // This case has been checked below.
+      } else if (i == 4) {
+        // There are 4 tets sharing at [p,lpt]. There must be 4 tets sharing
+        //   at [p,rpt].  There must be a face [p, lpt, rpt].  
+        if (apex(neightet) == rpt) {
+          // The edge (segment) has been already recovered!  
+          // Check if a 6-to-2 flip is possible (to remove 'p').
+          // Let 'searchtet' be [p,d,a,b]
+          esym(neightet, searchtet);
+          enextself(searchtet);
+          // Check if there are exactly three tets at edge [p,d].
+          wrktets[0] = searchtet; // [p,d,a,b]
+          for (i = 0; i < 2; i++) {
+            fnext(wrktets[i], wrktets[i+1]); // [p,d,b,c], [p,d,c,a]
+          }
+          if (apex(wrktets[0]) == oppo(wrktets[2])) {
+            loc = ONFACE;
+            removeflag = 1;
+          }
+        }
+      }
+    } else if (vt == FREEFACETVERTEX) {
+      // It is possible to do a 6-to-2 flip to remove the vertex.
+      point2tetorg(steinerpt, searchtet);
+      // Get the three faces of 'searchtet' which share at p.
+      //    All faces has p as origin.
+      wrktets[0] = searchtet;
+      wrktets[1] = searchtet;
+      esymself(wrktets[1]);
+      enextself(wrktets[1]);
+      wrktets[2] = searchtet;
+      eprevself(wrktets[2]);
+      esymself(wrktets[2]);
+      // All internal edges of the six tets have valance either 3 or 4.
+      // Get one edge which has valance 3.
+      searchtet.tet = NULL;
+      for (i = 0; i < 3; i++) {
+        spintet = wrktets[i];
+        valence = 0;
+        while (1) {
+          valence++;
+          fnextself(spintet);
+          if (spintet.tet == wrktets[i].tet) break;
+        }
+        if (valence == 3) {
+          // Found the edge.
+          searchtet = wrktets[i];
+          break;
+        } else {
+          assert(valence == 4);
+        }
+      }
+      assert(searchtet.tet != NULL);
+      // Note, we do not detach the three subfaces at p.
+      // They will be removed within a 4-to-1 flip.
+      loc = ONFACE;
+      removeflag = 1;
+    } else {
+      // assert(0); DEBUG IT
+    }
+    //removeflag = 1;
+  } 
+
+  if (!removeflag) {
+    if (vt == FREESEGVERTEX) { 
+      // Check is it possible to recover the edge [lpt,rpt].
+      // The condition to check is:  Whether each tet containing 'leftseg' is
+      //   adjacent to a tet containing 'rightseg'.
+      sstpivot1(leftseg, searchtet);
+      if (org(searchtet) != steinerpt) {
+        esymself(searchtet);
+      }
+      assert(org(searchtet) == steinerpt);
+      assert(dest(searchtet) == lpt);
+      spintet = searchtet;
+      while (1) {
+        // Go to the bottom face of this tet.
+        eprev(spintet, neightet);
+        esymself(neightet);  // [steinerpt, p1, p2, lpt]
+        // Get the adjacent tet.
+        fsymself(neightet);  // [p1, steinerpt, p2, rpt]
+        if (oppo(neightet) != rpt) {
+          // Found a non-matching adjacent tet.
+          break;
+        }
+        fnextself(spintet);
+        if (spintet.tet == searchtet.tet) {
+          // 'searchtet' is [p,d,p1,p2].
+          loc = ONEDGE;
+          removeflag = 1;
+          break;
+        }
+      }
+    } // if (vt == FREESEGVERTEX)
+  }
+
+  if (!removeflag) {
+    if (vt == FREESEGVERTEX) {
+      // Check if the edge [lpt, rpt] exists.
+      if (getedge(lpt, rpt, &searchtet)) {
+        // We have recovered this edge. Shift the vertex into the volume.
+        // We can recover this edge if the subfaces are not recovered yet.
+        if (!checksubfaceflag) {
+          // Remove the vertex from the surface mesh.
+          //   This will re-create the segment [lpt, rpt] and re-triangulate
+          //   all the facets at the segment.
+          // Detach the subsegments from their surrounding tets.
+          for (i = 0; i < 2; i++) {
+            checkseg = (i == 0) ? leftseg : rightseg;
+            sstpivot1(checkseg, neightet);
+            spintet = neightet;
+            while (1) {
+              tssdissolve1(spintet);
+              fnextself(spintet);
+              if (spintet.tet == neightet.tet) break;
+            }
+            sstdissolve1(checkseg);
+          } // i
+          slawson = 1; // Do lawson flip after removal.
+          spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
+          sremovevertex(steinerpt, &parentsh, &rightseg, slawson);
+          // Clear the list for new subfaces.
+          caveshbdlist->restart();
+          // Insert the new segment.
+          assert(org(searchtet) == lpt);
+          assert(dest(searchtet) == rpt);
+          sstbond1(rightseg, searchtet);
+          spintet = searchtet;
+          while (1) {
+            tsspivot1(spintet, checkseg); // FOR DEBUG ONLY
+            assert(checkseg.sh == NULL);  // FOR DEBUG ONLY
+            tssbond1(spintet, rightseg);
+            fnextself(spintet);
+            if (spintet.tet == searchtet.tet) break;
+          }
+          // The Steiner point has been shifted into the volume.
+          setpointtype(steinerpt, FREEVOLVERTEX);          
+          st_segref_count--;
+          st_volref_count++;
+          return 1;
+        } // if (!checksubfaceflag)
+      } // if (getedge(...))
+    } // if (vt == FREESEGVERTEX)
+  } // if (!removeflag)
+
+  if (!removeflag) {
+    return 0;
+  }
+
+  assert(org(searchtet) == steinerpt);
+
+  if (vt == FREESEGVERTEX) {
+    // Detach the subsegments from their surronding tets.
+    for (i = 0; i < 2; i++) {
+      checkseg = (i == 0) ? leftseg : rightseg;
+      sstpivot1(checkseg, neightet);
+      spintet = neightet;
+      while (1) {
+        tssdissolve1(spintet);
+        fnextself(spintet);
+        if (spintet.tet == neightet.tet) break;
+      }
+      sstdissolve1(checkseg);
+    } // i
+    if (checksubfaceflag) {
+      // Detach the subfaces at the subsegments from their attached tets.
+      for (i = 0; i < 2; i++) {
+        checkseg = (i == 0) ? leftseg : rightseg;
+        spivot(checkseg, parentsh);
+        if (parentsh.sh != NULL) {
+          spinsh = parentsh;
+          while (1) {
+            stpivot(spinsh, neightet);
+            if (neightet.tet != NULL) {
+              tsdissolve(neightet);
+            }
+            sesymself(spinsh);
+            stpivot(spinsh, neightet);
+            if (neightet.tet != NULL) {
+              tsdissolve(neightet);
+            }
+            stdissolve(spinsh);
+            spivotself(spinsh); // Go to the next subface.
+            if (spinsh.sh == parentsh.sh) break;
+          }
+        }
+      } // i
+    } // if (checksubfaceflag)
+  }
+
+  if (loc == INTETRAHEDRON) {
+    // Collect the four tets containing 'p'.
+    fliptets = new triface[4];
+    fliptets[0] = searchtet; // [p,d,a,b]
+    for (i = 0; i < 2; i++) {
+      fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a]
+    }
+    eprev(fliptets[0], fliptets[3]);
+    fnextself(fliptets[3]); // it is [a,p,b,c]
+    eprevself(fliptets[3]);
+    esymself(fliptets[3]); // [a,b,c,p].
+    // Remove p by a 4-to-1 flip.
+    //flip41(fliptets, 1, 0, 0);
+    flip41(fliptets, 1, &fc);
+    //recenttet = fliptets[0];
+  } else if (loc == ONFACE) {
+    // Let the original two tets be [a,b,c,d] and [b,a,c,e]. And p is in
+    //   face [a,b,c].  Let 'searchtet' be the tet [p,d,a,b].
+    // Collect the six tets containing 'p'.
+    fliptets = new triface[6];
+    fliptets[0] = searchtet; // [p,d,a,b]
+    for (i = 0; i < 2; i++) {
+      fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a]
+    }
+    eprev(fliptets[0], fliptets[3]);
+    fnextself(fliptets[3]); // [a,p,b,e]
+    esymself(fliptets[3]);  // [p,a,e,b]
+    eprevself(fliptets[3]); // [e,p,a,b]
+    for (i = 3; i < 5; i++) {
+      fnext(fliptets[i], fliptets[i+1]); // [e,p,b,c], [e,p,c,a]
+    }
+    if (vt == FREEFACETVERTEX) {
+      // We need to determine the location of three subfaces at p.
+      valence = 0; // Re-use it.
+      // Check if subfaces are all located in the lower three tets.
+      //   i.e., [e,p,a,b], [e,p,b,c], and [e,p,c,a].
+      for (i = 3; i < 6; i++) {
+        if (issubface(fliptets[i])) valence++;
+      }
+      if (valence > 0) {
+        assert(valence == 2);
+        // We must do 3-to-2 flip in the upper part. We simply re-arrange
+        //   the six tets.
+        for (i = 0; i < 3; i++) {
+          esym(fliptets[i+3], wrktets[i]);
+          esym(fliptets[i], fliptets[i+3]);
+          fliptets[i] = wrktets[i];
+        }
+        // Swap the last two pairs, i.e., [1]<->[[2], and [4]<->[5]
+        wrktets[1] = fliptets[1];
+        fliptets[1] = fliptets[2];
+        fliptets[2] = wrktets[1];
+        wrktets[1] = fliptets[4];
+        fliptets[4] = fliptets[5];
+        fliptets[5] = wrktets[1];
+      }
+    }
+    // Remove p by a 6-to-2 flip, which is a combination of two flips:
+    //   a 3-to-2 (deletes the edge [e,p]), and
+    //   a 4-to-1 (deletes the vertex p).
+    // First do a 3-to-2 flip on [e,p,a,b],[e,p,b,c],[e,p,c,a]. It creates
+    //   two new tets: [a,b,c,p] and [b,a,c,e].  The new tet [a,b,c,p] is
+    //   degenerate (has zero volume). It will be deleted in the followed
+    //   4-to-1 flip.
+    //flip32(&(fliptets[3]), 1, 0, 0);
+    flip32(&(fliptets[3]), 1, &fc);
+    // Second do a 4-to-1 flip on [p,d,a,b],[p,d,b,c],[p,d,c,a],[a,b,c,p].
+    //   This creates a new tet [a,b,c,d].
+    //flip41(fliptets, 1, 0, 0);
+    flip41(fliptets, 1, &fc);
+    //recenttet = fliptets[0];
+  } else if (loc == ONEDGE) {
+    // Let the original edge be [e,d] and p is in [e,d]. Assume there are n
+    //   tets sharing at edge [e,d] originally.  We number the link vertices
+    //   of [e,d]: p_0, p_1, ..., p_n-1. 'searchtet' is [p,d,p_0,p_1].
+    // Count the number of tets at edge [e,p] and [p,d] (this is n).
+    n = 0;
+    spintet = searchtet;
+    while (1) {
+      n++;
+      fnextself(spintet);
+      if (spintet.tet == searchtet.tet) break;
+    }
+    assert(n >= 3);
+    // Collect the 2n tets containing 'p'.
+    fliptets = new triface[2 * n];
+    fliptets[0] = searchtet; // [p,b,p_0,p_1] 
+    for (i = 0; i < (n - 1); i++) {
+      fnext(fliptets[i], fliptets[i+1]); // [p,d,p_i,p_i+1].
+    }
+    eprev(fliptets[0], fliptets[n]);
+    fnextself(fliptets[n]); // [p_0,p,p_1,e]
+    esymself(fliptets[n]);  // [p,p_0,e,p_1]
+    eprevself(fliptets[n]); // [e,p,p_0,p_1]
+    for (i = n; i <  (2 * n - 1); i++) {
+      fnext(fliptets[i], fliptets[i+1]); // [e,p,p_i,p_i+1].
+    }
+    // Remove p by a 2n-to-n flip, it is a sequence of n flips:
+    // - Do a 2-to-3 flip on 
+    //     [p_0,p_1,p,d] and 
+    //     [p,p_1,p_0,e].
+    //   This produces: 
+    //     [e,d,p_0,p_1], 
+    //     [e,d,p_1,p] (degenerated), and 
+    //     [e,d,p,p_0] (degenerated).
+    wrktets[0] = fliptets[0]; // [p,d,p_0,p_1]
+    eprevself(wrktets[0]);    // [p_0,p,d,p_1]
+    esymself(wrktets[0]);     // [p,p_0,p_1,d]
+    enextself(wrktets[0]);    // [p_0,p_1,p,d] [0]
+    wrktets[1] = fliptets[n]; // [e,p,p_0,p_1]
+    enextself(wrktets[1]);    // [p,p_0,e,p_1]
+    esymself(wrktets[1]);     // [p_0,p,p_1,e]
+    eprevself(wrktets[1]);    // [p_1,p_0,p,e] [1]
+    //flip23(wrktets, 1, 0, 0);
+    flip23(wrktets, 1, &fc);
+    // Save the new tet [e,d,p,p_0] (degenerated).
+    fliptets[n] = wrktets[2];
+    // Save the new tet [e,d,p_0,p_1].
+    fliptets[0] = wrktets[0];
+    // - Repeat from i = 1 to n-2: (n - 2) flips
+    //   - Do a 3-to-2 flip on 
+    //       [p,p_i,d,e], 
+    //       [p,p_i,e,p_i+1], and 
+    //       [p,p_i,p_i+1,d]. 
+    //     This produces: 
+    //       [d,e,p_i+1,p_i], and
+    //       [e,d,p_i+1,p] (degenerated).
+    for (i = 1; i < (n - 1); i++) {
+      wrktets[0] = wrktets[1]; // [e,d,p_i,p] (degenerated).
+      enextself(wrktets[0]);   // [d,p_i,e,p] (...)
+      esymself(wrktets[0]);    // [p_i,d,p,e] (...) 
+      eprevself(wrktets[0]);   // [p,p_i,d,e] (degenerated) [0].
+      wrktets[1] = fliptets[n+i];  // [e,p,p_i,p_i+1]
+      enextself(wrktets[1]);       // [p,p_i,e,p_i+1] [1]
+      wrktets[2] = fliptets[i]; // [p,d,p_i,p_i+1]
+      eprevself(wrktets[2]);    // [p_i,p,d,p_i+1]
+      esymself(wrktets[2]);     // [p,p_i,p_i+1,d] [2]
+      //flip32(wrktets, 1, 0, 0);
+      flip32(wrktets, 1, &fc);
+      // Save the new tet [e,d,p_i,p_i+1].         // FOR DEBUG ONLY
+      fliptets[i] = wrktets[0]; // [d,e,p_i+1,p_i] // FOR DEBUG ONLY
+      esymself(fliptets[i]);    // [e,d,p_i,p_i+1] // FOR DEBUG ONLY
+    }
+    // - Do a 4-to-1 flip on 
+    //     [p,p_0,e,d],     [d,e,p_0,p],
+    //     [p,p_0,d,p_n-1], [e,p_n-1,p_0,p], 
+    //     [p,p_0,p_n-1,e], [p_0,p_n-1,d,p], and
+    //     [e,d,p_n-1,p]. 
+    //   This produces 
+    //     [e,d,p_n-1,p_0] and 
+    //     deletes p.
+    wrktets[3] = wrktets[1];  // [e,d,p_n-1,p] (degenerated) [3]
+    wrktets[0] = fliptets[n]; // [e,d,p,p_0] (degenerated)
+    eprevself(wrktets[0]);    // [p,e,d,p_0] (...)
+    esymself(wrktets[0]);     // [e,p,p_0,d] (...)
+    enextself(wrktets[0]);    // [p,p_0,e,d] (degenerated) [0]
+    wrktets[1] = fliptets[n-1];   // [p,d,p_n-1,p_0]
+    esymself(wrktets[1]);         // [d,p,p_0,p_n-1]
+    enextself(wrktets[1]);        // [p,p_0,d,p_n-1] [1]
+    wrktets[2] = fliptets[2*n-1]; // [e,p,p_n-1,p_0]
+    enextself(wrktets[2]);        // [p_p_n-1,e,p_0]
+    esymself(wrktets[2]);         // [p_n-1,p,p_0,e]
+    enextself(wrktets[2]);        // [p,p_0,p_n-1,e] [2]
+    //flip41(wrktets, 1, 0, 0);
+    flip41(wrktets, 1, &fc);
+    // Save the new tet [e,d,p_n-1,p_0]             // FOR DEBUG ONLY
+    fliptets[n-1] = wrktets[0];  // [e,d,p_n-1,p_0] // FOR DEBUG ONLY
+    //recenttet = fliptets[0];
+  } else {
+    assert(0); // Unknown location.
+  } // if (iloc == ...)
+
+  delete [] fliptets;
+
+  if (vt == FREESEGVERTEX) {
+    // Remove the vertex from the surface mesh.
+    //   This will re-create the segment [lpt, rpt] and re-triangulate
+    //   all the facets at the segment.
+    // Only do lawson flip when subfaces are not recovery yet.
+    slawson = (checksubfaceflag ? 0 : 1);
+    spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
+    sremovevertex(steinerpt, &parentsh, &rightseg, slawson);
+
+    // The original segment is returned in 'rightseg'. 
+    rightseg.shver = 0;
+    assert(sorg(rightseg) == lpt);
+    assert(sdest(rightseg) == rpt);
+
+    // Insert the new segment.
+    point2tetorg(lpt, searchtet);
+    finddirection(&searchtet, rpt);
+    assert(dest(searchtet) == rpt);
+    sstbond1(rightseg, searchtet);
+    spintet = searchtet;
+    while (1) {
+      tsspivot1(spintet, checkseg); // FOR DEBUG ONLY
+      assert(checkseg.sh == NULL);  // FOR DEBUG ONLY
+      tssbond1(spintet, rightseg);
+      fnextself(spintet);
+      if (spintet.tet == searchtet.tet) break;
+    }
+
+    if (checksubfaceflag) {
+      // Insert subfaces at segment [lpt,rpt] into the tetrahedralization.
+      spivot(rightseg, parentsh);
+      if (parentsh.sh != NULL) {
+        spinsh = parentsh;
+        while (1) {
+          if (sorg(spinsh) != lpt) {
+            sesymself(spinsh);
+            assert(sorg(spinsh) == lpt);
+          }
+          assert(sdest(spinsh) == rpt);
+          apexpt = sapex(spinsh);
+          // Find the adjacent tet of [lpt,rpt,apexpt];
+          spintet = searchtet;
+          while (1) {
+            if (apex(spintet) == apexpt) {
+              tsbond(spintet, spinsh);
+              sesymself(spinsh); // Get to another side of this face.
+              fsym(spintet, neightet);
+              tsbond(neightet, spinsh);
+              sesymself(spinsh); // Get back to the original side.
+              break;
+            }
+            fnextself(spintet);
+            assert(spintet.tet != searchtet.tet);
+            //if (spintet.tet == searchtet.tet) break;
+          }
+          spivotself(spinsh);
+          if (spinsh.sh == parentsh.sh) break;
+        }
+      }
+    } // if (checksubfaceflag)
+
+    // Clear the set of new subfaces.
+    caveshbdlist->restart();
+  } // if (vt == FREESEGVERTEX)
+
+  // The point has been removed.
+  if (pointtype(steinerpt) != UNUSEDVERTEX) {
+    setpointtype(steinerpt, UNUSEDVERTEX);
+    unuverts++;
+  }
+  if (vt != VOLVERTEX) {
+    // Update the correspinding counters.
+    if (vt == FREESEGVERTEX) {
+      st_segref_count--;
+    } else if (vt == FREEFACETVERTEX) {
+      st_facref_count--;
+    } else if (vt == FREEVOLVERTEX) {
+      st_volref_count--;
+    }
+    if (steinerleft > 0) steinerleft++;
+  }
+
+  return 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// suppressbdrysteinerpoint()    Suppress a boundary Steiner point           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::suppressbdrysteinerpoint(point steinerpt)
+{
+  face parentsh, spinsh, *parysh;
+  face leftseg, rightseg;
+  point lpt = NULL, rpt = NULL;
+  int i;
+
+  verttype vt = pointtype(steinerpt);
+
+  if (vt == FREESEGVERTEX) {
+    sdecode(point2sh(steinerpt), leftseg);
+    leftseg.shver = 0;
+    if (sdest(leftseg) == steinerpt) {
+      senext(leftseg, rightseg);
+      spivotself(rightseg);
+      assert(rightseg.sh != NULL);
+      rightseg.shver = 0;
+      assert(sorg(rightseg) == steinerpt);
+    } else {
+      assert(sorg(leftseg) == steinerpt);
+      rightseg = leftseg;
+      senext2(rightseg, leftseg);
+      spivotself(leftseg);
+      assert(leftseg.sh != NULL);
+      leftseg.shver = 0;
+      assert(sdest(leftseg) == steinerpt);
+    }
+    lpt = sorg(leftseg);
+    rpt = sdest(rightseg);
+    if (b->verbose > 2) {
+      printf("      Suppressing Steiner point %d in segment (%d, %d).\n",
+             pointmark(steinerpt), pointmark(lpt), pointmark(rpt));
+    }
+    // Get all subfaces at the left segment [lpt, steinerpt].
+    spivot(leftseg, parentsh);
+    spinsh = parentsh;
+    while (1) {
+      cavesegshlist->newindex((void **) &parysh);
+      *parysh = spinsh;
+      // Orient the face consistently. 
+      if (sorg(*parysh)!= sorg(parentsh)) sesymself(*parysh);
+      spivotself(spinsh);
+      if (spinsh.sh == NULL) break;
+      if (spinsh.sh == parentsh.sh) break;
+    }
+    if (cavesegshlist->objects < 2) {
+      // It is a single segment. Not handle it yet.
+      cavesegshlist->restart();
+      return 0;
+    }
+  } else if (vt == FREEFACETVERTEX) {
+    if (b->verbose > 2) {
+      printf("      Suppressing Steiner point %d from facet.\n",
+             pointmark(steinerpt));
+    }
+    sdecode(point2sh(steinerpt), parentsh);
+    // A facet Steiner point. There are exactly two sectors.
+    for (i = 0; i < 2; i++) {
+      cavesegshlist->newindex((void **) &parysh);
+      *parysh = parentsh;
+      sesymself(parentsh);
+    }
+  } else {
+    return 0;
+  }
+
+  triface searchtet, neightet, *parytet;
+  point pa, pb, pc, pd;
+  REAL v1[3], v2[3], len, u;
+
+  REAL startpt[3] = {0,}, samplept[3] = {0,}, candpt[3] = {0,};
+  REAL ori, minvol, smallvol;
+  int samplesize;
+  int it, j, k;
+
+  int n = (int) cavesegshlist->objects;
+  point *newsteiners = new point[n];
+  for (i = 0; i < n; i++) newsteiners[i] = NULL;
+
+  // Search for each sector an interior vertex. 
+  for (i = 0; i < cavesegshlist->objects; i++) {
+    parysh = (face *) fastlookup(cavesegshlist, i);
+    stpivot(*parysh, searchtet);
+    // Skip it if it is outside.
+    if (ishulltet(searchtet)) continue;
+    // Get the "half-ball". Tets in 'cavetetlist' all contain 'steinerpt' as
+    //   opposite.  Subfaces in 'caveshlist' all contain 'steinerpt' as apex.
+    //   Moreover, subfaces are oriented towards the interior of the ball.
+    setpoint2tet(steinerpt, encode(searchtet));
+    getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist);
+    // Calculate the searching vector.
+    pa = sorg(*parysh);
+    pb = sdest(*parysh);
+    pc = sapex(*parysh);
+    facenormal(pa, pb, pc, v1, 1, NULL);
+    len = sqrt(dot(v1, v1));
+    assert(len > 0.0);
+    v1[0] /= len;
+    v1[1] /= len;
+    v1[2] /= len;
+    if (vt == FREESEGVERTEX) {
+      parysh = (face *) fastlookup(cavesegshlist, (i + 1) % n);
+      pd = sapex(*parysh);
+      facenormal(pb, pa, pd, v2, 1, NULL);
+      len = sqrt(dot(v2, v2));
+      assert(len > 0.0);
+      v2[0] /= len;
+      v2[1] /= len;
+      v2[2] /= len;
+      // Average the two vectors.
+      v1[0] = 0.5 * (v1[0] + v2[0]);
+      v1[1] = 0.5 * (v1[1] + v2[1]);
+      v1[2] = 0.5 * (v1[2] + v2[2]);
+    }
+    // Search the intersection of the ray starting from 'steinerpt' to
+    //   the search direction 'v1' and the shell of the half-ball.
+    // - Construct an endpoint.
+    len = distance(pa, pb);
+    v2[0] = steinerpt[0] + len * v1[0];
+    v2[1] = steinerpt[1] + len * v1[1];
+    v2[2] = steinerpt[2] + len * v1[2];
+    for (j = 0; j < cavetetlist->objects; j++) {
+      parytet = (triface *) fastlookup(cavetetlist, j);
+      pa = org(*parytet);
+      pb = dest(*parytet);
+      pc = apex(*parytet);
+      // Test if the ray startpt->v2 lies in the cone: where 'steinerpt'
+      //   is the apex, and three sides are defined by the triangle 
+      //   [pa, pb, pc].
+      ori = orient3d(steinerpt, pa, pb, v2);
+      if (ori >= 0) {
+        ori = orient3d(steinerpt, pb, pc, v2);
+        if (ori >= 0) {
+          ori = orient3d(steinerpt, pc, pa, v2);
+          if (ori >= 0) {
+            // Found! Calculate the intersection.
+            planelineint(pa, pb, pc, steinerpt, v2, startpt, &u);
+            assert(u != 0.0);
+            break;
+          }
+        }
+      }
+    } // j
+    assert(j < cavetetlist->objects); // There must be an intersection.
+    // Close the ball by adding the subfaces.
+    for (j = 0; j < caveshlist->objects; j++) {
+      parysh = (face *) fastlookup(caveshlist, j);
+      stpivot(*parysh, neightet);
+      cavetetlist->newindex((void **) &parytet);
+      *parytet = neightet;
+    }
+    // Search a best point inside the segment [startpt, steinerpt].
+    it = 0;
+    samplesize = 100;
+    v1[0] = steinerpt[0] - startpt[0];
+    v1[1] = steinerpt[1] - startpt[1];
+    v1[2] = steinerpt[2] - startpt[2];
+    minvol = -1.0;
+    while (it < 3) {
+      for (j = 1; j < samplesize - 1; j++) {
+        samplept[0] = startpt[0] + ((REAL) j / (REAL) samplesize) * v1[0];
+        samplept[1] = startpt[1] + ((REAL) j / (REAL) samplesize) * v1[1];
+        samplept[2] = startpt[2] + ((REAL) j / (REAL) samplesize) * v1[2];
+        // Find the minimum volume for 'samplept'.
+        smallvol = -1;
+        for (k = 0; k < cavetetlist->objects; k++) {
+          parytet = (triface *) fastlookup(cavetetlist, k);
+          pa = org(*parytet);
+          pb = dest(*parytet);
+          pc = apex(*parytet);
+          ori = orient3d(pb, pa, pc, samplept);
+          if (ori <= 0) {
+            break; // An invalid tet.
+          }
+          if (smallvol == -1) {
+            smallvol = ori;
+          } else {
+            if (ori < smallvol) smallvol = ori;
+          }
+        } // k
+        if (k == cavetetlist->objects) {
+          // Found a valid point. Remember it.
+          if (minvol == -1.0) {
+            candpt[0] = samplept[0];
+            candpt[1] = samplept[1];
+            candpt[2] = samplept[2];
+            minvol = smallvol;
+          } else {
+            if (minvol < smallvol) {
+              // It is a better location. Remember it.
+              candpt[0] = samplept[0];
+              candpt[1] = samplept[1];
+              candpt[2] = samplept[2];
+              minvol = smallvol;
+            } else {
+              // No improvement of smallest volume. 
+              // Since we are searching along the line [startpt, steinerpy],
+              // The smallest volume can only be decreased later.
+              break;
+            }
+          }
+        }
+      } // j
+      if (minvol > 0) break; 
+      samplesize *= 10;
+      it++;
+    } // while (it < 3)
+    if (minvol == -1.0) {
+      // Failed to find a valid point.
+      cavetetlist->restart();
+      caveshlist->restart();
+      break;
+    }
+    // Create a new Steiner point inside this section.
+    makepoint(&(newsteiners[i]), FREEVOLVERTEX);
+    newsteiners[i][0] = candpt[0];
+    newsteiners[i][1] = candpt[1];
+    newsteiners[i][2] = candpt[2];
+    cavetetlist->restart();
+    caveshlist->restart();
+  } // i
+
+  if (i < cavesegshlist->objects) {
+    // Failed to suppress the vertex.
+    for (; i > 0; i--) {
+      if (newsteiners[i - 1] != NULL) {
+        pointdealloc(newsteiners[i - 1]);
+      }
+    }
+    delete [] newsteiners;
+    cavesegshlist->restart();
+    return 0;
+  }
+
+  // Remove p from the segment or the facet.
+  triface newtet, newface, spintet;
+  face newsh, neighsh;
+  face *splitseg, checkseg;
+  int slawson = 0; // Do not do flip afterword.
+  int t1ver;
+
+  if (vt == FREESEGVERTEX) {
+    // Detach 'leftseg' and 'rightseg' from their adjacent tets.
+    //   These two subsegments will be deleted. 
+    sstpivot1(leftseg, neightet);
+    spintet = neightet;
+    while (1) {
+      tssdissolve1(spintet);
+      fnextself(spintet);
+      if (spintet.tet == neightet.tet) break;
+    }
+    sstpivot1(rightseg, neightet);
+    spintet = neightet;
+    while (1) {
+      tssdissolve1(spintet);
+      fnextself(spintet);
+      if (spintet.tet == neightet.tet) break;
+    }
+  }
+
+  // Loop through all sectors bounded by facets at this segment.
+  //   Within each sector, create a new Steiner point 'np', and replace 'p'
+  //   by 'np' for all tets in this sector.
+  for (i = 0; i < cavesegshlist->objects; i++) {
+    parysh = (face *) fastlookup(cavesegshlist, i);
+    // 'parysh' is the face [lpt, steinerpt, #].
+    stpivot(*parysh, neightet);
+    // Get all tets in this sector.
+    setpoint2tet(steinerpt, encode(neightet));
+    getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist);
+    if (!ishulltet(neightet)) {
+      // Within each tet in the ball, replace 'p' by 'np'.
+      for (j = 0; j < cavetetlist->objects; j++) {
+        parytet = (triface *) fastlookup(cavetetlist, j);
+        setoppo(*parytet, newsteiners[i]);
+      } // j
+      // Point to a parent tet.
+      parytet = (triface *) fastlookup(cavetetlist, 0);
+      setpoint2tet(newsteiners[i], (tetrahedron) (parytet->tet)); 
+      st_volref_count++;
+      if (steinerleft > 0) steinerleft--;
+    }
+    // Disconnect the set of boundary faces. They're temporarily open faces.
+    //   They will be connected to the new tets after 'p' is removed.
+    for (j = 0; j < caveshlist->objects; j++) {
+      // Get a boundary face.
+      parysh = (face *) fastlookup(caveshlist, j);
+      stpivot(*parysh, neightet);
+      //assert(apex(neightet) == newpt);
+      // Clear the connection at this face.
+      dissolve(neightet);
+      tsdissolve(neightet);
+    }
+    // Clear the working lists.
+    cavetetlist->restart();
+    caveshlist->restart();
+  } // i
+  cavesegshlist->restart();
+
+  if (vt == FREESEGVERTEX) { 
+    spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
+    splitseg = &rightseg;
+  } else {
+    if (sdest(parentsh) == steinerpt) {
+      senextself(parentsh);
+    } else if (sapex(parentsh) == steinerpt) {
+      senext2self(parentsh);
+    }
+    assert(sorg(parentsh) == steinerpt);
+    splitseg = NULL;
+  }
+  sremovevertex(steinerpt, &parentsh, splitseg, slawson);
+
+  if (vt == FREESEGVERTEX) {
+    // The original segment is returned in 'rightseg'. 
+    rightseg.shver = 0;
+  }
+
+  // For each new subface, create two new tets at each side of it.
+  //   Both of the two new tets have its opposite be dummypoint. 
+  for (i = 0; i < caveshbdlist->objects; i++) {
+    parysh = (face *) fastlookup(caveshbdlist, i);
+    sinfect(*parysh); // Mark it for connecting new tets.
+    newsh = *parysh;
+    pa = sorg(newsh);
+    pb = sdest(newsh);
+    pc = sapex(newsh);
+    maketetrahedron(&newtet);
+    maketetrahedron(&neightet);
+    setvertices(newtet, pa, pb, pc, dummypoint);
+    setvertices(neightet, pb, pa, pc, dummypoint);
+    bond(newtet, neightet);
+    tsbond(newtet, newsh);
+    sesymself(newsh);
+    tsbond(neightet, newsh);
+  }
+  // Temporarily increase the hullsize.
+  hullsize += (caveshbdlist->objects * 2l);
+
+  if (vt == FREESEGVERTEX) {
+    // Connecting new tets at the recovered segment.
+    spivot(rightseg, parentsh);
+    assert(parentsh.sh != NULL);
+    spinsh = parentsh;
+    while (1) {
+      if (sorg(spinsh) != lpt) sesymself(spinsh);
+      // Get the new tet at this subface.
+      stpivot(spinsh, newtet);
+      tssbond1(newtet, rightseg);
+      // Go to the other face at this segment.
+      spivot(spinsh, neighsh);
+      if (sorg(neighsh) != lpt) sesymself(neighsh);
+      sesymself(neighsh);
+      stpivot(neighsh, neightet);
+      tssbond1(neightet, rightseg);
+      sstbond1(rightseg, neightet); 
+      // Connecting two adjacent tets at this segment.
+      esymself(newtet);
+      esymself(neightet);
+      // Connect the two tets (at rightseg) together.
+      bond(newtet, neightet);
+      // Go to the next subface.
+      spivotself(spinsh);
+      if (spinsh.sh == parentsh.sh) break;
+    }
+  }
+
+  // Connecting new tets at new subfaces together.
+  for (i = 0; i < caveshbdlist->objects; i++) {
+    parysh = (face *) fastlookup(caveshbdlist, i);
+    newsh = *parysh;
+    //assert(sinfected(newsh));
+    // Each new subface contains two new tets.
+    for (k = 0; k < 2; k++) {
+      stpivot(newsh, newtet);
+      for (j = 0; j < 3; j++) {
+        // Check if this side is open.
+        esym(newtet, newface);
+        if (newface.tet[newface.ver & 3] == NULL) {
+          // An open face. Connect it to its adjacent tet.
+          sspivot(newsh, checkseg);
+          if (checkseg.sh != NULL) {
+            // A segment. It must not be the recovered segment.
+            tssbond1(newtet, checkseg);
+            sstbond1(checkseg, newtet);
+          }
+          spivot(newsh, neighsh);
+          if (neighsh.sh != NULL) {
+            // The adjacent subface exists. It's not a dangling segment.
+            if (sorg(neighsh) != sdest(newsh)) sesymself(neighsh);
+            stpivot(neighsh, neightet);
+            if (sinfected(neighsh)) {
+              esymself(neightet);
+              assert(neightet.tet[neightet.ver & 3] == NULL);          
+            } else {
+              // Search for an open face at this edge.
+              spintet = neightet;
+              while (1) {
+                esym(spintet, searchtet);
+                fsym(searchtet, spintet);
+                if (spintet.tet == NULL) break;
+                assert(spintet.tet != neightet.tet);
+              }
+              // Found an open face at 'searchtet'.
+              neightet = searchtet;
+            }
+          } else {
+            // The edge (at 'newsh') is a dangling segment.
+            assert(checkseg.sh != NULL);
+            // Get an adjacent tet at this segment.
+            sstpivot1(checkseg, neightet);
+            assert(!isdeadtet(neightet));
+            if (org(neightet) != sdest(newsh)) esymself(neightet);
+            assert((org(neightet) == sdest(newsh)) &&
+                   (dest(neightet) == sorg(newsh)));
+            // Search for an open face at this edge.
+            spintet = neightet;
+            while (1) {
+              esym(spintet, searchtet);
+              fsym(searchtet, spintet);
+              if (spintet.tet == NULL) break;
+              assert(spintet.tet != neightet.tet);
+            }
+            // Found an open face at 'searchtet'.
+            neightet = searchtet;
+          }
+          pc = apex(newface);
+          if (apex(neightet) == steinerpt) {
+            // Exterior case. The 'neightet' is a hull tet which contain
+            //   'steinerpt'. It will be deleted after 'steinerpt' is removed. 
+            assert(pc == dummypoint);
+            caveoldtetlist->newindex((void **) &parytet);
+            *parytet = neightet;
+            // Connect newface to the adjacent hull tet of 'neightet', which
+            //   has the same edge as 'newface', and does not has 'steinerpt'.
+            fnextself(neightet);
+          } else {
+            if (pc == dummypoint) {
+              if (apex(neightet) != dummypoint) {
+                setapex(newface, apex(neightet));
+                // A hull tet has turned into an interior tet.
+                hullsize--; // Must update the hullsize.
+              } 
+            }
+          }
+          bond(newface, neightet);
+        } // if (newface.tet[newface.ver & 3] == NULL)
+        enextself(newtet);
+        senextself(newsh);
+      } // j
+      sesymself(newsh);
+    } // k
+  } // i
+
+  // Unmark all new subfaces.
+  for (i = 0; i < caveshbdlist->objects; i++) {
+    parysh = (face *) fastlookup(caveshbdlist, i);
+    suninfect(*parysh);
+  }
+  caveshbdlist->restart();
+
+  if (caveoldtetlist->objects > 0l) {
+    // Delete hull tets which contain 'steinerpt'.
+    for (i = 0; i < caveoldtetlist->objects; i++) {
+      parytet = (triface *) fastlookup(caveoldtetlist, i);
+      tetrahedrondealloc(parytet->tet);
+    }
+    // Must update the hullsize.
+    hullsize -= caveoldtetlist->objects;
+    caveoldtetlist->restart();
+  }
+
+  setpointtype(steinerpt, UNUSEDVERTEX);
+  unuverts++;
+  if (vt == FREESEGVERTEX) {
+    st_segref_count--;
+  } else { // vt == FREEFACETVERTEX
+    st_facref_count--;
+  }
+  if (steinerleft > 0) steinerleft++;  // We've removed a Steiner points.
+
+
+  point *parypt;
+  int steinercount = 0;
+
+  int bak_fliplinklevel = b->fliplinklevel;
+  b->fliplinklevel = 100000; // Unlimited flip level.
+
+  // Try to remove newly added Steiner points.
+  for (i = 0; i < n; i++) {
+    if (newsteiners[i] != NULL) {
+      if (!removevertexbyflips(newsteiners[i])) {
+        if (b->nobisect_param > 0) { // Not -Y0
+          // Save it in subvertstack for removal.
+          subvertstack->newindex((void **) &parypt);
+          *parypt = newsteiners[i];
+        }
+        steinercount++;
+      }
+    }
+  }
+
+  b->fliplinklevel = bak_fliplinklevel;
+
+  if (steinercount > 0) {
+    if (b->verbose > 2) {
+      printf("      Added %d interior Steiner points.\n", steinercount);
+    }
+  }
+
+  delete [] newsteiners;
+
+  return 1;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// suppresssteinerpoints()    Suppress Steiner points.                       //
+//                                                                           //
+// All Steiner points have been saved in 'subvertstack' in the routines      //
+// carveholes() and suppresssteinerpoint().                                  //
+// Each Steiner point is either removed or shifted into the interior.        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::suppresssteinerpoints()
+{
+
+  if (!b->quiet) {
+    printf("Suppressing Steiner points ...\n");
+  }
+
+  point rempt, *parypt;
+
+  int bak_fliplinklevel = b->fliplinklevel;
+  b->fliplinklevel = 100000; // Unlimited flip level.
+  int suppcount = 0, remcount = 0;
+  int i;
+
+  // Try to suppress boundary Steiner points.
+  for (i = 0; i < subvertstack->objects; i++) {
+    parypt = (point *) fastlookup(subvertstack, i);
+    rempt = *parypt;
+    if (pointtype(rempt) != UNUSEDVERTEX) {
+      if ((pointtype(rempt) == FREESEGVERTEX) || 
+          (pointtype(rempt) == FREEFACETVERTEX)) {
+        if (suppressbdrysteinerpoint(rempt)) {
+          suppcount++;
+        }
+      }
+    }
+  } // i
+
+  if (suppcount > 0) {
+    if (b->verbose) {
+      printf("  Suppressed %d boundary Steiner points.\n", suppcount);
+    }
+  }
+
+  if (b->nobisect_param > 0) { // -Y1
+    for (i = 0; i < subvertstack->objects; i++) {
+      parypt = (point *) fastlookup(subvertstack, i);
+      rempt = *parypt;
+      if (pointtype(rempt) != UNUSEDVERTEX) {
+        if (pointtype(rempt) == FREEVOLVERTEX) {
+          if (removevertexbyflips(rempt)) {
+            remcount++;
+          }
+        }
+      }
+    }
+  }
+
+  if (remcount > 0) {
+    if (b->verbose) {
+      printf("  Removed %d interior Steiner points.\n", remcount);
+    }
+  }
+
+  b->fliplinklevel = bak_fliplinklevel;
+
+  if (b->nobisect_param > 1) { // -Y2
+    // Smooth interior Steiner points.
+    optparameters opm;
+    triface *parytet;
+    point *ppt;
+    REAL ori;
+    int smtcount, count, ivcount;
+    int nt, j;
+
+    // Point smooth options.
+    opm.max_min_volume = 1;
+    opm.numofsearchdirs = 20;
+    opm.searchstep = 0.001;
+    opm.maxiter = 30; // Limit the maximum iterations.
+
+    smtcount = 0;
+
+    do {
+
+      nt = 0;
+
+      while (1) {
+        count = 0;
+        ivcount = 0; // Clear the inverted count.
+
+        for (i = 0; i < subvertstack->objects; i++) {
+          parypt = (point *) fastlookup(subvertstack, i);
+          rempt = *parypt;
+          if (pointtype(rempt) == FREEVOLVERTEX) {
+            getvertexstar(1, rempt, cavetetlist, NULL, NULL);
+            // Calculate the initial smallest volume (maybe zero or negative).
+            for (j = 0; j < cavetetlist->objects; j++) {
+              parytet = (triface *) fastlookup(cavetetlist, j);
+              ppt = (point *) &(parytet->tet[4]);
+              ori = orient3dfast(ppt[1], ppt[0], ppt[2], ppt[3]);
+              if (j == 0) {
+                opm.initval = ori;
+              } else {
+                if (opm.initval > ori) opm.initval = ori; 
+              }
+            }
+            if (smoothpoint(rempt, cavetetlist, 1, &opm)) {
+              count++;
+            }
+            if (opm.imprval <= 0.0) {
+              ivcount++; // The mesh contains inverted elements.
+            }
+            cavetetlist->restart();
+          }
+        } // i
+
+        smtcount += count;
+
+        if (count == 0) {
+          // No point has been smoothed.
+          break;
+        }
+
+        nt++;
+        if (nt > 2) {
+          break; // Already three iterations.
+        }
+      } // while
+
+      if (ivcount > 0) {
+        // There are inverted elements!
+        if (opm.maxiter > 0) {
+          // Set unlimited smoothing steps. Try again.
+          opm.numofsearchdirs = 30;
+          opm.searchstep = 0.0001;
+          opm.maxiter = -1;
+          continue;
+        }
+      }
+
+      break;
+    } while (1); // Additional loop for (ivcount > 0)
+
+    if (ivcount > 0) {
+      printf("BUG Report!  The mesh contain inverted elements.\n");
+    }
+
+    if (b->verbose) {
+      if (smtcount > 0) {
+        printf("  Smoothed %d Steiner points.\n", smtcount); 
+      }
+    }
+  } // -Y2
+
+  subvertstack->restart();
+
+  return 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// recoverboundary()    Recover segments and facets.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::recoverboundary(clock_t& tv)
+{
+  arraypool *misseglist, *misshlist;
+  arraypool *bdrysteinerptlist;
+  face searchsh, *parysh;
+  face searchseg, *paryseg;
+  point rempt, *parypt;
+  long ms; // The number of missing segments/subfaces.
+  int nit; // The number of iterations.
+  int s, i;
+
+  // Counters.
+  long bak_segref_count, bak_facref_count, bak_volref_count;
+
+  if (!b->quiet) {
+    printf("Recovering boundaries...\n");
+  }
+
+
+  if (b->verbose) {
+    printf("  Recovering segments.\n");
+  }
+
+  // Segments will be introduced.
+  checksubsegflag = 1;
+
+  misseglist = new arraypool(sizeof(face), 8);
+  bdrysteinerptlist = new arraypool(sizeof(point), 8);
+
+  // In random order.
+  subsegs->traversalinit();
+  for (i = 0; i < subsegs->items; i++) {
+    s = randomnation(i + 1);
+    // Move the s-th seg to the i-th.
+    subsegstack->newindex((void **) &paryseg);
+    *paryseg = * (face *) fastlookup(subsegstack, s);
+    // Put i-th seg to be the s-th.
+    searchseg.sh = shellfacetraverse(subsegs);
+    paryseg = (face *) fastlookup(subsegstack, s);
+    *paryseg = searchseg;
+  }
+
+  // The init number of missing segments.
+  ms = subsegs->items;
+  nit = 0; 
+  if (b->fliplinklevel < 0) {
+    autofliplinklevel = 1; // Init value.
+  }
+
+  // First, trying to recover segments by only doing flips.
+  while (1) {
+    recoversegments(misseglist, 0, 0);
+
+    if (misseglist->objects > 0) {
+      if (b->fliplinklevel >= 0) {
+        break;
+      } else {
+        if (misseglist->objects >= ms) {
+          nit++;
+          if (nit >= 3) {
+            //break;
+            // Do the last round with unbounded flip link level.
+            b->fliplinklevel = 100000;
+          }
+        } else {
+          ms = misseglist->objects;
+          if (nit > 0) {
+            nit--;
+          }
+        }
+        for (i = 0; i < misseglist->objects; i++) {
+          subsegstack->newindex((void **) &paryseg);
+          *paryseg = * (face *) fastlookup(misseglist, i);
+        }
+        misseglist->restart();
+        autofliplinklevel+=b->fliplinklevelinc;
+      }
+    } else {
+      // All segments are recovered.
+      break;
+    }
+  } // while (1)
+
+  if (b->verbose) {
+    printf("  %ld (%ld) segments are recovered (missing).\n", 
+           subsegs->items - misseglist->objects, misseglist->objects);
+  }
+
+  if (misseglist->objects > 0) {
+    // Second, trying to recover segments by doing more flips (fullsearch).
+    while (misseglist->objects > 0) {
+      ms = misseglist->objects;
+      for (i = 0; i < misseglist->objects; i++) {
+        subsegstack->newindex((void **) &paryseg);
+        *paryseg = * (face *) fastlookup(misseglist, i);
+      }
+      misseglist->restart();
+
+      recoversegments(misseglist, 1, 0);
+
+      if (misseglist->objects < ms) {
+        // The number of missing segments is reduced.
+        continue;
+      } else {
+        break;
+      }
+    }
+    if (b->verbose) {
+      printf("  %ld (%ld) segments are recovered (missing).\n", 
+             subsegs->items - misseglist->objects, misseglist->objects);
+    }
+  }
+
+  if (misseglist->objects > 0) {
+    // Third, trying to recover segments by doing more flips (fullsearch)
+    //   and adding Steiner points in the volume.
+    while (misseglist->objects > 0) {
+      ms = misseglist->objects;
+      for (i = 0; i < misseglist->objects; i++) {
+        subsegstack->newindex((void **) &paryseg);
+        *paryseg = * (face *) fastlookup(misseglist, i);
+      }
+      misseglist->restart();
+
+      recoversegments(misseglist, 1, 1);
+
+      if (misseglist->objects < ms) {
+        // The number of missing segments is reduced.
+        continue;
+      } else {
+        break;
+      }
+    }
+    if (b->verbose) {
+      printf("  Added %ld Steiner points in volume.\n", st_volref_count);
+    }
+  }
+
+  if (misseglist->objects > 0) {
+    // Last, trying to recover segments by doing more flips (fullsearch),
+    //   and adding Steiner points in the volume, and splitting segments.
+    long bak_inpoly_count = st_volref_count; //st_inpoly_count;
+    for (i = 0; i < misseglist->objects; i++) {
+      subsegstack->newindex((void **) &paryseg);
+      *paryseg = * (face *) fastlookup(misseglist, i);
+    }
+    misseglist->restart();
+
+    recoversegments(misseglist, 1, 2);
+
+    if (b->verbose) {
+      printf("  Added %ld Steiner points in segments.\n", st_segref_count);
+      if (st_volref_count > bak_inpoly_count) {
+        printf("  Added another %ld Steiner points in volume.\n", 
+               st_volref_count - bak_inpoly_count);
+      }
+    }
+    assert(misseglist->objects == 0l);
+  }
+
+
+  if (st_segref_count > 0) {
+    // Try to remove the Steiner points added in segments.
+    bak_segref_count = st_segref_count;
+    bak_volref_count = st_volref_count;
+    for (i = 0; i < subvertstack->objects; i++) {
+      // Get the Steiner point.
+      parypt = (point *) fastlookup(subvertstack, i);
+      rempt = *parypt;
+      if (!removevertexbyflips(rempt)) {
+        // Save it in list.
+        bdrysteinerptlist->newindex((void **) &parypt);
+        *parypt = rempt;
+      }
+    }
+    if (b->verbose) {
+      if (st_segref_count < bak_segref_count) {
+        if (bak_volref_count < st_volref_count) {
+          printf("  Suppressed %ld Steiner points in segments.\n", 
+                 st_volref_count - bak_volref_count);
+        }
+        if ((st_segref_count + (st_volref_count - bak_volref_count)) <
+            bak_segref_count) {
+          printf("  Removed %ld Steiner points in segments.\n", 
+                 bak_segref_count - 
+                   (st_segref_count + (st_volref_count - bak_volref_count)));
+        }
+      }
+    }
+    subvertstack->restart();
+  }
+
+
+  tv = clock();
+
+  if (b->verbose) {
+    printf("  Recovering facets.\n");
+  }
+
+  // Subfaces will be introduced.
+  checksubfaceflag = 1;
+
+  misshlist = new arraypool(sizeof(face), 8);
+
+  // Randomly order the subfaces.
+  subfaces->traversalinit();
+  for (i = 0; i < subfaces->items; i++) {
+    s = randomnation(i + 1);
+    // Move the s-th subface to the i-th.
+    subfacstack->newindex((void **) &parysh);
+    *parysh = * (face *) fastlookup(subfacstack, s);
+    // Put i-th subface to be the s-th.
+    searchsh.sh = shellfacetraverse(subfaces);
+    parysh = (face *) fastlookup(subfacstack, s);
+    *parysh = searchsh;
+  }
+
+  ms = subfaces->items;
+  nit = 0; 
+  b->fliplinklevel = -1; // Init.
+  if (b->fliplinklevel < 0) {
+    autofliplinklevel = 1; // Init value.
+  }
+
+  while (1) {
+    recoversubfaces(misshlist, 0);
+
+    if (misshlist->objects > 0) {
+      if (b->fliplinklevel >= 0) {
+        break;
+      } else {
+        if (misshlist->objects >= ms) {
+          nit++;
+          if (nit >= 3) {
+            //break;
+            // Do the last round with unbounded flip link level.
+            b->fliplinklevel = 100000;
+          }
+        } else {
+          ms = misshlist->objects;
+          if (nit > 0) {
+            nit--;
+          }
+        }
+        for (i = 0; i < misshlist->objects; i++) {
+          subfacstack->newindex((void **) &parysh);
+          *parysh = * (face *) fastlookup(misshlist, i);
+        }
+        misshlist->restart();
+        autofliplinklevel+=b->fliplinklevelinc;
+      }
+    } else {
+      // All subfaces are recovered.
+      break;
+    }
+  } // while (1)
+
+  if (b->verbose) {
+    printf("  %ld (%ld) subfaces are recovered (missing).\n", 
+           subfaces->items - misshlist->objects, misshlist->objects);
+  }
+
+  if (misshlist->objects > 0) {
+    // There are missing subfaces. Add Steiner points.
+    for (i = 0; i < misshlist->objects; i++) {
+      subfacstack->newindex((void **) &parysh);
+      *parysh = * (face *) fastlookup(misshlist, i);
+    }
+    misshlist->restart();
+
+    recoversubfaces(NULL, 1);
+
+    if (b->verbose) {
+      printf("  Added %ld Steiner points in facets.\n", st_facref_count);
+    }
+  }
+
+
+  if (st_facref_count > 0) {
+    // Try to remove the Steiner points added in facets.
+    bak_facref_count = st_facref_count;
+    for (i = 0; i < subvertstack->objects; i++) {
+      // Get the Steiner point.
+      parypt = (point *) fastlookup(subvertstack, i);
+      rempt = *parypt;
+      if (!removevertexbyflips(*parypt)) {
+        // Save it in list.
+        bdrysteinerptlist->newindex((void **) &parypt);
+        *parypt = rempt;
+      }
+    }
+    if (b->verbose) {
+      if (st_facref_count < bak_facref_count) {
+        printf("  Removed %ld Steiner points in facets.\n", 
+               bak_facref_count - st_facref_count);
+      }
+    }
+    subvertstack->restart();
+  }
+
+
+  if (bdrysteinerptlist->objects > 0) {
+    if (b->verbose) {
+      printf("  %ld Steiner points remained in boundary.\n",
+             bdrysteinerptlist->objects);
+    }
+  } // if
+
+
+  // Accumulate the dynamic memory.
+  totalworkmemory += (misseglist->totalmemory + misshlist->totalmemory +
+                      bdrysteinerptlist->totalmemory);
+
+  delete bdrysteinerptlist;
+  delete misseglist;
+  delete misshlist;
+}
+
+////                                                                       ////
+////                                                                       ////
+//// steiner_cxx //////////////////////////////////////////////////////////////
+
+
+//// reconstruct_cxx //////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// carveholes()    Remove tetrahedra not in the mesh domain.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+
+void tetgenmesh::carveholes()
+{
+  arraypool *tetarray, *hullarray;
+  triface tetloop, neightet, *parytet, *parytet1;
+  triface *regiontets = NULL;
+  face checksh, *parysh;
+  face checkseg;
+  point ptloop, *parypt;
+  int t1ver;
+  int i, j, k;
+
+  if (!b->quiet) {
+    if (b->convex) {
+      printf("Marking exterior tetrahedra ...\n");
+    } else {
+      printf("Removing exterior tetrahedra ...\n");
+    }
+  }
+
+  // Initialize the pool of exterior tets.
+  tetarray = new arraypool(sizeof(triface), 10);
+  hullarray = new arraypool(sizeof(triface), 10);
+
+  // Collect unprotected tets and hull tets.
+  tetrahedrons->traversalinit();
+  tetloop.ver = 11; // The face opposite to dummypoint.
+  tetloop.tet = alltetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    if (ishulltet(tetloop)) {
+      // Is this side protected by a subface?
+      if (!issubface(tetloop)) {
+        // Collect an unprotected hull tet and tet.
+        infect(tetloop);
+        hullarray->newindex((void **) &parytet);
+        *parytet = tetloop;
+        // tetloop's face number is 11 & 3 = 3.
+        decode(tetloop.tet[3], neightet);
+        if (!infected(neightet)) {
+          infect(neightet);
+          tetarray->newindex((void **) &parytet);
+          *parytet = neightet;
+        }
+      }
+    }
+    tetloop.tet = alltetrahedrontraverse();
+  }
+
+  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);
+      if (locate(&(in->holelist[i]), &neightet) != OUTSIDE) {
+        // The tet 'neightet' contain this point.
+        if (!infected(neightet)) {
+          infect(neightet);
+          tetarray->newindex((void **) &parytet);
+          *parytet = neightet;
+          // Add its adjacent tet if it is not protected.
+          if (!issubface(neightet)) {
+            decode(neightet.tet[neightet.ver & 3], tetloop);
+            if (!infected(tetloop)) {
+              infect(tetloop);
+              if (ishulltet(tetloop)) {
+                hullarray->newindex((void **) &parytet);
+              } else {
+                tetarray->newindex((void **) &parytet);
+              }
+              *parytet = tetloop;
+            }
+          }
+          else {
+            // It is protected. Check if its adjacent tet is a hull tet.
+            decode(neightet.tet[neightet.ver & 3], tetloop);
+            if (ishulltet(tetloop)) {
+              // It is hull tet, add it into the list. Moreover, the subface
+              //   is dead, i.e., both sides are in exterior.
+              if (!infected(tetloop)) {
+                infect(tetloop);
+                hullarray->newindex((void **) &parytet);
+                *parytet = tetloop;
+              }
+            }
+            if (infected(tetloop)) {
+              // Both sides of this subface are in exterior.
+              tspivot(neightet, checksh);
+              sinfect(checksh); // Only queue it once.
+              subfacstack->newindex((void **) &parysh);
+              *parysh = checksh;
+            }
+          }
+        } // if (!infected(neightet))
+      } else {
+        // A hole point locates outside of the convex hull.
+        if (!b->quiet) {
+          printf("Warning:  The %d-th hole point ", i/3 + 1);
+          printf("lies outside the convex hull.\n");
+        }
+      }
+    } // i
+  } // if (in->numberofholes > 0)
+
+  if (b->regionattrib && (in->numberofregions > 0)) { // -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 region point.
+      neightet.tet = NULL;
+      randomsample(&(in->regionlist[i]), &neightet);
+      if (locate(&(in->regionlist[i]), &neightet) != OUTSIDE) {
+        regiontets[i/5] = neightet;
+      } else {
+        if (!b->quiet) {
+          printf("Warning:  The %d-th region point ", i/5+1);
+          printf("lies outside the convex hull.\n");
+        }
+        regiontets[i/5].tet = NULL;
+      }
+    }
+  }
+
+  // Collect all exterior tets (in concave place and in holes).
+  for (i = 0; i < tetarray->objects; i++) {
+    parytet = (triface *) fastlookup(tetarray, i);
+    j = (parytet->ver & 3); // j is the current face number.
+    // Check the other three adjacent tets.
+    for (k = 1; k < 4; k++) {
+      decode(parytet->tet[(j + k) % 4], neightet); 
+      // neightet may be a hull tet.
+      if (!infected(neightet)) {
+        // Is neightet protected by a subface.
+        if (!issubface(neightet)) {
+          // Not proected. Collect it. (It must not be a hull tet).
+          infect(neightet);
+          tetarray->newindex((void **) &parytet1);
+          *parytet1 = neightet;
+        } else {
+          // Protected. Check if it is a hull tet.
+          if (ishulltet(neightet)) {
+            // A hull tet. Collect it.
+            infect(neightet);
+            hullarray->newindex((void **) &parytet1);
+            *parytet1 = neightet;
+            // Both sides of this subface are exterior.
+            tspivot(neightet, checksh);
+            // Queue this subface (to be deleted later).
+            assert(!sinfected(checksh));
+            sinfect(checksh); // Only queue it once.
+            subfacstack->newindex((void **) &parysh);
+            *parysh = checksh;
+          }
+        }
+      } else {
+        // Both sides of this face are in exterior.
+        // If there is a subface. It should be collected.
+        if (issubface(neightet)) {
+          tspivot(neightet, checksh);
+          if (!sinfected(checksh)) {
+            sinfect(checksh);
+            subfacstack->newindex((void **) &parysh);
+            *parysh = checksh;
+          }
+        }
+      }
+    } // j, k
+  } // i
+
+  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 ", i+1);
+          printf("lies in the exterior of the domain.\n");
+        }
+        regiontets[i].tet = NULL;
+      }
+    }
+  }
+
+  // Collect vertices which point to infected tets. These vertices
+  //   may get deleted after the removal of exterior tets.
+  //   If -Y1 option is used, collect all Steiner points for removal.
+  //   The lists 'cavetetvertlist' and 'subvertstack' are re-used.
+  points->traversalinit();
+  ptloop = pointtraverse();
+  while (ptloop != NULL) {
+    if ((pointtype(ptloop) != UNUSEDVERTEX) &&
+        (pointtype(ptloop) != DUPLICATEDVERTEX)) {
+      decode(point2tet(ptloop), neightet);
+      if (infected(neightet)) {
+        cavetetvertlist->newindex((void **) &parypt);
+        *parypt = ptloop;
+      }
+      if (b->nobisect && (b->nobisect_param > 0)) { // -Y1
+        // Queue it if it is a Steiner point.
+        if (pointmark(ptloop) > 
+              (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
+          subvertstack->newindex((void **) &parypt);
+          *parypt = ptloop;
+        }
+      }
+    }
+    ptloop = pointtraverse();
+  }
+
+  if (!b->convex && (tetarray->objects > 0l)) { // No -c option.
+    // Remove exterior tets. Hull tets are updated.
+    arraypool *newhullfacearray;
+    triface hulltet, casface;
+    point pa, pb, pc;
+
+    newhullfacearray = new arraypool(sizeof(triface), 10);
+
+    // Create and save new hull tets.
+    for (i = 0; i < tetarray->objects; i++) {
+      parytet = (triface *) fastlookup(tetarray, i);
+      for (j = 0; j < 4; j++) {
+        decode(parytet->tet[j], tetloop);
+        if (!infected(tetloop)) {
+          // Found a new hull face (must be a subface).
+          tspivot(tetloop, checksh);
+          maketetrahedron(&hulltet);
+          pa = org(tetloop);
+          pb = dest(tetloop);
+          pc = apex(tetloop);
+          setvertices(hulltet, pb, pa, pc, dummypoint);
+          bond(tetloop, hulltet);
+          // Update the subface-to-tet map.
+          sesymself(checksh);
+          tsbond(hulltet, checksh);
+          // Update the segment-to-tet map.
+          for (k = 0; k < 3; k++) {
+            if (issubseg(tetloop)) {
+              tsspivot1(tetloop, checkseg);
+              tssbond1(hulltet, checkseg);
+              sstbond1(checkseg, hulltet);
+            }
+            enextself(tetloop);
+            eprevself(hulltet);
+          }
+          // Update the point-to-tet map.
+          setpoint2tet(pa, (tetrahedron) tetloop.tet);
+          setpoint2tet(pb, (tetrahedron) tetloop.tet);
+          setpoint2tet(pc, (tetrahedron) tetloop.tet);
+          // Save the exterior tet at this hull face. It still holds pointer
+          //   to the adjacent interior tet. Use it to connect new hull tets. 
+          newhullfacearray->newindex((void **) &parytet1);
+          parytet1->tet = parytet->tet;
+          parytet1->ver = j;
+        } // if (!infected(tetloop))
+      } // j
+    } // i
+
+    // Connect new hull tets.
+    for (i = 0; i < newhullfacearray->objects; i++) {
+      parytet = (triface *) fastlookup(newhullfacearray, i);
+      fsym(*parytet, neightet);
+      // Get the new hull tet.
+      fsym(neightet, hulltet);
+      for (j = 0; j < 3; j++) {
+        esym(hulltet, casface);
+        if (casface.tet[casface.ver & 3] == NULL) {
+          // Since the boundary of the domain may not be a manifold, we
+          //   find the adjacent hull face by traversing the tets in the
+          //   exterior (which are all infected tets).
+          neightet = *parytet;
+          while (1) {
+            fnextself(neightet);
+            if (!infected(neightet)) break;
+          }
+          if (!ishulltet(neightet)) {
+            // An interior tet. Get the new hull tet.
+            fsymself(neightet);
+            esymself(neightet);
+          } 
+          // Bond them together.
+          bond(casface, neightet);
+        }
+        enextself(hulltet);
+        enextself(*parytet);
+      } // j
+    } // i
+
+    if (subfacstack->objects > 0l) {
+      // Remove all subfaces which do not attach to any tetrahedron.
+      //   Segments which are not attached to any subfaces and tets
+      //   are deleted too.
+      face casingout, casingin;
+      long delsegcount = 0l;
+
+      for (i = 0; i < subfacstack->objects; i++) {
+        parysh = (face *) fastlookup(subfacstack, i);
+        if (i == 0) {
+          if (b->verbose) {
+            printf("Warning:  Removing an open face (%d, %d, %d)\n",
+                   pointmark(sorg(*parysh)), pointmark(sdest(*parysh)),
+                   pointmark(sapex(*parysh)));
+          }
+        }
+        // Dissolve this subface from face links.
+        for (j = 0; j < 3; j++) {         
+          spivot(*parysh, casingout);
+          sspivot(*parysh, checkseg);
+          if (casingout.sh != NULL) {
+            casingin = casingout;
+            while (1) {
+              spivot(casingin, checksh);
+              if (checksh.sh == parysh->sh) break;
+              casingin = checksh;
+            }
+            if (casingin.sh != casingout.sh) {
+              // Update the link: ... -> casingin -> casingout ->...
+              sbond1(casingin, casingout);
+            } else {
+              // Only one subface at this edge is left.
+              sdissolve(casingout);
+            }
+            if (checkseg.sh != NULL) {
+              // Make sure the segment does not connect to a dead one.
+              ssbond(casingout, checkseg);
+            }
+          } else {
+            if (checkseg.sh != NULL) {
+              // The segment is also dead.
+              if (delsegcount == 0) {
+                if (b->verbose) {
+                  printf("Warning:  Removing a dangling segment (%d, %d)\n",
+                       pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
+                }
+              }
+              shellfacedealloc(subsegs, checkseg.sh);
+              delsegcount++;
+            }
+          }
+          senextself(*parysh);
+        } // j
+        // Delete this subface.
+        shellfacedealloc(subfaces, parysh->sh);
+      } // i
+      if (b->verbose) {
+        printf("  Deleted %ld subfaces.\n", subfacstack->objects);
+        if (delsegcount > 0) {
+          printf("  Deleted %ld segments.\n", delsegcount);
+        }
+      }
+      subfacstack->restart();
+    } // if (subfacstack->objects > 0l)
+
+    if (cavetetvertlist->objects > 0l) {
+      // Some vertices may lie in exterior. Marke them as UNUSEDVERTEX.
+      long delvertcount = unuverts;
+      long delsteinercount = 0l;
+
+      for (i = 0; i < cavetetvertlist->objects; i++) {
+        parypt = (point *) fastlookup(cavetetvertlist, i);
+        decode(point2tet(*parypt), neightet);
+        if (infected(neightet)) {
+          // Found an exterior vertex.
+          if (pointmark(*parypt) > 
+                (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
+            // A Steiner point.
+            if (pointtype(*parypt) == FREESEGVERTEX) {
+              st_segref_count--;
+            } else if (pointtype(*parypt) == FREEFACETVERTEX) {
+              st_facref_count--;
+            } else {
+              assert(pointtype(*parypt) == FREEVOLVERTEX);
+              st_volref_count--;
+            }
+            delsteinercount++;
+            if (steinerleft > 0) steinerleft++;
+          }
+          setpointtype(*parypt, UNUSEDVERTEX);
+          unuverts++;
+        }
+      }
+
+      if (b->verbose) {
+        if (unuverts > delvertcount) {
+          if (delsteinercount > 0l) {
+            if (unuverts > (delvertcount + delsteinercount)) {
+              printf("  Removed %ld exterior input vertices.\n", 
+                     unuverts - delvertcount - delsteinercount);
+            }
+            printf("  Removed %ld exterior Steiner vertices.\n", 
+                   delsteinercount);
+          } else {
+            printf("  Removed %ld exterior input vertices.\n", 
+                   unuverts - delvertcount);
+          }
+        }
+      }
+      cavetetvertlist->restart();
+      // Comment: 'subvertstack' will be cleaned in routine
+      //   suppresssteinerpoints().
+    } // if (cavetetvertlist->objects > 0l)
+
+    // Update the hull size.
+    hullsize += (newhullfacearray->objects - hullarray->objects);
+
+    // Delete all exterior tets and old hull tets.
+    for (i = 0; i < tetarray->objects; i++) {
+      parytet = (triface *) fastlookup(tetarray, i);
+      tetrahedrondealloc(parytet->tet);
+    }
+    tetarray->restart();
+
+    for (i = 0; i < hullarray->objects; i++) {
+      parytet = (triface *) fastlookup(hullarray, i);
+      tetrahedrondealloc(parytet->tet);
+    }
+    hullarray->restart();
+
+    delete newhullfacearray;
+  } // if (!b->convex && (tetarray->objects > 0l))
+
+  if (b->convex && (tetarray->objects > 0l)) { // With -c option
+    // In this case, all exterior tets get a region marker '-1'.
+    assert(b->regionattrib > 0); // -A option must be enabled.
+    int attrnum = numelemattrib - 1;
+
+    for (i = 0; i < tetarray->objects; i++) {
+      parytet = (triface *) fastlookup(tetarray, i);
+      setelemattribute(parytet->tet, attrnum, -1);
+    }
+    tetarray->restart();
+
+    for (i = 0; i < hullarray->objects; i++) {
+      parytet = (triface *) fastlookup(hullarray, i);
+      uninfect(*parytet);
+    }
+    hullarray->restart();
+
+    if (subfacstack->objects > 0l) {
+      for (i = 0; i < subfacstack->objects; i++) {
+        parysh = (face *) fastlookup(subfacstack, i);
+        suninfect(*parysh);
+      }
+      subfacstack->restart();
+    }
+
+    if (cavetetvertlist->objects > 0l) {
+      cavetetvertlist->restart();
+    }
+  } // if (b->convex && (tetarray->objects > 0l))
+
+  if (b->regionattrib) { // With -A option.
+    if (!b->quiet) {
+      printf("Spreading region attributes.\n");
+    }
+    REAL volume;
+    int attr, maxattr = 0; // Choose a small number here.
+    int attrnum = numelemattrib - 1; 
+    // Comment: The element region marker is at the end of the list of
+    //   the element attributes.
+    int regioncount = 0;
+
+    // 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];
+          if (attr > maxattr) {
+            maxattr = attr;
+          }
+          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 (k = 0; k < 4; k++) {
+              decode(tetloop.tet[k], neightet);
+              // Is the adjacent already checked?
+              if (!infected(neightet)) {
+                // Is this side protected by a subface?
+                if (!issubface(neightet)) {
+                  infect(neightet);
+                  tetarray->newindex((void **) &parytet);
+                  *parytet = neightet;
+                }
+              }
+            } // k
+          } // j
+          regioncount++;
+        } // if (regiontets[i/5].tet != NULL)
+      } // i
+    }
+
+    // Set attributes for all tetrahedra.
+    attr = maxattr + 1;
+    tetrahedrons->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 (k = 0; k < 4; k++) {
+            decode(tetloop.tet[k], neightet);
+            // Is the adjacent tet already checked?
+            if (!infected(neightet)) {
+              // Is this side protected by a subface?
+              if (!issubface(neightet)) {
+                infect(neightet);
+                tetarray->newindex((void **) &parytet);
+                *parytet = neightet;
+              }
+            }
+          } // k
+        } // j
+        attr++; // Increase the attribute.
+        regioncount++;
+      }
+      tetloop.tet = tetrahedrontraverse();
+    }
+    // Until here, every tet has a region attribute.
+
+    // Uninfect processed tets.
+    tetrahedrons->traversalinit();
+    tetloop.tet = tetrahedrontraverse();
+    while (tetloop.tet != (tetrahedron *) NULL) {
+      uninfect(tetloop);
+      tetloop.tet = tetrahedrontraverse();
+    }
+
+    if (b->verbose) {
+      //assert(regioncount > 0);
+      if (regioncount > 1) {
+        printf("  Found %d subdomains.\n", regioncount);
+      } else {
+        printf("  Found %d domain.\n", regioncount);
+      }
+    }
+  } // if (b->regionattrib)
+
+  if (regiontets != NULL) {
+    delete [] regiontets;
+  }
+  delete tetarray;
+  delete hullarray;
+
+  if (!b->convex) { // No -c option
+    // The mesh is non-convex now.
+    nonconvex = 1;
+
+    // Push all hull tets into 'flipstack'.
+    tetrahedrons->traversalinit();
+    tetloop.ver = 11; // The face opposite to dummypoint.
+    tetloop.tet = alltetrahedrontraverse();
+    while (tetloop.tet != (tetrahedron *) NULL) {
+      if ((point) tetloop.tet[7] == dummypoint) {
+        fsym(tetloop, neightet);
+        flippush(flipstack, &neightet);
+      }
+      tetloop.tet = alltetrahedrontraverse();
+    }
+
+    flipconstraints fc;
+    fc.enqflag = 2;
+    long sliver_peel_count = lawsonflip3d(&fc);
+
+    if (sliver_peel_count > 0l) {
+      if (b->verbose) {
+        printf("  Removed %ld hull slivers.\n", sliver_peel_count);
+      }
+    }
+    unflipqueue->restart();
+  } // if (!b->convex)
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// reconstructmesh()    Reconstruct a tetrahedral mesh.                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::reconstructmesh()
+{
+  tetrahedron *ver2tetarray;
+  point *idx2verlist;
+  triface tetloop, checktet, prevchktet;
+  triface hulltet, face1, face2;
+  tetrahedron tptr;
+  face subloop, neighsh, nextsh;
+  face segloop;
+  shellface sptr;
+  point p[4], q[3];
+  REAL ori, attrib, volume;
+  REAL angtol, ang;
+  int eextras, marker = 0;
+  int bondflag;
+  int t1ver;
+  int idx, i, j, k;
+
+  if (!b->quiet) {
+    printf("Reconstructing mesh ...\n");
+  }
+
+  if (b->convex) { // -c option.
+    // Assume the mesh is convex. Exterior tets have region attribute -1.
+    assert(in->numberoftetrahedronattributes > 0);
+  } else {
+    // Assume the mesh is non-convex.
+    nonconvex = 1;
+  }
+
+  // Create a map from indices to vertices. 
+  makeindex2pointmap(idx2verlist);
+  // 'idx2verlist' has length 'in->numberofpoints + 1'.
+  if (in->firstnumber == 1) {
+    idx2verlist[0] = dummypoint; // Let 0th-entry be dummypoint.
+  }
+
+  // Allocate an array that maps each vertex to its adjacent tets.
+  ver2tetarray = new tetrahedron[in->numberofpoints + 1];
+  //for (i = 0; i < in->numberofpoints + 1; i++) {
+  for (i = in->firstnumber; i < in->numberofpoints + in->firstnumber; i++) {
+    setpointtype(idx2verlist[i], VOLVERTEX); // initial type.
+    ver2tetarray[i] = NULL;
+  }
+
+  // Create the tetrahedra and connect those that share a common face.
+  for (i = 0; i < in->numberoftetrahedra; i++) {
+    // Get the four vertices.
+    idx = i * in->numberofcorners;
+    for (j = 0; j < 4; j++) {
+      p[j] = idx2verlist[in->tetrahedronlist[idx++]];
+    }
+    // Check the orientation.
+    ori = orient3d(p[0], p[1], p[2], p[3]);
+    if (ori > 0.0) {
+      // Swap the first two vertices.
+      q[0] = p[0]; p[0] = p[1]; p[1] = q[0];
+    } else if (ori == 0.0) {
+      if (!b->quiet) {
+        printf("Warning:  Tet #%d is degenerate.\n", i + in->firstnumber);
+      }
+    }
+    // Create a new tetrahedron.
+    maketetrahedron(&tetloop); // tetloop.ver = 11.
+    setvertices(tetloop, p[0], p[1], p[2], p[3]);
+    // Set element attributes if they exist.
+    for (j = 0; j < in->numberoftetrahedronattributes; j++) {
+      idx = i * in->numberoftetrahedronattributes;
+      attrib = in->tetrahedronattributelist[idx + j];
+      setelemattribute(tetloop.tet, j, attrib);
+    }
+    // If -a switch is used (with no number follows) Set a volume
+    //   constraint if it exists.
+    if (b->varvolume) {
+      if (in->tetrahedronvolumelist != (REAL *) NULL) {
+        volume = in->tetrahedronvolumelist[i];
+      } else {
+        volume = -1.0;
+      }
+      setvolumebound(tetloop.tet, volume);
+    }
+    // Try connecting this tet to others that share the common faces.
+    for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
+      p[3] = oppo(tetloop);
+      // Look for other tets having this vertex.
+      idx = pointmark(p[3]);
+      tptr = ver2tetarray[idx];
+      // Link the current tet to the next one in the stack.
+      tetloop.tet[8 + tetloop.ver] = tptr;
+      // Push the current tet onto the stack.
+      ver2tetarray[idx] = encode(tetloop);
+      decode(tptr, checktet);
+      if (checktet.tet != NULL) {
+        p[0] =  org(tetloop); // a
+        p[1] = dest(tetloop); // b
+        p[2] = apex(tetloop); // c
+        prevchktet = tetloop;
+        do {
+          q[0] =  org(checktet); // a'
+          q[1] = dest(checktet); // b'
+          q[2] = apex(checktet); // c'
+          // Check the three faces at 'd' in 'checktet'.
+          bondflag = 0;
+          for (j = 0; j < 3; j++) {
+            // Go to the face [b',a',d], or [c',b',d], or [a',c',d].
+            esym(checktet, face2);
+            if (face2.tet[face2.ver & 3] == NULL) {
+              k = ((j + 1) % 3);
+              if (q[k] == p[0]) {   // b', c', a' = a
+                if (q[j] == p[1]) { // a', b', c' = b
+                  // [#,#,d] is matched to [b,a,d].
+                  esym(tetloop, face1);
+                  bond(face1, face2);
+                  bondflag++;
+                }
+              }
+              if (q[k] == p[1]) {   // b',c',a' = b
+                if (q[j] == p[2]) { // a',b',c' = c
+                  // [#,#,d] is matched to [c,b,d].
+                  enext(tetloop, face1);
+                  esymself(face1);
+                  bond(face1, face2);
+                  bondflag++;
+                }
+              }
+              if (q[k] == p[2]) {   // b',c',a' = c
+                if (q[j] == p[0]) { // a',b',c' = a
+                  // [#,#,d] is matched to [a,c,d].
+                  eprev(tetloop, face1);
+                  esymself(face1);
+                  bond(face1, face2);
+                  bondflag++;
+                }
+              }
+            } else {
+              bondflag++;
+            }
+            enextself(checktet);
+          } // j
+          // Go to the next tet in the link.
+          tptr = checktet.tet[8 + checktet.ver];
+          if (bondflag == 3) {
+            // All three faces at d in 'checktet' have been connected.
+            // It can be removed from the link.            
+            prevchktet.tet[8 + prevchktet.ver] = tptr;
+          } else {
+            // Bakup the previous tet in the link.
+            prevchktet = checktet;
+          }
+          decode(tptr, checktet);
+        } while (checktet.tet != NULL);
+      } // if (checktet.tet != NULL)
+    } // for (tetloop.ver = 0; ...
+  } // i
+
+  // Remember a tet of the mesh.
+  recenttet = tetloop;
+
+  // Create hull tets, create the point-to-tet map, and clean up the
+  //   temporary spaces used in each tet. 
+  hullsize = tetrahedrons->items;
+
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    tptr = encode(tetloop);
+    for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
+      if (tetloop.tet[tetloop.ver] == NULL) {
+        // Create a hull tet.
+        maketetrahedron(&hulltet);
+        p[0] =  org(tetloop);
+        p[1] = dest(tetloop);
+        p[2] = apex(tetloop);
+        setvertices(hulltet, p[1], p[0], p[2], dummypoint);
+        bond(tetloop, hulltet);
+        // Try connecting this to others that share common hull edges.
+        for (j = 0; j < 3; j++) {
+          fsym(hulltet, face2);
+          while (1) {
+            if (face2.tet == NULL) break;
+            esymself(face2);
+            if (apex(face2) == dummypoint) break;
+            fsymself(face2);
+          }
+          if (face2.tet != NULL) {
+            // Found an adjacent hull tet.
+            assert(face2.tet[face2.ver & 3] == NULL);
+            esym(hulltet, face1);
+            bond(face1, face2);
+          }
+          enextself(hulltet);
+        }
+        //hullsize++;
+      }
+      // Create the point-to-tet map.
+      setpoint2tet((point) (tetloop.tet[4 + tetloop.ver]), tptr);
+      // Clean the temporary used space.
+      tetloop.tet[8 + tetloop.ver] = NULL;
+    }
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  hullsize = tetrahedrons->items - hullsize;
+
+  // Subfaces will be inserted into the mesh. 
+  if (in->trifacelist != NULL) {
+    // A .face file is given. It may contain boundary faces. Insert them.
+    for (i = 0; i < in->numberoftrifaces; i++) {
+      // Is it a subface?
+      if (in->trifacemarkerlist != NULL) {
+        marker = in->trifacemarkerlist[i];
+      } else {
+        // Face markers are not available. Assume all of them are subfaces.
+        marker = 1;
+      }
+      if (marker > 0) {
+        idx = i * 3;
+        for (j = 0; j < 3; j++) {
+          p[j] = idx2verlist[in->trifacelist[idx++]];
+        }
+        // Search the subface.
+        bondflag = 0;
+        // Make sure all vertices are in the mesh. Avoid crash.
+        for (j = 0; j < 3; j++) {
+          decode(point2tet(p[j]), checktet);
+          if (checktet.tet == NULL) break;
+        }
+        if ((j == 3) && getedge(p[0], p[1], &checktet)) {
+          tetloop = checktet;
+          q[2] = apex(checktet);
+          while (1) {
+            if (apex(tetloop) == p[2]) {
+              // Found the face.
+              // Check if there exist a subface already?
+              tspivot(tetloop, neighsh); 
+              if (neighsh.sh != NULL) {
+                // Found a duplicated subface. 
+                // This happens when the mesh was generated by other mesher.
+                bondflag = 0;
+              } else {
+                bondflag = 1;
+              }
+              break;
+            }
+            fnextself(tetloop);
+            if (apex(tetloop) == q[2]) break;
+          }
+        }
+        if (bondflag) {
+          // Create a new subface.
+          makeshellface(subfaces, &subloop);
+          setshvertices(subloop, p[0], p[1], p[2]);
+          // Create the point-to-subface map.
+          sptr = sencode(subloop);
+          for (j = 0; j < 3; j++) {
+            setpointtype(p[j], FACETVERTEX); // initial type.
+            setpoint2sh(p[j], sptr);
+          }
+          if (in->trifacemarkerlist != NULL) {
+            setshellmark(subloop, in->trifacemarkerlist[i]);
+          }
+          // Insert the subface into the mesh.
+          tsbond(tetloop, subloop);
+          fsymself(tetloop);
+          sesymself(subloop);
+          tsbond(tetloop, subloop);
+        } else {
+          if (!b->quiet) {
+            if (neighsh.sh == NULL) {
+              printf("Warning:  Subface #%d [%d,%d,%d] is missing.\n", 
+                     i + in->firstnumber, pointmark(p[0]), pointmark(p[1]),
+                     pointmark(p[2]));
+            } else {
+              printf("Warning: Ignore a dunplicated subface #%d [%d,%d,%d].\n", 
+                     i + in->firstnumber, pointmark(p[0]), pointmark(p[1]),
+                     pointmark(p[2]));
+            }
+          }
+        } // if (bondflag)
+      } // if (marker > 0)
+    } // i
+  } // if (in->trifacelist)
+
+  // Indentify subfaces from the mesh.
+  // Create subfaces for hull faces (if they're not subface yet) and
+  //   interior faces which separate two different materials.
+  eextras = in->numberoftetrahedronattributes;
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
+      tspivot(tetloop, neighsh);
+      if (neighsh.sh == NULL) {
+        bondflag = 0;
+        fsym(tetloop, checktet);
+        if (ishulltet(checktet)) {
+          // A hull face.
+          if (!b->convex) {
+            bondflag = 1;  // Insert a hull subface.
+          }
+        } else {
+          if (eextras > 0) {
+            if (elemattribute(tetloop.tet, eextras - 1) !=
+                elemattribute(checktet.tet, eextras - 1)) {
+              bondflag = 1; // Insert an interior interface.
+            }
+          }
+        }
+        if (bondflag) {
+          // Create a new subface.
+          makeshellface(subfaces, &subloop);
+          p[0] = org(tetloop);
+          p[1] = dest(tetloop);
+          p[2] = apex(tetloop);
+          setshvertices(subloop, p[0], p[1], p[2]);
+          // Create the point-to-subface map.
+          sptr = sencode(subloop);
+          for (j = 0; j < 3; j++) {
+            setpointtype(p[j], FACETVERTEX); // initial type.
+            setpoint2sh(p[j], sptr);
+          }
+          setshellmark(subloop, 0); // Default marker.
+          // Insert the subface into the mesh.
+          tsbond(tetloop, subloop);
+          sesymself(subloop);
+          tsbond(checktet, subloop);
+        } // if (bondflag)
+      } // if (neighsh.sh == NULL)
+    }
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  // Connect subfaces together. 
+  subfaces->traversalinit();
+  subloop.shver = 0;
+  subloop.sh = shellfacetraverse(subfaces);
+  while (subloop.sh != (shellface *) NULL) {
+    for (i = 0; i < 3; i++) {
+      spivot(subloop, neighsh);
+      if (neighsh.sh == NULL) {
+        // Form a subface ring by linking all subfaces at this edge.
+        // Traversing all faces of the tets at this edge.
+        stpivot(subloop, tetloop);
+        q[2] = apex(tetloop);
+        neighsh = subloop;
+        while (1) {
+          fnextself(tetloop);
+          tspivot(tetloop, nextsh);
+          if (nextsh.sh != NULL) {
+            // Link neighsh <= nextsh.
+            sbond1(neighsh, nextsh);
+            neighsh = nextsh;
+          }
+          if (apex(tetloop) == q[2]) {
+            assert(nextsh.sh == subloop.sh); // It's a ring.
+            break;
+          }
+        } // while (1)
+      } // if (neighsh.sh == NULL)
+      senextself(subloop);
+    }
+    subloop.sh = shellfacetraverse(subfaces);
+  }
+
+
+  // Segments will be introduced. 
+  if (in->edgelist != NULL) {
+    // A .edge file is given. It may contain boundary edges. Insert them.
+    for (i = 0; i < in->numberofedges; i++) {
+      // Is it a segment?
+      if (in->edgemarkerlist != NULL) {
+        marker = in->edgemarkerlist[i];
+      } else {
+        // Edge markers are not available. Assume all of them are segments.
+        marker = 1;
+      }
+      if (marker != 0) { 
+        // Insert a segment.
+        idx = i * 2;
+        for (j = 0; j < 2; j++) {
+          p[j] = idx2verlist[in->edgelist[idx++]];
+        }
+        // Make sure all vertices are in the mesh. Avoid crash.
+        for (j = 0; j < 2; j++) {
+          decode(point2tet(p[j]), checktet);
+          if (checktet.tet == NULL) break;
+        }
+        // Search the segment.
+        if ((j == 2) && getedge(p[0], p[1], &checktet)) {
+          // Create a new subface.
+          makeshellface(subsegs, &segloop);
+          setshvertices(segloop, p[0], p[1], NULL);
+          // Create the point-to-segment map.
+          sptr = sencode(segloop);
+          for (j = 0; j < 2; j++) {
+            setpointtype(p[j], RIDGEVERTEX); // initial type.
+            setpoint2sh(p[j], sptr);
+          }
+          if (in->edgemarkerlist != NULL) {
+            setshellmark(segloop, marker);
+          }
+          // Insert the segment into the mesh.
+          tetloop = checktet;
+          q[2] = apex(checktet);
+          subloop.sh = NULL;
+          while (1) {
+            tssbond1(tetloop, segloop);
+            tspivot(tetloop, subloop);
+            if (subloop.sh != NULL) {
+              ssbond1(subloop, segloop);
+              sbond1(segloop, subloop);
+            }
+            fnextself(tetloop);
+            if (apex(tetloop) == q[2]) break;
+          } // while (1)
+          // Remember an adjacent tet for this segment.
+          sstbond1(segloop, tetloop);
+        } else {
+          if (!b->quiet) {
+            printf("Warning:  Segment #%d [%d,%d] is missing.\n", 
+                   i + in->firstnumber, pointmark(p[0]), pointmark(p[1]));
+          }
+        }
+      } // if (marker != 0)
+    } // i
+  } // if (in->edgelist)
+
+  // Identify segments from the mesh. 
+  // Create segments for non-manifold edges (which are shared by more 
+  //   than two subfaces), and for non-coplanar edges, i.e., two subfaces
+  //   form an dihedral angle > 'b->facet_ang_tol' (degree).
+  angtol = b->facet_ang_tol / 180.0 * PI;
+  subfaces->traversalinit();
+  subloop.shver = 0;
+  subloop.sh = shellfacetraverse(subfaces);
+  while (subloop.sh != (shellface *) NULL) {
+    for (i = 0; i < 3; i++) {
+      sspivot(subloop, segloop);
+      if (segloop.sh == NULL) {
+        // Check if this edge is a segment.
+        bondflag = 0;
+        // Counter the number of subfaces at this edge.
+        idx = 0;
+        nextsh = subloop;
+        while (1) {
+          idx++;
+          spivotself(nextsh);
+          if (nextsh.sh == subloop.sh) break;
+        }
+        if (idx != 2) {
+          // It's a non-manifold edge. Insert a segment.
+          p[0] = sorg(subloop);
+          p[1] = sdest(subloop);
+          bondflag = 1;
+        } else {
+          spivot(subloop, neighsh);
+          if (shellmark(subloop) != shellmark(neighsh)) {
+            // It's an interior interface. Insert a segment.
+            p[0] = sorg(subloop);
+            p[1] = sdest(subloop);
+            bondflag = 1;
+          } else {
+            if (!b->convex) {
+              // Check the dihedral angle formed by the two subfaces.
+              p[0] = sorg(subloop);
+              p[1] = sdest(subloop);
+              p[2] = sapex(subloop);
+              p[3] = sapex(neighsh);
+              ang = facedihedral(p[0], p[1], p[2], p[3]);
+              if (ang > PI) ang = 2 * PI - ang;
+              if (ang < angtol) {
+                bondflag = 1;
+              }
+            }
+          }
+        }
+        if (bondflag) {
+          // Create a new segment.
+          makeshellface(subsegs, &segloop);
+          setshvertices(segloop, p[0], p[1], NULL);
+          // Create the point-to-segment map.
+          sptr = sencode(segloop);
+          for (j = 0; j < 2; j++) {
+            setpointtype(p[j], RIDGEVERTEX); // initial type.
+            setpoint2sh(p[j], sptr);
+          }
+          setshellmark(segloop, 0); // Initially has no marker.
+          // Insert the subface into the mesh.
+          stpivot(subloop, tetloop);
+          q[2] = apex(tetloop);
+          while (1) {
+            tssbond1(tetloop, segloop);
+            tspivot(tetloop, neighsh);
+            if (neighsh.sh != NULL) {
+              ssbond1(neighsh, segloop);
+            }
+            fnextself(tetloop);
+            if (apex(tetloop) == q[2]) break;
+          } // while (1)
+          // Remember an adjacent tet for this segment.
+          sstbond1(segloop, tetloop);
+          sbond1(segloop, subloop);
+        } // if (bondflag)
+      } // if (neighsh.sh == NULL)
+      senextself(subloop);
+    } // i
+    subloop.sh = shellfacetraverse(subfaces);
+  }
+
+  // Remember the number of input segments.
+  insegments = subsegs->items;
+
+  if (!b->nobisect || checkconstraints) {
+    // Mark Steiner points on segments and facets.
+    //   - all vertices which remaining type FEACTVERTEX become
+    //     Steiner points in facets (= FREEFACERVERTEX).
+    //   - vertices on segment need to be checked.
+    face* segperverlist;
+    int* idx2seglist;
+    face parentseg, nextseg;
+    verttype vt;
+    REAL area, len, l1, l2;
+    int fmarker;
+
+    makepoint2submap(subsegs, idx2seglist, segperverlist);
+
+    points->traversalinit();
+    point ptloop = pointtraverse();
+    while (ptloop != NULL) {
+      vt = pointtype(ptloop);
+      if (vt == VOLVERTEX) {
+        setpointtype(ptloop, FREEVOLVERTEX);
+        st_volref_count++;
+      } else if (vt == FACETVERTEX) {
+        setpointtype(ptloop, FREEFACETVERTEX);
+        st_facref_count++;
+      } else if (vt == RIDGEVERTEX) {
+        idx = pointmark(ptloop) - in->firstnumber;
+        if ((idx2seglist[idx + 1] - idx2seglist[idx]) == 2) {
+          i = idx2seglist[idx];
+          parentseg = segperverlist[i];
+          nextseg = segperverlist[i + 1];
+          sesymself(nextseg);
+          p[0] = sorg(nextseg);
+          p[1] = sdest(parentseg);
+          // Check if three points p[0], ptloop, p[2] are (nearly) collinear.
+          len = distance(p[0], p[1]);
+          l1 = distance(p[0], ptloop);
+          l2 = distance(ptloop, p[1]);
+          if (((l1 + l2 - len) / len) < b->epsilon) {
+            // They are (nearly) collinear.
+            setpointtype(ptloop, FREESEGVERTEX);
+            // Connect nextseg and parentseg together at ptloop.
+            senextself(nextseg);
+            senext2self(parentseg);
+            sbond(nextseg, parentseg);
+            st_segref_count++;
+          }
+        }
+      }
+      ptloop = pointtraverse();
+    }
+
+    // Are there area constraints?
+    if (b->quality && (in->facetconstraintlist != (REAL *) NULL)) {
+      // Set maximum area constraints on facets.
+      for (i = 0; i < in->numberoffacetconstraints; i++) {
+        fmarker = (int) in->facetconstraintlist[i * 2];
+        area = in->facetconstraintlist[i * 2 + 1];
+        subfaces->traversalinit();
+        subloop.sh = shellfacetraverse(subfaces);
+        while (subloop.sh != NULL) {
+          if (shellmark(subloop) == fmarker) {
+            setareabound(subloop, area);
+          }
+          subloop.sh = shellfacetraverse(subfaces);
+        }
+      }
+    }
+
+    // Are there length constraints?
+    if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
+      // Set maximum length constraints on segments.
+      int e1, e2;
+      for (i = 0; i < in->numberofsegmentconstraints; i++) {
+        e1 = (int) in->segmentconstraintlist[i * 3];
+        e2 = (int) in->segmentconstraintlist[i * 3 + 1];
+        len = in->segmentconstraintlist[i * 3 + 2];
+        // Search for edge [e1, e2].
+        idx = e1 - in->firstnumber;
+        for (j = idx2seglist[idx]; j <  idx2seglist[idx + 1]; j++) {
+          parentseg = segperverlist[j];
+          if (pointmark(sdest(parentseg)) == e2) {
+            setareabound(parentseg, len);
+            break;
+          }
+        }
+      }
+    }
+
+    delete [] idx2seglist;
+    delete [] segperverlist;
+  }
+
+
+  // Set global flags.
+  checksubsegflag = 1;
+  checksubfaceflag = 1;
+
+  delete [] idx2verlist;
+  delete [] ver2tetarray;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// scoutpoint()    Search a point in mesh.                                   //
+//                                                                           //
+// This function searches the point in a mesh whose domain may be not convex.//
+// In case of a convex domain, the locate() function is sufficient.          //
+//                                                                           //
+// If 'randflag' is used, randomly select a start searching tet.  Otherwise, //
+// start searching directly from 'searchtet'.                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::scoutpoint(point searchpt, triface *searchtet, int randflag)
+{
+  point pa, pb, pc, pd;
+  enum locateresult loc = OUTSIDE;
+  REAL vol, ori1, ori2 = 0, ori3 = 0, ori4 = 0;
+  int t1ver;
+
+
+  // Randomly select a good starting tet.
+  if (randflag) {
+    randomsample(searchpt, searchtet);
+  } else {
+    if (searchtet->tet == NULL) {
+      *searchtet = recenttet;
+    }
+  }
+  loc = locate(searchpt, searchtet);
+
+  if (loc == OUTSIDE) {
+    if (b->convex) { // -c option
+      // The point lies outside of the convex hull.
+      return (int) loc;
+    }
+    // Test if it lies nearly on the hull face.
+    // Reuse vol, ori1.
+    pa = org(*searchtet);
+    pb = dest(*searchtet);
+    pc = apex(*searchtet);
+    vol = triarea(pa, pb, pc);
+    ori1 = orient3dfast(pa, pb, pc, searchpt);
+    if (fabs(ori1 / vol) < b->epsilon) {
+      loc = ONFACE; // On face (or on edge, or on vertex).
+      fsymself(*searchtet);
+    }
+  }
+
+  if (loc != OUTSIDE) {
+    // Round the result of location.
+    pa = org(*searchtet);
+    pb = dest(*searchtet);
+    pc = apex(*searchtet);
+    pd = oppo(*searchtet);
+    vol = orient3dfast(pa, pb, pc, pd);
+    ori1 = orient3dfast(pa, pb, pc, searchpt);
+    ori2 = orient3dfast(pb, pa, pd, searchpt);
+    ori3 = orient3dfast(pc, pb, pd, searchpt);
+    ori4 = orient3dfast(pa, pc, pd, searchpt);
+    if (fabs(ori1 / vol) < b->epsilon) ori1 = 0;
+    if (fabs(ori2 / vol) < b->epsilon) ori2 = 0;
+    if (fabs(ori3 / vol) < b->epsilon) ori3 = 0;
+    if (fabs(ori4 / vol) < b->epsilon) ori4 = 0;
+  } else { // if (loc == OUTSIDE) {
+    // Do a brute force search for the point (with rounding).
+    tetrahedrons->traversalinit();
+    searchtet->tet = tetrahedrontraverse();
+    while (searchtet->tet != NULL) {
+      pa = org(*searchtet);
+      pb = dest(*searchtet);
+      pc = apex(*searchtet);
+      pd = oppo(*searchtet);
+
+      vol = orient3dfast(pa, pb, pc, pd); 
+      if (vol < 0) {
+        ori1 = orient3dfast(pa, pb, pc, searchpt);
+        if (fabs(ori1 / vol) < b->epsilon) ori1 = 0; // Rounding.
+        if (ori1 <= 0) {
+          ori2 = orient3dfast(pb, pa, pd, searchpt);
+          if (fabs(ori2 / vol) < b->epsilon) ori2 = 0;
+          if (ori2 <= 0) {
+            ori3 = orient3dfast(pc, pb, pd, searchpt);
+            if (fabs(ori3 / vol) < b->epsilon) ori3 = 0;
+            if (ori3 <= 0) {
+              ori4 = orient3dfast(pa, pc, pd, searchpt);
+              if (fabs(ori4 / vol) < b->epsilon) ori4 = 0;
+              if (ori4 <= 0) {
+                // Found the tet. Return its location. 
+                break;
+              } // ori4
+            } // ori3
+          } // ori2
+        } // ori1
+      }
+
+      searchtet->tet = tetrahedrontraverse();
+    } // while (searchtet->tet != NULL)
+    nonregularcount++;  // Re-use this counter.
+  }
+
+  if (searchtet->tet != NULL) {
+    // Return the point location.
+    if (ori1 == 0) { // on face [a,b,c]
+      if (ori2 == 0) { // on edge [a,b].
+        if (ori3 == 0) { // on vertex [b].
+          assert(ori4 != 0);
+          enextself(*searchtet); // [b,c,a,d]
+          loc = ONVERTEX;
+        } else {
+          if (ori4 == 0) { // on vertex [a]
+            loc =  ONVERTEX; // [a,b,c,d]
+          } else {    
+            loc =  ONEDGE; // [a,b,c,d]
+          }
+        }
+      } else { // ori2 != 0
+        if (ori3 == 0) { // on edge [b,c]
+          if (ori4 == 0) { // on vertex [c]
+            eprevself(*searchtet); // [c,a,b,d]
+            loc =  ONVERTEX;
+          } else {
+            enextself(*searchtet); // [b,c,a,d]
+            loc =  ONEDGE;
+          }
+        } else { // ori3 != 0
+          if (ori4 == 0) { // on edge [c,a]
+            eprevself(*searchtet); // [c,a,b,d]
+            loc =  ONEDGE;
+          } else {
+            loc =  ONFACE;
+          }
+        }
+      }
+    } else { // ori1 != 0
+      if (ori2 == 0) { // on face [b,a,d]
+        esymself(*searchtet); // [b,a,d,c]
+        if (ori3 == 0) { // on edge [b,d]
+          eprevself(*searchtet); // [d,b,a,c]
+          if (ori4 == 0) { // on vertex [d]                      
+            loc =  ONVERTEX;
+          } else {
+            loc =  ONEDGE;
+          }
+        } else { // ori3 != 0
+          if (ori4 == 0) { // on edge [a,d]
+            enextself(*searchtet); // [a,d,b,c]
+            loc =  ONEDGE;
+          } else {
+            loc =  ONFACE;
+          }
+        }
+      } else { // ori2 != 0
+        if (ori3 == 0) { // on face [c,b,d]
+          enextself(*searchtet);
+          esymself(*searchtet);
+          if (ori4 == 0) { // on edge [c,d]
+            eprevself(*searchtet);
+            loc =  ONEDGE;
+          } else {
+            loc =  ONFACE;
+          }
+        } else {
+          if (ori4 == 0) { // on face [a,c,d]
+            eprevself(*searchtet);
+            esymself(*searchtet);
+            loc =  ONFACE;
+          } else { // inside tet [a,b,c,d]
+            loc =  INTETRAHEDRON;
+          } // ori4
+        } // ori3
+      } // ori2
+    } // ori1
+  } else {
+    loc = OUTSIDE;
+  }
+
+  return (int) loc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// getpointmeshsize()    Interpolate the mesh size at given point.           //
+//                                                                           //
+// 'iloc' indicates the location of the point w.r.t. 'searchtet'.  The size  //
+// is obtained by linear interpolation on the vertices of the tet.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc)
+{
+  point *pts, pa, pb, pc;
+  REAL volume, vol[4], wei[4];
+  REAL size;
+  int i;
+
+  size = 0;
+
+  if (iloc == (int) INTETRAHEDRON) {
+    pts = (point *) &(searchtet->tet[4]);
+    assert(pts[3] != dummypoint);
+    // Only do interpolation if all vertices have non-zero sizes.
+    if ((pts[0][pointmtrindex] > 0) && (pts[1][pointmtrindex] > 0) &&
+        (pts[2][pointmtrindex] > 0) && (pts[3][pointmtrindex] > 0)) {
+      // P1 interpolation.
+      volume = orient3dfast(pts[0], pts[1], pts[2], pts[3]);
+      vol[0] = orient3dfast(searchpt, pts[1], pts[2], pts[3]);
+      vol[1] = orient3dfast(pts[0], searchpt, pts[2], pts[3]);
+      vol[2] = orient3dfast(pts[0], pts[1], searchpt, pts[3]);
+      vol[3] = orient3dfast(pts[0], pts[1], pts[2], searchpt);
+      for (i = 0; i < 4; i++) {
+        wei[i] = fabs(vol[i] / volume);
+        size += (wei[i] * pts[i][pointmtrindex]);
+      }
+    }
+  } else if (iloc == (int) ONFACE) {
+    pa = org(*searchtet);
+    pb = dest(*searchtet);
+    pc = apex(*searchtet);
+    if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) &&
+        (pc[pointmtrindex] > 0)) {
+      volume = triarea(pa, pb, pc);
+      vol[0] = triarea(searchpt, pb, pc);
+      vol[1] = triarea(pa, searchpt, pc);
+      vol[2] = triarea(pa, pb, searchpt);
+      size = (vol[0] / volume) * pa[pointmtrindex]
+           + (vol[1] / volume) * pb[pointmtrindex]
+           + (vol[2] / volume) * pc[pointmtrindex];
+    }
+  } else if (iloc == (int) ONEDGE) {
+    pa = org(*searchtet);
+    pb = dest(*searchtet);
+    if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0)) {
+      volume = distance(pa, pb);
+      vol[0] = distance(searchpt, pb);
+      vol[1] = distance(pa, searchpt);
+      size = (vol[0] / volume) * pa[pointmtrindex]
+           + (vol[1] / volume) * pb[pointmtrindex];
+    }
+  } else if (iloc == (int) ONVERTEX) {
+    pa = org(*searchtet);
+    if (pa[pointmtrindex] > 0) {
+      size = pa[pointmtrindex];
+    }
+  }
+
+  return size;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// interpolatemeshsize()    Interpolate the mesh size from a background mesh //
+//                          (source) to the current mesh (destination).      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::interpolatemeshsize()
+{
+  triface searchtet;
+  point ploop;
+  REAL minval = 0.0, maxval = 0.0;
+  int iloc;
+  int count;
+
+  if (!b->quiet) {
+    printf("Interpolating mesh size ...\n");
+  }
+
+  long bak_nonregularcount = nonregularcount;
+  nonregularcount = 0l; // Count the number of (slow) global searches.
+  long baksmaples = bgm->samples;
+  bgm->samples = 3l;
+  count = 0; // Count the number of interpolated points.
+
+  // Interpolate sizes for all points in the current mesh.
+  points->traversalinit();
+  ploop = pointtraverse();
+  while (ploop != NULL) {
+    // Search a tet in bgm which containing this point.
+    searchtet.tet = NULL;
+    iloc = bgm->scoutpoint(ploop, &searchtet, 1); // randflag = 1
+    if (iloc != (int) OUTSIDE) {
+      // Interpolate the mesh size.
+      ploop[pointmtrindex] = bgm->getpointmeshsize(ploop, &searchtet, iloc);
+      setpoint2bgmtet(ploop, bgm->encode(searchtet));
+      if (count == 0) {
+        // This is the first interpolated point.
+        minval = maxval = ploop[pointmtrindex];
+      } else {
+        if (ploop[pointmtrindex] < minval) {
+          minval = ploop[pointmtrindex];
+        }
+        if (ploop[pointmtrindex] > maxval) {
+          maxval = ploop[pointmtrindex];
+        }
+      }
+      count++;
+    } else {
+      if (!b->quiet) {
+        printf("Warnning:  Failed to locate point %d in source mesh.\n",
+               pointmark(ploop));
+      }
+    }
+    ploop = pointtraverse();
+  }
+
+  if (b->verbose) {
+    printf("  Interoplated %d points.\n", count);
+    if (nonregularcount > 0l) {
+      printf("  Performed %ld brute-force searches.\n", nonregularcount);
+    }
+    printf("  Size rangle [%.17g, %.17g].\n", minval, maxval);
+  }
+
+  bgm->samples = baksmaples;
+  nonregularcount = bak_nonregularcount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertconstrainedpoints()    Insert a list of points into the mesh.       //
+//                                                                           //
+// Assumption:  The bounding box of the insert point set should be no larger //
+// than the bounding box of the mesh.  (Required by point sorting).          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::insertconstrainedpoints(point *insertarray, int arylen,
+                                         int rejflag)
+{
+  triface searchtet, spintet;
+  face splitsh;
+  face splitseg;
+  insertvertexflags ivf;
+  flipconstraints fc;
+  int randflag = 0;
+  int t1ver;
+  int i;
+
+  if (b->verbose) {
+    printf("  Inserting %d constrained points\n", arylen);
+  }
+
+  if (b->no_sort) { // -b/1 option.
+    if (b->verbose) {
+      printf("  Using the input order.\n"); 
+    }
+  } else {
+    if (b->verbose) {
+      printf("  Permuting vertices.\n"); 
+    }
+    point swappoint;
+    int randindex;
+    srand(arylen);
+    for (i = 0; i < arylen; i++) {
+      randindex = rand() % (i + 1); 
+      swappoint = insertarray[i];
+      insertarray[i] = insertarray[randindex];
+      insertarray[randindex] = swappoint;
+    }
+    if (b->brio_hilbert) { // -b1 option
+      if (b->verbose) {
+        printf("  Sorting vertices.\n"); 
+      }
+      hilbert_init(in->mesh_dim);
+      int ngroup = 0; 
+      brio_multiscale_sort(insertarray, arylen, b->brio_threshold, 
+                           b->brio_ratio, &ngroup);
+    } else { // -b0 option.
+      randflag = 1;
+    } // if (!b->brio_hilbert)
+  } // if (!b->no_sort)
+
+  long bak_nonregularcount = nonregularcount;
+  nonregularcount = 0l;
+  long baksmaples = samples;
+  samples = 3l; // Use at least 3 samples. Updated in randomsample().
+
+  long bak_seg_count = st_segref_count;
+  long bak_fac_count = st_facref_count;
+  long bak_vol_count = st_volref_count;
+
+  // Initialize the insertion parameters. 
+  if (b->incrflip) { // -l option
+    // Use incremental flip algorithm.
+    ivf.bowywat = 0; 
+    ivf.lawson = 1;
+    ivf.validflag = 0; // No need to validate the cavity.
+    fc.enqflag = 2;
+  } else {
+    // Use Bowyer-Watson algorithm.
+    ivf.bowywat = 1; 
+    ivf.lawson = 0;
+    ivf.validflag = 1; // Validate the B-W cavity.
+  }
+  ivf.rejflag = rejflag;
+  ivf.chkencflag = 0; 
+  ivf.sloc = (int) INSTAR;
+  ivf.sbowywat = 3; 
+  ivf.splitbdflag = 1;
+  ivf.respectbdflag = 1;
+  ivf.assignmeshsize = b->metric;
+
+  encseglist = new arraypool(sizeof(face), 8);
+  encshlist = new arraypool(sizeof(badface), 8);
+
+  // Insert the points.
+  for (i = 0; i < arylen; i++) {
+    // Find the location of the inserted point.
+    // Do not use 'recenttet', since the mesh may be non-convex.
+    searchtet.tet = NULL; 
+    ivf.iloc = scoutpoint(insertarray[i], &searchtet, randflag);
+
+    // Decide the right type for this point.
+    setpointtype(insertarray[i], FREEVOLVERTEX); // Default.
+    splitsh.sh = NULL;
+    splitseg.sh = NULL;
+    if (ivf.iloc == (int) ONEDGE) {
+      if (issubseg(searchtet)) {
+        tsspivot1(searchtet, splitseg);
+        setpointtype(insertarray[i], FREESEGVERTEX);
+        //ivf.rejflag = 0;
+      } else {
+        // Check if it is a subface edge.
+        spintet = searchtet;
+        while (1) {
+          if (issubface(spintet)) {
+            tspivot(spintet, splitsh);
+            setpointtype(insertarray[i], FREEFACETVERTEX);
+            //ivf.rejflag |= 1;
+            break;
+          }
+          fnextself(spintet);
+          if (spintet.tet == searchtet.tet) break;
+        }
+      }
+    } else if (ivf.iloc == (int) ONFACE) {
+      if (issubface(searchtet)) {
+        tspivot(searchtet, splitsh);
+        setpointtype(insertarray[i], FREEFACETVERTEX);
+        //ivf.rejflag |= 1;
+      }
+    }
+
+    // Now insert the point.
+    if (insertpoint(insertarray[i], &searchtet, &splitsh, &splitseg, &ivf)) {
+      if (flipstack != NULL) {
+        // There are queued faces. Use flips to recover Delaunayness.
+        lawsonflip3d(&fc);
+        // There may be unflippable edges. Ignore them.
+        unflipqueue->restart();
+      }
+      // Update the Steiner counters.
+      if (pointtype(insertarray[i]) == FREESEGVERTEX) {
+        st_segref_count++;
+      } else if (pointtype(insertarray[i]) == FREEFACETVERTEX) {
+        st_facref_count++;
+      } else {
+        st_volref_count++;
+      }
+    } else {
+      // Point is not inserted.
+      //pointdealloc(insertarray[i]);
+      setpointtype(insertarray[i], UNUSEDVERTEX);
+      unuverts++;
+      encseglist->restart();
+      encshlist->restart();
+    }
+  } // i
+
+  delete encseglist;
+  delete encshlist;
+
+  if (b->verbose) {
+    printf("  Inserted %ld (%ld, %ld, %ld) vertices.\n", 
+           st_segref_count + st_facref_count + st_volref_count - 
+           (bak_seg_count + bak_fac_count + bak_vol_count),
+           st_segref_count - bak_seg_count, st_facref_count - bak_fac_count,
+           st_volref_count - bak_vol_count);
+    if (nonregularcount > 0l) {
+      printf("  Performed %ld brute-force searches.\n", nonregularcount);
+    }
+  }
+
+  nonregularcount = bak_nonregularcount;
+  samples = baksmaples; 
+}
+
+void tetgenmesh::insertconstrainedpoints(tetgenio *addio)
+{
+  point *insertarray, newpt;
+  REAL x, y, z, w;
+  int index, attribindex, mtrindex;
+  int arylen, i, j;
+
+  if (!b->quiet) {
+    printf("Inserting constrained points ...\n");
+  }
+
+  insertarray = new point[addio->numberofpoints];
+  arylen = 0;
+  index = 0;
+  attribindex = 0;
+  mtrindex = 0;
+
+  for (i = 0; i < addio->numberofpoints; i++) {
+    x = addio->pointlist[index++];
+    y = addio->pointlist[index++];
+    z = addio->pointlist[index++];
+    // Test if this point lies inside the bounding box.
+    if ((x < xmin) || (x > xmax) || (y < ymin) || (y > ymax) ||
+        (z < zmin) || (z > zmax)) {
+      if (b->verbose) {
+        printf("Warning:  Point #%d lies outside the bounding box. Ignored\n",
+               i + in->firstnumber);
+      }
+      continue;
+    }
+    makepoint(&newpt, UNUSEDVERTEX);
+    newpt[0] = x;
+    newpt[1] = y;
+    newpt[2] = z;
+    // Read the point attributes. (Including point weights.)
+    for (j = 0; j < addio->numberofpointattributes; j++) {
+      newpt[3 + j] = addio->pointattributelist[attribindex++];
+    }
+    // Read the point metric tensor.
+    for (j = 0; j < addio->numberofpointmtrs; j++) {
+      newpt[pointmtrindex + j] = addio->pointmtrlist[mtrindex++];
+    }
+    if (b->weighted) { // -w option
+      if (addio->numberofpointattributes > 0) {
+        // The first point attribute is its weight.
+        w = newpt[3];
+      } else {
+        // No given weight available. Default choose the maximum
+        //   absolute value among its coordinates.        
+        w = fabs(x);
+        if (w < fabs(y)) w = fabs(y);
+        if (w < fabs(z)) w = fabs(z);
+      }
+      if (b->weighted_param == 0) {
+        newpt[3] = x * x + y * y + z * z - w; // Weighted DT.
+      } else { // -w1 option
+        newpt[3] = w;  // Regular tetrahedralization.
+      }
+    }
+    insertarray[arylen] = newpt;
+    arylen++;
+  } // i
+
+  // Insert the points.
+  int rejflag = 0;  // Do not check encroachment.
+  if (b->metric) { // -m option.
+    rejflag |= 4; // Reject it if it lies in some protecting balls.
+  }
+
+  insertconstrainedpoints(insertarray, arylen, rejflag);
+
+  delete [] insertarray;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// meshcoarsening()    Deleting (selected) vertices.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::collectremovepoints(arraypool *remptlist)
+{
+  point ptloop, *parypt;
+  verttype vt;
+
+  // If a mesh sizing function is given. Collect vertices whose mesh size
+  //   is greater than its smallest edge length.
+  if (b->metric) { // -m option
+    REAL len, smlen;
+    int i;
+    points->traversalinit();
+    ptloop = pointtraverse();
+    while (ptloop != NULL) {
+      if (ptloop[pointmtrindex] > 0) {
+        // Get the smallest edge length at this vertex.
+        getvertexstar(1, ptloop, cavetetlist, cavetetvertlist, NULL);
+        parypt = (point *) fastlookup(cavetetvertlist, 0);
+        smlen = distance(ptloop, *parypt);
+        for (i = 1; i < cavetetvertlist->objects; i++) {
+          parypt = (point *) fastlookup(cavetetvertlist, i);
+          len = distance(ptloop, *parypt);
+          if (len < smlen) {
+            smlen = len;
+          }
+        }
+        cavetetvertlist->restart();
+        cavetetlist->restart();
+        if (smlen < ptloop[pointmtrindex]) {
+          pinfect(ptloop);
+          remptlist->newindex((void **) &parypt);
+          *parypt = ptloop;
+        }
+      }
+      ptloop = pointtraverse();
+    }
+    if (b->verbose > 1) {
+      printf("    Coarsen %ld oversized points.\n", remptlist->objects); 
+    }
+  }
+
+  // If 'in->pointmarkerlist' exists, Collect vertices with markers '-1'.
+  if (in->pointmarkerlist != NULL) {
+    long bak_count = remptlist->objects;
+    points->traversalinit();
+    ptloop = pointtraverse();
+    int index = 0;
+    while (ptloop != NULL) {
+      if (index < in->numberofpoints) {
+        if (in->pointmarkerlist[index] == -1) {
+          pinfect(ptloop);
+          remptlist->newindex((void **) &parypt);
+          *parypt = ptloop;
+        }
+      } else {
+        // Remaining are not input points. Stop here.
+        break; 
+      }
+      index++;
+      ptloop = pointtraverse();
+    }
+    if (b->verbose > 1) {
+      printf("    Coarsen %ld marked points.\n", remptlist->objects - bak_count); 
+    }
+  } // if (in->pointmarkerlist != NULL)
+
+  if (b->coarsen_param > 0) { // -R1/#
+    // Remove a coarsen_percent number of interior points.
+    assert((b->coarsen_percent > 0) && (b->coarsen_percent <= 1.0));
+    if (b->verbose > 1) {
+      printf("    Coarsen %g percent of interior points.\n", 
+             b->coarsen_percent * 100.0);
+    }
+    arraypool *intptlist = new arraypool(sizeof(point *), 10);
+    // Count the total number of interior points.
+    points->traversalinit();
+    ptloop = pointtraverse();
+    while (ptloop != NULL) {
+      vt = pointtype(ptloop);
+      if ((vt == VOLVERTEX) || (vt == FREEVOLVERTEX) || 
+          (vt == FREEFACETVERTEX) || (vt == FREESEGVERTEX)) {
+        intptlist->newindex((void **) &parypt);
+        *parypt = ptloop;
+      }
+      ptloop = pointtraverse();
+    }
+    if (intptlist->objects > 0l) {
+      // Sort the list of points randomly.
+      point *parypt_i, swappt;
+      int randindex, i;
+      srand(intptlist->objects);
+      for (i = 0; i < intptlist->objects; i++) {
+        randindex = rand() % (i + 1); // randomnation(i + 1);
+        parypt_i = (point *) fastlookup(intptlist, i); 
+        parypt = (point *) fastlookup(intptlist, randindex);
+        // Swap this two points.
+        swappt = *parypt_i;
+        *parypt_i = *parypt;
+        *parypt = swappt;
+      }
+      int remcount = (int) ((REAL) intptlist->objects * b->coarsen_percent);
+      // Return the first remcount points.
+      for (i = 0; i < remcount; i++) {
+        parypt_i = (point *) fastlookup(intptlist, i);
+        if (!pinfected(*parypt_i)) {
+          pinfected(*parypt_i);
+          remptlist->newindex((void **) &parypt);
+          *parypt = *parypt_i;
+        }
+      }
+    }
+    delete intptlist;
+  }
+
+  // Unmark all collected vertices.
+  for (int i = 0; i < remptlist->objects; i++) {
+    parypt = (point *) fastlookup(remptlist, i);
+    puninfect(*parypt);
+  }
+}
+
+void tetgenmesh::meshcoarsening()
+{
+  arraypool *remptlist;
+
+  if (!b->quiet) {
+    printf("Mesh coarsening ...\n");
+  }
+
+  // Collect the set of points to be removed
+  remptlist = new arraypool(sizeof(point *), 10);
+  collectremovepoints(remptlist);
+
+  if (remptlist->objects == 0l) {
+    delete remptlist;
+    return;
+  }
+
+  if (b->verbose) {
+    if (remptlist->objects > 0l) {
+      printf("  Removing %ld points...\n", remptlist->objects);
+    }
+  }
+
+  point *parypt, *plastpt;
+  long ms = remptlist->objects;
+  int nit = 0; 
+  int bak_fliplinklevel = b->fliplinklevel;
+  b->fliplinklevel = -1;
+  autofliplinklevel = 1; // Init value.
+  int i;
+
+  while (1) {
+  
+    if (b->verbose > 1) {
+      printf("    Removing points [%s level = %2d] #:  %ld.\n", 
+             (b->fliplinklevel > 0) ? "fixed" : "auto",
+             (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
+             remptlist->objects);
+    }
+
+    // Remove the list of points.
+    for (i = 0; i < remptlist->objects; i++) {
+      parypt = (point *) fastlookup(remptlist, i);
+      assert(pointtype(*parypt) != UNUSEDVERTEX);
+      if (removevertexbyflips(*parypt)) {
+        // Move the last entry to the current place.
+        plastpt = (point *) fastlookup(remptlist, remptlist->objects - 1);
+        *parypt = *plastpt;
+        remptlist->objects--;
+        i--;
+      }
+    }
+
+    if (remptlist->objects > 0l) {
+      if (b->fliplinklevel >= 0) {
+        break; // We have tried all levels.
+      }
+      if (remptlist->objects == ms) {
+        nit++;
+        if (nit >= 3) {
+          // Do the last round with unbounded flip link level.
+          b->fliplinklevel = 100000;
+        }
+      } else {
+        ms = remptlist->objects;
+        if (nit > 0) {
+          nit--;
+        }
+      }
+      autofliplinklevel+=b->fliplinklevelinc;
+    } else {
+      // All points are removed.
+      break;
+    }
+  } // while (1)
+
+  if (remptlist->objects > 0l) {
+    if (b->verbose) {
+      printf("  %ld points are not removed !\n", remptlist->objects);
+    }
+  }
+
+  b->fliplinklevel = bak_fliplinklevel;
+  delete remptlist;
+}
+
+////                                                                       ////
+////                                                                       ////
+//// reconstruct_cxx //////////////////////////////////////////////////////////
+
+//// refine_cxx ///////////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// makefacetverticesmap()    Create a map from facet to its vertices.        //
+//                                                                           //
+// All facets will be indexed (starting from 0).  The map is saved in two    //
+// global arrays: 'idx2facetlist' and 'facetverticeslist'.                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::makefacetverticesmap()
+{
+  arraypool *facetvertexlist, *vertlist, **paryvertlist;
+  face subloop, neighsh, *parysh, *parysh1;
+  point pa, *ppt, *parypt;
+  verttype vt;
+  int facetindex, totalvertices;
+  int i, j, k;
+
+  if (b->verbose) {
+    printf("  Creating the facet vertices map.\n");
+  }
+
+  facetvertexlist = new arraypool(sizeof(arraypool *), 10);
+  facetindex = totalvertices = 0;
+
+  subfaces->traversalinit();
+  subloop.sh = shellfacetraverse(subfaces);
+  while (subloop.sh != NULL) {
+    if (!sinfected(subloop)) {
+      // A new facet. Create its vertices list.
+      vertlist = new arraypool(sizeof(point *), 8);
+      ppt = (point *) &(subloop.sh[3]);
+      for (k = 0; k < 3; k++) {
+        vt = pointtype(ppt[k]);
+        if ((vt != FREESEGVERTEX) && (vt != FREEFACETVERTEX)) {
+          pinfect(ppt[k]);
+          vertlist->newindex((void **) &parypt);
+          *parypt = ppt[k];
+        }
+      }
+      sinfect(subloop);
+      caveshlist->newindex((void **) &parysh);
+      *parysh = subloop;
+      for (i = 0; i < caveshlist->objects; i++) {
+        parysh = (face *) fastlookup(caveshlist, i);
+        setfacetindex(*parysh, facetindex);
+        for (j = 0; j < 3; j++) {
+          if (!isshsubseg(*parysh)) {
+            spivot(*parysh, neighsh);
+            assert(neighsh.sh != NULL);
+            if (!sinfected(neighsh)) {
+              pa = sapex(neighsh);
+              if (!pinfected(pa)) {
+                vt = pointtype(pa);
+                if ((vt != FREESEGVERTEX) && (vt != FREEFACETVERTEX)) {
+                  pinfect(pa);
+                  vertlist->newindex((void **) &parypt);
+                  *parypt = pa;
+                }
+              }
+              sinfect(neighsh);
+              caveshlist->newindex((void **) &parysh1);
+              *parysh1 = neighsh;
+            }
+          }
+          senextself(*parysh);
+        }
+      } // i
+      totalvertices += (int) vertlist->objects;
+      // Uninfect facet vertices.
+      for (k = 0; k < vertlist->objects; k++) {
+        parypt = (point *) fastlookup(vertlist, k);
+        puninfect(*parypt);
+      }
+      caveshlist->restart();
+      // Save this vertex list.
+      facetvertexlist->newindex((void **) &paryvertlist);
+      *paryvertlist = vertlist;
+      facetindex++;
+    } 
+    subloop.sh = shellfacetraverse(subfaces);
+  }
+
+  // All subfaces are infected. Uninfect them.
+  subfaces->traversalinit();
+  subloop.sh = shellfacetraverse(subfaces);
+  while (subloop.sh != NULL) {
+    assert(sinfected(subloop));
+    suninfect(subloop);
+    subloop.sh = shellfacetraverse(subfaces);
+  }
+
+  if (b->verbose) {
+    printf("  Found %ld facets.\n", facetvertexlist->objects);
+  }
+
+  idx2facetlist = new int[facetindex + 1];
+  facetverticeslist = new point[totalvertices];
+
+  totalworkmemory += ((facetindex + 1) * sizeof(int) + 
+                      totalvertices * sizeof(point *));
+
+  idx2facetlist[0] = 0;
+  for (i = 0, k = 0; i < facetindex; i++) {
+    paryvertlist = (arraypool **) fastlookup(facetvertexlist, i);
+    vertlist = *paryvertlist;
+    idx2facetlist[i + 1] = (idx2facetlist[i] + (int) vertlist->objects);
+    for (j = 0; j < vertlist->objects; j++) {
+      parypt = (point *) fastlookup(vertlist, j);
+      facetverticeslist[k] = *parypt;
+      k++;
+    }
+  }
+  assert(k == totalvertices);
+
+  // Free the lists.
+  for (i = 0; i < facetvertexlist->objects; i++) {
+    paryvertlist = (arraypool **) fastlookup(facetvertexlist, i);
+    vertlist = *paryvertlist;
+    delete vertlist;
+  }
+  delete facetvertexlist;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Check whether two segments, or a segment and a facet, or two facets are   //
+// adjacent to each other.                                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::segsegadjacent(face *seg1, face *seg2)
+{
+  int segidx1 = getfacetindex(*seg1);
+  int segidx2 = getfacetindex(*seg2);
+
+  if (segidx1 == segidx2) return 0;
+
+  point pa1 = segmentendpointslist[segidx1 * 2];
+  point pb1 = segmentendpointslist[segidx1 * 2 + 1];
+  point pa2 = segmentendpointslist[segidx2 * 2];
+  point pb2 = segmentendpointslist[segidx2 * 2 + 1];
+
+  if ((pa1 == pa2) || (pa1 == pb2) || (pb1 == pa2) || (pb1 == pb2)) {
+    return 1;
+  }
+  return 0; 
+}
+
+int tetgenmesh::segfacetadjacent(face *subseg, face *subsh)
+{
+  int segidx = getfacetindex(*subseg);
+  point pa = segmentendpointslist[segidx * 2];
+  point pb = segmentendpointslist[segidx * 2 + 1];
+
+  pinfect(pa);
+  pinfect(pb);
+
+  int fidx = getfacetindex(*subsh);
+  int count = 0, i;
+
+  for (i = idx2facetlist[fidx]; i < idx2facetlist[fidx+1]; i++) {
+    if (pinfected(facetverticeslist[i])) count++;
+  } 
+
+  puninfect(pa);
+  puninfect(pb);
+
+  return count == 1;
+}
+
+int tetgenmesh::facetfacetadjacent(face *subsh1, face *subsh2)
+{
+  int count = 0, i;
+
+  int fidx1 = getfacetindex(*subsh1);
+  int fidx2 = getfacetindex(*subsh2);
+
+  if (fidx1 == fidx2) return 0;
+
+  for (i = idx2facetlist[fidx1]; i < idx2facetlist[fidx1+1]; i++) {
+    pinfect(facetverticeslist[i]);
+  }
+
+  for (i = idx2facetlist[fidx2]; i < idx2facetlist[fidx2+1]; i++) {
+    if (pinfected(facetverticeslist[i])) count++;
+  }
+
+  // Uninfect the vertices.
+  for (i = idx2facetlist[fidx1]; i < idx2facetlist[fidx1+1]; i++) {
+    puninfect(facetverticeslist[i]);
+  }
+
+  return count > 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkseg4encroach()    Check if an edge is encroached upon by a point.    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checkseg4encroach(point pa, point pb, point checkpt)
+{
+  // Check if the point lies inside the diametrical sphere of this seg. 
+  REAL v1[3], v2[3];
+
+  v1[0] = pa[0] - checkpt[0];
+  v1[1] = pa[1] - checkpt[1];
+  v1[2] = pa[2] - checkpt[2];
+  v2[0] = pb[0] - checkpt[0];
+  v2[1] = pb[1] - checkpt[1];
+  v2[2] = pb[2] - checkpt[2];
+
+  if (dot(v1, v2) < 0) {
+    // Inside.
+    if (b->metric) { // -m option.
+      if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0)) {
+        // The projection of 'checkpt' lies inside the segment [a,b].
+        REAL prjpt[3], u, v, t;
+        projpt2edge(checkpt, pa, pb, prjpt);
+        // Interoplate the mesh size at the location 'prjpt'.
+        u = distance(pa, pb);
+        v = distance(pa, prjpt);
+        t = v / u;
+        // 'u' is the mesh size at 'prjpt'
+        u = pa[pointmtrindex] + t * (pb[pointmtrindex] - pa[pointmtrindex]);
+        v = distance(checkpt, prjpt);
+        if (v < u) {
+          return 1; // Encroached prot-ball!
+        }
+      } else {
+        return 1; // NO protecting ball. Encroached.
+      }
+    } else {
+      return 1; // Inside! Encroached.
+    }
+  }
+
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkseg4split()    Check if we need to split a segment.                  //
+//                                                                           //
+// A segment needs to be split if it is in the following case:               //
+//  (1) It is encroached by an existing vertex.                              //
+//  (2) It has bad quality (too long).                                       //
+//  (3) Its length is larger than the mesh sizes at its endpoints.           //
+//                                                                           //
+// Return 1 if it needs to be split, otherwise, return 0.  'pencpt' returns  //
+// an encroaching point if there exists. 'qflag' returns '1' if the segment  //
+// has a length larger than the desired edge length.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checkseg4split(face *chkseg, point& encpt, int& qflag)
+{
+  REAL ccent[3], len, r;
+  int i;
+
+  point forg = sorg(*chkseg);
+  point fdest = sdest(*chkseg);
+
+  // Initialize the return values.
+  encpt = NULL;
+  qflag = 0;
+
+  len = distance(forg, fdest);
+  r = 0.5 * len;
+  for (i = 0; i < 3; i++) {
+    ccent[i] = 0.5 * (forg[i] + fdest[i]);
+  }
+
+  // First check its quality.
+  if (checkconstraints && (areabound(*chkseg) > 0.0)) {
+    if (len > areabound(*chkseg)) {
+      qflag = 1;
+      return 1;
+    }
+  }
+
+  if (b->fixedvolume) {
+    if ((len * len * len) > b->maxvolume) {
+      qflag = 1;
+      return 1;
+    }
+  }
+
+  if (b->metric) { // -m option. Check mesh size. 
+    // Check if the ccent lies outside one of the prot.balls at vertices.
+    if (((forg[pointmtrindex] > 0) && (r > forg[pointmtrindex])) ||
+        ((fdest[pointmtrindex]) > 0 && (r > fdest[pointmtrindex]))) {
+      qflag = 1; // Enforce mesh size.
+      return 1;
+    }
+  }
+
+
+  // Second check if it is encroached.
+  // Comment: There may exist more than one encroaching points of this segment. 
+  //   The 'encpt' returns the one which is closet to it.
+  triface searchtet, spintet;
+  point eapex;
+  REAL d, diff, smdist = 0;
+  int t1ver;
+
+  sstpivot1(*chkseg, searchtet);
+  spintet = searchtet;
+  while (1) {
+    eapex = apex(spintet);
+    if (eapex != dummypoint) {
+      d = distance(ccent, eapex);
+      diff = d - r;
+      if (fabs(diff) / r < b->epsilon) diff = 0.0; // Rounding.
+      if (diff < 0) {
+        // This segment is encroached by eapex.
+        if (useinsertradius) {
+          if (encpt == NULL) {
+            encpt = eapex;
+            smdist = d;
+          } else {
+            // Choose the closet encroaching point.
+            if (d < smdist) {
+              encpt = eapex;
+              smdist = d;
+            }
+          }
+        } else {
+          encpt = eapex;
+          break;
+        }
+      }
+    }
+    fnextself(spintet);
+    if (spintet.tet == searchtet.tet) break;
+  } // while (1)
+
+  if (encpt != NULL) {
+    return 1;
+  }
+
+  return 0; // No need to split it.
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// splitsegment()    Split a segment.                                        //
+//                                                                           //
+// The segment 'splitseg' is intended to be split. It will be split if it    //
+// is in one of the following cases:                                         //
+//   (1) It is encroached by an existing vertex 'encpt != NULL'; or          //
+//   (2) It is in bad quality 'qflag == 1'; or                               //
+//   (3) Its length is larger than the mesh sizes at its endpoints.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::splitsegment(face *splitseg, point encpt, REAL rrp, 
+                             point encpt1, point encpt2, int qflag, 
+                             int chkencflag)
+{
+  point pa = sorg(*splitseg);
+  point pb = sdest(*splitseg);
+
+
+
+  if ((encpt == NULL) && (qflag == 0)) {
+    if (useinsertradius) {
+      // Do not split this segment if the length is smaller than the smaller
+      //   insertion radius at its endpoints.
+      REAL len = distance(pa, pb);
+      REAL smrrv = getpointinsradius(pa);
+      REAL rrv = getpointinsradius(pb);
+      if (rrv > 0) {
+        if (smrrv > 0) {
+          if (rrv < smrrv) {
+            smrrv = rrv;
+          }
+        } else {
+          smrrv = rrv;
+        }
+      }
+      if (smrrv > 0) {
+        if ((fabs(smrrv - len) / len) < b->epsilon) smrrv = len;
+        if (len < smrrv) {
+          return 0;
+        }
+      }
+    }
+  }
+
+  if (b->nobisect) { // With -Y option.
+    // Only split this segment if it is allowed to be split.
+    if (checkconstraints) {
+      // Check if it has a non-zero length bound. 
+      if (areabound(*splitseg) == 0) {
+        // It is not allowed.  However, if all of facets containing this seg
+        //   is allowed to be split, we still split it.
+        face parentsh, spinsh;
+        //splitseg.shver = 0;
+        spivot(*splitseg, parentsh);
+        if (parentsh.sh == NULL) {
+          return 0; // A dangling segment. Do not split it.
+        }
+        spinsh = parentsh;
+        while (1) {
+          if (areabound(spinsh) == 0) break;
+          spivotself(spinsh);
+          if (spinsh.sh == parentsh.sh) break;
+        }
+        if (areabound(spinsh) == 0) {
+          // All facets at this seg are not allowed to be split.
+          return 0;  // Do not split it.
+        }
+      }
+    } else {
+      return 0; // Do not split this segment.
+    }
+  } // if (b->nobisect)
+
+  triface searchtet;
+  face searchsh;
+  point newpt;
+  insertvertexflags ivf;
+
+  makepoint(&newpt, FREESEGVERTEX);
+  getsteinerptonsegment(splitseg, encpt, newpt);
+
+  // Split the segment by the Bowyer-Watson algorithm.
+  sstpivot1(*splitseg, searchtet);
+  ivf.iloc = (int) ONEDGE;
+  // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
+  ivf.bowywat = 3;
+  ivf.validflag = 1; // Validate the B-W cavity.
+  ivf.lawson = 2; // Do flips to recover Delaunayness.
+  ivf.rejflag = 0;     // Do not check encroachment of new segments/facets.
+  if (b->metric) {
+    ivf.rejflag |= 4;  // Do check encroachment of protecting balls.
+  }
+  ivf.chkencflag = chkencflag;
+  ivf.sloc = (int) INSTAR; // ivf.iloc;
+  ivf.sbowywat = 3; // ivf.bowywat;  // Surface mesh options.
+  ivf.splitbdflag = 1;
+  ivf.respectbdflag = 1;
+  ivf.assignmeshsize = b->metric;
+  ivf.smlenflag = useinsertradius;
+
+
+  if (insertpoint(newpt, &searchtet, &searchsh, splitseg, &ivf)) {
+    st_segref_count++;
+    if (steinerleft > 0) steinerleft--;
+    if (useinsertradius) {
+      // Update 'rv' (to be the shortest distance).
+      REAL rv = ivf.smlen, rp;
+      if (pointtype(ivf.parentpt) == FREESEGVERTEX) {
+        face parentseg1, parentseg2;
+        sdecode(point2sh(newpt), parentseg1);
+        sdecode(point2sh(ivf.parentpt), parentseg2);
+        if (segsegadjacent(&parentseg1, &parentseg2)) {
+          rp = getpointinsradius(ivf.parentpt);
+          if (rv < rp) {
+            rv = rp; // The relaxed insertion radius of 'newpt'.
+          }
+        }
+      } else if (pointtype(ivf.parentpt) == FREEFACETVERTEX) {
+        face parentseg, parentsh;
+        sdecode(point2sh(newpt), parentseg);
+        sdecode(point2sh(ivf.parentpt), parentsh);
+        if (segfacetadjacent(&parentseg, &parentsh)) {
+          rp = getpointinsradius(ivf.parentpt);
+          if (rv < rp) {
+            rv = rp; // The relaxed insertion radius of 'newpt'.
+          }            
+        }
+      }
+      setpointinsradius(newpt, rv);
+    }
+    if (flipstack != NULL) {
+      flipconstraints fc;
+      fc.chkencflag = chkencflag;
+      fc.enqflag = 2;
+      lawsonflip3d(&fc);
+      unflipqueue->restart();
+    }
+    return 1;
+  } else {
+    // Point is not inserted.
+    pointdealloc(newpt);
+    return 0;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// repairencsegs()    Repair encroached (sub) segments.                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::repairencsegs(int chkencflag)
+{
+  face *bface;
+  point encpt = NULL;
+  int qflag = 0;
+
+  // Loop until the pool 'badsubsegs' is empty. Note that steinerleft == -1
+  //   if an unlimited number of Steiner points is allowed.
+  while ((badsubsegs->items > 0) && (steinerleft != 0)) {
+    badsubsegs->traversalinit();
+    bface = (face *) badsubsegs->traverse();
+    while ((bface != NULL) && (steinerleft != 0)) {
+      // Skip a deleleted element.
+      if (bface->shver >= 0) {
+        // A queued segment may have been deleted (split).
+        if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
+          // A queued segment may have been processed. 
+          if (smarktest2ed(*bface)) {
+            sunmarktest2(*bface);
+            if (checkseg4split(bface, encpt, qflag)) {
+              splitsegment(bface, encpt, 0, NULL, NULL, qflag, chkencflag);
+            }
+          }
+        }
+        // Remove this entry from list.
+        bface->shver = -1; // Signal it as a deleted element.
+        badsubsegs->dealloc((void *) bface);
+      }
+      bface = (face *) badsubsegs->traverse();
+    }
+  }
+
+  if (badsubsegs->items > 0) {
+    if (steinerleft == 0) {
+      if (b->verbose) {
+        printf("The desired number of Steiner points is reached.\n");
+      }
+    } else {
+      assert(0); // Unknown case.
+    }
+    badsubsegs->traversalinit();
+    bface = (face *) badsubsegs->traverse();
+    while (bface  != NULL) {
+      // Skip a deleleted element.
+      if (bface->shver >= 0) {
+        if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
+          if (smarktest2ed(*bface)) {
+            sunmarktest2(*bface);
+          }
+        }
+      }
+      bface = (face *) badsubsegs->traverse();
+    }
+    badsubsegs->restart();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// enqueuesubface()    Queue a subface or a subsegment for encroachment chk. //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::enqueuesubface(memorypool *pool, face *chkface)
+{
+  if (!smarktest2ed(*chkface)) {
+    smarktest2(*chkface); // Only queue it once.
+    face *queface = (face *) pool->alloc();
+    *queface = *chkface;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkfac4encroach()    Check if a subface is encroached by a point.       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checkfac4encroach(point pa, point pb, point pc, point checkpt,
+                                  REAL* cent, REAL* r)
+{
+  REAL rd, len;
+
+  circumsphere(pa, pb, pc, NULL, cent, &rd);
+  assert(rd != 0);
+  len = distance(cent, checkpt);
+  if ((fabs(len - rd) / rd) < b->epsilon) len = rd; // Rounding.
+ 
+  if (len < rd) {
+    // The point lies inside the circumsphere of this face.
+    if (b->metric) { // -m option.
+      if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) &&
+          (pc[pointmtrindex] > 0)) {
+        // Get the projection of 'checkpt' in the plane of pa, pb, and pc.
+        REAL prjpt[3], n[3];
+        REAL a, a1, a2, a3;
+        projpt2face(checkpt, pa, pb, pc, prjpt);
+        // Get the face area of [a,b,c].
+        facenormal(pa, pb, pc, n, 1, NULL);
+        a = sqrt(dot(n,n));
+        // Get the face areas of [a,b,p], [b,c,p], and [c,a,p].
+        facenormal(pa, pb, prjpt, n, 1, NULL);
+        a1 = sqrt(dot(n,n));
+        facenormal(pb, pc, prjpt, n, 1, NULL);
+        a2 = sqrt(dot(n,n));
+        facenormal(pc, pa, prjpt, n, 1, NULL);
+        a3 = sqrt(dot(n,n));
+        if ((fabs(a1 + a2 + a3 - a) / a) < b->epsilon) {
+          // This face contains the projection.
+          // Get the mesh size at the location of the projection point.
+          rd = a1 / a * pc[pointmtrindex]
+             + a2 / a * pa[pointmtrindex]
+             + a3 / a * pb[pointmtrindex];
+          len = distance(prjpt, checkpt);
+          if (len < rd) {
+            return 1; // Encroached.
+          }
+        }
+      } else {
+        return 1;  // No protecting ball. Encroached.
+      }
+    } else {
+      *r = rd;
+      return 1;  // Encroached.
+    }
+  }
+
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkfac4split()    Check if a subface needs to be split.                 //
+//                                                                           //
+// A subface needs to be split if it is in the following case:               //
+//  (1) It is encroached by an existing vertex.                              //
+//  (2) It has bad quality (has a small angle, -q).                          //
+//  (3) It's area is larger than a prescribed value (.var).                  //
+//                                                                           //
+// Return 1 if it needs to be split, otherwise, return 0.                    //
+// 'chkfac' represents its longest edge.                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checkfac4split(face *chkfac, point& encpt, int& qflag, 
+                               REAL *cent)
+{
+  point pa, pb, pc;
+  REAL area, rd, len;
+  REAL A[4][4], rhs[4], D;
+  int indx[4];
+  int i;
+
+  encpt = NULL;
+  qflag = 0;
+
+  pa = sorg(*chkfac);
+  pb = sdest(*chkfac);
+  pc = sapex(*chkfac);
+
+  // Compute the coefficient matrix A (3x3).
+  A[0][0] = pb[0] - pa[0];
+  A[0][1] = pb[1] - pa[1];
+  A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
+  A[1][0] = pc[0] - pa[0];
+  A[1][1] = pc[1] - pa[1];
+  A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
+  cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
+
+  area = 0.5 * sqrt(dot(A[2], A[2])); // The area of [a,b,c].
+
+  // Compute the right hand side vector b (3x1).
+  rhs[0] = 0.5 * dot(A[0], A[0]); // edge [a,b]
+  rhs[1] = 0.5 * dot(A[1], A[1]); // edge [a,c]
+  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)) {
+    // A degenerate triangle. 
+    assert(0);
+  }
+
+  lu_solve(A, 3, indx, rhs, 0);
+  cent[0] = pa[0] + rhs[0];
+  cent[1] = pa[1] + rhs[1];
+  cent[2] = pa[2] + rhs[2];
+  rd = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
+
+  if (checkconstraints && (areabound(*chkfac) > 0.0)) {
+    // Check if the subface has too big area.
+    if (area > areabound(*chkfac)) {
+      qflag = 1;
+      return 1;
+    }
+  }
+
+  if (b->fixedvolume) {
+    if ((area * sqrt(area)) > b->maxvolume) {
+      qflag = 1;
+      return 1;
+    }
+  }
+
+  if (b->varvolume) {
+    triface adjtet;
+    REAL volbnd;
+    int t1ver;
+
+    stpivot(*chkfac, adjtet);
+    if (!ishulltet(adjtet)) {
+      volbnd = volumebound(adjtet.tet);
+      if ((volbnd > 0) && (area * sqrt(area)) > volbnd) {
+        qflag = 1;
+        return 1;
+      }
+    }
+    fsymself(adjtet);
+    if (!ishulltet(adjtet)) {
+      volbnd = volumebound(adjtet.tet);
+      if ((volbnd > 0) && (area * sqrt(area)) > volbnd) {
+        qflag = 1;
+        return 1;
+      }
+    }
+  }
+
+  if (b->metric) { // -m option. Check mesh size. 
+    // Check if the ccent lies outside one of the prot.balls at vertices.
+    if (((pa[pointmtrindex] > 0) && (rd > pa[pointmtrindex])) ||
+        ((pb[pointmtrindex] > 0) && (rd > pb[pointmtrindex])) ||
+        ((pc[pointmtrindex] > 0) && (rd > pc[pointmtrindex]))) {
+      qflag = 1; // Enforce mesh size.
+      return 1;
+    }
+  }
+
+  triface searchtet;
+  REAL smlen = 0;
+
+  // Check if this subface is locally encroached.
+  for (i = 0; i < 2; i++) {
+    stpivot(*chkfac, searchtet);
+    if (!ishulltet(searchtet)) {
+      len = distance(oppo(searchtet), cent);
+      if ((fabs(len - rd) / rd) < b->epsilon) len = rd;// Rounding.
+      if (len < rd) {
+        if (smlen == 0) {
+          smlen = len;
+          encpt = oppo(searchtet);
+        } else {
+          if (len < smlen) {
+            smlen = len;
+            encpt = oppo(searchtet);
+          }
+        }
+        //return 1;
+      }
+    }
+    sesymself(*chkfac);
+  }
+
+  return encpt != NULL; //return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// splitsubface()    Split a subface.                                        //
+//                                                                           //
+// The subface may be encroached, or in bad-quality. It is split at its cir- //
+// cumcenter ('ccent'). Do not split it if 'ccent' encroaches upon any seg-  //
+// ment. Instead, one of the encroached segments is split.  It is possible   //
+// that none of the encroached segments can be split.                        //
+//                                                                           //
+// The return value indicates whether a new point is inserted (> 0) or not   //
+// (= 0).  Furthermore, it is inserted on an encroached segment (= 1) or     //
+// in-side the facet (= 2).                                                  //
+//                                                                           //
+// 'encpt' is a vertex encroaching upon this subface, i.e., it causes the    //
+// split of this subface. If 'encpt' is NULL, then the cause of the split    //
+// this subface is a rejected tet circumcenter 'p', and 'encpt1' is the      //
+// parent of 'p'.                                                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::splitsubface(face *splitfac, point encpt, point encpt1, 
+                             int qflag, REAL *ccent, int chkencflag)
+{
+  point pa = sorg(*splitfac);
+  point pb = sdest(*splitfac);
+  point pc = sapex(*splitfac);
+
+
+
+  if (b->nobisect) { // With -Y option.
+    if (checkconstraints) {
+      // Only split if it is allowed to be split.
+      // Check if this facet has a non-zero constraint.
+      if (areabound(*splitfac) == 0) {
+        return 0; // Do not split it.
+      }
+    } else {
+      return 0;
+    }
+  } // if (b->nobisect)
+
+  face searchsh;
+  insertvertexflags ivf;
+  point newpt;
+  REAL rv = 0., rp; // Insertion radius of newpt.
+  int i;
+
+  // Initialize the inserting point.
+  makepoint(&newpt, FREEFACETVERTEX);
+  // Split the subface at its circumcenter.
+  for (i = 0; i < 3; i++) newpt[i] = ccent[i];
+
+  if (useinsertradius) {
+    if (encpt != NULL) {
+      rv = distance(newpt, encpt);
+      if (pointtype(encpt) == FREESEGVERTEX) {
+        face parentseg;
+        sdecode(point2sh(encpt), parentseg);
+        if (segfacetadjacent(&parentseg, splitfac)) {
+          rp = getpointinsradius(encpt);
+          if (rv < (sqrt(2.0) * rp)) {
+            // This insertion may cause no termination. 
+            pointdealloc(newpt);
+            return 0; // Reject the insertion of newpt.
+          }
+        }
+      } else if (pointtype(encpt) == FREEFACETVERTEX) {
+        face parentsh;
+        sdecode(point2sh(encpt), parentsh);
+        if (facetfacetadjacent(&parentsh, splitfac)) {
+          rp = getpointinsradius(encpt);
+          if (rv < rp) {
+            pointdealloc(newpt);
+            return 0; // Reject the insertion of newpt.
+          }
+        }
+      }
+    }
+  } // if (useinsertradius)
+
+  // Search a subface which contains 'newpt'.
+  searchsh = *splitfac;
+  // Calculate an above point. It lies above the plane containing
+  //   the subface [a,b,c], and save it in dummypoint. Moreover,
+  //   the vector cent->dummypoint is the normal of the plane.
+  calculateabovepoint4(newpt, pa, pb, pc);
+  //   Parameters: 'aflag' = 1, - above point exists.
+  //   'cflag' = 0, - non-convex, check co-planarity of the result.
+  //   'rflag' = 0, - no need to round the locating result.
+  ivf.iloc = (int) slocate(newpt, &searchsh, 1, 0, 0);
+
+  if (!((ivf.iloc == (int) ONFACE) || (ivf.iloc == (int) ONEDGE))) {
+    pointdealloc(newpt);
+    return 0;
+  }
+
+
+  triface searchtet;
+  face *paryseg;
+  int splitflag;
+
+  // Insert the point.
+  stpivot(searchsh, searchtet);
+  //assert((ivf.iloc == (int) ONFACE) || (ivf.iloc == (int) ONEDGE));
+  // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
+  ivf.bowywat = 3; 
+  ivf.lawson = 2;
+  ivf.rejflag = 1; // Do check the encroachment of segments.
+  if (b->metric) {
+    ivf.rejflag |= 4;  // Do check encroachment of protecting balls.
+  }
+  ivf.chkencflag = chkencflag;
+  ivf.sloc = (int) INSTAR; // ivf.iloc;
+  ivf.sbowywat = 3; // ivf.bowywat;
+  ivf.splitbdflag = 1;
+  ivf.validflag = 1;
+  ivf.respectbdflag = 1;
+  ivf.assignmeshsize = b->metric;
+
+  ivf.refineflag = 2;
+  ivf.refinesh = searchsh;
+  ivf.smlenflag = useinsertradius; // Update the insertion radius.
+
+
+  if (insertpoint(newpt, &searchtet, &searchsh, NULL, &ivf)) {
+    st_facref_count++;
+    if (steinerleft > 0) steinerleft--;
+    if (useinsertradius) {
+      // Update 'rv' (to be the shortest distance).
+      rv = ivf.smlen;
+      if (pointtype(ivf.parentpt) == FREESEGVERTEX) {
+        face parentseg, parentsh;
+        sdecode(point2sh(ivf.parentpt), parentseg);
+        sdecode(point2sh(newpt), parentsh);
+        if (segfacetadjacent(&parentseg, &parentsh)) {
+          rp = getpointinsradius(ivf.parentpt);
+          if (rv < (sqrt(2.0) * rp)) {
+            rv = sqrt(2.0) * rp; // The relaxed insertion radius of 'newpt'.
+          }
+        }
+      } else if (pointtype(ivf.parentpt) == FREEFACETVERTEX) {
+        face parentsh1, parentsh2;
+        sdecode(point2sh(ivf.parentpt), parentsh1);
+        sdecode(point2sh(newpt), parentsh2);
+        if (facetfacetadjacent(&parentsh1, &parentsh2)) {
+          rp = getpointinsradius(ivf.parentpt);
+          if (rv < rp) {
+            rv = rp; // The relaxed insertion radius of 'newpt'.
+          }          
+        }
+      }
+      setpointinsradius(newpt, rv);
+    } // if (useinsertradius)
+    if (flipstack != NULL) {
+      flipconstraints fc;
+      fc.chkencflag = chkencflag;
+      fc.enqflag = 2;
+      lawsonflip3d(&fc);
+      unflipqueue->restart();
+    }
+    return 1;
+  } else {
+    // Point was not inserted.
+    pointdealloc(newpt);
+    if (ivf.iloc == (int) ENCSEGMENT) {
+      // Select an encroached segment and split it.
+      splitflag = 0;
+      for (i = 0; i < encseglist->objects; i++) {
+        paryseg = (face *) fastlookup(encseglist, i);
+        if (splitsegment(paryseg, NULL, rv, encpt, encpt1, qflag, 
+                         chkencflag | 1)) {
+          splitflag = 1; // A point is inserted on a segment.
+          break;
+        }
+      }
+      encseglist->restart();
+      if (splitflag) {
+        // Some segments may need to be repaired.
+        repairencsegs(chkencflag | 1);
+        // Queue this subface if it is still alive and not queued.
+        //if ((splitfac->sh != NULL) && (splitfac->sh[3] != NULL)) {
+        //  // Only queue it if 'qflag' is set.
+        //  if (qflag) { 
+        //    enqueuesubface(badsubfacs, splitfac);
+        //  }
+        //}
+      }
+      return splitflag;
+    } else {
+      return 0;
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// repairencfacs()    Repair encroached subfaces.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::repairencfacs(int chkencflag)
+{
+  face *bface;
+  point encpt = NULL;
+  int qflag = 0;
+  REAL ccent[3];
+
+  // Loop until the pool 'badsubfacs' is empty. Note that steinerleft == -1
+  //   if an unlimited number of Steiner points is allowed.
+  while ((badsubfacs->items > 0) && (steinerleft != 0)) {
+    badsubfacs->traversalinit();
+    bface = (face *) badsubfacs->traverse();
+    while ((bface != NULL) && (steinerleft != 0)) {
+      // Skip a deleted element.
+      if (bface->shver >= 0) {
+        // A queued subface may have been deleted (split).
+        if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
+          // A queued subface may have been processed. 
+          if (smarktest2ed(*bface)) {
+            sunmarktest2(*bface);
+            if (checkfac4split(bface, encpt, qflag, ccent)) {
+              splitsubface(bface, encpt, NULL, qflag, ccent, chkencflag);
+            }
+          }
+        }
+        bface->shver = -1; // Signal it as a deleted element.
+        badsubfacs->dealloc((void *) bface); // Remove this entry from list.
+      }
+      bface = (face *) badsubfacs->traverse();
+    }
+  }
+
+  if (badsubfacs->items > 0) {
+    if (steinerleft == 0) {
+      if (b->verbose) {
+        printf("The desired number of Steiner points is reached.\n");
+      }
+    } else {
+      assert(0); // Unknown case.
+    }
+    badsubfacs->traversalinit();
+    bface = (face *) badsubfacs->traverse();
+    while (bface  != NULL) {
+      // Skip a deleted element.
+      if (bface->shver >= 0) {
+        if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
+          if (smarktest2ed(*bface)) {
+            sunmarktest2(*bface);
+          }
+        }
+      }
+      bface = (face *) badsubfacs->traverse();
+    }
+    badsubfacs->restart();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// enqueuetetrahedron()    Queue a tetrahedron for quality check.            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::enqueuetetrahedron(triface *chktet)
+{
+  if (!marktest2ed(*chktet)) {
+    marktest2(*chktet); // Only queue it once.
+    triface *quetet = (triface *) badtetrahedrons->alloc();
+    *quetet = *chktet;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checktet4split()    Check if the tet needs to be split.                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent) 
+{
+  point pa, pb, pc, pd, *ppt;
+  REAL vda[3], vdb[3], vdc[3];
+  REAL vab[3], vbc[3], vca[3];
+  REAL N[4][3], L[4], cosd[6], elen[6];
+  REAL maxcosd, vol, volbnd, smlen = 0, rd;
+  REAL A[4][4], rhs[4], D;
+  int indx[4];
+  int i, j;
+
+  if (b->convex) { // -c
+    // Skip this tet if it lies in the exterior.
+    if (elemattribute(chktet->tet, numelemattrib - 1) == -1.0) {
+      return 0;
+    }
+  }
+
+  qflag = 0;
+
+  pd = (point) chktet->tet[7];
+  if (pd == dummypoint) {
+    return 0; // Do not split a hull tet.
+  }
+
+  pa = (point) chktet->tet[4];
+  pb = (point) chktet->tet[5];
+  pc = (point) chktet->tet[6];
+
+  // Get the edge vectors vda: d->a, vdb: d->b, vdc: d->c.
+  // Set the matrix A = [vda, vdb, vdc]^T.
+  for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
+  for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
+  for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
+
+  // Get the other edge vectors.
+  for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i];
+  for (i = 0; i < 3; i++) vbc[i] = pc[i] - pb[i];
+  for (i = 0; i < 3; i++) vca[i] = pa[i] - pc[i];
+
+  if (!lu_decmp(A, 3, indx, &D, 0)) {
+    // A degenerated tet (vol = 0).
+    // This is possible due to the use of exact arithmetic.  We temporarily
+    //   leave this tet. It should be fixed by mesh optimization.
+    return 0; 
+  }
+
+  // Check volume if '-a#' and '-a' options are used.
+  if (b->varvolume || b->fixedvolume) {
+    vol = fabs(A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
+    if (b->fixedvolume) {
+      if (vol > b->maxvolume) {
+        qflag = 1;
+      }
+    } 
+    if (!qflag && b->varvolume) {
+      volbnd = volumebound(chktet->tet);
+      if ((volbnd > 0.0) && (vol > volbnd)) {
+        qflag = 1;
+      }
+    }
+    if (qflag == 1) {
+      // Calculate the circumcenter of this tet.
+      rhs[0] = 0.5 * dot(vda, vda);
+      rhs[1] = 0.5 * dot(vdb, vdb);
+      rhs[2] = 0.5 * dot(vdc, vdc);
+      lu_solve(A, 3, indx, rhs, 0);            
+      for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
+      return 1;
+    }
+  }
+
+  if (b->metric) { // -m option. Check mesh size. 
+    // Calculate the circumradius of this tet.
+    rhs[0] = 0.5 * dot(vda, vda);
+    rhs[1] = 0.5 * dot(vdb, vdb);
+    rhs[2] = 0.5 * dot(vdc, vdc);
+    lu_solve(A, 3, indx, rhs, 0);            
+    for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
+    rd = sqrt(dot(rhs, rhs));
+    // Check if the ccent lies outside one of the prot.balls at vertices.
+    ppt = (point *) &(chktet->tet[4]);
+    for (i = 0; i < 4; i++) {
+      if (ppt[i][pointmtrindex] > 0) {
+        if (rd > ppt[i][pointmtrindex]) {
+          qflag = 1; // Enforce mesh size.
+          return 1;
+        }
+      }
+    }
+  }
+
+  if (in->tetunsuitable != NULL) {
+    // Execute the user-defined meshing sizing evaluation.
+    if ((*(in->tetunsuitable))(pa, pb, pc, pd, NULL, 0)) {
+      // Calculate the circumcenter of this tet.
+      rhs[0] = 0.5 * dot(vda, vda);
+      rhs[1] = 0.5 * dot(vdb, vdb);
+      rhs[2] = 0.5 * dot(vdc, vdc);
+      lu_solve(A, 3, indx, rhs, 0);            
+      for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
+      return 1;
+    }
+  }
+
+  if (useinsertradius) {
+    // Do not split this tet if the shortest edge is shorter than the
+    //   insertion radius of one of its endpoints.
+    triface checkedge;
+    point e1, e2;
+    REAL rrv, smrrv;
+
+    // Get the shortest edge of this tet.
+    checkedge.tet = chktet->tet;
+    for (i = 0; i < 6; i++) {
+      checkedge.ver = edge2ver[i];
+      e1 = org(checkedge);
+      e2 = dest(checkedge);
+      elen[i] = distance(e1, e2);
+      if (i == 0) {
+        smlen = elen[i];
+        j = 0;
+      } else {
+        if (elen[i] < smlen) {
+          smlen = elen[i];
+          j = i;
+        }
+      }
+    }
+    // Check if the edge is too short.
+    checkedge.ver = edge2ver[j];
+    // Get the smallest rrv of e1 and e2.
+    // Note: if rrv of e1 and e2 is zero. Do not use it.
+    e1 = org(checkedge);
+    smrrv = getpointinsradius(e1);
+    e2 = dest(checkedge);
+    rrv = getpointinsradius(e2);
+    if (rrv > 0) {
+      if (smrrv > 0) {
+        if (rrv < smrrv) {
+          smrrv = rrv;
+        }
+      } else {
+        smrrv = rrv;
+      }
+    }
+    if (smrrv > 0) {
+      // To avoid rounding error, round smrrv before doing comparison.
+      if ((fabs(smrrv - smlen) / smlen) < b->epsilon) {
+        smrrv = smlen;
+      }
+      if (smrrv > smlen) {
+        return 0;
+      }
+    }
+  } // if (useinsertradius)
+
+  // Check the radius-edge ratio. Set by -q#.
+  if (b->minratio > 0) { 
+    // Calculate the circumcenter and radius of this tet.
+    rhs[0] = 0.5 * dot(vda, vda);
+    rhs[1] = 0.5 * dot(vdb, vdb);
+    rhs[2] = 0.5 * dot(vdc, vdc);
+    lu_solve(A, 3, indx, rhs, 0);            
+    for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
+    rd = sqrt(dot(rhs, rhs));
+    if (!useinsertradius) {
+      // Calculate the shortest edge length.
+      elen[0] = dot(vda, vda);
+      elen[1] = dot(vdb, vdb);
+      elen[2] = dot(vdc, vdc);
+      elen[3] = dot(vab, vab);
+      elen[4] = dot(vbc, vbc);
+      elen[5] = dot(vca, vca);
+      smlen = elen[0]; //sidx = 0;
+      for (i = 1; i < 6; i++) {
+        if (smlen > elen[i]) { 
+          smlen = elen[i]; //sidx = i; 
+        }
+      }
+      smlen = sqrt(smlen);
+    }
+    D = rd / smlen;
+    if (D > b->minratio) {
+      // A bad radius-edge ratio.
+      return 1;
+    }
+  }
+
+  // Check the minimum dihedral angle. Set by -qq#.
+  if (b->mindihedral > 0) { 
+    // Compute the 4 face normals (N[0], ..., N[3]).
+    for (j = 0; j < 3; j++) {
+      for (i = 0; i < 3; i++) N[j][i] = 0.0;
+      N[j][j] = 1.0;  // Positive means the inside direction
+      lu_solve(A, 3, indx, N[j], 0);
+    }
+    for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
+    // Normalize the normals.
+    for (i = 0; i < 4; i++) {
+      L[i] = sqrt(dot(N[i], N[i]));
+      assert(L[i] > 0);
+      //if (L[i] > 0.0) {
+        for (j = 0; j < 3; j++) N[i][j] /= L[i];
+      //}
+    }
+    // Calculate the six dihedral angles.
+    cosd[0] = -dot(N[0], N[1]); // Edge cd, bd, bc.
+    cosd[1] = -dot(N[0], N[2]);
+    cosd[2] = -dot(N[0], N[3]);
+    cosd[3] = -dot(N[1], N[2]); // Edge ad, ac
+    cosd[4] = -dot(N[1], N[3]);
+    cosd[5] = -dot(N[2], N[3]); // Edge ab
+    // Get the smallest dihedral angle.
+    //maxcosd = mincosd = cosd[0];
+    maxcosd = cosd[0];
+    for (i = 1; i < 6; i++) {
+      //if (cosd[i] > maxcosd) maxcosd = cosd[i];
+      maxcosd = (cosd[i] > maxcosd ? cosd[i] : maxcosd);
+      //mincosd = (cosd[i] < mincosd ? cosd[i] : maxcosd);
+    }
+    if (maxcosd > cosmindihed) {
+      // Calculate the circumcenter of this tet.
+      // A bad dihedral angle.
+      //if ((b->quality & 1) == 0) {
+        rhs[0] = 0.5 * dot(vda, vda);
+        rhs[1] = 0.5 * dot(vdb, vdb);
+        rhs[2] = 0.5 * dot(vdc, vdc);
+        lu_solve(A, 3, indx, rhs, 0);            
+        for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
+        //*rd = sqrt(dot(rhs, rhs));
+      //}
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// splittetrahedron()    Split a tetrahedron.                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::splittetrahedron(triface* splittet, int qflag, REAL *ccent, 
+                                 int chkencflag)
+{
+  triface searchtet;
+  face *paryseg;
+  point newpt;
+  badface *bface;
+  insertvertexflags ivf;
+  int splitflag;
+  int i;
+
+
+
+  REAL rv = 0.; // Insertion radius of 'newpt'.
+
+  makepoint(&newpt, FREEVOLVERTEX);
+  for (i = 0; i < 3; i++) newpt[i] = ccent[i];
+
+  if (useinsertradius) {
+    rv = distance(newpt, org(*splittet));
+    setpointinsradius(newpt, rv);
+  }
+
+  searchtet = *splittet;
+  ivf.iloc = (int) OUTSIDE;
+  // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
+  ivf.bowywat = 3;
+  ivf.lawson = 2;
+  ivf.rejflag = 3;  // Do check for encroached segments and subfaces.
+  if (b->metric) {
+    ivf.rejflag |= 4; // Reject it if it lies in some protecting balls.
+  }
+  ivf.chkencflag = chkencflag;
+  ivf.sloc = ivf.sbowywat = 0; // No use.
+  ivf.splitbdflag = 0; // No use.
+  ivf.validflag = 1;
+  ivf.respectbdflag = 1;
+  ivf.assignmeshsize = b->metric;
+
+  ivf.refineflag = 1;
+  ivf.refinetet = *splittet;
+
+
+  if (insertpoint(newpt, &searchtet, NULL, NULL, &ivf)) {
+    // Vertex is inserted.
+    st_volref_count++;
+    if (steinerleft > 0) steinerleft--;
+    if (flipstack != NULL) {
+      flipconstraints fc;
+      fc.chkencflag = chkencflag;
+      fc.enqflag = 2;
+      lawsonflip3d(&fc);
+      unflipqueue->restart();
+    }
+    return 1;
+  } else {
+    // Point is not inserted.
+    pointdealloc(newpt);
+    // Check if there are encroached segments/subfaces.
+    if (ivf.iloc == (int) ENCSEGMENT) {
+      splitflag = 0;
+      //if (!b->nobisect) { // not -Y option
+      if (!b->nobisect || checkconstraints) {  
+        // Select an encroached segment and split it.
+        for (i = 0; i < encseglist->objects; i++) {
+          paryseg = (face *) fastlookup(encseglist, i);
+          if (splitsegment(paryseg, NULL, rv, org(*splittet), NULL, qflag, 
+                           chkencflag | 3)) {
+            splitflag = 1; // A point is inserted on a segment.
+            break;
+          }
+        }
+      } // if (!b->nobisect)
+      encseglist->restart();
+      if (splitflag) {
+        // Some segments may need to be repaired.
+        repairencsegs(chkencflag | 3);
+        // Some subfaces may need to be repaired.
+        repairencfacs(chkencflag | 2);
+        // Queue the tet if it is still alive and not queued.
+        if ((splittet->tet != NULL) && (splittet->tet[4] != NULL)) {
+          enqueuetetrahedron(splittet);
+        }
+      }
+      return splitflag;
+    } else if (ivf.iloc == (int) ENCSUBFACE) {
+      splitflag = 0;
+      //if (!b->nobisect) { // not -Y option
+      if (!b->nobisect || checkconstraints) {
+        // Select an encroached subface and split it.
+        for (i = 0; i < encshlist->objects; i++) {
+          bface = (badface *) fastlookup(encshlist, i);
+          if (splitsubface(&(bface->ss), NULL, org(*splittet), qflag, 
+                           bface->cent, chkencflag | 2)){
+            splitflag = 1; // A point is inserted on a subface or a segment.
+            break;
+          }
+        }
+      } // if (!b->nobisect)
+      encshlist->restart();
+      if (splitflag) {
+        assert(badsubsegs->items == 0l);
+        // Some subfaces may need to be repaired.
+        repairencfacs(chkencflag | 2);
+        // Queue the tet if it is still alive.
+        if ((splittet->tet != NULL) && (splittet->tet[4] != NULL)) {
+          enqueuetetrahedron(splittet);
+        }
+      }
+      return splitflag;
+    }
+    return 0;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// repairbadtets()    Repair bad quality tetrahedra.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::repairbadtets(int chkencflag)
+{
+  triface *bface;
+  REAL ccent[3];
+  int qflag = 0;
+
+
+  // Loop until the pool 'badsubfacs' is empty. Note that steinerleft == -1
+  //   if an unlimited number of Steiner points is allowed.
+  while ((badtetrahedrons->items > 0) && (steinerleft != 0)) {
+    badtetrahedrons->traversalinit();
+    bface = (triface *) badtetrahedrons->traverse();
+    while ((bface != NULL) && (steinerleft != 0)) {
+      // Skip a deleted element.
+      if (bface->ver >= 0) {
+        // A queued tet may have been deleted.
+        if (!isdeadtet(*bface)) {
+          // A queued tet may have been processed.
+          if (marktest2ed(*bface)) {
+            unmarktest2(*bface);
+            if (checktet4split(bface, qflag, ccent)) {
+              splittetrahedron(bface, qflag, ccent, chkencflag);
+            }
+          }
+        }
+        bface->ver = -1; // Signal it as a deleted element.
+        badtetrahedrons->dealloc((void *) bface);
+      }
+      bface = (triface *) badtetrahedrons->traverse();
+    }
+  }
+
+  if (badtetrahedrons->items > 0) {
+    if (steinerleft == 0) {
+      if (b->verbose) {
+        printf("The desired number of Steiner points is reached.\n");
+      }
+    } else {
+      assert(0); // Unknown case.
+    }
+    // Unmark all queued tet.
+    badtetrahedrons->traversalinit();
+    bface = (triface *) badtetrahedrons->traverse();
+    while (bface != NULL) {
+      // Skip a deleted element.
+      if (bface->ver >= 0) {
+        if (!isdeadtet(*bface)) {
+          if (marktest2ed(*bface)) {
+            unmarktest2(*bface);
+          }
+        }
+      }
+      bface = (triface *) badtetrahedrons->traverse();
+    }
+    // Clear the pool.
+    badtetrahedrons->restart();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// delaunayrefinement()    Refine the mesh by Delaunay refinement.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::delaunayrefinement()
+{
+  triface checktet;
+  face checksh;
+  face checkseg;
+  long steinercount;
+  int chkencflag;
+
+  long bak_segref_count, bak_facref_count, bak_volref_count;
+  long bak_flipcount = flip23count + flip32count + flip44count;
+
+  if (!b->quiet) {
+    printf("Refining mesh...\n");
+  }
+
+  if (b->verbose) {
+    printf("  Min radiu-edge ratio = %g.\n", b->minratio);
+    printf("  Min dihedral   angle = %g.\n", b->mindihedral);
+    //printf("  Min Edge length = %g.\n", b->minedgelength);
+  }
+
+  steinerleft = b->steinerleft;  // Upperbound of # Steiner points (by -S#).
+  if (steinerleft > 0) {
+    // Check if we've already used up the given number of Steiner points.
+    steinercount = st_segref_count + st_facref_count + st_volref_count;
+    if (steinercount < steinerleft) {
+      steinerleft -= steinercount;
+    } else {
+      if (!b->quiet) {
+        printf("\nWarning:  ");
+        printf("The desired number of Steiner points (%d) has reached.\n\n",
+               b->steinerleft);
+      }
+      return; // No more Steiner points.
+    }
+  }
+
+  if (useinsertradius) {
+    if ((b->plc && b->nobisect) || b->refine) { // '-pY' or '-r' option.
+      makesegmentendpointsmap();
+    }
+    makefacetverticesmap();
+  }
+
+
+  encseglist = new arraypool(sizeof(face), 8);
+  encshlist = new arraypool(sizeof(badface), 8);
+
+
+  //if (!b->nobisect) { // if no '-Y' option
+  if (!b->nobisect || checkconstraints) {
+    if (b->verbose) {
+      printf("  Splitting encroached subsegments.\n");
+    }
+
+    chkencflag = 1; // Only check encroaching subsegments.
+    steinercount = points->items;
+
+    // Initialize the pool of encroached subsegments.
+    badsubsegs = new memorypool(sizeof(face), b->shellfaceperblock, 
+                                sizeof(void *), 0);
+
+    // Add all segments into the pool.
+    subsegs->traversalinit();
+    checkseg.sh = shellfacetraverse(subsegs);
+    while (checkseg.sh != (shellface *) NULL) {
+      enqueuesubface(badsubsegs, &checkseg);
+      checkseg.sh = shellfacetraverse(subsegs);
+    }
+
+    // Split all encroached segments.
+    repairencsegs(chkencflag);
+
+    if (b->verbose) {
+      printf("  Added %ld Steiner points.\n", points->items - steinercount);
+    }
+
+    if (b->reflevel > 1) { // '-D2' option
+      if (b->verbose) {
+        printf("  Splitting encroached subfaces.\n");
+      }
+
+      chkencflag = 2; // Only check encroaching subfaces.
+      steinercount = points->items;
+      bak_segref_count = st_segref_count;
+      bak_facref_count = st_facref_count;
+
+      // Initialize the pool of encroached subfaces.
+      badsubfacs = new memorypool(sizeof(face), b->shellfaceperblock, 
+                                  sizeof(void *), 0);
+
+      // Add all subfaces into the pool.
+      subfaces->traversalinit();
+      checksh.sh = shellfacetraverse(subfaces);
+      while (checksh.sh != (shellface *) NULL) {
+        enqueuesubface(badsubfacs, &checksh);
+        checksh.sh = shellfacetraverse(subfaces);
+      }
+
+      // Split all encroached subfaces.
+      repairencfacs(chkencflag);
+
+      if (b->verbose) {
+        printf("  Added %ld (%ld,%ld) Steiner points.\n",  
+               points->items-steinercount, st_segref_count-bak_segref_count,
+               st_facref_count-bak_facref_count);
+      }
+    } // if (b->reflevel > 1)
+  } // if (!b->nobisect)
+
+  if (b->reflevel > 2) { // '-D3' option (The default option)
+    if (b->verbose) {
+      printf("  Splitting bad quality tets.\n");
+    }
+
+    chkencflag = 4; // Only check tetrahedra.
+    steinercount = points->items;
+    bak_segref_count = st_segref_count;
+    bak_facref_count = st_facref_count;
+    bak_volref_count = st_volref_count;
+
+    // The cosine value of the min dihedral angle (-qq) for tetrahedra.
+    cosmindihed = cos(b->mindihedral / 180.0 * PI);
+
+    // Initialize the pool of bad quality tetrahedra.
+    badtetrahedrons = new memorypool(sizeof(triface), b->tetrahedraperblock,
+                                     sizeof(void *), 0);
+    // Add all tetrahedra (no hull tets) into the pool.
+    tetrahedrons->traversalinit();
+    checktet.tet = tetrahedrontraverse();
+    while (checktet.tet != NULL) {
+      enqueuetetrahedron(&checktet);
+      checktet.tet = tetrahedrontraverse();
+    }
+
+    // Split all bad quality tetrahedra.
+    repairbadtets(chkencflag);
+
+    if (b->verbose) {
+      printf("  Added %ld (%ld,%ld,%ld) Steiner points.\n", 
+             points->items - steinercount, 
+             st_segref_count - bak_segref_count,
+             st_facref_count - bak_facref_count,
+             st_volref_count - bak_volref_count);
+    }
+  } // if (b->reflevel > 2)
+
+  if (b->verbose) {
+    if (flip23count + flip32count + flip44count > bak_flipcount) {
+      printf("  Performed %ld flips.\n", flip23count + flip32count +
+             flip44count - bak_flipcount);
+    }
+  }
+
+  if (steinerleft == 0) {
+    if (!b->quiet) {
+      printf("\nWarnning:  ");
+      printf("The desired number of Steiner points (%d) is reached.\n\n",
+             b->steinerleft);
+    }
+  }
+
+
+  delete encseglist;
+  delete encshlist;
+
+  //if (!b->nobisect) {
+  if (!b->nobisect || checkconstraints) {
+    totalworkmemory += (badsubsegs->maxitems * badsubsegs->itembytes);
+    delete badsubsegs;
+    if (b->reflevel > 1) {
+      totalworkmemory += (badsubfacs->maxitems * badsubfacs->itembytes);
+      delete badsubfacs;
+    }
+  }
+  if (b->reflevel > 2) {
+    totalworkmemory += (badtetrahedrons->maxitems*badtetrahedrons->itembytes);
+    delete badtetrahedrons;
+  }
+}
+
+////                                                                       ////
+////                                                                       ////
+//// refine_cxx ///////////////////////////////////////////////////////////////
+
+//// optimize_cxx /////////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// lawsonflip3d()    A three-dimensional Lawson's algorithm.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+long tetgenmesh::lawsonflip3d(flipconstraints *fc)
+{
+  triface fliptets[5], neightet, hulltet;
+  face checksh, casingout;
+  badface *popface, *bface;
+  point pd, pe, *pts;
+  REAL sign, ori;
+  long flipcount, totalcount = 0l;
+  long sliver_peels = 0l;
+  int t1ver;
+  int i;
+
+
+  while (1) {
+
+    if (b->verbose > 2) {
+      printf("      Lawson flip %ld faces.\n", flippool->items);
+    }
+    flipcount = 0l;
+
+    while (flipstack != (badface *) NULL) {
+      // Pop a face from the stack.
+      popface = flipstack;
+      fliptets[0] = popface->tt;
+      flipstack = flipstack->nextitem; // The next top item in stack.
+      flippool->dealloc((void *) popface);
+
+      // Skip it if it is a dead tet (destroyed by previous flips).
+      if (isdeadtet(fliptets[0])) continue;
+      // Skip it if it is not the same tet as we saved.
+      if (!facemarked(fliptets[0])) continue;
+
+      unmarkface(fliptets[0]);
+
+      if (ishulltet(fliptets[0])) continue;
+
+      fsym(fliptets[0], fliptets[1]);
+      if (ishulltet(fliptets[1])) {
+        if (nonconvex) {
+          // Check if 'fliptets[0]' it is a hull sliver.
+          tspivot(fliptets[0], checksh);
+          for (i = 0; i < 3; i++) {
+            if (!isshsubseg(checksh)) {
+              spivot(checksh, casingout);
+              //assert(casingout.sh != NULL);
+              if (sorg(checksh) != sdest(casingout)) sesymself(casingout);
+              stpivot(casingout, neightet);
+              if (neightet.tet == fliptets[0].tet) {
+                // Found a hull sliver 'neightet'. Let it be [e,d,a,b], where 
+                //   [e,d,a] and [d,e,b] are hull faces.
+                edestoppo(neightet, hulltet); // [a,b,e,d]
+                fsymself(hulltet); // [b,a,e,#]
+                if (oppo(hulltet) == dummypoint) {
+                  pe = org(neightet);
+                  if ((pointtype(pe) == FREEFACETVERTEX) ||
+                      (pointtype(pe) == FREESEGVERTEX)) {
+                    removevertexbyflips(pe);
+                  }
+                } else {
+                  eorgoppo(neightet, hulltet); // [b,a,d,e]
+                  fsymself(hulltet); // [a,b,d,#]
+                  if (oppo(hulltet) == dummypoint) {
+                    pd = dest(neightet);
+                    if ((pointtype(pd) == FREEFACETVERTEX) ||
+                        (pointtype(pd) == FREESEGVERTEX)) {
+                      removevertexbyflips(pd);
+                    }
+                  } else {
+                    // Perform a 3-to-2 flip to remove the sliver.
+                    fliptets[0] = neightet;          // [e,d,a,b]
+                    fnext(fliptets[0], fliptets[1]); // [e,d,b,c]
+                    fnext(fliptets[1], fliptets[2]); // [e,d,c,a]
+                    flip32(fliptets, 1, fc);
+                    // Update counters.
+                    flip32count--;
+                    flip22count--;
+                    sliver_peels++;
+                    if (fc->remove_ndelaunay_edge) {
+                      // Update the volume (must be decreased).
+                      //assert(fc->tetprism_vol_sum <= 0);
+                      tetprism_vol_sum += fc->tetprism_vol_sum;
+                      fc->tetprism_vol_sum = 0.0; // Clear it.
+                    }
+                  }
+                }
+                break;
+              } // if (neightet.tet == fliptets[0].tet)
+            } // if (!isshsubseg(checksh))
+            senextself(checksh);
+          } // i
+        } // if (nonconvex)
+        continue;
+      }
+
+      if (checksubfaceflag) {
+        // Do not flip if it is a subface.
+        if (issubface(fliptets[0])) continue;
+      }
+
+      // Test whether the face is locally Delaunay or not.
+      pts = (point *) fliptets[1].tet; 
+      sign = insphere_s(pts[4], pts[5], pts[6], pts[7], oppo(fliptets[0]));
+
+      if (sign < 0) {
+        // A non-Delaunay face. Try to flip it.
+        pd = oppo(fliptets[0]);
+        pe = oppo(fliptets[1]);
+
+        // Check the convexity of its three edges. Stop checking either a
+        //   locally non-convex edge (ori < 0) or a flat edge (ori = 0) is
+        //   encountered, and 'fliptet' represents that edge.
+        for (i = 0; i < 3; i++) {
+          ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe);
+          if (ori <= 0) break;
+          enextself(fliptets[0]);
+        }
+
+        if (ori > 0) {
+          // A 2-to-3 flip is found.
+          //   [0] [a,b,c,d], 
+          //   [1] [b,a,c,e]. no dummypoint.
+          flip23(fliptets, 0, fc);
+          flipcount++;
+          if (fc->remove_ndelaunay_edge) {
+            // Update the volume (must be decreased).
+            //assert(fc->tetprism_vol_sum <= 0);
+            tetprism_vol_sum += fc->tetprism_vol_sum;
+            fc->tetprism_vol_sum = 0.0; // Clear it.
+          }
+          continue;
+        } else { // ori <= 0
+          // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat,
+          //   where the edge [a',b'] is one of [a,b], [b,c], and [c,a].
+          if (checksubsegflag) {
+            // Do not flip if it is a segment.
+            if (issubseg(fliptets[0])) continue;
+          }
+          // Check if there are three or four tets sharing at this edge.        
+          esymself(fliptets[0]); // [b,a,d,c]
+          for (i = 0; i < 3; i++) {
+            fnext(fliptets[i], fliptets[i+1]);
+          }
+          if (fliptets[3].tet == fliptets[0].tet) {
+            // A 3-to-2 flip is found. (No hull tet.)
+            flip32(fliptets, 0, fc); 
+            flipcount++;
+            if (fc->remove_ndelaunay_edge) {
+              // Update the volume (must be decreased).
+              //assert(fc->tetprism_vol_sum <= 0);
+              tetprism_vol_sum += fc->tetprism_vol_sum;
+              fc->tetprism_vol_sum = 0.0; // Clear it.
+            }
+            continue;
+          } else {
+            // There are more than 3 tets at this edge.
+            fnext(fliptets[3], fliptets[4]);
+            if (fliptets[4].tet == fliptets[0].tet) {
+              // There are exactly 4 tets at this edge.
+              if (nonconvex) {
+                if (apex(fliptets[3]) == dummypoint) {
+                  // This edge is locally non-convex on the hull.
+                  // It can be removed by a 4-to-4 flip.                  
+                  ori = 0;
+                }
+              } // if (nonconvex)
+              if (ori == 0) {
+                // A 4-to-4 flip is found. (Two hull tets may be involved.)
+                // Current tets in 'fliptets':
+                //   [0] [b,a,d,c] (d may be newpt)
+                //   [1] [b,a,c,e]
+                //   [2] [b,a,e,f] (f may be dummypoint)
+                //   [3] [b,a,f,d]
+                esymself(fliptets[0]); // [a,b,c,d] 
+                // A 2-to-3 flip replaces face [a,b,c] by edge [e,d].
+                //   This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]).
+                //   It will be removed by the followed 3-to-2 flip.
+                flip23(fliptets, 0, fc); // No hull tet.
+                fnext(fliptets[3], fliptets[1]);
+                fnext(fliptets[1], fliptets[2]);
+                // Current tets in 'fliptets':
+                //   [0] [...]
+                //   [1] [b,a,d,e] (degenerated, d may be new point).
+                //   [2] [b,a,e,f] (f may be dummypoint)
+                //   [3] [b,a,f,d]
+                // A 3-to-2 flip replaces edge [b,a] by face [d,e,f].
+                //   Hull tets may be involved (f may be dummypoint).
+                flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc);
+                flipcount++;
+                flip23count--;
+                flip32count--;
+                flip44count++;
+                if (fc->remove_ndelaunay_edge) {
+                  // Update the volume (must be decreased).
+                  //assert(fc->tetprism_vol_sum <= 0);
+                  tetprism_vol_sum += fc->tetprism_vol_sum;
+                  fc->tetprism_vol_sum = 0.0; // Clear it.
+                }
+                continue;
+              } // if (ori == 0)
+            }
+          }
+        } // if (ori <= 0)
+
+        // This non-Delaunay face is unflippable. Save it.
+        unflipqueue->newindex((void **) &bface);
+        bface->tt = fliptets[0];
+        bface->forg  = org(fliptets[0]);
+        bface->fdest = dest(fliptets[0]);
+        bface->fapex = apex(fliptets[0]);
+      } // if (sign < 0)
+    } // while (flipstack)
+
+    if (b->verbose > 2) {
+      if (flipcount > 0) {
+        printf("      Performed %ld flips.\n", flipcount);
+      }
+    }
+    // Accumulate the counter of flips.
+    totalcount += flipcount;
+
+    assert(flippool->items == 0l);
+    // Return if no unflippable faces left.
+    if (unflipqueue->objects == 0l) break; 
+    // Return if no flip has been performed.
+    if (flipcount == 0l) break;
+
+    // Try to flip the unflippable faces.
+    for (i = 0; i < unflipqueue->objects; i++) {
+      bface = (badface *) fastlookup(unflipqueue, i);
+      if (!isdeadtet(bface->tt) && 
+          (org(bface->tt) == bface->forg) &&
+          (dest(bface->tt) == bface->fdest) &&
+          (apex(bface->tt) == bface->fapex)) {
+        flippush(flipstack, &(bface->tt));
+      }
+    }
+    unflipqueue->restart();
+
+  } // while (1)
+
+  if (b->verbose > 2) {
+    if (totalcount > 0) {
+      printf("      Performed %ld flips.\n", totalcount);
+    }
+    if (sliver_peels > 0) {
+      printf("      Removed %ld hull slivers.\n", sliver_peels);
+    }
+    if (unflipqueue->objects > 0l) {
+      printf("      %ld unflippable edges remained.\n", unflipqueue->objects);
+    }
+  }
+
+  return totalcount + sliver_peels;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// recoverdelaunay()    Recovery the locally Delaunay property.              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::recoverdelaunay()
+{
+  arraypool *flipqueue, *nextflipqueue, *swapqueue;
+  triface tetloop, neightet, *parytet;
+  badface *bface, *parybface;
+  point *ppt;
+  flipconstraints fc;
+  int i, j;
+
+  if (!b->quiet) {
+    printf("Recovering Delaunayness...\n");
+  }
+
+  tetprism_vol_sum = 0.0; // Initialize it.
+
+  // Put all interior faces of the mesh into 'flipstack'.
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != NULL) {
+    for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
+      decode(tetloop.tet[tetloop.ver], neightet);
+      if (!facemarked(neightet)) {
+        flippush(flipstack, &tetloop);
+      }
+    }
+    ppt = (point *) &(tetloop.tet[4]);
+    tetprism_vol_sum += tetprismvol(ppt[0], ppt[1], ppt[2], ppt[3]);
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  // Calulate a relatively lower bound for small improvement. 
+  //   Used to avoid rounding error in volume calculation.
+  fc.bak_tetprism_vol = tetprism_vol_sum * b->epsilon * 1e-3;
+
+  if (b->verbose) {
+    printf("  Initial obj = %.17g\n", tetprism_vol_sum);
+  }
+
+  if (b->verbose > 1) {
+    printf("    Recover Delaunay [Lawson] : %ld\n", flippool->items);
+  }
+
+  // First only use the basic Lawson's flip.
+  fc.remove_ndelaunay_edge = 1;
+  fc.enqflag = 2;
+
+  lawsonflip3d(&fc);
+
+  if (b->verbose > 1) {
+    printf("    obj (after Lawson) = %.17g\n", tetprism_vol_sum);
+  }
+
+  if (unflipqueue->objects == 0l) {
+    return; // The mesh is Delaunay.
+  }
+
+  fc.unflip = 1; // Unflip if the edge is not flipped.
+  fc.collectnewtets = 1; // new tets are returned in 'cavetetlist'.
+  fc.enqflag = 0;
+
+  autofliplinklevel = 1; // Init level.
+  b->fliplinklevel = -1; // No fixed level.
+
+  // For efficiency reason, we limit the maximium size of the edge star.
+  int bakmaxflipstarsize = b->flipstarsize;
+  b->flipstarsize = 10; // default
+
+  flipqueue = new arraypool(sizeof(badface), 10);
+  nextflipqueue = new arraypool(sizeof(badface), 10);
+  
+  // Swap the two flip queues.
+  swapqueue = flipqueue;
+  flipqueue = unflipqueue;
+  unflipqueue = swapqueue;
+
+  while (flipqueue->objects > 0l) {
+
+    if (b->verbose > 1) {
+      printf("    Recover Delaunay [level = %2d] #:  %ld.\n",
+             autofliplinklevel, flipqueue->objects);
+    }
+
+    for (i = 0; i < flipqueue->objects; i++) {
+      bface  = (badface *) fastlookup(flipqueue, i);
+      if (getedge(bface->forg, bface->fdest, &bface->tt)) {
+        if (removeedgebyflips(&(bface->tt), &fc) == 2) {
+          tetprism_vol_sum += fc.tetprism_vol_sum;
+          fc.tetprism_vol_sum = 0.0; // Clear it.
+          // Queue new faces for flips.
+          for (j = 0; j < cavetetlist->objects; j++) {
+            parytet = (triface *) fastlookup(cavetetlist, j);
+            // A queued new tet may be dead.
+            if (!isdeadtet(*parytet)) {
+              for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
+                // Avoid queue a face twice.
+                decode(parytet->tet[parytet->ver], neightet);
+                if (!facemarked(neightet)) {
+                  flippush(flipstack, parytet);
+                }
+              } // parytet->ver
+            }
+          } // j
+          cavetetlist->restart();
+          // Remove locally non-Delaunay faces. New non-Delaunay edges
+          //   may be found. They are saved in 'unflipqueue'.
+          fc.enqflag = 2;
+          lawsonflip3d(&fc);
+          fc.enqflag = 0;
+          // There may be unflipable faces. Add them in flipqueue.
+          for (j = 0; j < unflipqueue->objects; j++) {
+            bface  = (badface *) fastlookup(unflipqueue, j);
+            flipqueue->newindex((void **) &parybface);
+            *parybface = *bface;
+          }
+          unflipqueue->restart();
+        } else {
+          // Unable to remove this edge. Save it.
+          nextflipqueue->newindex((void **) &parybface);
+          *parybface = *bface;
+          // Normally, it should be zero. 
+          //assert(fc.tetprism_vol_sum == 0.0);
+          // However, due to rounding errors, a tiny value may appear.
+          fc.tetprism_vol_sum = 0.0;
+        }
+      }
+    } // i
+
+    if (b->verbose > 1) {
+      printf("    obj (after level %d) = %.17g.\n", autofliplinklevel,
+             tetprism_vol_sum);
+    }
+    flipqueue->restart();
+
+    // Swap the two flip queues.
+    swapqueue = flipqueue;
+    flipqueue = nextflipqueue;
+    nextflipqueue = swapqueue;
+
+    if (flipqueue->objects > 0l) {
+      // default 'b->delmaxfliplevel' is 1.
+      if (autofliplinklevel >= b->delmaxfliplevel) {
+        // For efficiency reason, we do not search too far.
+        break;
+      }
+      autofliplinklevel+=b->fliplinklevelinc;
+    }
+  } // while (flipqueue->objects > 0l)
+
+  if (flipqueue->objects > 0l) {
+    if (b->verbose > 1) {
+      printf("    %ld non-Delaunay edges remained.\n", flipqueue->objects);
+    }
+  }
+
+  if (b->verbose) {
+    printf("  Final obj  = %.17g\n", tetprism_vol_sum);
+  }
+
+  b->flipstarsize = bakmaxflipstarsize;
+  delete flipqueue;
+  delete nextflipqueue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// gettetrahedron()    Get a tetrahedron which have the given vertices.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::gettetrahedron(point pa, point pb, point pc, point pd, 
+                               triface *searchtet)
+{
+  triface spintet;
+  int t1ver; 
+
+  if (getedge(pa, pb, searchtet)) {
+    spintet = *searchtet;
+    while (1) {
+      if (apex(spintet) == pc) {
+        *searchtet = spintet;
+        break;
+      }
+      fnextself(spintet);
+      if (spintet.tet == searchtet->tet) break;
+    }
+    if (apex(*searchtet) == pc) {
+      if (oppo(*searchtet) == pd) {
+        return 1;
+      } else {
+        fsymself(*searchtet);
+        if (oppo(*searchtet) == pd) {
+          return 1;
+        }
+      }
+    }
+  }
+
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// improvequalitybyflips()    Improve the mesh quality by flips.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+long tetgenmesh::improvequalitybyflips()
+{
+  arraypool *flipqueue, *nextflipqueue, *swapqueue;
+  badface *bface, *parybface;
+  triface *parytet;
+  point *ppt;
+  flipconstraints fc;
+  REAL *cosdd, ncosdd[6], maxdd;
+  long totalremcount, remcount;
+  int remflag;
+  int n, i, j, k;
+
+  //assert(unflipqueue->objects > 0l);
+  flipqueue = new arraypool(sizeof(badface), 10);
+  nextflipqueue = new arraypool(sizeof(badface), 10);
+
+  // Backup flip edge options.
+  int bakautofliplinklevel = autofliplinklevel;
+  int bakfliplinklevel = b->fliplinklevel;
+  int bakmaxflipstarsize = b->flipstarsize;
+
+  // Set flip edge options.
+  autofliplinklevel = 1; 
+  b->fliplinklevel = -1;
+  b->flipstarsize = 10; // b->optmaxflipstarsize;
+
+  fc.remove_large_angle = 1;
+  fc.unflip = 1;
+  fc.collectnewtets = 1;
+  fc.checkflipeligibility = 1;
+
+  totalremcount = 0l;
+
+  // Swap the two flip queues.
+  swapqueue = flipqueue;
+  flipqueue = unflipqueue;
+  unflipqueue = swapqueue;
+
+  while (flipqueue->objects > 0l) {
+
+    remcount = 0l;
+
+    while (flipqueue->objects > 0l) {
+      if (b->verbose > 1) {
+        printf("    Improving mesh qualiy by flips [%d]#:  %ld.\n",
+               autofliplinklevel, flipqueue->objects);
+      }
+
+      for (k = 0; k < flipqueue->objects; k++) {
+        bface  = (badface *) fastlookup(flipqueue, k);
+        if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
+                           bface->foppo, &bface->tt)) {
+          //assert(!ishulltet(bface->tt));
+          // There are bad dihedral angles in this tet.
+          if (bface->tt.ver != 11) {
+            // The dihedral angles are permuted.
+            // Here we simply re-compute them. Slow!!.
+            ppt = (point *) & (bface->tt.tet[4]);
+            tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent, 
+                           &bface->key, NULL);
+            bface->forg = ppt[0];
+            bface->fdest = ppt[1];
+            bface->fapex = ppt[2];
+            bface->foppo = ppt[3];
+            bface->tt.ver = 11;
+          }
+          if (bface->key == 0) {
+            // Re-comput the quality values. Due to smoothing operations.
+            ppt = (point *) & (bface->tt.tet[4]);
+            tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent, 
+                           &bface->key, NULL);
+          }
+          cosdd = bface->cent;
+          remflag = 0;
+          for (i = 0; (i < 6) && !remflag; i++) {
+            if (cosdd[i] < cosmaxdihed) {
+              // Found a large dihedral angle.
+              bface->tt.ver = edge2ver[i]; // Go to the edge.
+              fc.cosdihed_in = cosdd[i];
+              fc.cosdihed_out = 0.0; // 90 degree.
+              n = removeedgebyflips(&(bface->tt), &fc);
+              if (n == 2) {
+                // Edge is flipped.
+                remflag = 1;
+                if (fc.cosdihed_out < cosmaxdihed) {
+                  // Queue new bad tets for further improvements.
+                  for (j = 0; j < cavetetlist->objects; j++) {
+                    parytet = (triface *) fastlookup(cavetetlist, j);
+                    if (!isdeadtet(*parytet)) {
+                      ppt = (point *) & (parytet->tet[4]);
+                      // Do not test a hull tet.
+                      if (ppt[3] != dummypoint) {
+                        tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd, 
+                                       &maxdd, NULL);
+                        if (maxdd < cosmaxdihed) {
+                          // There are bad dihedral angles in this tet.
+                          nextflipqueue->newindex((void **) &parybface); 
+                          parybface->tt.tet = parytet->tet;
+                          parybface->tt.ver = 11;
+                          parybface->forg = ppt[0];
+                          parybface->fdest = ppt[1];
+                          parybface->fapex = ppt[2];
+                          parybface->foppo = ppt[3];
+                          parybface->key = maxdd;
+                          for (n = 0; n < 6; n++) {
+                            parybface->cent[n] = ncosdd[n];
+                          }
+                        }
+                      } // if (ppt[3] != dummypoint) 
+                    }
+                  } // j
+                } // if (fc.cosdihed_out < cosmaxdihed)
+                cavetetlist->restart();
+                remcount++;
+              }
+            }
+          } // i          
+          if (!remflag) {
+            // An unremoved bad tet. Queue it again. 
+            unflipqueue->newindex((void **) &parybface);
+            *parybface = *bface;
+          }
+        } // if (gettetrahedron(...))
+      } // k
+
+      flipqueue->restart();
+
+      // Swap the two flip queues.
+      swapqueue = flipqueue;
+      flipqueue = nextflipqueue;
+      nextflipqueue = swapqueue;
+    } // while (flipqueues->objects > 0)
+
+    if (b->verbose > 1) {
+      printf("    Removed %ld bad tets.\n", remcount);
+    }
+    totalremcount += remcount;
+
+    if (unflipqueue->objects > 0l) {
+      //if (autofliplinklevel >= b->optmaxfliplevel) {
+      if (autofliplinklevel >= b->optlevel) {
+        break;
+      }
+      autofliplinklevel+=b->fliplinklevelinc;
+      //b->flipstarsize = 10 + (1 << (b->optlevel - 1));
+    }
+
+    // Swap the two flip queues.
+    swapqueue = flipqueue;
+    flipqueue = unflipqueue;
+    unflipqueue = swapqueue;
+  } // while (flipqueues->objects > 0)
+
+  // Restore original flip edge options.
+  autofliplinklevel = bakautofliplinklevel;
+  b->fliplinklevel = bakfliplinklevel;
+  b->flipstarsize = bakmaxflipstarsize;
+
+  delete flipqueue;
+  delete nextflipqueue;
+
+  return totalremcount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// smoothpoint()    Moving a vertex to improve the mesh quality.             //
+//                                                                           //
+// 'smtpt' (p) is a point to be smoothed. Generally, it is a Steiner point.  //
+// It may be not a vertex of the mesh.                                       //
+//                                                                           //
+// This routine tries to move 'p' inside its star until a selected objective //
+// function over all tetrahedra in the star is improved. The function may be //
+// the some quality measures, i.e., aspect ratio, maximum dihedral angel, or //
+// simply the volume of the tetrahedra.                                      //
+//                                                                           //
+// 'linkfacelist' contains the list of link faces of 'p'.  Since a link face //
+// has two orientations, ccw or cw, with respect to 'p'.  'ccw' indicates    //
+// the orientation is ccw (1) or not (0).                                    //
+//                                                                           //
+// 'opm' is a structure contains the parameters of the objective function.   //
+// It is needed by the evaluation of the function value.                     //
+//                                                                           //
+// The return value indicates weather the point is smoothed or not.          //
+//                                                                           //
+// ASSUMPTION: This routine assumes that all link faces are true faces, i.e, //
+// no face has 'dummypoint' as its vertex.                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::smoothpoint(point smtpt, arraypool *linkfacelist, int ccw,
+                            optparameters *opm)
+{
+  triface *parytet, *parytet1, swaptet;
+  point pa, pb, pc;
+  REAL fcent[3], startpt[3], nextpt[3], bestpt[3];
+  REAL oldval, minval = 0.0, val;
+  REAL maxcosd; // oldang, newang;
+  REAL ori, diff;
+  int numdirs, iter;
+  int i, j, k;
+
+  // Decide the number of moving directions.
+  numdirs = (int) linkfacelist->objects;
+  if (numdirs > opm->numofsearchdirs) {
+    numdirs = opm->numofsearchdirs; // Maximum search directions.
+  }
+
+  // Set the initial value.
+  if (!opm->max_min_volume) {
+    assert(opm->initval >= 0.0);
+  }
+  opm->imprval = opm->initval;
+  iter = 0;
+
+  for (i = 0; i < 3; i++) {
+    bestpt[i] = startpt[i] = smtpt[i];
+  }
+
+  // Iterate until the obj function is not improved.
+  while (1) {
+
+    // Find the best next location.
+    oldval = opm->imprval;
+
+    for (i = 0; i < numdirs; i++) {
+      // Randomly pick a link face (0 <= k <= objects - i - 1).
+      k = (int) randomnation(linkfacelist->objects - i);
+      parytet = (triface *) fastlookup(linkfacelist, k);
+      // Calculate a new position from 'p' to the center of this face.
+      pa = org(*parytet);
+      pb = dest(*parytet);
+      pc = apex(*parytet);
+      for (j = 0; j < 3; j++) {
+        fcent[j] = (pa[j] + pb[j] + pc[j]) / 3.0;
+      }
+      for (j = 0; j < 3; j++) {
+        nextpt[j] = startpt[j] + opm->searchstep * (fcent[j] - startpt[j]); 
+      }
+      // Calculate the largest minimum function value for the new location.
+      for (j = 0; j < linkfacelist->objects; j++) {
+        parytet = (triface *) fastlookup(linkfacelist, j);
+        if (ccw) {
+          pa = org(*parytet);
+          pb = dest(*parytet);
+        } else {
+          pb = org(*parytet);
+          pa = dest(*parytet);
+        }
+        pc = apex(*parytet);
+        ori = orient3d(pa, pb, pc, nextpt);
+        if (ori < 0.0) {
+          // Calcuate the objective function value. 
+          if (opm->max_min_volume) {
+            //val = -ori;
+            val = - orient3dfast(pa, pb, pc, nextpt);
+          } else if (opm->max_min_aspectratio) {
+            val = tetaspectratio(pa, pb, pc, nextpt);
+          } else if (opm->min_max_dihedangle) {
+            tetalldihedral(pa, pb, pc, nextpt, NULL, &maxcosd, NULL);
+            if (maxcosd < -1) maxcosd = -1.0; // Rounding.
+            val = maxcosd + 1.0; // Make it be positive. 
+          } else {
+            // Unknown objective function.
+            val = 0.0;
+          }  
+        } else { // ori >= 0.0;
+          // An invalid new tet. 
+          // This may happen if the mesh contains inverted elements.
+          if (opm->max_min_volume) {
+            //val = -ori;
+            val = - orient3dfast(pa, pb, pc, nextpt);    
+          } else {
+            // Discard this point.
+            break; // j
+          }
+        } // if (ori >= 0.0)
+        // Stop looping when the object value is not improved.
+        if (val <= opm->imprval) {
+          break; // j
+        } else {
+          // Remember the smallest improved value.
+          if (j == 0) {
+            minval = val;
+          } else {
+            minval = (val < minval) ? val : minval;
+          }
+        }
+      } // j
+      if (j == linkfacelist->objects) {
+        // The function value has been improved.
+        opm->imprval = minval;
+        // Save the new location of the point.
+        for (j = 0; j < 3; j++) bestpt[j] = nextpt[j];
+      }
+      // Swap k-th and (object-i-1)-th entries.
+      j = linkfacelist->objects - i - 1;
+      parytet  = (triface *) fastlookup(linkfacelist, k);
+      parytet1 = (triface *) fastlookup(linkfacelist, j);
+      swaptet = *parytet1;
+      *parytet1 = *parytet;
+      *parytet = swaptet;
+    } // i
+
+    diff = opm->imprval - oldval;
+    if (diff > 0.0) {
+      // Is the function value improved effectively?
+      if (opm->max_min_volume) {
+        //if ((diff / oldval) < b->epsilon) diff = 0.0;  
+      } else if (opm->max_min_aspectratio) {
+        if ((diff / oldval) < 1e-3) diff = 0.0;
+      } else if (opm->min_max_dihedangle) {
+        //oldang = acos(oldval - 1.0);
+        //newang = acos(opm->imprval - 1.0);
+        //if ((oldang - newang) < 0.00174) diff = 0.0; // about 0.1 degree.
+      } else {
+        // Unknown objective function.
+        assert(0); // Not possible.
+      }
+    }
+
+    if (diff > 0.0) {
+      // Yes, move p to the new location and continue.
+      for (j = 0; j < 3; j++) startpt[j] = bestpt[j];
+      iter++;
+      if ((opm->maxiter > 0) && (iter >= opm->maxiter)) {
+        // Maximum smoothing iterations reached.
+        break;
+      }
+    } else {
+      break;
+    }
+
+  } // while (1)
+
+  if (iter > 0) {
+    // The point has been smoothed.
+    opm->smthiter = iter; // Remember the number of iterations. 
+    // The point has been smoothed. Update it to its new position.
+    for (i = 0; i < 3; i++) smtpt[i] = startpt[i];
+  }
+
+  return iter;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// improvequalitysmoothing()    Improve mesh quality by smoothing.           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+long tetgenmesh::improvequalitybysmoothing(optparameters *opm)
+{
+  arraypool *flipqueue, *swapqueue;
+  triface *parytet;
+  badface *bface, *parybface;
+  point *ppt;
+  long totalsmtcount, smtcount;
+  int smtflag;
+  int iter, i, j, k;
+
+  //assert(unflipqueue->objects > 0l);
+  flipqueue = new arraypool(sizeof(badface), 10);
+
+  // Swap the two flip queues.
+  swapqueue = flipqueue;
+  flipqueue = unflipqueue;
+  unflipqueue = swapqueue;
+
+  totalsmtcount = 0l;
+  iter = 0;
+
+  while (flipqueue->objects > 0l) {
+
+    smtcount = 0l;
+
+    if (b->verbose > 1) {
+      printf("    Improving mesh quality by smoothing [%d]#:  %ld.\n",
+             iter, flipqueue->objects);
+    }
+
+    for (k = 0; k < flipqueue->objects; k++) {      
+      bface  = (badface *) fastlookup(flipqueue, k);
+      if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
+                         bface->foppo, &bface->tt)) {
+        // Operate on it if it is not in 'unflipqueue'.
+        if (!marktested(bface->tt)) {
+          // Here we simply re-compute the quality. Since other smoothing
+          //   operation may have moved the vertices of this tet.
+          ppt = (point *) & (bface->tt.tet[4]);
+          tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent, 
+                         &bface->key, NULL);
+          if (bface->key < cossmtdihed) { // if (maxdd < cosslidihed) {
+            // It is a sliver. Try to smooth its vertices.
+            smtflag = 0;
+            opm->initval = bface->key + 1.0; 
+            for (i = 0; (i < 4) && !smtflag; i++) {
+              if (pointtype(ppt[i]) == FREEVOLVERTEX) {
+                getvertexstar(1, ppt[i], cavetetlist, NULL, NULL);
+                opm->searchstep = 0.001; // Search step size
+                smtflag = smoothpoint(ppt[i], cavetetlist, 1, opm);
+                if (smtflag) {
+                  while (opm->smthiter == opm->maxiter) {
+                    opm->searchstep *= 10.0; // Increase the step size.
+                    opm->initval = opm->imprval;
+                    opm->smthiter = 0; // reset
+                    smoothpoint(ppt[i], cavetetlist, 1, opm);
+                  }
+                  // This tet is modifed.
+                  smtcount++;
+                  if ((opm->imprval - 1.0) < cossmtdihed) {
+                    // There are slivers in new tets. Queue them.
+                    for (j = 0; j < cavetetlist->objects; j++) {
+                      parytet = (triface *) fastlookup(cavetetlist, j);
+                      assert(!isdeadtet(*parytet));
+                      // Operate it if it is not in 'unflipqueue'.
+                      if (!marktested(*parytet)) {
+                        // Evaluate its quality.
+                        // Re-use ppt, bface->key, bface->cent.
+                        ppt = (point *) & (parytet->tet[4]);
+                        tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], 
+                                       bface->cent, &bface->key, NULL);
+                        if (bface->key < cossmtdihed) {
+                          // A new sliver. Queue it.
+                          marktest(*parytet); // It is in unflipqueue.
+                          unflipqueue->newindex((void **) &parybface);
+                          parybface->tt = *parytet;
+                          parybface->forg = ppt[0];
+                          parybface->fdest = ppt[1];
+                          parybface->fapex = ppt[2];
+                          parybface->foppo = ppt[3];
+                          parybface->tt.ver = 11; 
+                          parybface->key = 0.0;
+                        }
+                      }
+                    } // j
+                  } // if ((opm->imprval - 1.0) < cossmtdihed)
+                } // if (smtflag)
+                cavetetlist->restart();
+              } // if (pointtype(ppt[i]) == FREEVOLVERTEX)
+            } // i
+            if (!smtflag) {
+              // Didn't smooth. Queue it again.
+              marktest(bface->tt); // It is in unflipqueue.
+              unflipqueue->newindex((void **) &parybface);
+              parybface->tt = bface->tt;
+              parybface->forg = ppt[0];
+              parybface->fdest = ppt[1];
+              parybface->fapex = ppt[2];
+              parybface->foppo = ppt[3];
+              parybface->tt.ver = 11;
+              parybface->key = 0.0;
+            }
+	      } // if (maxdd < cosslidihed)
+        } // if (!marktested(...))
+      } // if (gettetrahedron(...))
+    } // k
+
+    flipqueue->restart();
+
+    // Unmark the tets in unflipqueue.
+    for (i = 0; i < unflipqueue->objects; i++) {
+      bface  = (badface *) fastlookup(unflipqueue, i);
+      unmarktest(bface->tt);
+    }
+
+    if (b->verbose > 1) {
+      printf("    Smooth %ld points.\n", smtcount);
+    }
+    totalsmtcount += smtcount;
+
+    if (smtcount == 0l) {
+      // No point has been smoothed. 
+      break;
+    } else {
+      iter++;
+      if (iter == 2) { //if (iter >= b->optpasses) {
+        break;
+      }
+    }
+
+    // Swap the two flip queues.
+    swapqueue = flipqueue;
+    flipqueue = unflipqueue;
+    unflipqueue = swapqueue;
+  } // while
+
+  delete flipqueue;
+
+  return totalsmtcount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// splitsliver()    Split a sliver.                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::splitsliver(triface *slitet, REAL cosd, int chkencflag)
+{
+  triface *abtets;
+  triface searchtet, spintet, *parytet;
+  point pa, pb, steinerpt;
+  optparameters opm;
+  insertvertexflags ivf;
+  REAL smtpt[3], midpt[3];
+  int success;
+  int t1ver;
+  int n, i;
+
+  // 'slitet' is [c,d,a,b], where [c,d] has a big dihedral angle. 
+  // Go to the opposite edge [a,b].
+  edestoppo(*slitet, searchtet); // [a,b,c,d].
+
+  // Do not split a segment.
+  if (issubseg(searchtet)) {
+    return 0; 
+  }
+
+  // Count the number of tets shared at [a,b].
+  // Do not split it if it is a hull edge.
+  spintet = searchtet;
+  n = 0; 
+  while (1) {
+    if (ishulltet(spintet)) break;
+    n++;
+    fnextself(spintet);
+    if (spintet.tet == searchtet.tet) break;
+  }
+  if (ishulltet(spintet)) {
+    return 0; // It is a hull edge.
+  }
+  assert(n >= 3);
+
+  // Get all tets at edge [a,b].
+  abtets = new triface[n];
+  spintet = searchtet;
+  for (i = 0; i < n; i++) {
+    abtets[i] = spintet;
+    fnextself(spintet);
+  }
+
+  // Initialize the list of 2n boundary faces.
+  for (i = 0; i < n; i++) {    
+    eprev(abtets[i], searchtet);
+    esymself(searchtet); // [a,p_i,p_i+1].
+    cavetetlist->newindex((void **) &parytet);
+    *parytet = searchtet;
+    enext(abtets[i], searchtet);
+    esymself(searchtet); // [p_i,b,p_i+1].
+    cavetetlist->newindex((void **) &parytet);
+    *parytet = searchtet;
+  }
+
+  // Init the Steiner point at the midpoint of edge [a,b].
+  pa = org(abtets[0]);
+  pb = dest(abtets[0]);
+  for (i = 0; i < 3; i++) {
+    smtpt[i] = midpt[i] = 0.5 * (pa[i] + pb[i]);
+  }
+
+  // Point smooth options.
+  opm.min_max_dihedangle = 1;
+  opm.initval = cosd + 1.0; // Initial volume is zero.
+  opm.numofsearchdirs = 20;
+  opm.searchstep = 0.001;  
+  opm.maxiter = 100; // Limit the maximum iterations.
+
+  success = smoothpoint(smtpt, cavetetlist, 1, &opm);
+
+  if (success) {
+    while (opm.smthiter == opm.maxiter) {
+      // It was relocated and the prescribed maximum iteration reached. 
+      // Try to increase the search stepsize.
+      opm.searchstep *= 10.0;
+      //opm.maxiter = 100; // Limit the maximum iterations.
+      opm.initval = opm.imprval;
+      opm.smthiter = 0; // Init.
+      smoothpoint(smtpt, cavetetlist, 1, &opm);  
+    }
+  } // if (success)
+
+  cavetetlist->restart();
+
+  if (!success) {
+    delete [] abtets;
+    return 0;
+  }
+
+
+  // Insert the Steiner point.
+  makepoint(&steinerpt, FREEVOLVERTEX);
+  for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i];
+
+  // Insert the created Steiner point.
+  for (i = 0; i < n; i++) {
+    infect(abtets[i]);
+    caveoldtetlist->newindex((void **) &parytet);
+    *parytet = abtets[i];
+  }
+
+  searchtet = abtets[0]; // No need point location.
+  if (b->metric) {
+    locate(steinerpt, &searchtet); // For size interpolation.
+  }
+
+  delete [] abtets;
+
+  ivf.iloc = (int) INSTAR;
+  ivf.chkencflag = chkencflag;
+  ivf.assignmeshsize = b->metric; 
+
+
+  if (insertpoint(steinerpt, &searchtet, NULL, NULL, &ivf)) {
+    // The vertex has been inserted.
+    st_volref_count++; 
+    if (steinerleft > 0) steinerleft--;
+    return 1;
+  } else {
+    // The Steiner point is too close to an existing vertex. Reject it.
+    pointdealloc(steinerpt);
+    return 0;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// removeslivers()    Remove slivers by adding Steiner points.               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+long tetgenmesh::removeslivers(int chkencflag)
+{
+  arraypool *flipqueue, *swapqueue;
+  badface *bface, *parybface;
+  triface slitet, *parytet;
+  point *ppt;
+  REAL cosdd[6], maxcosd;
+  long totalsptcount, sptcount;
+  int iter, i, j, k;
+
+  //assert(unflipqueue->objects > 0l);
+  flipqueue = new arraypool(sizeof(badface), 10);
+
+  // Swap the two flip queues.
+  swapqueue = flipqueue;
+  flipqueue = unflipqueue;
+  unflipqueue = swapqueue;
+
+  totalsptcount = 0l;
+  iter = 0;
+
+  while ((flipqueue->objects > 0l) && (steinerleft != 0)) {
+
+    sptcount = 0l;
+
+    if (b->verbose > 1) {
+      printf("    Splitting bad quality tets [%d]#:  %ld.\n",
+             iter, flipqueue->objects);
+    }
+
+    for (k = 0; (k < flipqueue->objects) && (steinerleft != 0); k++) {      
+      bface  = (badface *) fastlookup(flipqueue, k);
+      if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
+                         bface->foppo, &bface->tt)) {
+        if ((bface->key == 0) || (bface->tt.ver != 11)) {
+          // Here we need to re-compute the quality. Since other smoothing
+          //   operation may have moved the vertices of this tet.
+          ppt = (point *) & (bface->tt.tet[4]);
+          tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent, 
+                         &bface->key, NULL);
+        }
+        if (bface->key < cosslidihed) { 
+          // It is a sliver. Try to split it.
+          slitet.tet = bface->tt.tet;
+          //cosdd = bface->cent;
+          for (j = 0; j < 6; j++) {
+            if (bface->cent[j] < cosslidihed) { 
+              // Found a large dihedral angle.
+              slitet.ver = edge2ver[j]; // Go to the edge.
+              if (splitsliver(&slitet, bface->cent[j], chkencflag)) {
+                sptcount++;
+                break;
+              }
+            }
+          } // j
+          if (j < 6) {
+            // A sliver is split. Queue new slivers.
+            badtetrahedrons->traversalinit();
+            parytet = (triface *) badtetrahedrons->traverse();
+            while (parytet != NULL) {
+              unmarktest2(*parytet);
+              ppt = (point *) & (parytet->tet[4]);
+              tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], cosdd, 
+                             &maxcosd, NULL);
+              if (maxcosd < cosslidihed) {
+                // A new sliver. Queue it.
+                unflipqueue->newindex((void **) &parybface);
+                parybface->forg = ppt[0];
+                parybface->fdest = ppt[1];
+                parybface->fapex = ppt[2];
+                parybface->foppo = ppt[3];
+                parybface->tt.tet = parytet->tet;
+                parybface->tt.ver = 11;
+                parybface->key = maxcosd;
+                for (i = 0; i < 6; i++) {
+                  parybface->cent[i] = cosdd[i];
+                }
+              }
+              parytet = (triface *) badtetrahedrons->traverse();
+            }
+            badtetrahedrons->restart();
+          } else {
+            // Didn't split. Queue it again.
+            unflipqueue->newindex((void **) &parybface);
+            *parybface = *bface;
+          } // if (j == 6)
+        } // if (bface->key < cosslidihed)
+      } // if (gettetrahedron(...))
+    } // k
+
+    flipqueue->restart();
+
+    if (b->verbose > 1) {
+      printf("    Split %ld tets.\n", sptcount);
+    }
+    totalsptcount += sptcount;
+
+    if (sptcount == 0l) {
+      // No point has been smoothed. 
+      break;
+    } else {
+      iter++;
+      if (iter == 2) { //if (iter >= b->optpasses) {
+        break;
+      }
+    }
+
+    // Swap the two flip queues.
+    swapqueue = flipqueue;
+    flipqueue = unflipqueue;
+    unflipqueue = swapqueue;
+  } // while
+
+  delete flipqueue;
+
+  return totalsptcount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// optimizemesh()    Optimize mesh for specified objective functions.        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::optimizemesh()
+{
+  badface *parybface;
+  triface checktet;
+  point *ppt;
+  int optpasses;
+  optparameters opm;
+  REAL ncosdd[6], maxdd;
+  long totalremcount, remcount;
+  long totalsmtcount, smtcount;
+  long totalsptcount, sptcount;
+  int chkencflag;
+  int iter;
+  int n;
+
+  if (!b->quiet) {
+    printf("Optimizing mesh...\n");
+  }
+
+  optpasses = ((1 << b->optlevel) - 1);
+
+  if (b->verbose) {
+    printf("  Optimization level  = %d.\n", b->optlevel);
+    printf("  Optimization scheme = %d.\n", b->optscheme);
+    printf("  Number of iteration = %d.\n", optpasses);
+    printf("  Min_Max dihed angle = %g.\n", b->optmaxdihedral);
+  }
+
+  totalsmtcount = totalsptcount = totalremcount = 0l;
+
+  cosmaxdihed = cos(b->optmaxdihedral / 180.0 * PI);
+  cossmtdihed = cos(b->optminsmtdihed / 180.0 * PI);
+  cosslidihed = cos(b->optminslidihed / 180.0 * PI);
+
+  int attrnum = numelemattrib - 1; 
+
+  // Put all bad tetrahedra into array.
+  tetrahedrons->traversalinit();
+  checktet.tet = tetrahedrontraverse();
+  while (checktet.tet != NULL) {
+    if (b->convex) { // -c
+      // Skip this tet if it lies in the exterior.
+      if (elemattribute(checktet.tet, attrnum) == -1.0) {
+        checktet.tet = tetrahedrontraverse();
+        continue;
+      }
+    }
+    ppt = (point *) & (checktet.tet[4]);
+    tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd, &maxdd, NULL);
+    if (maxdd < cosmaxdihed) {
+      // There are bad dihedral angles in this tet.
+      unflipqueue->newindex((void **) &parybface); 
+      parybface->tt.tet = checktet.tet;
+      parybface->tt.ver = 11;
+      parybface->forg = ppt[0];
+      parybface->fdest = ppt[1];
+      parybface->fapex = ppt[2];
+      parybface->foppo = ppt[3];
+      parybface->key = maxdd;
+      for (n = 0; n < 6; n++) {
+        parybface->cent[n] = ncosdd[n];
+      }
+    }
+    checktet.tet = tetrahedrontraverse();
+  }
+
+  totalremcount = improvequalitybyflips();
+
+  if ((unflipqueue->objects > 0l) && 
+      ((b->optscheme & 2) || (b->optscheme & 4))) {
+    // The pool is only used by removeslivers().
+    badtetrahedrons = new memorypool(sizeof(triface), b->tetrahedraperblock,
+                                     sizeof(void *), 0);
+
+    // Smoothing options.
+    opm.min_max_dihedangle = 1;
+    opm.numofsearchdirs = 10;
+    // opm.searchstep = 0.001;  
+    opm.maxiter = 30; // Limit the maximum iterations.
+    //opm.checkencflag = 4; // Queue affected tets after smoothing.
+    chkencflag = 4; // Queue affected tets after splitting a sliver.
+    iter = 0;
+
+    while (iter < optpasses) {
+      smtcount = sptcount = remcount = 0l;
+      if (b->optscheme & 2) {
+        smtcount += improvequalitybysmoothing(&opm);
+        totalsmtcount += smtcount;
+        if (smtcount > 0l) {
+          remcount = improvequalitybyflips();
+          totalremcount += remcount;
+        }
+      }
+      if (unflipqueue->objects > 0l) {
+        if (b->optscheme & 4) {
+          sptcount += removeslivers(chkencflag);
+          totalsptcount += sptcount;
+          if (sptcount > 0l) {
+            remcount = improvequalitybyflips();
+            totalremcount += remcount;
+          }
+        }
+      }
+      if (unflipqueue->objects > 0l) {
+        if (remcount > 0l) {
+          iter++;
+        } else {
+          break;
+        }
+      } else {
+        break;
+      }
+    } // while (iter)
+
+    delete badtetrahedrons;
+
+  }
+
+  if (unflipqueue->objects > 0l) {
+    if (b->verbose > 1) {
+      printf("    %ld bad tets remained.\n", unflipqueue->objects);
+    }
+    unflipqueue->restart();
+  }
+
+  if (b->verbose) {
+    if (totalremcount > 0l) {
+      printf("  Removed %ld edges.\n", totalremcount);
+    }
+    if (totalsmtcount > 0l) {
+      printf("  Smoothed %ld points.\n", totalsmtcount);
+    }
+    if (totalsptcount > 0l) {
+      printf("  Split %ld slivers.\n", totalsptcount);
+    }
+  }
+}
+
+////                                                                       ////
+////                                                                       ////
+//// optimize_cxx /////////////////////////////////////////////////////////////
+
+//// meshstat_cxx /////////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// printfcomma()    Print a (large) number with the 'thousands separator'.   // 
+//                                                                           //
+// The following code was simply copied from "stackoverflow".                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::printfcomma(unsigned long n)
+{
+  unsigned long n2 = 0;
+  int scale = 1;
+  while (n >= 1000) {
+    n2 = n2 + scale * (n % 1000);
+    n /= 1000;
+    scale *= 1000;
+  }
+  printf ("%ld", n);
+  while (scale != 1) {
+    scale /= 1000;
+    n = n2 / scale;
+    n2 = n2  % scale;
+    printf (",%03ld", n);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkmesh()    Test the mesh for topological consistency.                 //
+//                                                                           //
+// If 'topoflag' is set, only check the topological connection of the mesh,  //
+// i.e., do not report degenerated or inverted elements.                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checkmesh(int topoflag)
+{
+  triface tetloop, 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.
+  tetrahedrons->traversalinit();
+  tetloop.tet = alltetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    // Check all four faces of the tetrahedron.
+    for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
+      pa = org(tetloop);
+      pb = dest(tetloop);
+      pc = apex(tetloop);
+      pd = oppo(tetloop);
+      if (tetloop.ver == 0) {  // Only test for inversion once.
+        if (!ishulltet(tetloop)) {  // Only do test if it is not a hull tet.
+          if (!topoflag) {
+            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));
+          horrors++;
+        }
+        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));
+          horrors++;
+        }
+      }
+      if (tetloop.tet[tetloop.ver] == 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.
+        fsym(tetloop, neightet);
+        // Check that the tetrahedron's neighbor knows it's a neighbor.
+        fsym(neightet, symtet);
+        if ((tetloop.tet != symtet.tet) || (tetloop.ver != symtet.ver)) {
+          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.ver = edge2ver[i];
+      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 = alltetrahedrontraverse();
+  }
+  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 boundary mesh for topological consistency.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checkshells()
+{
+  triface neightet, symtet;
+  face shloop, spinsh, nextsh;
+  face checkseg;
+  point pa, pb;
+  int bakcount;
+  int horrors, i;
+
+  if (!b->quiet) {
+    printf("  Checking consistency of the mesh boundary...\n");
+  }
+  horrors = 0;
+
+  void **bakpathblock = subfaces->pathblock;
+  void *bakpathitem = subfaces->pathitem;
+  int bakpathitemsleft = subfaces->pathitemsleft;
+  int bakalignbytes = subfaces->alignbytes;
+
+  subfaces->traversalinit();
+  shloop.sh = shellfacetraverse(subfaces);
+  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);
+      bakcount = horrors;
+      while ((nextsh.sh != NULL) && (nextsh.sh != shloop.sh)) {
+        if (nextsh.sh[3] == NULL) {
+          printf("  !! !! Wrong subface-subface connection (Dead subface).\n");
+          printf("    First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
+                 pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), 
+                 pointmark(sapex(spinsh)));
+          printf("    Second: x%lx (DEAD)\n", (uintptr_t) nextsh.sh);
+          horrors++;
+          break;
+        }
+        // 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", (uintptr_t) spinsh.sh,
+                  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), 
+                  pointmark(sapex(spinsh)));
+           printf("    Scond: x%lx (%d, %d, %d).\n", (uintptr_t) nextsh.sh,
+                  pointmark(sorg(nextsh)), pointmark(sdest(nextsh)), 
+                  pointmark(sapex(nextsh)));
+           horrors++;
+           break;
+        }
+        // Check they should not have the same apex.
+        if (sapex(nextsh) == sapex(spinsh)) {
+           printf("  !! !! Existing two duplicated subfaces.\n");
+           printf("    First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
+                  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), 
+                  pointmark(sapex(spinsh)));
+           printf("    Scond: x%lx (%d, %d, %d).\n", (uintptr_t) nextsh.sh,
+                  pointmark(sorg(nextsh)), pointmark(sdest(nextsh)), 
+                  pointmark(sapex(nextsh)));
+           horrors++;
+           break;
+        }
+        spinsh = nextsh;
+        spivot(spinsh, nextsh);
+      }
+      // Check subface-subseg bond.
+      sspivot(shloop, checkseg);
+      if (checkseg.sh != NULL) {
+        if (checkseg.sh[3] == NULL) {
+          printf("  !! !! Wrong subface-subseg connection (Dead subseg).\n");
+          printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
+                 pointmark(sorg(shloop)), pointmark(sdest(shloop)), 
+                 pointmark(sapex(shloop)));
+          printf("    Sub: x%lx (Dead)\n", (uintptr_t) checkseg.sh);
+          horrors++;
+        } else {
+          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", (uintptr_t) shloop.sh,
+                   pointmark(sorg(shloop)), pointmark(sdest(shloop)), 
+                   pointmark(sapex(shloop)));
+            printf("    Seg: x%lx (%d, %d).\n", (uintptr_t) checkseg.sh,
+                   pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
+            horrors++;
+          }
+        }
+      }
+      if (horrors > bakcount) break; // An error detected. 
+      senextself(shloop);
+    }
+    // Check tet-subface connection.
+    stpivot(shloop, neightet);
+    if (neightet.tet != NULL) {
+      if (neightet.tet[4] == NULL) {
+        printf("  !! !! Wrong sub-to-tet connection (Dead tet)\n");
+        printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
+               pointmark(sorg(shloop)), pointmark(sdest(shloop)), 
+               pointmark(sapex(shloop)));
+        printf("    Tet: x%lx (DEAD)\n", (uintptr_t) neightet.tet);
+        horrors++;
+      } else {
+        if (!((sorg(shloop) == org(neightet)) && 
+              (sdest(shloop) == dest(neightet)))) {
+          printf("  !! !! Wrong sub-to-tet connection\n");
+          printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
+                 pointmark(sorg(shloop)), pointmark(sdest(shloop)), 
+                 pointmark(sapex(shloop)));
+          printf("    Tet: x%lx (%d, %d, %d, %d).\n",
+                 (uintptr_t) neightet.tet, pointmark(org(neightet)), 
+                 pointmark(dest(neightet)), pointmark(apex(neightet)),
+                 pointmark(oppo(neightet)));
+          horrors++;
+        }
+        tspivot(neightet, spinsh);
+        if (!((sorg(spinsh) == org(neightet)) && 
+              (sdest(spinsh) == dest(neightet)))) {
+          printf("  !! !! Wrong tet-sub connection.\n");
+          printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
+                 pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), 
+                 pointmark(sapex(spinsh)));
+          printf("    Tet: x%lx (%d, %d, %d, %d).\n", 
+                 (uintptr_t) neightet.tet, pointmark(org(neightet)), 
+                 pointmark(dest(neightet)), pointmark(apex(neightet)), 
+                 pointmark(oppo(neightet)));
+          horrors++;
+        }
+        fsym(neightet, symtet);
+        tspivot(symtet, spinsh);
+        if (spinsh.sh != NULL) {
+          if (!((sorg(spinsh) == org(symtet)) && 
+                (sdest(spinsh) == dest(symtet)))) {
+            printf("  !! !! Wrong tet-sub connection.\n");
+            printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
+                   pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), 
+                   pointmark(sapex(spinsh)));
+            printf("    Tet: x%lx (%d, %d, %d, %d).\n", 
+                   (uintptr_t) symtet.tet, pointmark(org(symtet)), 
+                   pointmark(dest(symtet)), pointmark(apex(symtet)), 
+                   pointmark(oppo(symtet)));
+            horrors++;
+          }
+        } else {
+          printf("  Warning: Broken tet-sub-tet connection.\n");
+        }
+      }
+    }
+    if (sinfected(shloop)) {
+      // This may be a bug. report it.
+      printf("  !! A infected subface: (%d, %d, %d).\n", 
+             pointmark(sorg(shloop)), pointmark(sdest(shloop)), 
+             pointmark(sapex(shloop)));
+    }
+    if (smarktested(shloop)) {
+      // This may be a bug. report it.
+      printf("  !! A marked subface: (%d, %d, %d).\n", pointmark(sorg(shloop)), 
+             pointmark(sdest(shloop)), pointmark(sapex(shloop)));
+    }
+    shloop.sh = shellfacetraverse(subfaces);
+  }
+
+  if (horrors == 0) {
+    if (!b->quiet) {
+      printf("  Mesh boundaries connected correctly.\n");
+    }
+  } else {
+    printf("  !! !! !! !! %d boundary connection viewed with horror.\n",
+           horrors);
+  }
+
+  subfaces->pathblock = bakpathblock;
+  subfaces->pathitem = bakpathitem;
+  subfaces->pathitemsleft = bakpathitemsleft;
+  subfaces->alignbytes = bakalignbytes;
+
+  return horrors;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checksegments()    Check the connections between tetrahedra and segments. //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checksegments()
+{
+  triface tetloop, neightet, spintet;
+  shellface *segs;
+  face neighsh, spinsh, checksh;
+  face sseg, checkseg;
+  point pa, pb;
+  int miscount;
+  int t1ver;
+  int horrors, i;
+
+
+  if (!b->quiet) {
+    printf("  Checking tet->seg connections...\n");
+  }
+
+  horrors = 0;
+  tetrahedrons->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.ver = edge2ver[i];
+          // 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", 
+                   (uintptr_t) tetloop.tet, pointmark(org(tetloop)),
+                   pointmark(dest(tetloop)), pointmark(apex(tetloop)),
+                   pointmark(oppo(tetloop)), (uintptr_t) sseg.sh,
+                   pointmark(pa), pointmark(pb));
+            horrors++;
+          } else {
+            // Loop all tets sharing at this edge.
+            neightet = tetloop;
+            do {
+              tsspivot1(neightet, checkseg);
+              if (checkseg.sh != sseg.sh) {
+                printf("  !! Wrong tet->seg connection.\n");
+                printf("    Tet: x%lx (%d, %d, %d, %d) - ", 
+                       (uintptr_t) 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", (uintptr_t) 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.
+          sstpivot1(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", 
+                     (uintptr_t) neightet.tet, pointmark(org(neightet)),
+                     pointmark(dest(neightet)), pointmark(apex(neightet)),
+                     pointmark(oppo(neightet)), (uintptr_t) sseg.sh,
+                     pointmark(pa), pointmark(pb));
+              horrors++;
+            }
+          }
+        }
+      }
+    }
+    // Loop the six edge of this tet.
+    neightet.tet = tetloop.tet;
+    for (i = 0; i < 6; i++) {
+      neightet.ver = edge2ver[i];
+      if (edgemarked(neightet)) {
+        // A possible bug. Report it.
+        printf("  !! A marked edge: (%d, %d, %d, %d) -- x%lx %d.\n",
+               pointmark(org(neightet)), pointmark(dest(neightet)),
+               pointmark(apex(neightet)), pointmark(oppo(neightet)),
+               (uintptr_t) neightet.tet, neightet.ver);
+        // Check if all tets at the edge are marked.
+        spintet = neightet;
+        while (1) {
+          fnextself(spintet);
+          if (!edgemarked(spintet)) {
+            printf("  !! !! An unmarked edge (%d, %d, %d, %d) -- x%lx %d.\n",
+                   pointmark(org(spintet)), pointmark(dest(spintet)),
+                   pointmark(apex(spintet)), pointmark(oppo(spintet)),
+                   (uintptr_t) spintet.tet, spintet.ver);
+            horrors++;
+          }
+          if (spintet.tet == neightet.tet) break;
+        }
+      }
+    }
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  if (!b->quiet) {
+    printf("  Checking seg->tet connections...\n");
+  }
+
+  miscount = 0; // Count the number of unrecovered segments.
+  subsegs->traversalinit();
+  sseg.shver = 0;
+  sseg.sh = shellfacetraverse(subsegs);
+  while (sseg.sh != NULL) {
+    pa = sorg(sseg);
+    pb = sdest(sseg);
+    spivot(sseg, neighsh);
+    if (neighsh.sh != NULL) {      
+      spinsh = neighsh;
+      while (1) {
+        // Check seg-subface bond.
+        if (((sorg(spinsh) == pa) && (sdest(spinsh) == pb)) ||
+	    ((sorg(spinsh) == pb) && (sdest(spinsh) == pa))) {
+          // Keep the same rotate direction.
+          //if (sorg(spinsh) != pa) {          
+          //  sesymself(spinsh);
+          //  printf("  !! Wrong ori at subface (%d, %d, %d) -- x%lx %d\n",
+          //         pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
+          //         pointmark(sapex(spinsh)), (uintptr_t) spinsh.sh,
+          //         spinsh.shver);
+          //  horrors++;
+          //}
+          stpivot(spinsh, spintet);
+          if (spintet.tet != NULL) {
+            // Check if all tets at this segment.
+            while (1) {
+              tsspivot1(spintet, checkseg);
+              if (checkseg.sh == NULL) {
+                printf("  !! !! No seg at tet (%d, %d, %d, %d) -- x%lx %d\n",
+                       pointmark(org(spintet)), pointmark(dest(spintet)),
+                       pointmark(apex(spintet)), pointmark(oppo(spintet)),
+                       (uintptr_t) spintet.tet, spintet.ver);
+                horrors++;
+              }
+              if (checkseg.sh != sseg.sh) {
+                printf("  !! !! Wrong seg (%d, %d) at tet (%d, %d, %d, %d)\n",
+                       pointmark(sorg(checkseg)), pointmark(sdest(checkseg)),
+                       pointmark(org(spintet)), pointmark(dest(spintet)),
+                       pointmark(apex(spintet)), pointmark(oppo(spintet)));
+                horrors++;
+              }
+              fnextself(spintet);
+              // Stop at the next subface.
+              tspivot(spintet, checksh);
+              if (checksh.sh != NULL) break;
+            } // while (1)
+          }
+        } else { 
+          printf("  !! Wrong seg-subface (%d, %d, %d) -- x%lx %d connect\n",
+                 pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
+                 pointmark(sapex(spinsh)), (uintptr_t) spinsh.sh,
+                 spinsh.shver);
+          horrors++;
+          break;
+        } // if pa, pb
+        spivotself(spinsh);
+        if (spinsh.sh == NULL) break; // A dangling segment.
+        if (spinsh.sh == neighsh.sh) break;
+      } // while (1)
+    } // if (neighsh.sh != NULL)
+    // Count the number of "un-recovered" segments.
+    sstpivot1(sseg, neightet);
+    if (neightet.tet == NULL) {
+      miscount++;
+    }
+    sseg.sh = shellfacetraverse(subsegs);
+  }
+
+  if (!b->quiet) {
+    printf("  Checking seg->seg connections...\n");
+  }
+
+  points->traversalinit();
+  pa = pointtraverse();
+  while (pa != NULL) {
+    if (pointtype(pa) == FREESEGVERTEX) {
+      // There should be two subsegments connected at 'pa'.
+      // Get a subsegment containing 'pa'.
+      sdecode(point2sh(pa), sseg);
+      if ((sseg.sh == NULL) || sseg.sh[3] == NULL) {
+        printf("  !! Dead point-to-seg pointer at point %d.\n",
+               pointmark(pa));
+        horrors++;
+      } else {
+        sseg.shver = 0;
+        if (sorg(sseg) != pa) {
+          if (sdest(sseg) != pa) {
+            printf("  !! Wrong point-to-seg pointer at point %d.\n",
+                   pointmark(pa));
+            horrors++;
+          } else {
+            // Find the next subsegment at 'pa'.
+            senext(sseg, checkseg);
+            if ((checkseg.sh == NULL) || (checkseg.sh[3] == NULL)) {
+              printf("  !! Dead seg-seg connection at point %d.\n",
+                     pointmark(pa));
+              horrors++;
+            } else {
+              spivotself(checkseg);
+              checkseg.shver = 0;
+              if (sorg(checkseg) != pa) {
+                printf("  !! Wrong seg-seg connection at point %d.\n",
+                     pointmark(pa));
+                horrors++;
+              }
+            }
+          }
+        } else {
+          // Find the previous subsegment at 'pa'.
+          senext2(sseg, checkseg);
+          if ((checkseg.sh == NULL) || (checkseg.sh[3] == NULL)) {
+            printf("  !! Dead seg-seg connection at point %d.\n",
+                   pointmark(pa));
+            horrors++;
+          } else {
+            spivotself(checkseg);
+            checkseg.shver = 0;
+            if (sdest(checkseg) != pa) {
+              printf("  !! Wrong seg-seg connection at point %d.\n",
+                     pointmark(pa));
+              horrors++;
+            }
+          }
+        }
+      }
+    }
+    pa = pointtraverse();
+  }
+
+  if (horrors == 0) {
+    printf("  Segments are connected properly.\n");
+  } else {
+    printf("  !! !! !! !! Found %d missing connections.\n", horrors);
+  }
+  if (miscount > 0) {
+    printf("  !! !! Found %d missing segments.\n", miscount);
+  }
+
+  return horrors;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkdelaunay()    Ensure that the mesh is (constrained) Delaunay.        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checkdelaunay()
+{
+  triface tetloop;
+  triface symtet;
+  face checksh;
+  point pa, pb, pc, pd, pe;
+  REAL sign;
+  int ndcount; // Count the non-locally Delaunay faces.
+  int horrors;
+
+  if (!b->quiet) {
+    printf("  Checking Delaunay property of the mesh...\n");
+  }
+
+  ndcount = 0;
+  horrors = 0;
+  tetloop.ver = 0;
+  // Run through the list of triangles, checking each one.
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    // Check all four faces of the tetrahedron.
+    for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
+      fsym(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_s(pa, pb, pc, pd, pe);
+        if (sign < 0.0) {
+          ndcount++;
+          if (checksubfaceflag) {
+            tspivot(tetloop, checksh);
+          }
+          if (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) {
+      if (ndcount > 0) {
+        printf("  The mesh is constrained Delaunay.\n");
+      } else {
+        printf("  The mesh is Delaunay.\n");
+      } 
+    }
+  } else {
+    printf("  !! !! !! !! Found %d non-Delaunay faces.\n", horrors);
+  }
+
+  return horrors;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Check if the current tetrahedralization is (constrained) regular.         //
+//                                                                           //
+// The parameter 'type' determines which regularity should be checked:       //
+//   - 0:  check the Delaunay property.                                      //
+//   - 1:  check the Delaunay property with symbolic perturbation.           //
+//   - 2:  check the regular property, the weights are stored in p[3].       //
+//   - 3:  check the regular property with symbolic perturbation.            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checkregular(int type)
+{
+  triface tetloop;
+  triface symtet;
+  face checksh;
+  point p[5];
+  REAL sign;
+  int ndcount; // Count the non-locally Delaunay faces.
+  int horrors;
+
+  if (!b->quiet) {
+    printf("  Checking %s %s property of the mesh...\n",
+           (type & 2) == 0 ? "Delaunay" : "regular",
+           (type & 1) == 0 ? " " : "(s)");
+  }
+
+  // Make sure orient3d(p[1], p[0], p[2], p[3]) > 0;
+  //   Hence if (insphere(p[1], p[0], p[2], p[3], p[4]) > 0) means that
+  //     p[4] lies inside the circumsphere of p[1], p[0], p[2], p[3].
+  //   The same if orient4d(p[1], p[0], p[2], p[3], p[4]) > 0 means that
+  //     p[4] lies below the oriented hyperplane passing through 
+  //     p[1], p[0], p[2], p[3].
+
+  ndcount = 0;
+  horrors = 0;
+  tetloop.ver = 0;
+  // Run through the list of triangles, checking each one.
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    // Check all four faces of the tetrahedron.
+    for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
+      fsym(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)) {
+        p[0] = org(tetloop);   // pa
+        p[1] = dest(tetloop);  // pb
+        p[2] = apex(tetloop);  // pc
+        p[3] = oppo(tetloop);  // pd
+        p[4] = oppo(symtet);   // pe
+
+        if (type == 0) {
+          sign = insphere(p[1], p[0], p[2], p[3], p[4]);
+        } else if (type == 1) {
+          sign = insphere_s(p[1], p[0], p[2], p[3], p[4]);
+        } else if (type == 2) {
+          sign = orient4d(p[1],    p[0],    p[2],    p[3],    p[4], 
+                          p[1][3], p[0][3], p[2][3], p[3][3], p[4][3]);
+        } else { // type == 3
+          sign = orient4d_s(p[1],    p[0],    p[2],    p[3],    p[4], 
+                            p[1][3], p[0][3], p[2][3], p[3][3], p[4][3]);
+        }
+
+        if (sign > 0.0) {
+          ndcount++;
+          if (checksubfaceflag) {
+            tspivot(tetloop, checksh);
+          }
+          if (checksh.sh == NULL) {
+            printf("  !! Non-locally %s (%d, %d, %d) - %d, %d\n",
+                   (type & 2) == 0 ? "Delaunay" : "regular",
+		   pointmark(p[0]), pointmark(p[1]), pointmark(p[2]), 
+                   pointmark(p[3]), pointmark(p[4]));
+            horrors++;
+          }
+        }
+      }
+    }
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  if (horrors == 0) {
+    if (!b->quiet) {
+      if (ndcount > 0) {
+        printf("  The mesh is constrained %s.\n",
+               (type & 2) == 0 ? "Delaunay" : "regular");
+      } else {
+        printf("  The mesh is %s.\n", (type & 2) == 0 ? "Delaunay" : "regular");
+      } 
+    }
+  } else {
+    printf("  !! !! !! !! Found %d non-%s faces.\n", horrors,
+           (type & 2) == 0 ? "Delaunay" : "regular");
+  }
+
+  return horrors;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// checkconforming()    Ensure that the mesh is conforming Delaunay.         //
+//                                                                           //
+// If 'flag' is 1, only check subsegments. If 'flag' is 2, check subfaces.   //
+// If 'flag' is 3, check both subsegments and subfaces.                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::checkconforming(int flag)
+{
+  triface searchtet, neightet, spintet;
+  face shloop;
+  face segloop;
+  point eorg, edest, eapex, pa, pb, pc;
+  REAL cent[3], radius, dist, diff, rd, len;
+  bool enq;
+  int encsubsegs, encsubfaces;
+  int t1ver; 
+  int i;
+
+  REAL A[4][4], rhs[4], D;
+  int indx[4];
+  REAL elen[3];
+
+  encsubsegs = 0;
+
+  if (flag & 1) {
+    if (!b->quiet) {
+      printf("  Checking conforming property of segments...\n");
+    }
+    encsubsegs = 0;
+
+    // Run through the list of subsegments, check each one.
+    subsegs->traversalinit();
+    segloop.sh = shellfacetraverse(subsegs);
+    while (segloop.sh != (shellface *) NULL) {
+      eorg = (point) segloop.sh[3];
+      edest = (point) segloop.sh[4];
+      radius = 0.5 * distance(eorg, edest);
+      for (i = 0; i < 3; i++) cent[i] = 0.5 * (eorg[i] + edest[i]);
+
+      enq = false;
+      sstpivot1(segloop, neightet);
+      if (neightet.tet != NULL) {
+        spintet = neightet;
+        while (1) {
+          eapex= apex(spintet);
+          if (eapex != dummypoint) {
+            dist = distance(eapex, cent);
+            diff = dist - radius;
+            if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
+            if (diff < 0) {
+              enq = true; break;
+            }
+          }
+          fnextself(spintet);
+          if (spintet.tet == neightet.tet) break;
+        }
+      }
+      if (enq) {
+        printf("  !! !! Non-conforming segment: (%d, %d)\n",
+               pointmark(eorg), pointmark(edest));
+        encsubsegs++;
+      }
+      segloop.sh = shellfacetraverse(subsegs);
+    }
+
+    if (encsubsegs == 0) {
+      if (!b->quiet) {
+        printf("  The segments are conforming Delaunay.\n");
+      }
+    } else {
+      printf("  !! !! %d subsegments are non-conforming.\n", encsubsegs);
+    }
+  } // if (flag & 1)
+
+  encsubfaces = 0;
+
+  if (flag & 2) {
+    if (!b->quiet) {
+      printf("  Checking conforming property of subfaces...\n");
+    }
+
+    // Run through the list of subfaces, check each one.
+    subfaces->traversalinit();
+    shloop.sh = shellfacetraverse(subfaces);
+    while (shloop.sh != (shellface *) NULL) {
+      pa = (point) shloop.sh[3];
+      pb = (point) shloop.sh[4];
+      pc = (point) shloop.sh[5];
+
+      // Compute the coefficient matrix A (3x3).
+      A[0][0] = pb[0] - pa[0];
+      A[0][1] = pb[1] - pa[1];
+      A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
+      A[1][0] = pc[0] - pa[0];
+      A[1][1] = pc[1] - pa[1];
+      A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
+      cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
+
+      // Compute the right hand side vector b (3x1).
+      elen[0] = dot(A[0], A[0]);
+      elen[1] = dot(A[1], A[1]);
+      rhs[0] = 0.5 * elen[0];
+      rhs[1] = 0.5 * elen[1];
+      rhs[2] = 0.0;
+
+      if (lu_decmp(A, 3, indx, &D, 0)) {
+        lu_solve(A, 3, indx, rhs, 0);
+        cent[0] = pa[0] + rhs[0];
+        cent[1] = pa[1] + rhs[1];
+        cent[2] = pa[2] + rhs[2];
+        rd = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
+
+        // Check if this subface is encroached.
+        for (i = 0; i < 2; i++) {
+          stpivot(shloop, searchtet);
+          if (!ishulltet(searchtet)) {
+            len = distance(oppo(searchtet), cent);
+            if ((fabs(len - rd) / rd) < b->epsilon) len = rd; // Rounding.
+            if (len < rd) {
+              printf("  !! !! Non-conforming subface: (%d, %d, %d)\n",
+                     pointmark(pa), pointmark(pb), pointmark(pc));
+              encsubfaces++;
+              enq = true; break;
+            }
+          }
+          sesymself(shloop);
+        }
+      }
+      shloop.sh = shellfacetraverse(subfaces);
+    }
+
+    if (encsubfaces == 0) {
+      if (!b->quiet) {
+        printf("  The subfaces are conforming Delaunay.\n");
+      }
+    } else {
+      printf("  !! !! %d subfaces are non-conforming.\n", encsubfaces);
+    }
+  } // if (flag & 2)
+
+  return encsubsegs + encsubfaces;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// qualitystatistics()    Print statistics about the quality of the mesh.    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::qualitystatistics()
+{
+  triface tetloop, neightet;
+  point p[4];
+  char sbuf[128];
+  REAL radiusratiotable[12];
+  REAL aspectratiotable[12];
+  REAL A[4][4], rhs[4], D;
+  REAL V[6][3], N[4][3], H[4]; // edge-vectors, face-normals, face-heights.
+  REAL edgelength[6], alldihed[6], faceangle[3];
+  REAL shortest, longest;
+  REAL smallestvolume, biggestvolume;
+  REAL smallestratio, biggestratio;
+  REAL smallestdiangle, biggestdiangle;
+  REAL smallestfaangle, biggestfaangle;
+  REAL total_tet_vol, total_tetprism_vol;
+  REAL tetvol, minaltitude;
+  REAL cirradius, minheightinv; // insradius;
+  REAL shortlen, longlen;
+  REAL tetaspect, tetradius;
+  REAL smalldiangle, bigdiangle;
+  REAL smallfaangle, bigfaangle;
+  unsigned long radiustable[12];
+  unsigned long aspecttable[16];
+  unsigned long dihedangletable[18];
+  unsigned long faceangletable[18];
+  int indx[4];
+  int radiusindex;
+  int aspectindex;
+  int tendegree;
+  int i, j;
+
+  printf("Mesh quality statistics:\n\n");
+
+  shortlen = longlen = 0.0;
+  smalldiangle = bigdiangle = 0.0;
+  total_tet_vol = 0.0;
+  total_tetprism_vol = 0.0;
+
+  radiusratiotable[0]  =    0.707;    radiusratiotable[1]  =     1.0;
+  radiusratiotable[2]  =      1.1;    radiusratiotable[3]  =     1.2;
+  radiusratiotable[4]  =      1.4;    radiusratiotable[5]  =     1.6;
+  radiusratiotable[6]  =      1.8;    radiusratiotable[7]  =     2.0;
+  radiusratiotable[8]  =      2.5;    radiusratiotable[9]  =     3.0;
+  radiusratiotable[10] =     10.0;    radiusratiotable[11] =     0.0;
+
+  aspectratiotable[0]  =      1.5;    aspectratiotable[1]  =     2.0;
+  aspectratiotable[2]  =      2.5;    aspectratiotable[3]  =     3.0;
+  aspectratiotable[4]  =      4.0;    aspectratiotable[5]  =     6.0;
+  aspectratiotable[6]  =     10.0;    aspectratiotable[7]  =    15.0;
+  aspectratiotable[8]  =     25.0;    aspectratiotable[9]  =    50.0;
+  aspectratiotable[10] =    100.0;    aspectratiotable[11] =     0.0;
+  
+  for (i = 0; i < 12; i++) radiustable[i] = 0l;
+  for (i = 0; i < 12; i++) aspecttable[i] = 0l;
+  for (i = 0; i < 18; i++) dihedangletable[i] = 0l;
+  for (i = 0; i < 18; i++) faceangletable[i] = 0l;
+
+  minaltitude = xmax - xmin + ymax - ymin + zmax - zmin;
+  minaltitude = minaltitude * minaltitude;
+  shortest = minaltitude;
+  longest = 0.0;
+  smallestvolume = minaltitude;
+  biggestvolume = 0.0;
+  smallestratio = 1e+16; // minaltitude;
+  biggestratio = 0.0;
+  smallestdiangle = smallestfaangle = 180.0;
+  biggestdiangle = biggestfaangle = 0.0;
+
+
+  int attrnum = numelemattrib - 1;
+
+  // Loop all elements, calculate quality parameters for each element.
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+
+    if (b->convex) {
+      // Skip tets in the exterior.
+      if (elemattribute(tetloop.tet, attrnum) == -1.0) {
+        tetloop.tet = tetrahedrontraverse();
+        continue;
+      }
+    }
+
+    // Get four vertices: p0, p1, p2, p3.
+    for (i = 0; i < 4; i++) p[i] = (point) tetloop.tet[4 + i];
+
+    // Get the tet volume.
+    tetvol = orient3dfast(p[1], p[0], p[2], p[3]) / 6.0;
+    total_tet_vol += tetvol;
+    total_tetprism_vol += tetprismvol(p[0], p[1], p[2], p[3]);
+
+    // Calculate the largest and smallest volume.
+    if (tetvol < smallestvolume) {
+      smallestvolume = tetvol;
+    } 
+    if (tetvol > biggestvolume) {
+      biggestvolume = tetvol;
+    }
+
+    // Set the edge vectors: V[0], ..., V[5]
+    for (i = 0; i < 3; i++) V[0][i] = p[0][i] - p[3][i]; // V[0]: p3->p0.
+    for (i = 0; i < 3; i++) V[1][i] = p[1][i] - p[3][i]; // V[1]: p3->p1.
+    for (i = 0; i < 3; i++) V[2][i] = p[2][i] - p[3][i]; // V[2]: p3->p2.
+    for (i = 0; i < 3; i++) V[3][i] = p[1][i] - p[0][i]; // V[3]: p0->p1.
+    for (i = 0; i < 3; i++) V[4][i] = p[2][i] - p[1][i]; // V[4]: p1->p2.
+    for (i = 0; i < 3; i++) V[5][i] = p[0][i] - p[2][i]; // V[5]: p2->p0.
+
+    // Get the squares of the edge lengths.
+    for (i = 0; i < 6; i++) edgelength[i] = dot(V[i], V[i]);
+
+    // Calculate the longest and shortest edge length.
+    for (i = 0; i < 6; i++) {
+      if (i == 0) {
+        shortlen = longlen = edgelength[i];
+      } else {
+        shortlen = edgelength[i] < shortlen ? edgelength[i] : shortlen;
+        longlen  = edgelength[i] > longlen  ? edgelength[i] : longlen;
+      }
+      if (edgelength[i] > longest) {
+        longest = edgelength[i];
+      } 
+      if (edgelength[i] < shortest) {
+        shortest = edgelength[i];
+      }
+    }
+
+    // Set the matrix A = [V[0], V[1], V[2]]^T.
+    for (j = 0; j < 3; j++) {
+      for (i = 0; i < 3; i++) A[j][i] = V[j][i];
+    }
+
+    // Decompose A just once.
+    if (lu_decmp(A, 3, indx, &D, 0)) {   
+      // Get the three faces normals.
+      for (j = 0; j < 3; j++) {
+        for (i = 0; i < 3; i++) rhs[i] = 0.0;
+        rhs[j] = 1.0;  // Positive means the inside direction
+        lu_solve(A, 3, indx, rhs, 0);
+        for (i = 0; i < 3; i++) N[j][i] = rhs[i];
+      }
+      // Get the fourth face normal by summing up the first three.
+      for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
+      // Get the radius of the circumsphere.
+      for (i = 0; i < 3; i++) rhs[i] = 0.5 * dot(V[i], V[i]);
+      lu_solve(A, 3, indx, rhs, 0);
+      cirradius = sqrt(dot(rhs, rhs));
+      // Normalize the face normals.
+      for (i = 0; i < 4; i++) {
+        // H[i] is the inverse of height of its corresponding face.
+        H[i] = sqrt(dot(N[i], N[i]));
+        for (j = 0; j < 3; j++) N[i][j] /= H[i];
+      }
+      // Get the radius of the inscribed sphere.
+      // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
+      // Get the biggest H[i] (corresponding to the smallest height).
+      minheightinv = H[0];
+      for (i = 1; i < 3; i++) {
+        if (H[i] > minheightinv) minheightinv = H[i];
+      }
+    } else {
+      // A nearly degenerated tet.
+      if (tetvol <= 0.0) {
+        // assert(tetvol != 0.0);
+        printf("  !! Warning:  A %s tet (%d,%d,%d,%d).\n", 
+               tetvol < 0 ? "inverted" : "degenerated", pointmark(p[0]),
+               pointmark(p[1]), pointmark(p[2]), pointmark(p[3]));
+        // Skip it.        
+        tetloop.tet = tetrahedrontraverse();
+        continue;
+      }
+      // Calculate the four face normals.
+      facenormal(p[2], p[1], p[3], N[0], 1, NULL);
+      facenormal(p[0], p[2], p[3], N[1], 1, NULL);
+      facenormal(p[1], p[0], p[3], N[2], 1, NULL);
+      facenormal(p[0], p[1], p[2], N[3], 1, NULL);
+      // Normalize the face normals.
+      for (i = 0; i < 4; i++) {
+        // H[i] is the twice of the area of the face.
+        H[i] = sqrt(dot(N[i], N[i]));
+        for (j = 0; j < 3; j++) N[i][j] /= H[i];
+      }
+      // Get the biggest H[i] / tetvol (corresponding to the smallest height).
+      minheightinv = (H[0] / tetvol);
+      for (i = 1; i < 3; i++) {
+        if ((H[i] / tetvol) > minheightinv) minheightinv = (H[i] / tetvol);
+      }
+      // Let the circumradius to be the half of its longest edge length.
+      cirradius = 0.5 * sqrt(longlen);
+    }
+
+    // Get the dihedrals (in degree) at each edges.
+    j = 0;
+    for (i = 1; i < 4; i++) {
+      alldihed[j] = -dot(N[0], N[i]); // Edge cd, bd, bc.
+      if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
+      else if (alldihed[j] > 1.0) alldihed[j] = 1;
+      alldihed[j] = acos(alldihed[j]) / PI * 180.0;
+      j++;
+    }
+    for (i = 2; i < 4; i++) {
+      alldihed[j] = -dot(N[1], N[i]); // Edge ad, ac.
+      if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
+      else if (alldihed[j] > 1.0) alldihed[j] = 1;
+      alldihed[j] = acos(alldihed[j]) / PI * 180.0;
+      j++;
+    }
+    alldihed[j] = -dot(N[2], N[3]); // Edge ab.
+    if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
+    else if (alldihed[j] > 1.0) alldihed[j] = 1;
+    alldihed[j] = acos(alldihed[j]) / PI * 180.0;
+
+    // Calculate the largest and smallest dihedral angles.
+    for (i = 0; i < 6; i++) {
+      if (i == 0) {
+        smalldiangle = bigdiangle = alldihed[i];
+      } else {
+        smalldiangle = alldihed[i] < smalldiangle ? alldihed[i] : smalldiangle;
+        bigdiangle = alldihed[i] > bigdiangle ? alldihed[i] : bigdiangle;
+      }
+      if (alldihed[i] < smallestdiangle) {
+        smallestdiangle = alldihed[i];
+      } 
+      if (alldihed[i] > biggestdiangle) {
+        biggestdiangle = alldihed[i];
+      }
+      // Accumulate the corresponding number in the dihedral angle histogram.
+      if (alldihed[i] < 5.0) {
+        tendegree = 0;
+      } else if (alldihed[i] >= 5.0 && alldihed[i] < 10.0) {
+        tendegree = 1;
+      } else if (alldihed[i] >= 80.0 && alldihed[i] < 110.0) {
+        tendegree = 9; // Angles between 80 to 110 degree are in one entry.
+      } else if (alldihed[i] >= 170.0 && alldihed[i] < 175.0) {
+        tendegree = 16;
+      } else if (alldihed[i] >= 175.0) {
+        tendegree = 17;
+      } else {
+        tendegree = (int) (alldihed[i] / 10.);
+        if (alldihed[i] < 80.0) {
+          tendegree++;  // In the left column.
+        } else {
+          tendegree--;  // In the right column.
+        }
+      }
+      dihedangletable[tendegree]++;
+    }
+
+
+
+    // Calculate the largest and smallest face angles.
+    for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
+      fsym(tetloop, neightet);
+      // Only do the calulation once for a face.
+      if (((point) neightet.tet[7] == dummypoint) || 
+          (tetloop.tet < neightet.tet)) {
+        p[0] = org(tetloop);
+        p[1] = dest(tetloop);
+        p[2] = apex(tetloop);
+        faceangle[0] = interiorangle(p[0], p[1], p[2], NULL);
+        faceangle[1] = interiorangle(p[1], p[2], p[0], NULL);
+        faceangle[2] = PI - (faceangle[0] + faceangle[1]);
+        // Translate angles into degrees.
+        for (i = 0; i < 3; i++) {
+          faceangle[i] = (faceangle[i] * 180.0) / PI;
+        }
+        // Calculate the largest and smallest face angles.
+        for (i = 0; i < 3; i++) {
+          if (i == 0) {
+            smallfaangle = bigfaangle = faceangle[i];
+          } else {
+            smallfaangle = faceangle[i] < smallfaangle ? 
+              faceangle[i] : smallfaangle;
+            bigfaangle = faceangle[i] > bigfaangle ? faceangle[i] : bigfaangle;
+          }
+          if (faceangle[i] < smallestfaangle) {
+            smallestfaangle = faceangle[i];
+          } 
+          if (faceangle[i] > biggestfaangle) {
+            biggestfaangle = faceangle[i];
+          }
+          tendegree = (int) (faceangle[i] / 10.);
+          faceangletable[tendegree]++;
+        }
+      }
+    }
+
+    // Calculate aspect ratio and radius-edge ratio for this element.
+    tetradius = cirradius / sqrt(shortlen);
+    // tetaspect = sqrt(longlen) / (2.0 * insradius);
+    tetaspect = sqrt(longlen) * minheightinv;
+    // Remember the largest and smallest aspect ratio.
+    if (tetaspect < smallestratio) {
+      smallestratio = tetaspect;
+    } 
+    if (tetaspect > biggestratio) {
+      biggestratio = tetaspect;
+    }
+    // Accumulate the corresponding number in the aspect ratio histogram.
+    aspectindex = 0;
+    while ((tetaspect > aspectratiotable[aspectindex]) && (aspectindex < 11)) {
+      aspectindex++;
+    }
+    aspecttable[aspectindex]++;
+    radiusindex = 0;
+    while ((tetradius > radiusratiotable[radiusindex]) && (radiusindex < 11)) {
+      radiusindex++;
+    }
+    radiustable[radiusindex]++;
+
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  shortest = sqrt(shortest);
+  longest = sqrt(longest);
+  minaltitude = sqrt(minaltitude);
+
+  printf("  Smallest volume: %16.5g   |  Largest volume: %16.5g\n",
+         smallestvolume, biggestvolume);
+  printf("  Shortest edge:   %16.5g   |  Longest edge:   %16.5g\n",
+         shortest, longest);
+  printf("  Smallest asp.ratio: %13.5g   |  Largest asp.ratio: %13.5g\n",
+         smallestratio, biggestratio);
+  sprintf(sbuf, "%.17g", biggestfaangle);
+  if (strlen(sbuf) > 8) {
+    sbuf[8] = '\0';
+  }
+  printf("  Smallest facangle: %14.5g   |  Largest facangle:       %s\n",
+         smallestfaangle, sbuf);
+  sprintf(sbuf, "%.17g", biggestdiangle);
+  if (strlen(sbuf) > 8) {
+    sbuf[8] = '\0';
+  }
+  printf("  Smallest dihedral: %14.5g   |  Largest dihedral:       %s\n\n",
+         smallestdiangle, sbuf);
+
+  printf("  Aspect ratio histogram:\n");
+  printf("         < %-6.6g    :  %8ld      | %6.6g - %-6.6g     :  %8ld\n",
+         aspectratiotable[0], aspecttable[0], aspectratiotable[5],
+         aspectratiotable[6], aspecttable[6]);
+  for (i = 1; i < 5; i++) {
+    printf("  %6.6g - %-6.6g    :  %8ld      | %6.6g - %-6.6g     :  %8ld\n",
+           aspectratiotable[i - 1], aspectratiotable[i], aspecttable[i],
+           aspectratiotable[i + 5], aspectratiotable[i + 6],
+           aspecttable[i + 6]);
+  }
+  printf("  %6.6g - %-6.6g    :  %8ld      | %6.6g -            :  %8ld\n",
+         aspectratiotable[4], aspectratiotable[5], aspecttable[5],
+         aspectratiotable[10], aspecttable[11]);
+  printf("  (A tetrahedron's aspect ratio is its longest edge length");
+  printf(" divided by its\n");
+  printf("    smallest side height)\n\n");
+
+  printf("  Face angle histogram:\n");
+  for (i = 0; i < 9; i++) {
+    printf("    %3d - %3d degrees:  %8ld      |    %3d - %3d degrees:  %8ld\n",
+           i * 10, i * 10 + 10, faceangletable[i],
+           i * 10 + 90, i * 10 + 100, faceangletable[i + 9]);
+  }
+  if (minfaceang != PI) {
+    printf("  Minimum input face angle is %g (degree).\n",
+           minfaceang / PI * 180.0);
+  }
+  printf("\n");
+
+  printf("  Dihedral angle histogram:\n");
+  // Print the three two rows:
+  printf("     %3d - %2d degrees:  %8ld      |    %3d - %3d degrees:  %8ld\n",
+         0, 5, dihedangletable[0], 80, 110, dihedangletable[9]);
+  printf("     %3d - %2d degrees:  %8ld      |    %3d - %3d degrees:  %8ld\n",
+         5, 10, dihedangletable[1], 110, 120, dihedangletable[10]);
+  // Print the third to seventh rows.
+  for (i = 2; i < 7; i++) {
+    printf("     %3d - %2d degrees:  %8ld      |    %3d - %3d degrees:  %8ld\n",
+           (i - 1) * 10, (i - 1) * 10 + 10, dihedangletable[i],
+           (i - 1) * 10 + 110, (i - 1) * 10 + 120, dihedangletable[i + 9]);
+  }
+  // Print the last two rows.
+  printf("     %3d - %2d degrees:  %8ld      |    %3d - %3d degrees:  %8ld\n",
+         60, 70, dihedangletable[7], 170, 175, dihedangletable[16]);
+  printf("     %3d - %2d degrees:  %8ld      |    %3d - %3d degrees:  %8ld\n",
+         70, 80, dihedangletable[8], 175, 180, dihedangletable[17]);
+  if (minfacetdihed != PI) {
+    printf("  Minimum input dihedral angle is %g (degree).\n",
+           minfacetdihed / PI * 180.0);
+  }
+  printf("\n");
+
+  printf("\n");
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// memorystatistics()    Report the memory usage.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::memorystatistics()
+{
+  printf("Memory usage statistics:\n\n");
+ 
+  // Count the number of blocks of tetrahedra. 
+  int tetblocks = 0;
+  tetrahedrons->pathblock = tetrahedrons->firstblock;
+  while (tetrahedrons->pathblock != NULL) {
+    tetblocks++;
+    tetrahedrons->pathblock = (void **) *(tetrahedrons->pathblock);  
+  }
+
+  // Calculate the total memory (in bytes) used by storing meshes.
+  unsigned long totalmeshmemory = 0l, totalt2shmemory = 0l;
+  totalmeshmemory = points->maxitems * points->itembytes +
+                    tetrahedrons->maxitems * tetrahedrons->itembytes;
+  if (b->plc || b->refine) {
+    totalmeshmemory += (subfaces->maxitems * subfaces->itembytes +
+                        subsegs->maxitems * subsegs->itembytes);
+    totalt2shmemory = (tet2subpool->maxitems * tet2subpool->itembytes +
+                       tet2segpool->maxitems * tet2segpool->itembytes);
+  }
+
+  unsigned long totalalgomemory = 0l;
+  totalalgomemory = cavetetlist->totalmemory + cavebdrylist->totalmemory +
+                    caveoldtetlist->totalmemory + 
+                    flippool->maxitems * flippool->itembytes;
+  if (b->plc || b->refine) {
+    totalalgomemory += (subsegstack->totalmemory + subfacstack->totalmemory +
+                        subvertstack->totalmemory + 
+                        caveshlist->totalmemory + caveshbdlist->totalmemory +
+                        cavesegshlist->totalmemory +
+                        cavetetshlist->totalmemory + 
+                        cavetetseglist->totalmemory +
+                        caveencshlist->totalmemory +
+                        caveencseglist->totalmemory +
+                        cavetetvertlist->totalmemory +
+                        unflipqueue->totalmemory);
+  }
+
+  printf("  Maximum number of tetrahedra:  %ld\n", tetrahedrons->maxitems);
+  printf("  Maximum number of tet blocks (blocksize = %d):  %d\n",
+         b->tetrahedraperblock, tetblocks);
+  /*
+  if (b->plc || b->refine) {
+    printf("  Approximate memory for tetrahedral mesh (bytes):  %ld\n",
+           totalmeshmemory);
+    
+    printf("  Approximate memory for extra pointers (bytes):  %ld\n",
+           totalt2shmemory);
+  } else {
+    printf("  Approximate memory for tetrahedralization (bytes):  %ld\n",
+           totalmeshmemory);
+  }
+  printf("  Approximate memory for algorithms (bytes):  %ld\n",
+         totalalgomemory);
+  printf("  Approximate memory for working arrays (bytes):  %ld\n",
+         totalworkmemory);
+  printf("  Approximate total used memory (bytes):  %ld\n",
+         totalmeshmemory + totalt2shmemory + totalalgomemory + 
+         totalworkmemory);
+  */
+  if (b->plc || b->refine) {
+    printf("  Approximate memory for tetrahedral mesh (bytes):  ");
+    printfcomma(totalmeshmemory); printf("\n");
+    
+    printf("  Approximate memory for extra pointers (bytes):  ");
+    printfcomma(totalt2shmemory); printf("\n");
+  } else {
+    printf("  Approximate memory for tetrahedralization (bytes):  ");
+    printfcomma(totalmeshmemory); printf("\n");
+  }
+  printf("  Approximate memory for algorithms (bytes):  ");
+  printfcomma(totalalgomemory); printf("\n");
+  printf("  Approximate memory for working arrays (bytes):  ");
+  printfcomma(totalworkmemory); printf("\n");
+  printf("  Approximate total used memory (bytes):  ");
+  printfcomma(totalmeshmemory + totalt2shmemory + totalalgomemory + 
+              totalworkmemory);
+  printf("\n");
+
+  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 = tetrahedrons->items - hullsize;
+  facenumber = (tetnumber * 4l + hullsize) / 2l;
+
+  if (b->weighted) { // -w option
+    printf("\n  Mesh points: %ld\n", points->items - nonregularcount);
+  } else {
+    printf("\n  Mesh points: %ld\n", points->items);
+  }
+  printf("  Mesh tetrahedra: %ld\n", tetnumber);
+  printf("  Mesh faces: %ld\n", facenumber);
+  if (meshedges > 0l) {
+    printf("  Mesh edges: %ld\n", meshedges);
+  } else {
+    if (!nonconvex) {
+      long vsize = points->items - dupverts - unuverts;
+      if (b->weighted) vsize -= nonregularcount;
+      meshedges = vsize + facenumber - tetnumber - 1;
+      printf("  Mesh edges: %ld\n", meshedges);
+    }
+  }
+
+  if (b->plc || b->refine) {
+    printf("  Mesh faces on facets: %ld\n", subfaces->items);
+    printf("  Mesh edges on segments: %ld\n", subsegs->items);
+    if (st_volref_count > 0l) {
+      printf("  Steiner points inside domain: %ld\n", st_volref_count);
+    }
+    if (st_facref_count > 0l) {
+      printf("  Steiner points on facets:  %ld\n", st_facref_count);
+    }
+    if (st_segref_count > 0l) {
+      printf("  Steiner points on segments:  %ld\n", st_segref_count);
+    }
+  } else {
+    printf("  Convex hull faces: %ld\n", hullsize);
+    if (meshhulledges > 0l) {
+      printf("  Convex hull edges: %ld\n", meshhulledges);
+    }
+  }
+  if (b->weighted) { // -w option
+    printf("  Skipped non-regular points: %ld\n", nonregularcount);
+  }
+  printf("\n");
+
+
+  if (b->verbose > 0) {
+    if (b->plc || b->refine) { // -p or -r
+      if (tetrahedrons->items > 0l) {
+        qualitystatistics();
+      }
+    }
+    if (tetrahedrons->items > 0l) {
+      memorystatistics();
+    }
+  }
+}
+
+////                                                                       ////
+////                                                                       ////
+//// meshstat_cxx /////////////////////////////////////////////////////////////
+
+//// output_cxx ///////////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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 redundant points.\n");
+  }
+
+  points->traversalinit();
+  pointloop = pointtraverse();
+  oldidx = newidx = 0; // in->firstnumber;
+  remcount = 0;
+  while (pointloop != (point) NULL) {
+    jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) || 
+      (pointtype(pointloop) == UNUSEDVERTEX);
+    if (jetflag) {
+      // It is a duplicated or unused point, delete it.
+      pointdealloc(pointloop);
+      remcount++;
+    } else {
+      // Re-index it.
+      setpointmark(pointloop, newidx + in->firstnumber);
+      if (in->pointmarkerlist != (int *) NULL) {
+        if (oldidx < in->numberofpoints) {
+          // Re-index the point marker as well.
+          in->pointmarkerlist[newidx] = in->pointmarkerlist[oldidx];
+        }
+      }
+      newidx++;
+    }
+    oldidx++;
+    pointloop = pointtraverse();
+  }
+  if (b->verbose) {
+    printf("  %ld duplicated vertices are removed.\n", dupverts);
+    printf("  %ld unused vertices are removed.\n", unuverts);
+  }
+  dupverts = 0l;
+  unuverts = 0l;
+
+  // 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.
+  points->deaditemstack = (void *) NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// highorder()   Create extra nodes for quadratic subparametric elements.    //
+//                                                                           //
+// 'highordertable' is an array (size = numberoftetrahedra * 6) for storing  //
+// high-order nodes of each tetrahedron.  This routine is used only when -o2 //
+// switch is used.                                                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::highorder()
+{
+  triface tetloop, worktet, spintet;
+  point *extralist, *adjextralist;
+  point torg, tdest, newpoint;
+  int highorderindex;
+  int t1ver;
+  int i, j;
+
+  if (!b->quiet) {
+    printf("Adding vertices for second-order tetrahedra.\n");
+  }
+
+  // Initialize the 'highordertable'.
+  highordertable = new point[tetrahedrons->items * 6];
+  if (highordertable == (point *) NULL) {
+    terminatetetgen(this, 1);
+  }
+
+  // This will overwrite the slot for element markers.
+  highorderindex = 11;
+
+  // The following line ensures that dead items in the pool of nodes cannot
+  //   be allocated for the extra nodes associated with high order elements.
+  //   This ensures that the primary nodes (at the corners of elements) will
+  //   occur earlier in the output files, and have lower indices, than the
+  //   extra nodes.
+  points->deaditemstack = (void *) NULL;
+
+  // Assign an entry for each tetrahedron to find its extra nodes. At the
+  //   mean while, initialize all extra nodes be NULL.
+  i = 0;
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    tetloop.tet[highorderindex] = (tetrahedron) &highordertable[i];
+    for (j = 0; j < 6; j++) {
+      highordertable[i + j] = (point) NULL;
+    }
+    i += 6;
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  // To create a unique node on each edge. Loop over all tetrahedra, and
+  //   look at the six edges of each tetrahedron.  If the extra node in
+  //   the tetrahedron corresponding to this edge is NULL, create a node
+  //   for this edge, at the same time, set the new node into the extra
+  //   node lists of all other tetrahedra sharing this edge.  
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    // Get the list of extra nodes.
+    extralist = (point *) tetloop.tet[highorderindex];
+    worktet.tet = tetloop.tet;
+    for (i = 0; i < 6; i++) {
+      if (extralist[i] == (point) NULL) {
+        // Go to the ith-edge.
+        worktet.ver = edge2ver[i];
+        // Create a new point in the middle of this edge.
+        torg = org(worktet);
+        tdest = dest(worktet);
+        makepoint(&newpoint, FREEVOLVERTEX);
+        for (j = 0; j < 3 + numpointattrib; j++) {
+          newpoint[j] = 0.5 * (torg[j] + tdest[j]);
+        }
+        // Interpolate its metrics.
+        for (j = 0; j < in->numberofpointmtrs; j++) {
+          newpoint[pointmtrindex + j] = 
+            0.5 * (torg[pointmtrindex + j] + tdest[pointmtrindex + j]);
+        }
+        // Set this point into all extra node lists at this edge.
+        spintet = worktet;
+        while (1) {
+          if (!ishulltet(spintet)) {
+            adjextralist = (point *) spintet.tet[highorderindex];
+            adjextralist[ver2edge[spintet.ver]] = newpoint;
+          }
+          fnextself(spintet);
+          if (spintet.tet == worktet.tet) break;
+        }
+      } // if (!extralist[i])
+    } // i
+    tetloop.tet = tetrahedrontraverse();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// numberedges()    Count the number of edges, save in "meshedges".          //
+//                                                                           //
+// This routine is called when '-p' or '-r', and '-E' options are used.  The //
+// total number of edges depends on the genus of the input surface mesh.     //
+//                                                                           //
+// NOTE:  This routine must be called after outelements().  So all elements  //
+// have been indexed.                                                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::numberedges()
+{
+  triface worktet, spintet;
+  int ishulledge;
+  int t1ver;
+  int i;
+
+  meshedges = meshhulledges = 0l;
+
+  tetrahedrons->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 index is smaller than
+    //   those of other non-hull tets which share this edge.
+    for (i = 0; i < 6; i++) {
+      worktet.ver = edge2ver[i];
+      ishulledge = 0;
+      fnext(worktet, spintet);
+      do {
+        if (!ishulltet(spintet)) {          
+          if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
+        } else {
+          ishulledge = 1;
+        }
+        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++;
+        if (ishulledge) meshhulledges++;
+      }
+    }
+    worktet.tet = tetrahedrontraverse();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outnodes()    Output the points to a .node file or a tetgenio structure.  //
+//                                                                           //
+// Note: each point has already been numbered on input (the first index is   //
+// 'in->firstnumber').                                                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outnodes(tetgenio* out)
+{
+  FILE *outfile = NULL;
+  char outnodefilename[FILENAMESIZE];
+  face parentsh;
+  point pointloop;
+  int nextras, bmark, marker = 0, weightDT = 0; 
+  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 = numpointattrib;
+  if (b->weighted) { // -w
+    if (b->weighted_param == 0) weightDT = 1; // Weighted DT.
+  }
+
+  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(this, 1);
+    }
+    // Number of points, number of dimensions, number of point attributes,
+    //   and number of boundary markers (zero or one).
+    fprintf(outfile, "%ld  %d  %d  %d\n", points->items, 3, nextras, bmark);
+  } else {
+    // Allocate space for 'pointlist';
+    out->pointlist = new REAL[points->items * 3];
+    if (out->pointlist == (REAL *) NULL) {
+      printf("Error:  Out of memory.\n");
+      terminatetetgen(this, 1);
+    }
+    // Allocate space for 'pointattributelist' if necessary;
+    if (nextras > 0) {
+      out->pointattributelist = new REAL[points->items * nextras];
+      if (out->pointattributelist == (REAL *) NULL) {
+        printf("Error:  Out of memory.\n");
+        terminatetetgen(this, 1);
+      }
+    }
+    // Allocate space for 'pointmarkerlist' if necessary;
+    if (bmark) {
+      out->pointmarkerlist = new int[points->items];
+      if (out->pointmarkerlist == (int *) NULL) {
+        printf("Error:  Out of memory.\n");
+        terminatetetgen(this, 1);
+      }
+    }
+    if (b->psc) {
+      out->pointparamlist = new tetgenio::pointparam[points->items];
+      if (out->pointparamlist == NULL) {
+        printf("Error:  Out of memory.\n");
+        terminatetetgen(this, 1);
+      }
+    }
+    out->numberofpoints = points->items;
+    out->numberofpointattributes = nextras;
+    coordindex = 0;
+    attribindex = 0;
+  }
+  
+  // Determine the first index (0 or 1).
+  firstindex = b->zeroindex ? 0 : in->firstnumber;
+
+  points->traversalinit();
+  pointloop = pointtraverse();
+  pointnumber = firstindex; // in->firstnumber;
+  index = 0;
+  while (pointloop != (point) NULL) {
+    if (bmark) {
+      // Default the vertex has a zero marker.
+      marker = 0;
+      // Is it an input vertex?
+      if (index < in->numberofpoints) {
+        // Input point's marker is directly copied to output.
+        marker = in->pointmarkerlist[index];       
+      } else {
+        if ((pointtype(pointloop) == FREESEGVERTEX) ||
+            (pointtype(pointloop) == FREEFACETVERTEX)) {
+          sdecode(point2sh(pointloop), parentsh);
+          if (parentsh.sh != NULL) {
+            marker = shellmark(parentsh);
+            if (pointtype(pointloop) == FREEFACETVERTEX) {
+              if (in->facetmarkerlist != NULL) {
+                marker = in->facetmarkerlist[marker - 1];
+              }
+            }
+          }
+        } // if (pointtype(...))
+      }
+    }
+    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.
+        if ((i == 0) && weightDT) {          
+          fprintf(outfile, "  %.17g", pointloop[0] * pointloop[0] +
+             pointloop[1] * pointloop[1] + pointloop[2] * pointloop[2] 
+             - pointloop[3 + i]);
+        } else { 
+          fprintf(outfile, "  %.17g", pointloop[3 + i]);
+        }
+      }
+      if (bmark) {
+        // Write the boundary marker.
+        fprintf(outfile, "    %d", marker);
+      }
+      if (b->psc) {
+        fprintf(outfile, "  %.8g  %.8g  %d", pointgeomuv(pointloop, 0),
+                pointgeomuv(pointloop, 1), pointgeomtag(pointloop));
+        if (pointtype(pointloop) == RIDGEVERTEX) {
+          fprintf(outfile, "  0");
+        } else if (pointtype(pointloop) == ACUTEVERTEX) {
+          fprintf(outfile, "  0");
+        } else if (pointtype(pointloop) == FREESEGVERTEX) {
+          fprintf(outfile, "  1");
+        } else if (pointtype(pointloop) == FREEFACETVERTEX) {
+          fprintf(outfile, "  2");
+        } else if (pointtype(pointloop) == FREEVOLVERTEX) {
+          fprintf(outfile, "  3");
+        } else {
+          fprintf(outfile, "  -1"); // Unknown type.
+        }
+      }
+      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.
+        if ((i == 0) && weightDT) {
+          out->pointattributelist[attribindex++] = 
+            pointloop[0] * pointloop[0] + pointloop[1] * pointloop[1] + 
+            pointloop[2] * pointloop[2] - pointloop[3 + i];
+        } else {
+          out->pointattributelist[attribindex++] = pointloop[3 + i];
+        }
+      }
+      if (bmark) {
+        // Output the boundary marker.  
+        out->pointmarkerlist[index] = marker;
+      }
+      if (b->psc) {
+        out->pointparamlist[index].uv[0] = pointgeomuv(pointloop, 0);
+        out->pointparamlist[index].uv[1] = pointgeomuv(pointloop, 1);
+        out->pointparamlist[index].tag = pointgeomtag(pointloop);
+        if (pointtype(pointloop) == RIDGEVERTEX) {
+          out->pointparamlist[index].type = 0;
+        } else if (pointtype(pointloop) == ACUTEVERTEX) {
+          out->pointparamlist[index].type = 0;
+        } else if (pointtype(pointloop) == FREESEGVERTEX) {
+          out->pointparamlist[index].type = 1;
+        } else if (pointtype(pointloop) == FREEFACETVERTEX) {
+          out->pointparamlist[index].type = 2;
+        } else if (pointtype(pointloop) == FREEVOLVERTEX) {
+          out->pointparamlist[index].type = 3;
+        } else {
+          out->pointparamlist[index].type = -1; // Unknown type.
+        }
+      }
+    }
+    pointloop = pointtraverse();
+    pointnumber++; 
+    index++;
+  }
+
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outmetrics()    Output the metric to a file (*.mtr) or a tetgenio obj.    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outmetrics(tetgenio* out)
+{
+  FILE *outfile = NULL;
+  char outmtrfilename[FILENAMESIZE];
+  point ptloop;
+  int mtrindex;
+
+  if (out == (tetgenio *) NULL) {
+    strcpy(outmtrfilename, b->outfilename);
+    strcat(outmtrfilename, ".mtr");
+  }
+
+  if (!b->quiet) {
+    if (out == (tetgenio *) NULL) {
+      printf("Writing %s.\n", outmtrfilename);
+    } else {
+      printf("Writing metrics.\n");
+    }
+  }
+
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(outmtrfilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", outmtrfilename);
+      terminatetetgen(this, 3);
+    }
+    // Number of points, number of point metrices,
+    // fprintf(outfile, "%ld  %d\n", points->items, sizeoftensor + 3);
+    fprintf(outfile, "%ld  %d\n", points->items, 1);
+  } else {
+    // Allocate space for 'pointmtrlist' if necessary;
+    // out->pointmtrlist = new REAL[points->items * (sizeoftensor + 3)];
+    out->pointmtrlist = new REAL[points->items];
+    if (out->pointmtrlist == (REAL *) NULL) {
+      terminatetetgen(this, 1);
+    }
+    out->numberofpointmtrs = 1; // (sizeoftensor + 3);
+    mtrindex = 0;
+  }
+
+  points->traversalinit();
+  ptloop = pointtraverse();
+  while (ptloop != (point) NULL) {
+    if (out == (tetgenio *) NULL) {
+      // for (i = 0; i < sizeoftensor; i++) {
+      //   fprintf(outfile, "%-16.8e ", ptloop[pointmtrindex + i]);
+      // }
+      fprintf(outfile, "%-16.8e\n", ptloop[pointmtrindex]);
+    } else {
+      // for (i = 0; i < sizeoftensor; i++) {
+      //   out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex + i];
+      // }
+      out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex];
+    }
+    ptloop = pointtraverse();
+  }
+  
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outelements()    Output the tetrahedra to an .ele file or a tetgenio      //
+//                  structure.                                               //
+//                                                                           //
+// This routine also indexes all tetrahedra (exclusing hull tets) (from in-> //
+// firstnumber). The total number of mesh edges is counted in 'meshedges'.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outelements(tetgenio* out)
+{
+  FILE *outfile = NULL;
+  char outelefilename[FILENAMESIZE];
+  tetrahedron* tptr;
+  point p1, p2, p3, p4;
+  point *extralist;
+  REAL *talist = NULL;
+  int *tlist = NULL;
+  long ntets;
+  int firstindex, shift;
+  int pointindex, attribindex;
+  int highorderindex = 11; 
+  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 = tetrahedrons->items - hullsize;
+
+  eextras = numelemattrib;
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(outelefilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", outelefilename);
+      terminatetetgen(this, 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(this, 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(this, 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 shift.
+  if ((in->firstnumber == 1) && (firstindex == 0)) {
+    shift = 1; // Shift the output indices by 1.
+  }
+
+  tetrahedrons->traversalinit();
+  tptr = tetrahedrontraverse();
+  elementnumber = firstindex; // in->firstnumber;
+  while (tptr != (tetrahedron *) NULL) {
+    if (!b->reversetetori) {
+      p1 = (point) tptr[4];
+      p2 = (point) tptr[5];
+    } else {
+      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];
+        // indices for 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);
+      }
+    }
+    // Remember the index of this element (for counting edges).
+    setelemindex(tptr, elementnumber);
+    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.      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outfaces(tetgenio* out)
+{
+  FILE *outfile = NULL;
+  char facefilename[FILENAMESIZE];
+  triface tface, tsymface;
+  face checkmark;
+  point torg, tdest, tapex;
+  long ntets, faces;
+  int *elist = NULL, *emlist = NULL;
+  int neigh1 = 0, neigh2 = 0;
+  int faceid, marker = 0;
+  int firstindex, shift;
+  int facenumber;
+  int index = 0;
+
+  // For -o2 option.
+  triface workface;
+  point *extralist, pp[3] = {0,0,0}; 
+  int highorderindex = 11; 
+  int o2index = 0, i;
+
+  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 = tetrahedrons->items - hullsize;
+  faces = (ntets * 4l + hullsize) / 2l;
+
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(facefilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", facefilename);
+      terminatetetgen(this, 1);
+    }
+    fprintf(outfile, "%ld  %d\n", faces, !b->nobound);
+  } else {
+    // Allocate memory for 'trifacelist'.
+    out->trifacelist = new int[faces * 3];
+    if (out->trifacelist == (int *) NULL) {
+      printf("Error:  Out of memory.\n");
+      terminatetetgen(this, 1);
+    }
+    if (b->order == 2) {
+      out->o2facelist = new int[faces * 3];
+    }
+    // Allocate memory for 'trifacemarkerlist' if necessary.
+    if (!b->nobound) {
+      out->trifacemarkerlist = new int[faces];
+      if (out->trifacemarkerlist == (int *) NULL) {
+        printf("Error:  Out of memory.\n");
+        terminatetetgen(this, 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(this, 1);
+      }
+    }
+    out->numberoftrifaces = faces;
+    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.
+  }
+
+  tetrahedrons->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 index than its neighbor.
+  while (tface.tet != (tetrahedron *) NULL) {
+    for (tface.ver = 0; tface.ver < 4; tface.ver ++) {
+      fsym(tface, tsymface);
+      if (ishulltet(tsymface) || 
+          (elemindex(tface.tet) < elemindex(tsymface.tet))) {
+        torg = org(tface);
+        tdest = dest(tface);
+        tapex = apex(tface);
+        if (b->order == 2) { // -o2
+          // Get the three extra vertices on edges.
+          extralist = (point *) (tface.tet[highorderindex]);
+          // The extra vertices are on edges opposite the corners.
+          enext(tface, workface);
+          for (i = 0; i < 3; i++) {
+            pp[i] = extralist[ver2edge[workface.ver]];
+            enextself(workface);
+          }
+        }
+        if (!b->nobound) {
+          // Get the boundary marker of this face.
+          if (b->plc || b->refine) { 
+            // Shell face is used.
+            tspivot(tface, checkmark);
+            if (checkmark.sh == NULL) {
+              marker = 0;  // It is an inner face. It's marker is 0.
+            } else {
+              if (in->facetmarkerlist) {
+                // The facet marker is given, get it.
+                faceid = shellmark(checkmark) - 1;
+                marker = in->facetmarkerlist[faceid];
+              } else {
+                marker = 1; // The default marker for subface is 1.
+              }
+            }
+          } else {
+            // Shell face is not used, only distinguish outer and inner face.
+            marker = (int) ishulltet(tsymface);
+          }
+        }
+        if (b->neighout > 1) {
+          // '-nn' switch. Output adjacent tets indices.
+          neigh1 = elemindex(tface.tet);
+          if (!ishulltet(tsymface)) {
+            neigh2 = elemindex(tsymface.tet);
+          } 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 (b->order == 2) { // -o2
+            fprintf(outfile, "  %4d  %4d  %4d", pointmark(pp[0]) - shift, 
+                    pointmark(pp[1]) - shift, pointmark(pp[2]) - shift);
+          }
+          if (!b->nobound) {
+            // 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 (b->order == 2) { // -o2
+            out->o2facelist[o2index++] = pointmark(pp[0]) - shift;
+            out->o2facelist[o2index++] = pointmark(pp[1]) - shift;
+            out->o2facelist[o2index++] = pointmark(pp[2]) - shift;
+          }
+          if (!b->nobound) {
+            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 = NULL;
+  char facefilename[FILENAMESIZE];
+  triface hulltet;
+  point torg, tdest, tapex;
+  int *elist = NULL;
+  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(this, 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(this, 1);
+    }
+    out->numberoftrifaces = hullsize;
+    elist = out->trifacelist;
+    index = 0;
+  }
+
+  // Determine the first index (0 or 1).
+  firstindex = b->zeroindex ? 0 : in->firstnumber;
+  shift = 0; // Default no shiftment.
+  if ((in->firstnumber == 1) && (firstindex == 0)) {
+    shift = 1; // Shift the output indices by 1.
+  }
+
+  tetrahedrons->traversalinit();
+  hulltet.tet = alltetrahedrontraverse();
+  facenumber = firstindex;
+  while (hulltet.tet != (tetrahedron *) NULL) {
+    if (ishulltet(hulltet)) {
+      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 (i.e. boundary faces) to a .face file or //
+//                  a tetgenio structure.                                    //
+//                                                                           //
+// The boundary faces are found in 'subfaces'. For listing triangle vertices //
+// in the same sense for all triangles in the mesh, the direction determined //
+// by right-hand rule is pointer to the inside of the volume.                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outsubfaces(tetgenio* out)
+{
+  FILE *outfile = NULL;
+  char facefilename[FILENAMESIZE];
+  int *elist = NULL;
+  int *emlist = NULL;
+  int index = 0, index1 = 0, index2 = 0;
+  triface abuttingtet;
+  face faceloop;
+  point torg, tdest, tapex;
+  int faceid = 0, marker = 0;
+  int firstindex, shift;
+  int neigh1 = 0, neigh2 = 0;
+  int facenumber;
+
+  // For -o2 option.
+  triface workface;
+  point *extralist, pp[3] = {0,0,0}; 
+  int highorderindex = 11;
+  int o2index = 0, i;
+
+  int t1ver; // used by fsymself()
+
+  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(this, 3);
+    }
+    // Number of subfaces.
+    fprintf(outfile, "%ld  %d\n", subfaces->items, !b->nobound);
+  } else {
+    // Allocate memory for 'trifacelist'.
+    out->trifacelist = new int[subfaces->items * 3];
+    if (out->trifacelist == (int *) NULL) {
+      terminatetetgen(this, 1);
+    }
+    if (b->order == 2) {
+      out->o2facelist = new int[subfaces->items * 3];
+    }
+    if (!b->nobound) {
+      // Allocate memory for 'trifacemarkerlist'.
+      out->trifacemarkerlist = new int[subfaces->items];
+      if (out->trifacemarkerlist == (int *) NULL) {
+        terminatetetgen(this, 1);
+      }
+    }
+    if (b->neighout > 1) {
+      // '-nn' switch.
+      out->adjtetlist = new int[subfaces->items * 2];
+      if (out->adjtetlist == (int *) NULL) {
+        terminatetetgen(this, 1);
+      }
+    }
+    out->numberoftrifaces = subfaces->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.
+  }
+
+  subfaces->traversalinit();
+  faceloop.sh = shellfacetraverse(subfaces);
+  facenumber = firstindex; // in->firstnumber;
+  while (faceloop.sh != (shellface *) NULL) {
+    stpivot(faceloop, abuttingtet);
+    // If there is a tetrahedron containing this subface, orient it so
+    //   that the normal of this face points to inside of the volume by
+    //   right-hand rule.
+    if (abuttingtet.tet != NULL) {
+      if (ishulltet(abuttingtet)) {
+        fsymself(abuttingtet);
+        assert(!ishulltet(abuttingtet));
+      }
+    }
+    if (abuttingtet.tet != NULL) {
+      torg = org(abuttingtet);
+      tdest = dest(abuttingtet);
+      tapex = apex(abuttingtet);
+      if (b->order == 2) { // -o2
+        // Get the three extra vertices on edges.
+        extralist = (point *) (abuttingtet.tet[highorderindex]);
+        workface = abuttingtet;
+        for (i = 0; i < 3; i++) {
+          pp[i] = extralist[ver2edge[workface.ver]];
+          enextself(workface);
+        }
+      }
+    } else {
+      // This may happen when only a surface mesh be generated.
+      torg = sorg(faceloop);
+      tdest = sdest(faceloop);
+      tapex = sapex(faceloop);
+      if (b->order == 2) { // -o2
+        // There is no extra node list available.
+        pp[0] = torg;
+        pp[1] = tdest;
+        pp[2] = tapex;
+      }
+    }
+    if (!b->nobound) {
+      if (b->refine) { // -r option.
+        if (in->trifacemarkerlist) {
+          marker = shellmark(faceloop);
+        } else {
+          marker = 1; // Default marker for a subface is 1.
+        }
+      } else {
+        if (in->facetmarkerlist) {
+          faceid = shellmark(faceloop) - 1;
+          marker = in->facetmarkerlist[faceid];
+        } else {
+          marker = 1; // Default marker for a subface is 1.
+        }
+      }
+    }
+    if (b->neighout > 1) {
+      // '-nn' switch. Output adjacent tets indices.
+      neigh1 = -1;
+      neigh2 = -1;
+      stpivot(faceloop, abuttingtet);
+      if (abuttingtet.tet != NULL) {
+        neigh1 = elemindex(abuttingtet.tet);
+        fsymself(abuttingtet);
+        if (!ishulltet(abuttingtet)) {
+          neigh2 = elemindex(abuttingtet.tet);
+        }
+      }
+    }
+    if (out == (tetgenio *) NULL) {
+      fprintf(outfile, "%5d   %4d  %4d  %4d", facenumber,
+              pointmark(torg) - shift, pointmark(tdest) - shift,
+              pointmark(tapex) - shift);
+      if (b->order == 2) { // -o2
+        fprintf(outfile, "  %4d  %4d  %4d", pointmark(pp[0]) - shift, 
+                pointmark(pp[1]) - shift, pointmark(pp[2]) - shift);
+      }
+      if (!b->nobound) {
+        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 (b->order == 2) { // -o2
+        out->o2facelist[o2index++] = pointmark(pp[0]) - shift;
+        out->o2facelist[o2index++] = pointmark(pp[1]) - shift;
+        out->o2facelist[o2index++] = pointmark(pp[2]) - shift;
+      }
+      if (!b->nobound) {
+        emlist[index1++] = marker;
+      }
+      if (b->neighout > 1) {
+        out->adjtetlist[index2++] = neigh1;
+        out->adjtetlist[index2++] = neigh2;
+      }
+    }
+    facenumber++;
+    faceloop.sh = shellfacetraverse(subfaces);
+  }
+
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outedges()    Output all edges to a .edge file or a 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 = NULL;
+  char edgefilename[FILENAMESIZE];
+  triface tetloop, worktet, spintet;
+  face checkseg;
+  point torg, tdest;
+  int *elist = NULL, *emlist = NULL;
+  int ishulledge;
+  int firstindex, shift;
+  int edgenumber, marker;
+  int index = 0, index1 = 0, index2 = 0;
+  int t1ver;
+  int i;
+
+  // For -o2 option.
+  point *extralist, pp = NULL; 
+  int highorderindex = 11;
+  int o2index = 0;
+
+  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 (meshedges == 0l) {
+    if (nonconvex) {
+      numberedges();  // Count the edges.
+    } else {
+      // Use Euler's characteristic to get the numbe of edges.
+      // It states V - E + F - C = 1, hence E = V + F - C - 1.
+      long tsize = tetrahedrons->items - hullsize;
+      long fsize = (tsize * 4l + hullsize) / 2l;
+      long vsize = points->items - dupverts - unuverts;
+      if (b->weighted) vsize -= nonregularcount;
+      meshedges = vsize + fsize - tsize - 1;
+    }
+  }
+
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(edgefilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", edgefilename);
+      terminatetetgen(this, 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(this, 1);
+    }
+    if (b->order == 2) { // -o2 switch
+      out->o2edgelist = new int[meshedges];
+    }
+    if (!b->nobound) {
+      out->edgemarkerlist = new int[meshedges];
+    }
+    if (b->neighout > 1) { // '-nn' switch.
+      out->edgeadjtetlist = new int[meshedges];
+    }
+    out->numberofedges = meshedges;
+    elist = out->edgelist;
+    emlist = out->edgemarkerlist;
+  }
+
+  // Determine the first index (0 or 1).
+  firstindex = b->zeroindex ? 0 : in->firstnumber;
+  shift = 0; // Default no shiftment.
+  if ((in->firstnumber == 1) && (firstindex == 0)) {
+    shift = 1; // Shift (reduce) the output indices by 1.
+  }
+
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  edgenumber = firstindex; // in->firstnumber;
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    // Count the number of Voronoi faces. 
+    worktet.tet = tetloop.tet;
+    for (i = 0; i < 6; i++) {
+      worktet.ver = edge2ver[i];
+      ishulledge = 0;
+      fnext(worktet, spintet);
+      do {
+        if (!ishulltet(spintet)) {
+          if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
+        } else {
+          ishulledge = 1;
+        }
+        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 (b->order == 2) { // -o2
+          // Get the extra vertex on this edge.
+          extralist = (point *) worktet.tet[highorderindex];
+          pp = extralist[ver2edge[worktet.ver]];
+        }
+        if (out == (tetgenio *) NULL) {
+          fprintf(outfile, "%5d   %4d  %4d", edgenumber,
+                  pointmark(torg) - shift, pointmark(tdest) - shift);
+          if (b->order == 2) { // -o2
+            fprintf(outfile, "  %4d", pointmark(pp) - shift);
+          }
+        } else {
+          // Output three vertices of this face;
+          elist[index++] = pointmark(torg) - shift;
+          elist[index++] = pointmark(tdest) - shift;
+          if (b->order == 2) { // -o2
+            out->o2edgelist[o2index++] = pointmark(pp) - shift;
+          }
+        }
+        if (!b->nobound) {
+          if (b->plc || b->refine) {
+            // Check if the edge is a segment.
+            tsspivot1(worktet, checkseg);
+            if (checkseg.sh != NULL) {
+              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.
+            }
+          } else {
+            // Mark it if it is a hull edge.
+            marker = ishulledge ? 1 : 0;
+          }
+          if (out == (tetgenio *) NULL) {
+            fprintf(outfile, "  %d", marker);
+          } else {
+            emlist[index1++] = marker;
+          }
+        }
+        if (b->neighout > 1) { // '-nn' switch.
+          if (out == (tetgenio *) NULL) {
+            fprintf(outfile, "  %d", elemindex(tetloop.tet));
+          } else {
+            out->edgeadjtetlist[index2++] = elemindex(tetloop.tet);
+          }
+        }
+        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 segments to a .edge file or a structure.       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outsubsegments(tetgenio* out)
+{
+  FILE *outfile = NULL;
+  char edgefilename[FILENAMESIZE];
+  int *elist = NULL;
+  int index, i;
+  face edgeloop;
+  point torg, tdest;
+  int firstindex, shift;
+  int marker;
+  int edgenumber;
+
+  // For -o2 option.
+  triface workface, spintet;
+  point *extralist, pp = NULL; 
+  int highorderindex = 11;
+  int o2index = 0;
+
+  // For -nn option.
+  int neigh = -1;
+  int index2 = 0;
+
+  int t1ver; // used by fsymself()
+
+  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(this, 3);
+    }
+    // Number of subsegments.
+    fprintf(outfile, "%ld  1\n", subsegs->items);
+  } else {
+    // Allocate memory for 'edgelist'.
+    out->edgelist = new int[subsegs->items * (b->order == 1 ? 2 : 3)];
+    if (out->edgelist == (int *) NULL) {
+      terminatetetgen(this, 1);
+    }
+    if (b->order == 2) {
+      out->o2edgelist = new int[subsegs->items];
+    }
+    out->edgemarkerlist = new int[subsegs->items];
+    if (out->edgemarkerlist == (int *) NULL) {
+      terminatetetgen(this, 1);
+    }
+    if (b->neighout > 1) {
+      out->edgeadjtetlist = new int[subsegs->items];
+    }
+    out->numberofedges = subsegs->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.
+  }
+  index = 0;
+  i = 0;
+
+  subsegs->traversalinit();
+  edgeloop.sh = shellfacetraverse(subsegs);
+  edgenumber = firstindex; // in->firstnumber;
+  while (edgeloop.sh != (shellface *) NULL) {
+    torg = sorg(edgeloop);
+    tdest = sdest(edgeloop);
+    if ((b->order == 2) || (b->neighout > 1)) {
+      sstpivot1(edgeloop, workface);
+      if (workface.tet != NULL) {
+        // We must find a non-hull tet.
+        if (ishulltet(workface)) {
+          spintet = workface;
+          while (1) {
+            fnextself(spintet);
+            if (!ishulltet(spintet)) break;
+            if (spintet.tet == workface.tet) break;
+          }
+          assert(!ishulltet(spintet));
+          workface = spintet;
+        }
+      }
+    }
+    if (b->order == 2) { // -o2
+      // Get the extra vertex on this edge.
+      if (workface.tet != NULL) {
+        extralist = (point *) workface.tet[highorderindex];
+        pp = extralist[ver2edge[workface.ver]];
+      } else {
+        pp = torg; // There is no extra node available.
+      }
+    }
+    if (b->neighout > 1) { // -nn
+      if (workface.tet != NULL) {
+        neigh = elemindex(workface.tet);
+      } else {
+        neigh = -1;
+      }
+    }
+    marker = shellmark(edgeloop);
+    if (marker == 0) {
+      marker = 1; // Default marker of a boundary edge is 1. 
+    }
+    if (out == (tetgenio *) NULL) {
+      fprintf(outfile, "%5d   %4d  %4d", edgenumber,
+              pointmark(torg) - shift, pointmark(tdest) - shift);
+      if (b->order == 2) { // -o2
+        fprintf(outfile, "  %4d", pointmark(pp) - shift);
+      }
+      fprintf(outfile, "  %d", marker);
+      if (b->neighout > 1) { // -nn
+        fprintf(outfile, "  %4d", neigh);
+      }
+      fprintf(outfile, "\n");
+    } else {
+      // Output three vertices of this face;
+      elist[index++] = pointmark(torg) - shift;
+      elist[index++] = pointmark(tdest) - shift;
+      if (b->order == 2) { // -o2
+        out->o2edgelist[o2index++] = pointmark(pp) - shift;
+      }
+      out->edgemarkerlist[i++] = marker;
+      if (b->neighout > 1) { // -nn
+        out->edgeadjtetlist[index2++] = neigh;
+      }
+    }
+    edgenumber++;
+    edgeloop.sh = shellfacetraverse(subsegs);
+  }
+
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outneighbors()    Output tet neighbors to a .neigh file or a structure.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outneighbors(tetgenio* out)
+{
+  FILE *outfile = NULL;
+  char neighborfilename[FILENAMESIZE];
+  int *nlist = NULL;
+  int index = 0;
+  triface tetloop, tetsym;
+  int neighbori[4];
+  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 = tetrahedrons->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(this, 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(this, 1);
+    }
+    nlist = out->neighborlist;
+  }
+
+  // Determine the first index (0 or 1).
+  firstindex = b->zeroindex ? 0 : in->firstnumber;
+
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  elementnumber = firstindex; // in->firstnumber;
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
+      fsym(tetloop, tetsym);
+      if (!ishulltet(tetsym)) {
+        neighbori[tetloop.ver] = elemindex(tetsym.tet);
+      } else {
+        neighbori[tetloop.ver] = -1;
+      }
+    }
+    if (out == (tetgenio *) NULL) {
+      // Tetrahedra number, neighboring tetrahedron numbers.
+      fprintf(outfile, "%4d    %4d  %4d  %4d  %4d\n", elementnumber,
+              neighbori[0], neighbori[1], neighbori[2], neighbori[3]);
+    } else {
+      nlist[index++] = neighbori[0];
+      nlist[index++] = neighbori[1];
+      nlist[index++] = neighbori[2];
+      nlist[index++] = neighbori[3];
+    }
+    tetloop.tet = tetrahedrontraverse();
+    elementnumber++;
+  }
+
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outvoronoi()    Output the Voronoi diagram to .v.node, .v.edge, v.face,   //
+//                 and .v.cell.                                              //
+//                                                                           //
+// The Voronoi diagram is the geometric dual of the Delaunay triangulation.  //
+// The Voronoi vertices are the circumcenters of Delaunay tetrahedra.  Each  //
+// Voronoi edge connects two Voronoi vertices at two sides of a common Dela- //
+// unay face. At a face of convex hull, it becomes a ray (goto the infinity).//
+// A Voronoi face is the convex hull of all Voronoi vertices around a common //
+// Delaunay edge. It is a closed polygon for any internal Delaunay edge. At a//
+// ridge, it is unbounded.  Each Voronoi cell is the convex hull of all Vor- //
+// onoi vertices around a common Delaunay vertex. It is a polytope for any   //
+// internal Delaunay vertex. It is an unbounded polyhedron for a Delaunay    //
+// vertex belonging to the convex hull.                                      //
+//                                                                           //
+// NOTE: This routine is only used when the input is only a set of point.    //
+// Comment: Special thanks to Victor Liu for finding and fixing few bugs.    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outvoronoi(tetgenio* out)
+{
+  FILE *outfile = NULL;
+  char outfilename[FILENAMESIZE];
+  tetgenio::voroedge *vedge = NULL;
+  tetgenio::vorofacet *vfacet = NULL;
+  arraypool *tetlist, *ptlist;
+  triface tetloop, worktet, spintet, firsttet;
+  point pt[4], ploop, neipt;
+  REAL ccent[3], infvec[3], vec1[3], vec2[3], L;
+  long ntets, faces, edges;
+  int *indexarray, *fidxs, *eidxs;
+  int arraysize, *vertarray = NULL;
+  int vpointcount, vedgecount, vfacecount, tcount;
+  int ishullvert, ishullface;
+  int index, shift, end1, end2;
+  int i, j;
+
+  int t1ver; // used by fsymself()
+
+  // Output Voronoi vertices to .v.node file.
+  if (out == (tetgenio *) NULL) {
+    strcpy(outfilename, b->outfilename);
+    strcat(outfilename, ".v.node");
+  }
+
+  if (!b->quiet) {
+    if (out == (tetgenio *) NULL) {
+      printf("Writing %s.\n", outfilename);
+    } else {
+      printf("Writing Voronoi vertices.\n");
+    }
+  }
+
+  // Determine the first index (0 or 1).
+  shift = (b->zeroindex ? 0 : in->firstnumber);
+
+  // Each face and edge of the tetrahedral mesh will be indexed for indexing
+  //   the Voronoi edges and facets. Indices of faces and edges are saved in
+  //   each tetrahedron (including hull tets).
+
+  // Allocate the total space once.
+  indexarray = new int[tetrahedrons->items * 10];
+
+  // Allocate space (10 integers) into each tetrahedron. It re-uses the slot
+  //   for element markers, flags.
+  i = 0;
+  tetrahedrons->traversalinit();
+  tetloop.tet = alltetrahedrontraverse();
+  while (tetloop.tet != NULL) {
+    tetloop.tet[11] = (tetrahedron) &(indexarray[i * 10]);
+    i++;
+    tetloop.tet = alltetrahedrontraverse();
+  }
+
+  // The number of tetrahedra (excluding hull tets) (Voronoi vertices).
+  ntets = tetrahedrons->items - hullsize;
+  // The number of Delaunay faces (Voronoi edges).
+  faces = (4l * ntets + hullsize) / 2l;
+  // The number of Delaunay edges (Voronoi faces).
+  long vsize = points->items - dupverts - unuverts;
+  if (b->weighted) vsize -= nonregularcount;
+  edges = vsize + faces - ntets - 1;
+
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(outfilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", outfilename);
+      terminatetetgen(this, 3);
+    }
+    // Number of voronoi points, 3 dim, no attributes, no marker.
+    fprintf(outfile, "%ld  3  0  0\n", ntets);
+  } else {
+    // Allocate space for 'vpointlist'.
+    out->numberofvpoints = (int) ntets;
+    out->vpointlist = new REAL[out->numberofvpoints * 3];
+    if (out->vpointlist == (REAL *) NULL) {
+      terminatetetgen(this, 1);
+    }
+  }
+
+  // Output Voronoi vertices (the circumcenters of tetrahedra). 
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  vpointcount = 0; // The (internal) v-index always starts from 0. 
+  index = 0;
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    for (i = 0; i < 4; i++) {
+      pt[i] = (point) tetloop.tet[4 + i];
+      setpoint2tet(pt[i], encode(tetloop));
+    }
+    if (b->weighted) {
+      orthosphere(pt[0], pt[1], pt[2], pt[3], pt[0][3], pt[1][3], pt[2][3], 
+                  pt[3][3], ccent, NULL);
+    } else {
+      circumsphere(pt[0], pt[1], pt[2], pt[3], ccent, NULL);
+    }
+    if (out == (tetgenio *) NULL) {
+      fprintf(outfile, "%4d  %16.8e %16.8e %16.8e\n", vpointcount + shift,
+              ccent[0], ccent[1], ccent[2]);
+    } else {
+      out->vpointlist[index++] = ccent[0];
+      out->vpointlist[index++] = ccent[1];
+      out->vpointlist[index++] = ccent[2];
+    }
+    setelemindex(tetloop.tet, vpointcount);
+    vpointcount++;
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+
+  // Output Voronoi edges to .v.edge file.
+  if (out == (tetgenio *) NULL) {
+    strcpy(outfilename, b->outfilename);
+    strcat(outfilename, ".v.edge");
+  }
+  
+  if (!b->quiet) {
+    if (out == (tetgenio *) NULL) {
+      printf("Writing %s.\n", outfilename);
+    } else {
+      printf("Writing Voronoi edges.\n");
+    }
+  }
+
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(outfilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", outfilename);
+      terminatetetgen(this, 3);
+    }
+    // Number of Voronoi edges, no marker.
+    fprintf(outfile, "%ld  0\n", faces);
+  } else {
+    // Allocate space for 'vpointlist'.
+    out->numberofvedges = (int) faces;
+    out->vedgelist = new tetgenio::voroedge[out->numberofvedges];
+  }
+
+  // Output the Voronoi edges. 
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  vedgecount = 0; // D-Face (V-edge) index (from zero).
+  index = 0; // The Delaunay-face index.
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    // Count the number of Voronoi edges. Look at the four faces of each
+    //   tetrahedron. Count the face if the tetrahedron's index is
+    //   smaller than its neighbor's or the neighbor is outside.
+    end1 = elemindex(tetloop.tet);
+    for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
+      fsym(tetloop, worktet);
+      if (ishulltet(worktet) || 
+          (elemindex(tetloop.tet) < elemindex(worktet.tet))) {
+        // Found a Voronoi edge. Operate on it.
+        if (out == (tetgenio *) NULL) {
+          fprintf(outfile, "%4d  %4d", vedgecount + shift, end1 + shift);
+        } else {
+          vedge = &(out->vedgelist[index++]);
+          vedge->v1 = end1 + shift;
+        }
+        if (!ishulltet(worktet)) {
+          end2 = elemindex(worktet.tet);
+        } else {
+          end2 = -1;
+        }
+        // Note that end2 may be -1 (worktet.tet is outside).
+        if (end2 == -1) {
+          // Calculate the out normal of this hull face.
+          pt[0] = dest(worktet);
+          pt[1] = org(worktet);
+          pt[2] = apex(worktet);
+          for (j = 0; j < 3; j++) vec1[j] = pt[1][j] - pt[0][j];
+          for (j = 0; j < 3; j++) vec2[j] = pt[2][j] - pt[0][j];
+          cross(vec1, vec2, infvec);
+          // Normalize it.
+          L = sqrt(infvec[0] * infvec[0] + infvec[1] * infvec[1]
+                   + infvec[2] * infvec[2]);
+          if (L > 0) for (j = 0; j < 3; j++) infvec[j] /= L;
+          if (out == (tetgenio *) NULL) {
+            fprintf(outfile, " -1");
+            fprintf(outfile, " %g %g %g\n", infvec[0], infvec[1], infvec[2]);
+          } else {
+            vedge->v2 = -1;
+            vedge->vnormal[0] = infvec[0];
+            vedge->vnormal[1] = infvec[1];
+            vedge->vnormal[2] = infvec[2];
+          }
+        } else {
+          if (out == (tetgenio *) NULL) {
+            fprintf(outfile, " %4d\n", end2 + shift);
+          } else {
+            vedge->v2 = end2 + shift;
+            vedge->vnormal[0] = 0.0;
+            vedge->vnormal[1] = 0.0;
+            vedge->vnormal[2] = 0.0;
+          }
+        }
+        // Save the V-edge index in this tet and its neighbor.
+        fidxs = (int *) (tetloop.tet[11]);
+        fidxs[tetloop.ver] = vedgecount;
+        fidxs = (int *) (worktet.tet[11]);
+        fidxs[worktet.ver & 3] = vedgecount;
+        vedgecount++;
+      }
+    } // tetloop.ver
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+
+  // Output Voronoi faces to .v.face file.
+  if (out == (tetgenio *) NULL) {
+    strcpy(outfilename, b->outfilename);
+    strcat(outfilename, ".v.face");
+  }
+  
+  if (!b->quiet) {
+    if (out == (tetgenio *) NULL) {
+      printf("Writing %s.\n", outfilename);
+    } else {
+      printf("Writing Voronoi faces.\n");
+    }
+  }
+
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(outfilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", outfilename);
+      terminatetetgen(this, 3);
+    }
+    // Number of Voronoi faces.
+    fprintf(outfile, "%ld  0\n", edges);
+  } else {
+    out->numberofvfacets = edges;
+    out->vfacetlist = new tetgenio::vorofacet[out->numberofvfacets];
+    if (out->vfacetlist == (tetgenio::vorofacet *) NULL) {
+      terminatetetgen(this, 1);
+    }
+  }
+
+  // Output the Voronoi facets.
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  vfacecount = 0; // D-edge (V-facet) index (from zero).
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    // Count the number of Voronoi faces. Look at the six edges of each
+    //   tetrahedron. Count the edge only if the tetrahedron's index is
+    //   smaller than those of all other tetrahedra that share the edge.
+    worktet.tet = tetloop.tet;
+    for (i = 0; i < 6; i++) {
+      worktet.ver = edge2ver[i];
+      // Count the number of faces at this edge. If the edge is a hull edge,
+      //   the face containing dummypoint is also counted.
+      //ishulledge = 0; // Is it a hull edge.
+      tcount = 0;
+      firsttet = worktet;
+      spintet = worktet;
+      while (1) {
+        tcount++;
+        fnextself(spintet);
+        if (spintet.tet == worktet.tet) break;
+        if (!ishulltet(spintet)) {
+          if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
+        } else {
+          //ishulledge = 1;
+          if (apex(spintet) == dummypoint) {
+            // We make this V-edge appear in the end of the edge list.
+            fnext(spintet, firsttet); 
+          }
+        }
+      } // while (1)
+      if (spintet.tet == worktet.tet) {
+        // Found a Voronoi facet. Operate on it.
+        pt[0] = org(worktet);
+        pt[1] = dest(worktet);
+        end1 = pointmark(pt[0]) - in->firstnumber; // V-cell index
+        end2 = pointmark(pt[1]) - in->firstnumber;
+        if (out == (tetgenio *) NULL) {
+          fprintf(outfile, "%4d  %4d %4d  %-2d ", vfacecount + shift, 
+                  end1 + shift, end2 + shift, tcount);
+        } else {
+          vfacet = &(out->vfacetlist[vfacecount]);
+          vfacet->c1 = end1 + shift;
+          vfacet->c2 = end2 + shift;
+          vfacet->elist = new int[tcount + 1];
+          vfacet->elist[0] = tcount;
+          index = 1;
+        }
+        // Output V-edges of this V-facet.
+        spintet = firsttet; //worktet;
+        while (1) {
+          fidxs = (int *) (spintet.tet[11]);
+          if (apex(spintet) != dummypoint) {
+            vedgecount = fidxs[spintet.ver & 3];
+            ishullface = 0;
+          } else {
+            ishullface = 1; // It's not a real face.
+          }
+          if (out == (tetgenio *) NULL) {
+            fprintf(outfile, " %d", !ishullface ? (vedgecount + shift) : -1); 
+          } else {
+            vfacet->elist[index++] = !ishullface ? (vedgecount + shift) : -1;
+          }
+          // Save the V-facet index in this tet at this edge.
+          eidxs = &(fidxs[4]);
+          eidxs[ver2edge[spintet.ver]] = vfacecount;
+          // Go to the next face.
+          fnextself(spintet);
+          if (spintet.tet == firsttet.tet) break;
+        } // while (1)
+        if (out == (tetgenio *) NULL) {
+          fprintf(outfile, "\n");
+        }
+        vfacecount++;
+      } // if (spintet.tet == worktet.tet)
+    } // if (i = 0; i < 6; i++)
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+
+  // Output Voronoi cells to .v.cell file.
+  if (out == (tetgenio *) NULL) {
+    strcpy(outfilename, b->outfilename);
+    strcat(outfilename, ".v.cell");
+  }
+  
+  if (!b->quiet) {
+    if (out == (tetgenio *) NULL) {
+      printf("Writing %s.\n", outfilename);
+    } else {
+      printf("Writing Voronoi cells.\n");
+    }
+  }
+
+  if (out == (tetgenio *) NULL) {
+    outfile = fopen(outfilename, "w");
+    if (outfile == (FILE *) NULL) {
+      printf("File I/O Error:  Cannot create file %s.\n", outfilename);
+      terminatetetgen(this, 3);
+    }
+    // Number of Voronoi cells.
+    fprintf(outfile, "%ld\n", points->items - unuverts - dupverts);
+  } else {
+    out->numberofvcells = points->items - unuverts - dupverts;
+    out->vcelllist = new int*[out->numberofvcells];
+    if (out->vcelllist == (int **) NULL) {
+      terminatetetgen(this, 1);
+    }
+  }
+
+  // Output Voronoi cells.
+  tetlist = cavetetlist;
+  ptlist = cavetetvertlist;
+  points->traversalinit();
+  ploop = pointtraverse();
+  vpointcount = 0;
+  while (ploop != (point) NULL) {
+    if ((pointtype(ploop) != UNUSEDVERTEX) &&
+        (pointtype(ploop) != DUPLICATEDVERTEX) &&
+        (pointtype(ploop) != NREGULARVERTEX)) { 
+      getvertexstar(1, ploop, tetlist, ptlist, NULL);
+      // Mark all vertices. Check if it is a hull vertex.
+      ishullvert = 0;
+      for (i = 0; i < ptlist->objects; i++) {
+        neipt = * (point *) fastlookup(ptlist, i);
+        if (neipt != dummypoint) {
+          pinfect(neipt);
+        } else {
+          ishullvert = 1;
+        }
+      }
+      tcount = (int) ptlist->objects;
+      if (out == (tetgenio *) NULL) {
+        fprintf(outfile, "%4d  %-2d ", vpointcount + shift, tcount);
+      } else {
+        arraysize = tcount;
+        vertarray = new int[arraysize + 1];
+        out->vcelllist[vpointcount] = vertarray;
+        vertarray[0] = tcount;
+        index = 1;
+      }
+      // List Voronoi facets bounding this cell.
+      for (i = 0; i < tetlist->objects; i++) {
+        worktet = * (triface *) fastlookup(tetlist, i);
+        // Let 'worktet' be [a,b,c,d] where d = ploop.
+        for (j = 0; j < 3; j++) {
+          neipt = org(worktet); // neipt is a, or b, or c
+          // Skip the dummypoint.
+          if (neipt != dummypoint) {
+            if (pinfected(neipt)) {
+              // It's not processed yet.
+              puninfect(neipt);
+              // Go to the DT edge [a,d], or [b,d], or [c,d]. 
+              esym(worktet, spintet);
+              enextself(spintet);
+              // Get the V-face dual to this edge.
+              eidxs = (int *) spintet.tet[11];
+              vfacecount = eidxs[4 + ver2edge[spintet.ver]];
+              if (out == (tetgenio *) NULL) {
+                fprintf(outfile, " %d", vfacecount + shift);
+              } else {
+                vertarray[index++] = vfacecount + shift;
+              }
+            }
+          }
+          enextself(worktet);
+        } // j
+      } // i
+      if (ishullvert) {
+        // Add a hull facet (-1) to the facet list.
+        if (out == (tetgenio *) NULL) {
+          fprintf(outfile, " -1");
+        } else {
+          vertarray[index++] = -1;
+        }
+      }
+      if (out == (tetgenio *) NULL) {
+        fprintf(outfile, "\n");
+      }
+      tetlist->restart();
+      ptlist->restart();
+      vpointcount++;
+    }
+    ploop = pointtraverse();
+  }
+
+  // Delete the space for face/edge indices.
+  delete [] indexarray;
+
+  if (out == (tetgenio *) NULL) {
+    fprintf(outfile, "# Generated by %s\n", b->commandline);
+    fclose(outfile);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outsmesh()    Write surface mesh to a .smesh file, which can be read and  //
+//               tetrahedralized by TetGen.                                  //
+//                                                                           //
+// You can specify a filename (without suffix) in 'smfilename'. If you don't //
+// supply a filename (let smfilename be NULL), the default name stored in    //
+// 'tetgenbehavior' will be used.                                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outsmesh(char* smfilename)
+{
+  FILE *outfile;
+  char nodfilename[FILENAMESIZE];
+  char smefilename[FILENAMESIZE];
+  face faceloop;
+  point p1, p2, p3;
+  int firstindex, shift;
+  int bmark;
+  int faceid, marker;
+  int i;
+
+  if (smfilename != (char *) NULL && smfilename[0] != '\0') {
+    strcpy(smefilename, smfilename);
+  } else if (b->outfilename[0] != '\0') {
+    strcpy(smefilename, b->outfilename);
+  } else {
+    strcpy(smefilename, "unnamed");
+  }
+  strcpy(nodfilename, smefilename);
+  strcat(smefilename, ".smesh");
+  strcat(nodfilename, ".node");
+
+  if (!b->quiet) {
+    printf("Writing %s.\n", smefilename);
+  }
+  outfile = fopen(smefilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot create file %s.\n", smefilename);
+    return;
+  }
+
+  // Determine the first index (0 or 1).
+  firstindex = b->zeroindex ? 0 : in->firstnumber;
+  shift = 0; // Default no shiftment.
+  if ((in->firstnumber == 1) && (firstindex == 0)) {
+    shift = 1; // Shift the output indices by 1.
+  }
+
+  fprintf(outfile, "# %s.  TetGen's input file.\n", smefilename);
+  fprintf(outfile, "\n# part 1: node list.\n");
+  fprintf(outfile, "0  3  0  0  # nodes are found in %s.\n", nodfilename);
+
+  marker = 0; // avoid compile warning.
+  bmark = !b->nobound && in->facetmarkerlist;  
+
+  fprintf(outfile, "\n# part 2: facet list.\n");
+  // Number of facets, boundary marker.
+  fprintf(outfile, "%ld  %d\n", subfaces->items, bmark);
+  
+  subfaces->traversalinit();
+  faceloop.sh = shellfacetraverse(subfaces);
+  while (faceloop.sh != (shellface *) NULL) {
+    p1 = sorg(faceloop);
+    p2 = sdest(faceloop);
+    p3 = sapex(faceloop);
+    if (bmark) {
+      faceid = shellmark(faceloop) - 1;
+      if (faceid >= 0) { 
+        marker = in->facetmarkerlist[faceid];
+      } else {
+        marker = 0; // This subface must be added manually later.
+      }
+    }
+    fprintf(outfile, "3    %4d  %4d  %4d", pointmark(p1) - shift,
+            pointmark(p2) - shift, pointmark(p3) - shift);
+    if (bmark) {
+      fprintf(outfile, "    %d", marker);
+    }
+    fprintf(outfile, "\n");
+    faceloop.sh = shellfacetraverse(subfaces);
+  }
+
+  // Copy input holelist.
+  fprintf(outfile, "\n# part 3: hole list.\n");
+  fprintf(outfile, "%d\n", in->numberofholes);
+  for (i = 0; i < in->numberofholes; i++) {
+    fprintf(outfile, "%d  %g  %g  %g\n", i + in->firstnumber,
+            in->holelist[i * 3], in->holelist[i * 3 + 1],
+            in->holelist[i * 3 + 2]);
+  }
+
+  // Copy input regionlist.
+  fprintf(outfile, "\n# part 4: region list.\n");
+  fprintf(outfile, "%d\n", in->numberofregions);
+  for (i = 0; i < in->numberofregions; i++) {
+    fprintf(outfile, "%d  %g  %g  %g  %d  %g\n", i + in->firstnumber,
+            in->regionlist[i * 5], in->regionlist[i * 5 + 1],
+            in->regionlist[i * 5 + 2], (int) in->regionlist[i * 5 + 3],
+            in->regionlist[i * 5 + 4]);
+  }
+
+  fprintf(outfile, "# Generated by %s\n", b->commandline);
+  fclose(outfile);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outmesh2medit()    Write mesh to a .mesh file, which can be read and      //
+//                    rendered by Medit (a free mesh viewer from INRIA).     //
+//                                                                           //
+// You can specify a filename (without suffix) in 'mfilename'.  If you don't //
+// supply a filename (let mfilename be NULL), the default name stored in     //
+// 'tetgenbehavior' will be used. The output file will have the suffix .mesh.//
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outmesh2medit(char* mfilename)
+{
+  FILE *outfile;
+  char mefilename[FILENAMESIZE];
+  tetrahedron* tetptr;
+  triface tface, tsymface;
+  face segloop, checkmark;
+  point ptloop, p1, p2, p3, p4;
+  long ntets, faces;
+  int pointnumber;
+  int faceid, marker;
+  int i;
+
+  if (mfilename != (char *) NULL && mfilename[0] != '\0') {
+    strcpy(mefilename, mfilename);
+  } else if (b->outfilename[0] != '\0') {
+    strcpy(mefilename, b->outfilename);
+  } else {
+    strcpy(mefilename, "unnamed");
+  }
+  strcat(mefilename, ".mesh");
+
+  if (!b->quiet) {
+    printf("Writing %s.\n", mefilename);
+  }
+  outfile = fopen(mefilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot create file %s.\n", mefilename);
+    return;
+  }
+
+  fprintf(outfile, "MeshVersionFormatted 1\n");
+  fprintf(outfile, "\n");
+  fprintf(outfile, "Dimension\n");
+  fprintf(outfile, "3\n");
+  fprintf(outfile, "\n");
+
+  fprintf(outfile, "\n# Set of mesh vertices\n");
+  fprintf(outfile, "Vertices\n");
+  fprintf(outfile, "%ld\n", points->items);
+
+  points->traversalinit();
+  ptloop = pointtraverse();
+  pointnumber = 1;                        // Medit need start number form 1.
+  while (ptloop != (point) NULL) {
+    // Point coordinates.
+    fprintf(outfile, "%.17g  %.17g  %.17g", ptloop[0], ptloop[1], ptloop[2]);
+    if (in->numberofpointattributes > 0) {
+      // Write an attribute, ignore others if more than one.
+      fprintf(outfile, "  %.17g\n", ptloop[3]);
+    } else {
+      fprintf(outfile, "    0\n");
+    }
+    setpointmark(ptloop, pointnumber);
+    ptloop = pointtraverse();
+    pointnumber++;
+  }
+
+  // Compute the number of faces.
+  ntets = tetrahedrons->items - hullsize;
+  faces = (ntets * 4l + hullsize) / 2l;
+
+  fprintf(outfile, "\n# Set of Triangles\n");
+  fprintf(outfile, "Triangles\n");
+  fprintf(outfile, "%ld\n", faces);
+
+  tetrahedrons->traversalinit();
+  tface.tet = tetrahedrontraverse();
+  while (tface.tet != (tetrahedron *) NULL) {
+    for (tface.ver = 0; tface.ver < 4; tface.ver ++) {
+      fsym(tface, tsymface);
+      if (ishulltet(tsymface) || 
+          (elemindex(tface.tet) < elemindex(tsymface.tet))) {
+        p1 = org (tface);
+        p2 = dest(tface);
+        p3 = apex(tface);
+        fprintf(outfile, "%5d  %5d  %5d",
+                pointmark(p1), pointmark(p2), pointmark(p3));
+        // Check if it is a subface.
+        tspivot(tface, checkmark);
+        if (checkmark.sh == NULL) {
+          marker = 0;  // It is an inner face. It's marker is 0.
+        } else {
+          if (in->facetmarkerlist) {
+            // The facet marker is given, get it.
+            faceid = shellmark(checkmark) - 1;
+            marker = in->facetmarkerlist[faceid];
+          } else {
+            marker = 1; // The default marker for subface is 1.
+          }
+        }
+        fprintf(outfile, "    %d\n", marker);
+      }
+    }
+    tface.tet = tetrahedrontraverse();
+  }
+
+  fprintf(outfile, "\n# Set of Tetrahedra\n");
+  fprintf(outfile, "Tetrahedra\n");
+  fprintf(outfile, "%ld\n", ntets);
+
+  tetrahedrons->traversalinit();
+  tetptr = tetrahedrontraverse();
+  while (tetptr != (tetrahedron *) NULL) {
+    if (!b->reversetetori) {
+      p1 = (point) tetptr[4];
+      p2 = (point) tetptr[5];
+    } else {
+      p1 = (point) tetptr[5];
+      p2 = (point) tetptr[4];
+    }
+    p3 = (point) tetptr[6];
+    p4 = (point) tetptr[7];
+    fprintf(outfile, "%5d  %5d  %5d  %5d",
+            pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4));
+    if (numelemattrib > 0) {
+      fprintf(outfile, "  %.17g", elemattribute(tetptr, 0));
+    } else {
+      fprintf(outfile, "  0");
+    }
+    fprintf(outfile, "\n");
+    tetptr = tetrahedrontraverse();
+  }
+
+  fprintf(outfile, "\nCorners\n");
+  fprintf(outfile, "%d\n", in->numberofpoints);
+
+  for (i = 0; i < in->numberofpoints; i++) {
+    fprintf(outfile, "%4d\n", i + 1);
+  }
+
+  if (b->plc || b->refine) {
+    fprintf(outfile, "\nEdges\n");
+    fprintf(outfile, "%ld\n", subsegs->items);
+
+    subsegs->traversalinit();
+    segloop.sh = shellfacetraverse(subsegs);
+    while (segloop.sh != (shellface *) NULL) {
+      p1 = sorg(segloop);
+      p2 = sdest(segloop);
+      fprintf(outfile, "%5d  %5d", pointmark(p1), pointmark(p2));
+      marker = shellmark(segloop);
+      fprintf(outfile, "    %d\n", marker);
+      segloop.sh = shellfacetraverse(subsegs);
+    }
+  }
+
+  fprintf(outfile, "\nEnd\n");
+  fclose(outfile);
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// outmesh2vtk()    Save mesh to file in VTK Legacy format.                  //
+//                                                                           //
+// This function was contributed by Bryn Llyod from ETH, 2007.               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::outmesh2vtk(char* ofilename)
+{
+  FILE *outfile;
+  char vtkfilename[FILENAMESIZE];
+  point pointloop, p1, p2, p3, p4;
+  tetrahedron* tptr;
+  double x, y, z;
+  int n1, n2, n3, n4;
+  int nnodes = 4;
+  int celltype = 10;
+
+  if (b->order == 2) {
+    printf("  Write VTK not implemented for order 2 elements \n");
+    return;
+  }
+
+  int NEL = tetrahedrons->items - hullsize;
+  int NN = points->items;
+
+  if (ofilename != (char *) NULL && ofilename[0] != '\0') {
+    strcpy(vtkfilename, ofilename);
+  } else if (b->outfilename[0] != '\0') {
+    strcpy(vtkfilename, b->outfilename);
+  } else {
+    strcpy(vtkfilename, "unnamed");
+  }
+  strcat(vtkfilename, ".vtk");
+
+  if (!b->quiet) {
+    printf("Writing %s.\n", vtkfilename);
+  }
+  outfile = fopen(vtkfilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("File I/O Error:  Cannot create file %s.\n", vtkfilename);
+    return;
+  }
+
+  //always write big endian
+  //bool ImALittleEndian = !testIsBigEndian();
+
+  fprintf(outfile, "# vtk DataFile Version 2.0\n");
+  fprintf(outfile, "Unstructured Grid\n");
+  fprintf(outfile, "ASCII\n"); // BINARY
+  fprintf(outfile, "DATASET UNSTRUCTURED_GRID\n");
+  fprintf(outfile, "POINTS %d double\n", NN);
+
+  points->traversalinit();
+  pointloop = pointtraverse();
+  for(int id=0; id<NN && pointloop != (point) NULL; id++){
+    x = pointloop[0];
+    y = pointloop[1];
+    z = pointloop[2];
+    fprintf(outfile, "%.17g %.17g %.17g\n", x, y, z);
+    pointloop = pointtraverse();
+  }
+  fprintf(outfile, "\n");
+
+  fprintf(outfile, "CELLS %d %d\n", NEL, NEL*(4+1));
+  //NEL rows, each has 1 type id + 4 node id's
+ 
+  tetrahedrons->traversalinit();
+  tptr = tetrahedrontraverse();
+  //elementnumber = firstindex; // in->firstnumber;
+  while (tptr != (tetrahedron *) NULL) {
+    if (!b->reversetetori) {
+      p1 = (point) tptr[4];
+      p2 = (point) tptr[5];
+    } else {
+      p1 = (point) tptr[5];
+      p2 = (point) tptr[4];
+    }
+    p3 = (point) tptr[6];
+    p4 = (point) tptr[7];
+    n1 = pointmark(p1) - in->firstnumber;
+    n2 = pointmark(p2) - in->firstnumber;
+    n3 = pointmark(p3) - in->firstnumber;
+    n4 = pointmark(p4) - in->firstnumber;
+    fprintf(outfile, "%d  %4d %4d %4d %4d\n", nnodes, n1, n2, n3, n4);
+    tptr = tetrahedrontraverse();
+  }
+  fprintf(outfile, "\n");
+
+  fprintf(outfile, "CELL_TYPES %d\n", NEL);
+  for(int tid=0; tid<NEL; tid++){
+    fprintf(outfile, "%d\n", celltype);
+  }
+  fprintf(outfile, "\n");
+
+  if (numelemattrib > 0) {
+    // Output tetrahedra region attributes.
+    fprintf(outfile, "CELL_DATA %d\n", NEL);
+    fprintf(outfile, "SCALARS cell_scalars int 1\n");
+    fprintf(outfile, "LOOKUP_TABLE default\n");
+    tetrahedrons->traversalinit();
+    tptr = tetrahedrontraverse();
+    while (tptr != (tetrahedron *) NULL) {
+      fprintf(outfile, "%d\n", (int) elemattribute(tptr, numelemattrib - 1));
+      tptr = tetrahedrontraverse();
+    }
+    fprintf(outfile, "\n");
+  }
+
+  fclose(outfile);
+}
+
+////                                                                       ////
+////                                                                       ////
+//// output_cxx ///////////////////////////////////////////////////////////////
+
+//// main_cxx /////////////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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 boundary segments and facets (-p or -Y).                     //
+// - 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), and a mesh size function (-m).                             //
+// - Optimize the mesh wrt. specified quality measures (-O and -o).          //
+// - Write the output files and print the statistics.                        //
+// - Check the consistency of the mesh (-C).                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
+                    tetgenio *addin, tetgenio *bgmin)
+{
+  tetgenmesh m;
+  clock_t tv[12], ts[5]; // Timing informations (defined in time.h)
+  REAL cps = (REAL) CLOCKS_PER_SEC;
+
+  tv[0] = clock();
+ 
+  m.b = b;
+  m.in = in;
+  m.addin = addin;
+
+  if (b->metric && bgmin && (bgmin->numberofpoints > 0)) {
+    m.bgm = new tetgenmesh(); // Create an empty background mesh.
+    m.bgm->b = b;
+    m.bgm->in = bgmin;
+  }
+
+  m.initializepools();
+  m.transfernodes();
+
+  exactinit(b->verbose, b->noexact, b->nostaticfilter,
+            m.xmax - m.xmin, m.ymax - m.ymin, m.zmax - m.zmin);
+
+  tv[1] = clock();
+
+  if (b->refine) { // -r
+    m.reconstructmesh();
+  } else { // -p
+    m.incrementaldelaunay(ts[0]);
+  }
+
+  tv[2] = clock();
+
+  if (!b->quiet) {
+    if (b->refine) {
+      printf("Mesh reconstruction seconds:  %g\n", ((REAL)(tv[2]-tv[1])) / cps);
+    } else {
+      printf("Delaunay seconds:  %g\n", ((REAL)(tv[2]-tv[1])) / cps);
+      if (b->verbose) {
+        printf("  Point sorting seconds:  %g\n", ((REAL)(ts[0]-tv[1])) / cps);
+      }
+    }
+  }
+
+  if (b->plc && !b->refine) { // -p
+    m.meshsurface();
+
+    ts[0] = clock();
+
+    if (!b->quiet) {
+      printf("Surface mesh seconds:  %g\n", ((REAL)(ts[0]-tv[2])) / cps);
+    }
+
+    if (b->diagnose) { // -d
+      m.detectinterfaces();
+
+      ts[1] = clock();
+
+      if (!b->quiet) {
+        printf("Self-intersection seconds:  %g\n", ((REAL)(ts[1]-ts[0])) / cps);
+      }
+
+      // Only output when self-intersecting faces exist.
+      if (m.subfaces->items > 0l) {
+        m.outnodes(out);
+        m.outsubfaces(out);
+      }
+
+      return;
+    }
+  }
+
+  tv[3] = clock();
+
+  if ((b->metric) && (m.bgm != NULL)) { // -m
+    m.bgm->initializepools();
+    m.bgm->transfernodes();
+    m.bgm->reconstructmesh();
+
+    ts[0] = clock();
+
+    if (!b->quiet) {
+      printf("Background mesh reconstruct seconds:  %g\n",
+             ((REAL)(ts[0] - tv[3])) / cps);
+    }
+
+    if (b->metric) { // -m
+      m.interpolatemeshsize();
+
+      ts[1] = clock();
+
+      if (!b->quiet) {
+        printf("Size interpolating seconds:  %g\n",((REAL)(ts[1]-ts[0])) / cps);
+      }
+    }
+  }
+
+  tv[4] = clock();
+
+  if (b->plc && !b->refine) { // -p
+    if (b->nobisect) { // -Y
+      m.recoverboundary(ts[0]);
+    } else {
+      m.constraineddelaunay(ts[0]);
+    }
+
+    ts[1] = clock();
+
+    if (!b->quiet) {
+      if (b->nobisect) {
+        printf("Boundary recovery ");
+      } else {
+        printf("Constrained Delaunay ");
+      }
+      printf("seconds:  %g\n", ((REAL)(ts[1] - tv[4])) / cps);
+      if (b->verbose) {
+        printf("  Segment recovery seconds:  %g\n",((REAL)(ts[0]-tv[4]))/ cps);
+        printf("  Facet recovery seconds:  %g\n", ((REAL)(ts[1]-ts[0])) / cps);
+      }
+    }
+
+    m.carveholes();
+
+    ts[2] = clock();
+
+    if (!b->quiet) {
+      printf("Exterior tets removal seconds:  %g\n",((REAL)(ts[2]-ts[1]))/cps);
+    }
+
+    if (b->nobisect) { // -Y
+      if (m.subvertstack->objects > 0l) {
+        m.suppresssteinerpoints();
+
+        ts[3] = clock();
+
+        if (!b->quiet) {
+          printf("Steiner suppression seconds:  %g\n",
+                 ((REAL)(ts[3]-ts[2]))/cps);
+        }
+      }
+    }
+  }
+
+  tv[5] = clock();
+
+  if (b->coarsen) { // -R
+    m.meshcoarsening();
+  }
+
+  tv[6] = clock();
+
+  if (!b->quiet) {
+    if (b->coarsen) {
+      printf("Mesh coarsening seconds:  %g\n", ((REAL)(tv[6] - tv[5])) / cps);
+    }
+  }
+
+  if ((b->plc && b->nobisect) || b->coarsen) {
+    m.recoverdelaunay();
+  }
+
+  tv[7] = clock();
+
+  if (!b->quiet) {
+    if ((b->plc && b->nobisect) || b->coarsen) {
+      printf("Delaunay recovery seconds:  %g\n", ((REAL)(tv[7] - tv[6]))/cps);
+    }
+  }
+
+  if ((b->plc || b->refine) && b->insertaddpoints) { // -i
+    if ((addin != NULL) && (addin->numberofpoints > 0)) {
+      m.insertconstrainedpoints(addin); 
+    }
+  }
+
+  tv[8] = clock();
+
+  if (!b->quiet) {
+    if ((b->plc || b->refine) && b->insertaddpoints) { // -i
+      if ((addin != NULL) && (addin->numberofpoints > 0)) {
+        printf("Constrained points seconds:  %g\n", ((REAL)(tv[8]-tv[7]))/cps);
+      }
+    }
+  }
+
+  if (b->quality) {
+    m.delaunayrefinement();    
+  }
+
+  tv[9] = clock();
+
+  if (!b->quiet) {
+    if (b->quality) {
+      printf("Refinement seconds:  %g\n", ((REAL)(tv[9] - tv[8])) / cps);
+    }
+  }
+
+  if ((b->plc || b->refine) && (b->optlevel > 0)) {
+    m.optimizemesh();
+  }
+
+  tv[10] = clock();
+
+  if (!b->quiet) {
+    if ((b->plc || b->refine) && (b->optlevel > 0)) {
+      printf("Optimization seconds:  %g\n", ((REAL)(tv[10] - tv[9])) / cps);
+    }
+  }
+
+  if (!b->nojettison && ((m.dupverts > 0) || (m.unuverts > 0)
+      || (b->refine && (in->numberofcorners == 10)))) {
+    m.jettisonnodes();
+  }
+
+  if ((b->order == 2) && !b->convex) {
+    m.highorder();
+  }
+
+  if (!b->quiet) {
+    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) {
+    if (!b->quiet) {
+      printf("NOT writing an .ele file.\n");
+    }
+  } else {
+    if (m.tetrahedrons->items > 0l) {
+      m.outelements(out);
+    }
+  }
+
+  if (b->nofacewritten) {
+    if (!b->quiet) {
+      printf("NOT writing an .face file.\n");
+    }
+  } else {
+    if (b->facesout) {
+      if (m.tetrahedrons->items > 0l) {
+        m.outfaces(out);  // Output all faces.
+      }
+    } else {
+      if (b->plc || b->refine) {
+        if (m.subfaces->items > 0l) {
+          m.outsubfaces(out); // Output boundary faces.
+        }
+      } else {
+        if (m.tetrahedrons->items > 0l) {
+          m.outhullfaces(out); // Output convex hull faces.
+        }
+      }
+    }
+  }
+
+
+  if (b->nofacewritten) {
+    if (!b->quiet) {
+      printf("NOT writing an .edge file.\n");
+    }
+  } else {
+    if (b->edgesout) { // -e
+      m.outedges(out); // output all mesh edges. 
+    } else {
+      if (b->plc || b->refine) {
+        m.outsubsegments(out); // output subsegments.
+      }
+    }
+  }
+
+  if ((b->plc || b->refine) && b->metric) { // -m
+    m.outmetrics(out);
+  }
+
+  if (!out && b->plc && 
+      ((b->object == tetgenbehavior::OFF) ||
+       (b->object == tetgenbehavior::PLY) ||
+       (b->object == tetgenbehavior::STL))) {
+    m.outsmesh(b->outfilename);
+  }
+
+  if (!out && b->meditview) {
+    m.outmesh2medit(b->outfilename); 
+  }
+
+
+  if (!out && b->vtkview) {
+    m.outmesh2vtk(b->outfilename); 
+  }
+
+  if (b->neighout) {
+    m.outneighbors(out);
+  }
+
+  if ((!(b->plc || b->refine)) && b->voroout) {
+    m.outvoronoi(out);
+  }
+
+
+  tv[11] = clock();
+
+  if (!b->quiet) {
+    printf("\nOutput seconds:  %g\n", ((REAL)(tv[11] - tv[10])) / cps);
+    printf("Total running seconds:  %g\n", ((REAL)(tv[11] - tv[0])) / cps);
+  }
+
+  if (b->docheck) {
+    m.checkmesh(0);
+    if (b->plc || b->refine) {
+      m.checkshells();
+      m.checksegments();
+    }
+    if (b->docheck > 1) {
+      m.checkdelaunay();
+    }
+  }
+
+  if (!b->quiet) {
+    m.statistics();
+  }
+  exactdeinit();
+}
+
+#ifndef TETLIBRARY
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// main()    The command line interface of TetGen.                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int main(int argc, char *argv[])
+
+#else // with TETLIBRARY
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetrahedralize()    The library interface of TetGen.                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+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(NULL, 10);
+  }
+
+  // Read input files.
+  if (b.refine) { // -r
+    if (!in.load_tetmesh(b.infilename, (int) b.object)) {
+      terminatetetgen(NULL, 10);
+    }
+  } else { // -p
+    if (!in.load_plc(b.infilename, (int) b.object)) {
+      terminatetetgen(NULL, 10);
+    }
+  }
+  if (b.insertaddpoints) { // -i
+    // Try to read a .a.node file.
+    addin.load_node(b.addinfilename);
+  }
+  if (b.metric) { // -m
+    // Try to read a background mesh in files .b.node, .b.ele.
+    bgmin.load_tetmesh(b.bgmeshfilename, (int) b.object);
+  }
+
+  tetrahedralize(&b, &in, NULL, &addin, &bgmin);
+
+  return 0;
+
+#else // with TETLIBRARY
+
+  if (!b.parse_commandline(switches)) {
+    terminatetetgen(NULL, 10);
+  }
+  tetrahedralize(&b, in, out, addin, bgmin);
+
+#endif // not TETLIBRARY
+}
+
+////                                                                       ////
+////                                                                       ////
+//// main_cxx /////////////////////////////////////////////////////////////////
+
diff --git a/meshpy/src/cpp/tetgen.h b/meshpy/src/cpp/tetgen.h
new file mode 100644
index 0000000000000000000000000000000000000000..ccef59bb85d03e07021842e4a9f875f883138477
--- /dev/null
+++ b/meshpy/src/cpp/tetgen.h
@@ -0,0 +1,3329 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// TetGen                                                                    //
+//                                                                           //
+// A Quality Tetrahedral Mesh Generator and A 3D Delaunay Triangulator       //
+//                                                                           //
+// Version 1.5                                                               //
+// November 4, 2013                                                          //
+//                                                                           //
+// TetGen is freely available through the website: http://www.tetgen.org.    //
+//   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
+
+// 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 were
+//   inserted in the code where I hoped to catch bugs. They may slow down the
+//   speed of TetGen.
+
+// #define NDEBUG
+
+// TetGen default uses the double precision (64 bit) for a real number. 
+//   Alternatively, one can use the single precision (32 bit) 'float' if the
+//   memory is limited.
+
+#define REAL double  // #define REAL float
+
+// Maximum number of characters in a file name (including the null).
+
+#define FILENAMESIZE 1024
+
+// Maximum number of chars in a line read from a file (including the null).
+
+#define INPUTLINESIZE 2048
+
+// TetGen only uses the C standard library.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include <assert.h> 
+#include <boost/noncopyable.hpp>
+
+// The types 'intptr_t' and 'uintptr_t' are signed and unsigned integer types,
+//   respectively. They are guaranteed to be the same width as a pointer.
+//   They are defined in <stdint.h> by the C99 Standard. However, Microsoft 
+//   Visual C++ 2003 -- 2008 (Visual C++ 7.1 - 9) doesn't ship with this header
+//   file. In such case, we can define them by ourself. 
+// Update (learned from Stack Overflow): Visual Studio 2010 and Visual C++ 2010
+//   Express both have stdint.h
+
+// The following piece of code was provided by Steven Johnson (MIT). Define the
+//   symbol _MSC_VER if you are using Microsoft Visual C++. Moreover, define 
+//   the _WIN64 symbol if you are running TetGen on Win64 systems.
+
+#ifdef _MSC_VER // Microsoft Visual C++
+#  ifdef _WIN64
+     typedef __int64 intptr_t;
+     typedef unsigned __int64 uintptr_t;
+#  else // not _WIN64
+     typedef int intptr_t;
+     typedef unsigned int uintptr_t;
+#  endif
+#else // not Visual C++
+#  include <stdint.h>
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetgenio                                                                  //
+//                                                                           //
+// A structure for transferring data into and out of TetGen's mesh structure,//
+// 'tetgenmesh' (declared below).                                            //
+//                                                                           //
+// The input of TetGen is either a 3D point set, or a 3D piecewise linear    //
+// complex (PLC), or a tetrahedral mesh.  Depending on the input object and  //
+// the specified options, the output of TetGen is either a Delaunay (or wei- //
+// ghted Delaunay) tetrahedralization, or a constrained (Delaunay) tetrahed- //
+// ralization, or a quality tetrahedral mesh.                                //
+//                                                                           //
+// A piecewise linear complex (PLC) represents a 3D polyhedral domain with   //
+// possibly internal boundaries(subdomains). It is introduced in [Miller et  //
+// al, 1996]. Basically it is a set of "cells", i.e., vertices, edges, poly- //
+// gons, and polyhedra, and the intersection of any two of its cells is the  //
+// union of other cells of it.                                               //
+//                                                                           //
+// TetGen uses a set of files to describe the inputs and outputs. Each file  //
+// is identified from its file extension (.node, .ele, .face, .edge, etc).   //
+//                                                                           //
+// The 'tetgenio' structure is a collection of arrays of data, i.e., points, //
+// facets, tetrahedra, and so forth. It contains functions to read and write //
+// (input and output) files of TetGen as well as other supported mesh files. //
+//                                                                           //
+// Once an object of tetgenio is declared,  no array is created. One has to  //
+// allocate enough memory for them. On deletion of this object, the memory   //
+// occupied by these arrays needs to be freed.  The routine deinitialize()   //
+// will be automatically called.  It frees the memory for an array if it is  //
+// not a NULL. Note that it assumes that the memory is allocated by the C++  //
+// "new" operator.  Otherwise, the user is responsible to free them and all  //
+// pointers must be NULL before the call of the destructor.                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+class tetgenio {
+
+public:
+
+  // A "polygon" describes a simple polygon (no holes). It is not necessarily
+  //   convex. Each polygon contains a number of corners (points) and the same
+  //   number of sides (edges).  The points of the polygon must be given in
+  //   either counterclockwise or clockwise order and they form a ring, so 
+  //   every two consecutive points forms an edge of the polygon.
+  struct polygon {
+    int *vertexlist;
+    int numberofvertices;
+
+    polygon();
+   ~polygon();
+  };
+
+  // A "facet" describes a polygonal region possibly with holes, edges, and 
+  //   points floating in it.  Each facet consists of a list of polygons and
+  //   a list of hole points (which lie strictly inside holes).
+  struct facet{
+    polygon *polygonlist;
+    int numberofpolygons;
+    REAL *holelist;
+    int numberofholes;
+
+    facet();
+    ~facet();
+  };
+
+  // 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;
+
+
+  // Additional parameters associated with an input (or mesh) vertex.
+  //   These informations are provided by CAD libraries. 
+  typedef struct {
+    REAL uv[2];
+    int tag;
+    int type; // 0, 1, or 2.
+  } pointparam;
+
+  // Callback functions for meshing PSCs.
+  typedef REAL (* GetVertexParamOnEdge)(void*, int, int);
+  typedef void (* GetSteinerOnEdge)(void*, int, REAL, REAL*);
+  typedef void (* GetVertexParamOnFace)(void*, int, int, REAL*);
+  typedef void (* GetEdgeSteinerParamOnFace)(void*, int, REAL, int, REAL*);
+  typedef void (* GetSteinerOnFace)(void*, int, REAL*, REAL*);
+
+  // A callback function for mesh refinement.
+  typedef bool (* TetSizeFunc)(REAL*, REAL*, REAL*, REAL*, REAL*, REAL);
+
+  // 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 1.
+  int useindex;
+
+  // 'pointlist':  An array of point coordinates.  The first point's x
+  //   coordinate is at index [0] and its y coordinate at index [1], its
+  //   z coordinate is at index [2], followed by the coordinates of the
+  //   remaining points.  Each point occupies three REALs. 
+  // 'pointattributelist':  An array of point attributes.  Each point's
+  //   attributes occupy 'numberofpointattributes' REALs.
+  // 'pointmtrlist': An array of metric tensors at points. Each point's
+  //   tensor occupies 'numberofpointmtr' REALs.
+  // 'pointmarkerlist':  An array of point markers; one integer per point.
+  REAL *pointlist;
+  REAL *pointattributelist;
+  REAL *pointmtrlist;
+  int  *pointmarkerlist;
+  pointparam *pointparamlist;
+  int numberofpoints;
+  int numberofpointattributes;
+  int numberofpointmtrs;
+ 
+  // 'tetrahedronlist':  An array of tetrahedron corners.  The first 
+  //   tetrahedron's first corner is at index [0], followed by its other 
+  //   corners, followed by six nodes on the edges of the tetrahedron if the
+  //   second order option (-o2) is applied. Each tetrahedron occupies
+  //   'numberofcorners' ints.  The second order nodes are ouput only. 
+  // 'tetrahedronattributelist':  An array of tetrahedron attributes.  Each
+  //   tetrahedron's attributes occupy 'numberoftetrahedronattributes' REALs.
+  // 'tetrahedronvolumelist':  An array of constraints, i.e. tetrahedron's
+  //   volume; one REAL per element.  Input only.
+  // 'neighborlist':  An array of tetrahedron neighbors; 4 ints per element. 
+  //   Output only.
+  int  *tetrahedronlist;
+  REAL *tetrahedronattributelist;
+  REAL *tetrahedronvolumelist;
+  int  *neighborlist;
+  int numberoftetrahedra;
+  int numberofcorners;
+  int numberoftetrahedronattributes;
+
+  // 'facetlist':  An 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':  An array of holes (in volume).  Each hole is given by a
+  //   seed (point) which lies strictly inside it. The first seed's x, y and z
+  //   coordinates are at indices [0], [1] and [2], followed by the
+  //   remaining seeds.  Three REALs per hole. 
+  REAL *holelist;
+  int numberofholes;
+
+  // 'regionlist': An array of regions (subdomains).  Each region is given by
+  //   a seed (point) which lies strictly inside it. The first seed's x, y and
+  //   z coordinates are at indices [0], [1] and [2], followed by the regional
+  //   attribute at index [3], followed by the maximum volume at index [4]. 
+  //   Five REALs per region.
+  // 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':  An array of facet constraints.  Each constraint
+  //   specifies a maximum area bound on the subfaces of that facet.  The
+  //   first facet constraint is given by a facet marker at index [0] and its
+  //   maximum area bound at index [1], followed by the remaining facet con-
+  //   straints. Two REALs per facet constraint.  Note: the facet marker is
+  //   actually an integer.
+  REAL *facetconstraintlist;
+  int numberoffacetconstraints;
+
+  // 'segmentconstraintlist': An array of segment constraints. Each constraint 
+  //   specifies a maximum length bound on the subsegments of that segment.
+  //   The first constraint is given by the two endpoints of the segment at
+  //   index [0] and [1], and the maximum length bound at index [2], followed
+  //   by the remaining segment constraints.  Three REALs per constraint. 
+  //   Note the segment endpoints are actually integers.
+  REAL *segmentconstraintlist;
+  int numberofsegmentconstraints;
+
+
+  // 'trifacelist':  An array of face (triangle) corners.  The first face's
+  //   three corners are at indices [0], [1] and [2], followed by the remaining
+  //   faces.  Three ints per face.
+  // 'trifacemarkerlist':  An array of face markers; one int per face.
+  // 'o2facelist':  An array of second order nodes (on the edges) of the face.
+  //   It is output only if the second order option (-o2) is applied. The
+  //   first face's three second order nodes are at [0], [1], and [2],
+  //   followed by the remaining faces.  Three ints per face.
+  // 'adjtetlist':  An array of adjacent tetrahedra to the faces. The first
+  //   face's two adjacent tetrahedra are at indices [0] and [1], followed by
+  //   the remaining faces.  A '-1' indicates outside (no adj. tet). This list
+  //   is output when '-nn' switch is used. Output only.
+  int *trifacelist;
+  int *trifacemarkerlist;
+  int *o2facelist;
+  int *adjtetlist;
+  int numberoftrifaces;
+
+  // 'edgelist':  An array of edge endpoints.  The first edge's endpoints
+  //   are at indices [0] and [1], followed by the remaining edges.
+  //   Two ints per edge.
+  // 'edgemarkerlist':  An array of edge markers; one int per edge.
+  // 'o2edgelist':  An array of midpoints of edges. It is output only if the
+  //   second order option (-o2) is applied. One int per edge.
+  // 'edgeadjtetlist':  An array of adjacent tetrahedra to the edges.  One
+  //   tetrahedron (an integer) per edge.
+  int *edgelist;
+  int *edgemarkerlist;
+  int *o2edgelist;
+  int *edgeadjtetlist;
+  int numberofedges;
+
+  // 'vpointlist':  An array of Voronoi vertex coordinates (like pointlist).
+  // 'vedgelist':  An array of Voronoi edges.  Each entry is a 'voroedge'.
+  // 'vfacetlist':  An array of Voronoi facets. Each entry is a 'vorofacet'.
+  // 'vcelllist':  An array of Voronoi cells.  Each entry is an array of
+  //   indices pointing into 'vfacetlist'. The 0th entry is used to store
+  //   the length of this array.
+  REAL *vpointlist;
+  voroedge *vedgelist;
+  vorofacet *vfacetlist;
+  int **vcelllist;
+  int numberofvpoints;
+  int numberofvedges;
+  int numberofvfacets;
+  int numberofvcells;
+
+  // Variable (and callback functions) for meshing PSCs.
+  void *geomhandle;
+  GetVertexParamOnEdge getvertexparamonedge;
+  GetSteinerOnEdge getsteineronedge;
+  GetVertexParamOnFace getvertexparamonface;
+  GetEdgeSteinerParamOnFace getedgesteinerparamonface;
+  GetSteinerOnFace getsteineronface;
+
+  // A callback function.
+  TetSizeFunc tetunsuitable;
+
+  // Input & output routines.
+  bool load_node_call(FILE* infile, int markers, int uvflag, char*);
+  bool load_node(char*);
+  bool load_edge(char*);
+  bool load_face(char*);
+  bool load_tet(char*);
+  bool load_vol(char*);
+  bool load_var(char*);
+  bool load_mtr(char*);
+  bool load_pbc(char*);
+  bool load_poly(char*);
+  bool load_off(char*);
+  bool load_ply(char*);
+  bool load_stl(char*);
+  bool load_vtk(char*);
+  bool load_medit(char*, int);
+  bool load_plc(char*, int);
+  bool load_tetmesh(char*, int);
+  void save_nodes(char*);
+  void save_elements(char*);
+  void save_faces(char*);
+  void save_edges(char*);
+  void save_neighbors(char*);
+  void save_poly(char*);
+  void save_faces2smesh(char*);
+
+  // Read line and parse string functions.
+  char *readline(char* string, FILE* infile, int *linenumber);
+  char *findnextfield(char* string);
+  char *readnumberline(char* string, FILE* infile, char* infilename);
+  char *findnextnumber(char* string);
+
+  static void init(polygon* p) {
+    p->vertexlist = (int *) NULL;
+    p->numberofvertices = 0;
+  }
+
+  static void init(facet* f) {
+    f->polygonlist = (polygon *) NULL;
+    f->numberofpolygons = 0;
+    f->holelist = (REAL *) NULL;
+    f->numberofholes = 0;
+  }
+
+  // Initialize routine.
+  void initialize()
+  {
+    firstnumber = 0;
+    mesh_dim = 3;
+    useindex = 1;
+
+    pointlist = (REAL *) NULL;
+    pointattributelist = (REAL *) NULL;
+    pointmtrlist = (REAL *) NULL;
+    pointmarkerlist = (int *) NULL;
+    pointparamlist = (pointparam *) NULL;
+    numberofpoints = 0;
+    numberofpointattributes = 0;
+    numberofpointmtrs = 0;
+
+    tetrahedronlist = (int *) NULL;
+    tetrahedronattributelist = (REAL *) NULL;
+    tetrahedronvolumelist = (REAL *) NULL;
+    neighborlist = (int *) NULL;
+    numberoftetrahedra = 0;
+    numberofcorners = 4; 
+    numberoftetrahedronattributes = 0;
+
+    trifacelist = (int *) NULL;
+    trifacemarkerlist = (int *) NULL;
+    o2facelist = (int *) NULL;
+    adjtetlist = (int *) NULL;
+    numberoftrifaces = 0; 
+
+    edgelist = (int *) NULL;
+    edgemarkerlist = (int *) NULL;
+    o2edgelist = (int *) NULL;
+    edgeadjtetlist = (int *) NULL;
+    numberofedges = 0;
+
+    facetlist = (facet *) NULL;
+    facetmarkerlist = (int *) NULL;
+    numberoffacets = 0; 
+
+    holelist = (REAL *) NULL;
+    numberofholes = 0;
+
+    regionlist = (REAL *) NULL;
+    numberofregions = 0;
+
+    facetconstraintlist = (REAL *) NULL;
+    numberoffacetconstraints = 0;
+    segmentconstraintlist = (REAL *) NULL;
+    numberofsegmentconstraints = 0;
+
+
+    vpointlist = (REAL *) NULL;
+    vedgelist = (voroedge *) NULL;
+    vfacetlist = (vorofacet *) NULL; 
+    vcelllist = (int **) NULL; 
+    numberofvpoints = 0;
+    numberofvedges = 0;
+    numberofvfacets = 0;
+    numberofvcells = 0;
+
+    tetunsuitable = NULL;
+
+    geomhandle = NULL;
+    getvertexparamonedge = NULL;
+    getsteineronedge = NULL;
+    getvertexparamonface = NULL;
+    getedgesteinerparamonface = NULL;
+    getsteineronface = NULL;
+  }
+
+  // Free the memory allocated in 'tetgenio'.  Note that it assumes that the 
+  //   memory was allocated by the "new" operator (C++).
+  void deinitialize()
+  {
+    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 (pointparamlist != (pointparam *) NULL) {
+      delete [] pointparamlist;
+    }
+
+    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 (trifacemarkerlist != (int *) NULL) {
+      delete [] trifacemarkerlist;
+    }
+    if (o2facelist != (int *) NULL) {
+      delete [] o2facelist;
+    }
+    if (adjtetlist != (int *) NULL) {
+      delete [] adjtetlist;
+    }
+
+    if (edgelist != (int *) NULL) {
+      delete [] edgelist;
+    }
+    if (edgemarkerlist != (int *) NULL) {
+      delete [] edgemarkerlist;
+    }
+    if (o2edgelist != (int *) NULL) {
+      delete [] o2edgelist;
+    }
+    if (edgeadjtetlist != (int *) NULL) {
+      delete [] edgeadjtetlist;
+    }
+
+    if (facetlist != (facet *) NULL) {
+      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 (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;
+    }
+  }
+
+  // Constructor & destructor.
+  tetgenio() {initialize();}
+  ~tetgenio() {deinitialize();}
+
+}; // class tetgenio
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetgenbehavior                                                            //
+//                                                                           //
+// A structure for maintaining the switches and parameters used by TetGen's  //
+// mesh data structure and algorithms.                                       //
+//                                                                           //
+// All switches and parameters are initialized with default values. They can //
+// be set by the command line arguments (a list of strings) of TetGen.       //
+//                                                                           //
+// NOTE: Some of the switches are incompatible. While some may depend on     //
+// other switches.  The routine parse_commandline() sets the switches from   //
+// the command line (a list of strings) and checks the consistency of the    //
+// applied switches.                                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+class tetgenbehavior {
+
+public:
+
+  // Switches of TetGen. 
+  int plc;                                                         // '-p', 0.
+  int psc;                                                         // '-s', 0.
+  int refine;                                                      // '-r', 0.
+  int quality;                                                     // '-q', 0.
+  int nobisect;                                                    // '-Y', 0.
+  int coarsen;                                                     // '-R', 0.
+  int weighted;                                                    // '-w', 0.
+  int brio_hilbert;                                                // '-b', 1.
+  int incrflip;                                                    // '-l', 0.
+  int flipinsert;                                                  // '-L', 0.
+  int metric;                                                      // '-m', 0.
+  int varvolume;                                                   // '-a', 0.
+  int fixedvolume;                                                 // '-a', 0.
+  int regionattrib;                                                // '-A', 0.
+  int conforming;                                                  // '-D', 0.
+  int insertaddpoints;                                             // '-i', 0.
+  int diagnose;                                                    // '-d', 0.
+  int convex;                                                      // '-c', 0.
+  int nomergefacet;                                                // '-M', 0.
+  int nomergevertex;                                               // '-M', 0.
+  int noexact;                                                     // '-X', 0.
+  int nostaticfilter;                                              // '-X', 0.
+  int zeroindex;                                                   // '-z', 0.
+  int facesout;                                                    // '-f', 0.
+  int edgesout;                                                    // '-e', 0.
+  int neighout;                                                    // '-n', 0.
+  int voroout;                                                     // '-v', 0.
+  int meditview;                                                   // '-g', 0.
+  int vtkview;                                                     // '-k', 0.
+  int nobound;                                                     // '-B', 0.
+  int nonodewritten;                                               // '-N', 0.
+  int noelewritten;                                                // '-E', 0.
+  int nofacewritten;                                               // '-F', 0.
+  int noiterationnum;                                              // '-I', 0.
+  int nojettison;                                                  // '-J', 0.
+  int reversetetori;                                               // '-R', 0.
+  int docheck;                                                     // '-C', 0.
+  int quiet;                                                       // '-Q', 0.
+  int verbose;                                                     // '-V', 0.
+
+  // Parameters of TetGen. 
+  int vertexperblock;                                           // '-x', 4092.
+  int tetrahedraperblock;                                       // '-x', 8188.
+  int shellfaceperblock;                                        // '-x', 2044.
+  int nobisect_param;                                              // '-Y', 2.
+  int addsteiner_algo;                                            // '-Y/', 1.
+  int coarsen_param;                                               // '-R', 0.
+  int weighted_param;                                              // '-w', 0.
+  int fliplinklevel;                                                    // -1.
+  int flipstarsize;                                                     // -1.
+  int fliplinklevelinc;                                                 //  1.
+  int reflevel;                                                    // '-D', 3.
+  int optlevel;                                                    // '-O', 2.
+  int optscheme;                                                   // '-O', 7.
+  int delmaxfliplevel;                                                   // 1.
+  int order;                                                       // '-o', 1.
+  int steinerleft;                                                 // '-S', 0.
+  int no_sort;                                                           // 0.
+  int hilbert_order;                                           // '-b///', 52.
+  int hilbert_limit;                                             // '-b//'  8.
+  int brio_threshold;                                              // '-b' 64.
+  REAL brio_ratio;                                             // '-b/' 0.125.
+  REAL facet_ang_tol;                                          // '-p', 179.9.
+  REAL maxvolume;                                               // '-a', -1.0.
+  REAL minratio;                                                 // '-q', 0.0.
+  REAL mindihedral;                                              // '-q', 5.0.
+  REAL optmaxdihedral;                                               // 165.0.
+  REAL optminsmtdihed;                                               // 179.0.
+  REAL optminslidihed;                                               // 179.0.  
+  REAL epsilon;                                               // '-T', 1.0e-8.
+  REAL minedgelength;                                                  // 0.0.
+  REAL coarsen_percent;                                         // -R1/#, 1.0.
+
+  // Strings of command line arguments and input/output file names.
+  char commandline[1024];
+  char infilename[1024];
+  char outfilename[1024];
+  char addinfilename[1024];
+  char bgmeshfilename[1024];
+
+  // The input object of TetGen. They are recognized by either the input 
+  //   file extensions or by the specified options. 
+  // Currently the following objects are supported:
+  //   - 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, only ASCII);
+  //   - 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 command line switch
+  //   (-p or -r) implies the object. 
+  enum objecttype {NODES, POLY, OFF, PLY, STL, MEDIT, VTK, MESH} object;
+
+
+  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);
+  }
+
+  // Initialize all variables.
+  tetgenbehavior()
+  {
+    plc = 0;
+    psc = 0;
+    refine = 0;
+    quality = 0;
+    nobisect = 0;
+    coarsen = 0;
+    metric = 0;
+    weighted = 0;
+    brio_hilbert = 1;
+    incrflip = 0;
+    flipinsert = 0;
+    varvolume = 0;
+    fixedvolume = 0;
+    noexact = 0;
+    nostaticfilter = 0;
+    insertaddpoints = 0;
+    regionattrib = 0;
+    conforming = 0;
+    diagnose = 0;
+    convex = 0;
+    zeroindex = 0;
+    facesout = 0;
+    edgesout = 0;
+    neighout = 0;
+    voroout = 0;
+    meditview = 0;
+    vtkview = 0;
+    nobound = 0;
+    nonodewritten = 0;
+    noelewritten = 0;
+    nofacewritten = 0;
+    noiterationnum = 0;
+    nomergefacet = 0;
+    nomergevertex = 0;
+    nojettison = 0;
+    reversetetori = 0;
+    docheck = 0;
+    quiet = 0;
+    verbose = 0;
+
+    vertexperblock = 4092;
+    tetrahedraperblock = 8188;
+    shellfaceperblock = 4092;
+    nobisect_param = 2;
+    addsteiner_algo = 1;
+    coarsen_param = 0;
+    weighted_param = 0;
+    fliplinklevel = -1; // No limit on linklevel.
+    flipstarsize = -1;  // No limit on flip star size.
+    fliplinklevelinc = 1;
+    reflevel = 3;
+    optscheme = 7;  // 1 & 2 & 4, // min_max_dihedral.
+    optlevel = 2;
+    delmaxfliplevel = 1;
+    order = 1;
+    steinerleft = -1;
+    no_sort = 0;
+    hilbert_order = 52; //-1;
+    hilbert_limit = 8;
+    brio_threshold = 64;
+    brio_ratio = 0.125;
+    facet_ang_tol = 179.9;
+    maxvolume = -1.0;
+    minratio = 2.0;
+    mindihedral = 0.0; // 5.0; 
+    optmaxdihedral = 165.00; // without -q, default is 179.0
+    optminsmtdihed = 179.00; // without -q, default is 179.999
+    optminslidihed = 179.00; // without -q, default is 179.999
+    epsilon = 1.0e-8;
+    minedgelength = 0.0;
+    coarsen_percent = 1.0;
+    object = NODES;
+
+    commandline[0] = '\0';
+    infilename[0] = '\0';
+    outfilename[0] = '\0';
+    addinfilename[0] = '\0';
+    bgmeshfilename[0] = '\0';
+
+  }
+
+}; // class tetgenbehavior
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Robust Geometric predicates                                               //
+//                                                                           //
+// Geometric predicates are simple tests of spatial relations of a set of d- //
+// dimensional points, such as the orientation test and the point-in-sphere  //
+// test. Each of these tests is performed by evaluating the sign of a deter- //
+// minant of a matrix whose entries are the coordinates of these points.  If //
+// the computation is performed by using the floating-point numbers, e.g.,   //
+// the single or double precision numbers in C/C++, roundoff error may cause //
+// an incorrect result. This may either lead to a wrong result or eventually //
+// lead to a failure of the program.  Computing the predicates exactly will  //
+// avoid the error and make the program robust.                              //
+//                                                                           //
+// The following routines are the robust geometric predicates for 3D orient- //
+// ation test and point-in-sphere test.  They were implemented by Shewchuk.  //
+// The source code are generously provided by him in the public domain,      //
+// http://www.cs.cmu.edu/~quake/robust.html. predicates.cxx is a C++ version //
+// of the original C code.                                                   //
+//                                                                           //
+// The original predicates of Shewchuk only use "dynamic filters", i.e., it  //
+// computes the error at run time step by step. TetGen first adds a "static  //
+// filter" in each predicate. It estimates the maximal possible error in all //
+// cases.  So it can safely and quickly answer many easy cases.              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void exactinit(int, int, int, REAL, REAL, REAL);
+void exactdeinit();
+REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd);
+REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe);
+REAL orient4d(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe,
+              REAL ah, REAL bh, REAL ch, REAL dh, REAL eh);
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// tetgenmesh                                                                //
+//                                                                           //
+// A structure for creating and updating tetrahedral meshes.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+class tetgenmesh {
+
+public:
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh data structure                                                       //
+//                                                                           //
+// A tetrahedral mesh T of a 3D piecewise linear complex (PLC) X is a 3D     //
+// simplicial complex whose underlying space is equal to the space of X.  T  //
+// contains a 2D subcomplex S which is a triangular mesh of the boundary of  //
+// X. S contains a 1D subcomplex L which is a linear mesh of the boundary of //
+// S. Faces and edges in S and L are respectively called subfaces and segme- //
+// nts to distinguish them from others in T.                                 //
+//                                                                           //
+// TetGen stores the tetrahedra and vertices of T. The basic structure of a  //
+// tetrahedron contains pointers to its vertices and adjacent tetrahedra. A  //
+// vertex stores its x-, y-, and z-coordinates, and a pointer to a tetrahed- //
+// ron containing it. Both tetrahedra and vertices may contain user data.    // 
+//                                                                           //
+// Each face of T belongs to either two tetrahedra or one tetrahedron. In    //
+// the latter case, the face is an exterior boundary face of T.  TetGen adds //
+// fictitious tetrahedra (one-to-one) at such faces, and connects them to an //
+// "infinite vertex" (which has no geometric coordinates).  One can imagine  //
+// such a vertex lies in 4D space and is visible by all exterior boundary    //
+// faces.  The extended set of tetrahedra (including the infinite vertex) is //
+// a tetrahedralization of a 3-pseudomanifold without boundary.  It has the  //
+// property that every face is shared by exactly two tetrahedra.             // 
+//                                                                           //
+// The current version of TetGen stores explicitly the subfaces and segments //
+// (which are in surface mesh S and the linear mesh L), respectively.  Extra //
+// pointers are allocated in tetrahedra and subfaces to point each others.   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  // The tetrahedron data structure.  It includes the following fields:
+  //   - a list of four adjoining tetrahedra;
+  //   - a list of four vertices;
+  //   - a pointer to a list of four subfaces (optional, for -p switch);
+  //   - a pointer to a list of six segments  (optional, for -p switch);
+  //   - a list of user-defined floating-point attributes (optional);
+  //   - a volume constraint (optional, for -a switch);
+  //   - an integer of element marker (and flags);
+  // The structure of a tetrahedron is an array of pointers.  Its actual size
+  //   (the length of the array) is determined at runtime.
+
+  typedef REAL **tetrahedron;
+
+  // The subface data structure.  It includes the following fields:
+  //   - a list of three adjoining subfaces;
+  //   - a list of three vertices;
+  //   - a list of three adjoining segments;
+  //   - two adjoining tetrahedra;
+  //   - an area constraint (optional, for -q switch);
+  //   - an integer for boundary marker;
+  //   - an integer for type, flags, etc.
+
+  typedef REAL **shellface;
+
+  // The point data structure.  It includes the following fields:
+  //   - x, y and z coordinates;
+  //   - a list of user-defined point attributes (optional);
+  //   - u, v coordinates (optional, for -s switch);
+  //   - a metric tensor (optional, for -q or -m switch);
+  //   - a pointer to an adjacent tetrahedron;
+  //   - a pointer to a parent (or a duplicate) point;
+  //   - a pointer to an adjacent subface or segment (optional, -p switch);
+  //   - a pointer to a tet in background mesh (optional, for -m switch);
+  //   - an integer for boundary marker (point index);
+  //   - an integer for point type (and flags).
+  //   - an integer for geometry tag (optional, for -s switch).
+  // The structure of a point is an array of REALs.  Its acutal size is 
+  //   determined at the runtime.
+
+  typedef REAL *point;
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Handles                                                                   //
+//                                                                           //
+// Navigation and manipulation in a tetrahedralization are accomplished by   //
+// operating on structures referred as ``handles". A handle is a pair (t,v), //
+// where t is a pointer to a tetrahedron, and v is a 4-bit integer, in the   //
+// range from 0 to 11. v is called the ``version'' of a tetrahedron, it rep- //
+// resents a directed edge of a specific face of the tetrahedron.            //
+//                                                                           //
+// There are 12 even permutations of the four vertices, each of them corres- //
+// ponds to a directed edge (a version) of the tetrahedron.  The 12 versions //
+// can be grouped into 4 distinct ``edge rings'' in 4 ``oriented faces'' of  //
+// this tetrahedron.  One can encode each version (a directed edge) into a   //
+// 4-bit integer such that the two upper bits encode the index (from 0 to 2) //
+// of this edge in the edge ring, and the two lower bits encode the index (  //
+// from 0 to 3) of the oriented face which contains this edge.               //  
+//                                                                           //
+// The four vertices of a tetrahedron are indexed from 0 to 3 (according to  //
+// their storage in the data structure).  Give each face the same index as   //
+// the node opposite it in the tetrahedron.  Denote the edge connecting face //
+// i to face j as i/j. We number the twelve versions as follows:             //
+//                                                                           //
+//           |   edge 0     edge 1     edge 2                                //
+//   --------|--------------------------------                               //
+//    face 0 |   0 (0/1)    4 (0/3)    8 (0/2)                               //
+//    face 1 |   1 (1/2)    5 (1/3)    9 (1/0)                               //
+//    face 2 |   2 (2/3)    6 (2/1)   10 (2/0)                               //
+//    face 3 |   3 (3/0)    7 (3/1)   11 (3/2)                               //
+//                                                                           //
+// Similarly, navigation and manipulation in a (boundary) triangulation are  //
+// done by using handles of triangles. Each handle is a pair (s, v), where s //
+// is a pointer to a triangle, and v is a version in the range from 0 to 5.  //
+// Each version corresponds to a directed edge of this triangle.             //
+//                                                                           //
+// Number the three vertices of a triangle from 0 to 2 (according to their   //
+// storage in the data structure). Give each edge the same index as the node //
+// opposite it in the triangle. The six versions of a triangle are:          //
+//                                                                           //
+//                 | edge 0   edge 1   edge 2                                //
+//  ---------------|--------------------------                               //
+//   ccw orieation |   0        2        4                                   //
+//    cw orieation |   1        3        5                                   //
+//                                                                           //
+// In the following, a 'triface' is a handle of tetrahedron, and a 'face' is //
+// a handle of a triangle.                                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  class triface {
+  public:
+    tetrahedron *tet;
+    int ver; // Range from 0 to 11.
+    triface() : tet(0), ver(0) {}
+    triface& operator=(const triface& t) {
+      tet = t.tet; ver = t.ver;
+      return *this;
+    }
+  };
+
+  class face {
+  public:
+    shellface *sh;
+    int shver; // Range from 0 to 5.
+    face() : sh(0), shver(0) {}
+    face& operator=(const face& s) {
+      sh = s.sh; shver = s.shver;
+      return *this;
+    }
+  };
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Arraypool                                                                 //
+//                                                                           //
+// A dynamic linear array. (It is written by J. Shewchuk)                    //
+//                                                                           //
+// 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 //
+// addresses 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 total memory in bytes.         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  class arraypool {
+
+  public:
+
+    int objectbytes;
+    int objectsperblock;
+    int log2objectsperblock;
+    int objectsperblockmark;
+    int toparraylen;
+    char **toparray;
+    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();
+  };
+
+// 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)->objectsperblockmark) * (pool)->objectbytes)
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Memorypool                                                                //
+//                                                                           //
+// A structure for memory allocation. (It is 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.                                              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  class memorypool {
+
+  public:
+
+    void **firstblock, **nowblock;
+    void *nextitem;
+    void *deaditemstack;
+    void **pathblock;
+    void *pathitem;
+    int  alignbytes;
+    int  itembytes, itemwords;
+    int  itemsperblock;
+    long items, maxitems;
+    int  unallocateditems;
+    int  pathitemsleft;
+
+    memorypool();
+    memorypool(int, int, int, int);
+    ~memorypool();
+    
+    void poolinit(int, int, int, int);
+    void restart();
+    void *alloc();
+    void dealloc(void*);
+    void traversalinit();
+    void *traverse();
+  };  
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// badface                                                                   //
+//                                                                           //
+// Despite of its name, a 'badface' can be used to represent one of 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 recently flipped face (saved for undoing the flip later).           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  class badface {
+  public:
+    triface tt; 
+    face ss;
+    REAL key, cent[6];  // circumcenter or cos(dihedral angles) at 6 edges.
+    point forg, fdest, fapex, foppo, noppo;
+    badface *nextitem; 
+    badface() : key(0), forg(0), fdest(0), fapex(0), foppo(0), noppo(0),
+      nextitem(0) {}
+  };
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertvertexflags                                                         //
+//                                                                           //
+// A collection of flags that pass to the routine insertvertex().            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  class insertvertexflags {
+
+  public:
+
+    int iloc;  // input/output.
+    int bowywat, lawson;
+    int splitbdflag, validflag, respectbdflag;
+    int rejflag, chkencflag, cdtflag;
+    int assignmeshsize;
+    int sloc, sbowywat;
+
+    // Used by Delaunay refinement.
+    int refineflag; // 0, 1, 2, 3
+    triface refinetet;
+    face refinesh;
+    int smlenflag; // for useinsertradius.
+    REAL smlen; // for useinsertradius.
+    point parentpt;
+
+    insertvertexflags() {
+      iloc = bowywat = lawson = 0;
+      splitbdflag = validflag = respectbdflag = 0;
+      rejflag = chkencflag = cdtflag = 0;
+      assignmeshsize = 0;
+      sloc = sbowywat = 0;
+
+      refineflag = 0;
+      refinetet.tet = NULL;
+      refinesh.sh = NULL;
+      smlenflag = 0;
+      smlen = 0.0;
+    }
+  };
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flipconstraints                                                           //
+//                                                                           //
+// A structure of a collection of data (options and parameters) which pass   //
+// to the edge flip function flipnm().                                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  class flipconstraints {
+
+  public:
+
+    // Elementary flip flags.
+    int enqflag; // (= flipflag)
+    int chkencflag;
+
+    // Control flags
+    int unflip;  // Undo the performed flips.
+    int collectnewtets; // Collect the new tets created by flips.
+    int collectencsegflag;
+
+    // Optimization flags.
+    int remove_ndelaunay_edge; // Remove a non-Delaunay edge.
+    REAL bak_tetprism_vol; // The value to be minimized.
+    REAL tetprism_vol_sum;
+    int remove_large_angle; // Remove a large dihedral angle at edge.
+    REAL cosdihed_in; // The input cosine of the dihedral angle (> 0).
+    REAL cosdihed_out; // The improved cosine of the dihedral angle.
+
+    // Boundary recovery flags.
+    int checkflipeligibility;
+    point seg[2];  // A constraining edge to be recovered.
+    point fac[3];  // A constraining face to be recovered.
+    point remvert; // A vertex to be removed.
+
+
+    flipconstraints() {
+      enqflag = 0; 
+      chkencflag = 0;
+
+      unflip = 0;
+      collectnewtets = 0;
+      collectencsegflag = 0;
+
+      remove_ndelaunay_edge = 0;
+      bak_tetprism_vol = 0.0;
+      tetprism_vol_sum = 0.0;
+      remove_large_angle = 0;
+      cosdihed_in = 0.0;
+      cosdihed_out = 0.0;
+
+      checkflipeligibility = 0;
+      seg[0] = NULL;
+      fac[0] = NULL;
+      remvert = NULL;
+    }
+  };
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// optparameters                                                             //
+//                                                                           //
+// Optimization options and parameters.                                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  class optparameters {
+
+  public:
+
+    // The one of goals of optimization.
+    int max_min_volume;      // Maximize the minimum volume.
+    int max_min_aspectratio; // Maximize the minimum aspect ratio.
+    int min_max_dihedangle;  // Minimize the maximum dihedral angle. 
+
+    // The initial and improved value.
+    REAL initval, imprval;
+
+    int numofsearchdirs;
+    REAL searchstep;
+    int maxiter;  // Maximum smoothing iterations (disabled by -1).
+    int smthiter; // Performed iterations.
+
+
+    optparameters() {
+      max_min_volume = 0;
+      max_min_aspectratio = 0;
+      min_max_dihedangle = 0;
+
+      initval = imprval = 0.0;
+
+      numofsearchdirs = 10;
+      searchstep = 0.01;
+      maxiter = -1;   // Unlimited smoothing iterations.
+      smthiter = 0;
+
+    }
+  };
+
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Labels (enumeration declarations) used by TetGen.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  // Labels that signify the type of a vertex. 
+  enum verttype {UNUSEDVERTEX, DUPLICATEDVERTEX, RIDGEVERTEX, ACUTEVERTEX,
+                 FACETVERTEX, VOLVERTEX, FREESEGVERTEX, FREEFACETVERTEX, 
+                 FREEVOLVERTEX, NREGULARVERTEX, DEADVERTEX};
+ 
+  // Labels that signify the result of triangle-triangle intersection test.
+  enum interresult {DISJOINT, INTERSECT, SHAREVERT, SHAREEDGE, SHAREFACE,
+                    TOUCHEDGE, TOUCHFACE, ACROSSVERT, ACROSSEDGE, ACROSSFACE, 
+                    COLLISIONFACE, ACROSSSEG, ACROSSSUB};
+
+  // Labels that signify the result of point location.
+  enum locateresult {UNKNOWN, OUTSIDE, INTETRAHEDRON, ONFACE, ONEDGE, ONVERTEX,
+                     ENCVERTEX, ENCSEGMENT, ENCSUBFACE, NEARVERTEX, NONREGULAR,
+                     INSTAR, BADELEMENT};
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Variables of TetGen                                                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  // Pointer to the input data (a set of nodes, a PLC, or a mesh).
+  tetgenio *in, *addin;
+
+  // Pointer to the switches and parameters.
+  tetgenbehavior *b;
+
+  // Pointer to a background mesh (contains size specification map).
+  tetgenmesh *bgm;
+
+  // Memorypools to store mesh elements (points, tetrahedra, subfaces, and
+  //   segments) and extra pointers between tetrahedra, subfaces, and segments.
+  memorypool *tetrahedrons, *subfaces, *subsegs, *points;
+  memorypool *tet2subpool, *tet2segpool;
+
+  // Memorypools to store bad-quality (or encroached) elements.
+  memorypool *badtetrahedrons, *badsubfacs, *badsubsegs;
+
+  // A memorypool to store faces to be flipped.
+  memorypool *flippool;
+  arraypool *unflipqueue;
+  badface *flipstack; 
+
+  // Arrays used for point insertion (the Bowyer-Watson algorithm).
+  arraypool *cavetetlist, *cavebdrylist, *caveoldtetlist;
+  arraypool *cavetetshlist, *cavetetseglist, *cavetetvertlist;
+  arraypool *caveencshlist, *caveencseglist;
+  arraypool *caveshlist, *caveshbdlist, *cavesegshlist;
+
+  // Stacks used for CDT construction and boundary recovery.
+  arraypool *subsegstack, *subfacstack, *subvertstack;
+
+  // Arrays of encroached segments and subfaces (for mesh refinement).
+  arraypool *encseglist, *encshlist;
+
+  // The map between facets to their vertices (for mesh refinement).
+  int *idx2facetlist;
+  point *facetverticeslist;
+
+  // The map between segments to their endpoints (for mesh refinement).
+  point *segmentendpointslist;
+
+  // The infinite vertex.
+  point dummypoint;
+  // The recently visited tetrahedron, subface.
+  triface recenttet;
+  face recentsh;
+
+  // PI is the ratio of a circle's circumference to its diameter.
+  static REAL PI;
+
+  // Array (size = numberoftetrahedra * 6) for storing high-order nodes of
+  //   tetrahedra (only used when -o2 switch is selected).
+  point *highordertable;
+
+  // Various variables.
+  int numpointattrib;                          // Number of point attributes.
+  int numelemattrib;                     // Number of tetrahedron attributes.
+  int sizeoftensor;                     // Number of REALs per metric tensor.
+  int pointmtrindex;           // Index to find the metric tensor of a point.
+  int pointparamindex;       // Index to find the u,v coordinates of a point.
+  int point2simindex;         // Index to find a simplex adjacent to a point.
+  int pointmarkindex;            // Index to find boundary marker of a point.
+  int elemattribindex;          // Index to find attributes of a tetrahedron.
+  int volumeboundindex;       // Index to find volume bound of a tetrahedron.
+  int elemmarkerindex;              // Index to find marker of a tetrahedron.
+  int shmarkindex;             // Index to find boundary marker of a subface.
+  int areaboundindex;               // Index to find area bound of a subface.
+  int checksubsegflag;   // Are there segments in the tetrahedralization yet?
+  int checksubfaceflag;  // Are there subfaces in the tetrahedralization yet?
+  int checkconstraints;  // Are there variant (node, seg, facet) constraints?
+  int nonconvex;                               // Is current mesh non-convex?
+  int autofliplinklevel;        // The increase of link levels, default is 1.
+  int useinsertradius;       // Save the insertion radius for Steiner points.
+  long samples;               // Number of random samples for point location.
+  unsigned long randomseed;                    // Current random number seed.
+  REAL cosmaxdihed, cosmindihed;    // The cosine values of max/min dihedral.
+  REAL cossmtdihed;     // The cosine value of a bad dihedral to be smoothed.
+  REAL cosslidihed;      // The cosine value of the max dihedral of a sliver.
+  REAL minfaceang, minfacetdihed;     // The minimum input (dihedral) angles.
+  REAL tetprism_vol_sum;   // The total volume of tetrahedral-prisms (in 4D).
+  REAL longest;                          // The longest possible edge length.
+  REAL xmax, xmin, ymax, ymin, zmax, zmin;         // Bounding box of points.
+
+  // Counters.
+  long insegments;                               // Number of input segments.
+  long hullsize;                        // Number of exterior boundary faces.
+  long meshedges;                                    // Number of mesh edges.
+  long meshhulledges;                       // Number of boundary mesh edges.
+  long steinerleft;                 // Number of Steiner points not yet used.
+  long dupverts;                            // Are there duplicated vertices?
+  long unuverts;                                // Are there unused vertices?
+  long nonregularcount;                    // Are there non-regular vertices?
+  long st_segref_count, st_facref_count, st_volref_count;  // Steiner points.
+  long fillregioncount, cavitycount, cavityexpcount;
+  long flip14count, flip26count, flipn2ncount;
+  long flip23count, flip32count, flip44count, flip41count;
+  long flip31count, flip22count;
+  unsigned long totalworkmemory;      // Total memory used by working arrays.
+
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh manipulation primitives                                              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  // Fast lookup tables for mesh manipulation primitives.
+  static int bondtbl[12][12], fsymtbl[12][12];
+  static int esymtbl[12], enexttbl[12], eprevtbl[12];
+  static int enextesymtbl[12], eprevesymtbl[12]; 
+  static int eorgoppotbl[12], edestoppotbl[12];
+  static int facepivot1[12], facepivot2[12][12];
+  static int orgpivot[12], destpivot[12], apexpivot[12], oppopivot[12];
+  static int tsbondtbl[12][6], stbondtbl[12][6];
+  static int tspivottbl[12][6], stpivottbl[12][6];
+  static int ver2edge[12], edge2ver[6], epivot[12];
+  static int sorgpivot [6], sdestpivot[6], sapexpivot[6];
+  static int snextpivot[6];
+
+  void inittables();
+
+  // Primitives for tetrahedra.
+  inline tetrahedron encode(triface& t);
+  inline tetrahedron encode2(tetrahedron* ptr, int ver);
+  inline void decode(tetrahedron ptr, triface& t);
+  inline void bond(triface& t1, triface& t2);
+  inline void dissolve(triface& t);
+  inline void esym(triface& t1, triface& t2);
+  inline void esymself(triface& t);
+  inline void enext(triface& t1, triface& t2);
+  inline void enextself(triface& t);
+  inline void eprev(triface& t1, triface& t2);
+  inline void eprevself(triface& t);
+  inline void enextesym(triface& t1, triface& t2);
+  inline void enextesymself(triface& t);
+  inline void eprevesym(triface& t1, triface& t2);
+  inline void eprevesymself(triface& t);
+  inline void eorgoppo(triface& t1, triface& t2);
+  inline void eorgoppoself(triface& t);
+  inline void edestoppo(triface& t1, triface& t2);
+  inline void edestoppoself(triface& t);
+  inline void fsym(triface& t1, triface& t2);
+  inline void fsymself(triface& t);
+  inline void fnext(triface& t1, triface& t2);
+  inline void fnextself(triface& t);
+  inline point org (triface& t);
+  inline point dest(triface& t);
+  inline point apex(triface& t);
+  inline point oppo(triface& t);
+  inline void setorg (triface& t, point p);
+  inline void setdest(triface& t, point p);
+  inline void setapex(triface& t, point p);
+  inline void setoppo(triface& t, point p);
+  inline REAL elemattribute(tetrahedron* ptr, int attnum);
+  inline void setelemattribute(tetrahedron* ptr, int attnum, REAL value);
+  inline REAL volumebound(tetrahedron* ptr);
+  inline void setvolumebound(tetrahedron* ptr, REAL value);
+  inline int  elemindex(tetrahedron* ptr);
+  inline void setelemindex(tetrahedron* ptr, int value);
+  inline int  elemmarker(tetrahedron* ptr);
+  inline void setelemmarker(tetrahedron* ptr, int value);
+  inline void infect(triface& t);
+  inline void uninfect(triface& t);
+  inline bool infected(triface& t);
+  inline void marktest(triface& t);
+  inline void unmarktest(triface& t);
+  inline bool marktested(triface& t);
+  inline void markface(triface& t);
+  inline void unmarkface(triface& t);
+  inline bool facemarked(triface& t);
+  inline void markedge(triface& t);
+  inline void unmarkedge(triface& t);
+  inline bool edgemarked(triface& t);
+  inline void marktest2(triface& t);
+  inline void unmarktest2(triface& t);
+  inline bool marktest2ed(triface& t);
+  inline int  elemcounter(triface& t);
+  inline void setelemcounter(triface& t, int value);
+  inline void increaseelemcounter(triface& t);
+  inline void decreaseelemcounter(triface& t);
+  inline bool ishulltet(triface& t);
+  inline bool isdeadtet(triface& t);
+ 
+  // Primitives for subfaces and subsegments.
+  inline void sdecode(shellface sptr, face& s);
+  inline shellface sencode(face& s);
+  inline shellface sencode2(shellface *sh, int shver);
+  inline void spivot(face& s1, face& s2);
+  inline void spivotself(face& s);
+  inline void sbond(face& s1, face& s2);
+  inline void sbond1(face& s1, face& s2);
+  inline void sdissolve(face& s);
+  inline point sorg(face& s);
+  inline point sdest(face& s);
+  inline point sapex(face& s);
+  inline void setsorg(face& s, point pointptr);
+  inline void setsdest(face& s, point pointptr);
+  inline void setsapex(face& s, point pointptr);
+  inline void sesym(face& s1, face& s2);
+  inline void sesymself(face& s);
+  inline void senext(face& s1, face& s2);
+  inline void senextself(face& s);
+  inline void senext2(face& s1, face& s2);
+  inline void senext2self(face& s);
+  inline REAL areabound(face& s);
+  inline void setareabound(face& s, REAL value);
+  inline int shellmark(face& s);
+  inline void setshellmark(face& s, int value);
+  inline void sinfect(face& s);
+  inline void suninfect(face& s);
+  inline bool sinfected(face& s);
+  inline void smarktest(face& s);
+  inline void sunmarktest(face& s);
+  inline bool smarktested(face& s);
+  inline void smarktest2(face& s);
+  inline void sunmarktest2(face& s);
+  inline bool smarktest2ed(face& s);
+  inline void smarktest3(face& s);
+  inline void sunmarktest3(face& s);
+  inline bool smarktest3ed(face& s);
+  inline void setfacetindex(face& f, int value);
+  inline int  getfacetindex(face& f);
+
+  // Primitives for interacting tetrahedra and subfaces.
+  inline void tsbond(triface& t, face& s);
+  inline void tsdissolve(triface& t);
+  inline void stdissolve(face& s);
+  inline void tspivot(triface& t, face& s);
+  inline void stpivot(face& s, triface& t);
+
+  // Primitives for interacting tetrahedra and segments.
+  inline void tssbond1(triface& t, face& seg);
+  inline void sstbond1(face& s, triface& t);
+  inline void tssdissolve1(triface& t);
+  inline void sstdissolve1(face& s);
+  inline void tsspivot1(triface& t, face& s);
+  inline void sstpivot1(face& s, triface& t);
+
+  // Primitives for interacting subfaces and segments.
+  inline void ssbond(face& s, face& edge);
+  inline void ssbond1(face& s, face& edge);
+  inline void ssdissolve(face& s);
+  inline void sspivot(face& s, face& edge);
+
+  // Primitives for points.
+  inline int  pointmark(point pt);
+  inline void setpointmark(point pt, int value);
+  inline enum verttype pointtype(point pt);
+  inline void setpointtype(point pt, enum verttype value);
+  inline int  pointgeomtag(point pt);
+  inline void setpointgeomtag(point pt, int value);
+  inline REAL pointgeomuv(point pt, int i);
+  inline void setpointgeomuv(point pt, int i, REAL value);
+  inline void pinfect(point pt);
+  inline void puninfect(point pt);
+  inline bool pinfected(point pt);
+  inline void pmarktest(point pt);
+  inline void punmarktest(point pt);
+  inline bool pmarktested(point pt);
+  inline void pmarktest2(point pt);
+  inline void punmarktest2(point pt);
+  inline bool pmarktest2ed(point pt);
+  inline void pmarktest3(point pt);
+  inline void punmarktest3(point pt);
+  inline bool pmarktest3ed(point pt);
+  inline tetrahedron point2tet(point pt);
+  inline void setpoint2tet(point pt, tetrahedron value);
+  inline shellface point2sh(point pt);
+  inline void setpoint2sh(point pt, shellface value);
+  inline point point2ppt(point pt);
+  inline void setpoint2ppt(point pt, point value);
+  inline tetrahedron point2bgmtet(point pt);
+  inline void setpoint2bgmtet(point pt, tetrahedron value);
+  inline void setpointinsradius(point pt, REAL value);
+  inline REAL getpointinsradius(point pt);
+
+  // Advanced primitives.
+  inline void point2tetorg(point pt, triface& t);
+  inline void point2shorg(point pa, face& s);
+  inline point farsorg(face& seg);
+  inline point farsdest(face& seg);
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+//  Memory managment                                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  void tetrahedrondealloc(tetrahedron*);
+  tetrahedron *tetrahedrontraverse();
+  tetrahedron *alltetrahedrontraverse();
+  void shellfacedealloc(memorypool*, shellface*);
+  shellface *shellfacetraverse(memorypool*);
+  void pointdealloc(point);
+  point pointtraverse();
+
+  void makeindex2pointmap(point*&);
+  void makepoint2submap(memorypool*, int*&, face*&);
+  void maketetrahedron(triface*);
+  void makeshellface(memorypool*, face*);
+  void makepoint(point*, enum verttype);
+
+  void initializepools();
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Advanced geometric predicates and calculations                            //
+//                                                                           //
+// TetGen uses a simplified symbolic perturbation scheme from Edelsbrunner,  //
+// et al [*].  Hence the point-in-sphere test never returns a zero. The idea //
+// is to perturb the weights of vertices in the fourth dimension.  TetGen    //
+// uses the indices of the vertices decide the amount of perturbation. It is //
+// implemented in the routine insphere_s().
+//                                                                           //
+// The routine tri_edge_test() determines whether or not a triangle and an   //
+// edge intersect in 3D. If they intersect, their intersection type is also  //
+// reported. This test is a combination of n 3D orientation tests (n is bet- //
+// ween 3 and 9). It uses the robust orient3d() test to make the branch dec- //
+// isions.  The routine tri_tri_test() determines whether or not two triang- //
+// les intersect in 3D. It also uses the robust orient3d() test.             //
+//                                                                           //
+// There are a number of routines to calculate geometrical quantities, e.g., //
+// circumcenters, angles, dihedral angles, face normals, face areas, etc.    //
+// They are so far done by the default floating-point arithmetics which are  //
+// non-robust. They should be improved in the future.                        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  // Symbolic perturbations (robust)
+  REAL insphere_s(REAL*, REAL*, REAL*, REAL*, REAL*);
+  REAL orient4d_s(REAL*, REAL*, REAL*, REAL*, REAL*, 
+                  REAL, REAL, REAL, REAL, REAL);
+
+  // Triangle-edge intersection test (robust)
+  int tri_edge_2d(point, point, point, point, point, point, int, int*, int*);
+  int tri_edge_tail(point, point, point, point, point, point, REAL, REAL, int,
+                    int*, int*);
+  int tri_edge_test(point, point, point, point, point, point, int, int*, int*);
+
+  // Triangle-triangle intersection test (robust)
+  int tri_edge_inter_tail(point, point, point, point, point, REAL, REAL);
+  int tri_tri_inter(point, point, point, point, point, point);
+
+  // Linear algebra functions
+  inline REAL dot(REAL* v1, REAL* v2);
+  inline void cross(REAL* v1, REAL* v2, REAL* n);
+  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);
+
+  // An embedded 2-dimensional geometric predicate (non-robust)
+  REAL incircle3d(point pa, point pb, point pc, point pd);
+
+  // Geometric calculations (non-robust)
+  REAL orient3dfast(REAL *pa, REAL *pb, REAL *pc, REAL *pd);
+  inline REAL norm2(REAL x, REAL y, REAL z);
+  inline REAL distance(REAL* p1, REAL* p2);
+  void facenormal(point pa, point pb, point pc, REAL *n, int pivot, REAL *lav);
+  REAL shortdistance(REAL* p, REAL* e1, REAL* e2);
+  REAL triarea(REAL* pa, REAL* pb, REAL* pc);
+  REAL interiorangle(REAL* o, REAL* p1, REAL* p2, REAL* n);
+  void projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj);
+  void projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj);
+  REAL facedihedral(REAL* pa, REAL* pb, REAL* pc1, REAL* pc2);
+  bool tetalldihedral(point, point, point, point, REAL*, REAL*, REAL*);
+  void tetallnormal(point, point, point, point, REAL N[4][3], REAL* volume);
+  REAL tetaspectratio(point, point, point, point);
+  bool circumsphere(REAL*, REAL*, REAL*, REAL*, REAL* cent, REAL* radius);
+  bool orthosphere(REAL*,REAL*,REAL*,REAL*,REAL,REAL,REAL,REAL,REAL*,REAL*);
+  void planelineint(REAL*, REAL*, REAL*, REAL*, REAL*, REAL*, REAL*);
+  int linelineint(REAL*, REAL*, REAL*, REAL*, REAL*, REAL*, REAL*, REAL*);
+  REAL tetprismvol(REAL* pa, REAL* pb, REAL* pc, REAL* pd);
+  bool calculateabovepoint(arraypool*, point*, point*, point*);
+  void calculateabovepoint4(point, point, point, point);
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Local mesh transformations                                                //
+//                                                                           //
+// A local transformation replaces a small set of tetrahedra with another    //
+// set of tetrahedra which fills the same space and the same boundaries.     //
+//   In 3D, the most simplest local transformations are the elementary flips //
+// performed within the convex hull of five vertices: 2-to-3, 3-to-2, 1-to-4,//
+// and 4-to-1 flips,  where the numbers indicate the number of tetrahedra    //
+// before and after each flip.  The 1-to-4 and 4-to-1 flip involve inserting //
+// or deleting a vertex, respectively.                                       //
+//   There are complex local transformations which can be decomposed as a    //
+// combination of elementary flips. For example,a 4-to-4 flip which replaces //
+// two coplanar edges can be regarded by a 2-to-3 flip and a 3-to-2 flip.    //
+// Note that the first 2-to-3 flip will temporarily create a degenerate tet- //
+// rahedron which is removed immediately by the followed 3-to-2 flip.  More  //
+// generally, a n-to-m flip, where n > 3, m = (n - 2) * 2, which removes an  //
+// edge can be done by first performing a sequence of (n - 3) 2-to-3 flips   //
+// followed by a 3-to-2 flip.                                                //
+//                                                                           //
+// The routines flip23(), flip32(), and flip41() perform the three element-  //
+// ray flips. The flip14() is available inside the routine insertpoint().    //
+//                                                                           //
+// The routines flipnm() and flipnm_post() implement a generalized edge flip //
+// algorithm which uses a combination of elementary flips.                   //
+//                                                                           //
+// The routine insertpoint() implements a variant of Bowyer-Watson's cavity  //
+// algorithm to insert a vertex. It works for arbitrary tetrahedralization,  //
+// either Delaunay, or constrained Delaunay, or non-Delaunay.                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  // The elementary flips.
+  void flip23(triface*, int, flipconstraints* fc);
+  void flip32(triface*, int, flipconstraints* fc);
+  void flip41(triface*, int, flipconstraints* fc);
+
+  // A generalized edge flip.
+  int flipnm(triface*, int n, int level, int, flipconstraints* fc);
+  int flipnm_post(triface*, int n, int nn, int, flipconstraints* fc);
+
+  // Point insertion.
+  int  insertpoint(point, triface*, face*, face*, insertvertexflags*);
+  void insertpoint_abort(face*, insertvertexflags*);
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Delaunay tetrahedralization                                               //
+//                                                                           //
+// The routine incrementaldelaunay() implemented two incremental algorithms  //
+// for constructing Delaunay tetrahedralizations (DTs):  the Bowyer-Watson   //
+// (B-W) algorithm and the incremental flip algorithm of Edelsbrunner and    //
+// Shah, "Incremental topological flipping works for regular triangulation," //
+// Algorithmica, 15:233-241, 1996.                                           //
+//                                                                           //
+// The routine incrementalflip() implements the flip algorithm of [Edelsbru- //
+// nner and Shah, 1996].  It flips a queue of locally non-Delaunay faces (in //
+// an arbitrary order).  The success is guaranteed when the Delaunay tetrah- //
+// edralization is constructed incrementally by adding one vertex at a time. //
+//                                                                           //
+// The routine locate() finds a tetrahedron contains a new point in current  //
+// DT.  It uses a simple stochastic walk algorithm: starting from an arbitr- //
+// ary tetrahedron in DT, it finds the destination by visit one tetrahedron  //
+// at a time, randomly chooses a tetrahedron if there are more than one      //
+// choices. This algorithm terminates due to Edelsbrunner's acyclic theorem. //
+//   Choose a good starting tetrahedron is crucial to the speed of the walk. //
+// TetGen originally uses the "jump-and-walk" algorithm of Muecke, E.P.,     //
+// Saias, I., and Zhu, B. "Fast Randomized Point Location Without Preproces- //
+// sing." In Proceedings of the 12th ACM Symposium on Computational Geometry,//
+// 274-283, 1996.  It first randomly samples several tetrahedra in the DT    //
+// and then choosing the closet one to start walking.                        //
+//   The above algorithm slows download dramatically as the number of points //
+// grows -- reported in Amenta, N., Choi, S. and Rote, G., "Incremental      //
+// construction con {BRIO}," In Proceedings of 19th ACM Symposium on         //
+// Computational Geometry, 211-219, 2003.  On the other hand, Liu and        //
+// Snoeyink showed that the point location can be made in constant time if   //
+// the points are pre-sorted so that the nearby points in space have nearby  //
+// indices, then adding the points in this order. They sorted the points     //
+// along the 3D Hilbert curve.                                               //
+//                                                                           //
+// The routine hilbert_sort3() sorts a set of 3D points along the 3D Hilbert //
+// curve. It recursively splits a point set according to the Hilbert indices //
+// mapped to the subboxes of the bounding box of the point set.              //
+//   The Hilbert indices is calculated by Butz's algorithm in 1971.  A nice  //
+// exposition of this algorithm can be found in the paper of Hamilton, C.,   //
+// "Compact Hilbert Indices", Technical Report CS-2006-07, Computer Science, //
+// Dalhousie University, 2006 (the Section 2). My implementation also refer- //
+// enced Steven Witham's implementation of "Hilbert walk" (hopefully, it is  //
+// still available at: http://www.tiac.net/~sw/2008/10/Hilbert/).            //
+//                                                                           //
+// TetGen sorts the points using the method in the paper of Boissonnat,J.-D.,//
+// Devillers, O. and Hornus, S. "Incremental Construction of the Delaunay    //
+// Triangulation and the Delaunay Graph in Medium Dimension," In Proceedings //
+// of the 25th ACM Symposium on Computational Geometry, 2009.                //
+//   It first randomly sorts the points into subgroups using the Biased Rand-//
+// omized Insertion Ordering (BRIO) of Amenta et al 2003, then sorts the     //
+// points in each subgroup along the 3D Hilbert curve.  Inserting points in  //
+// this order ensures a randomized "sprinkling" of the points over the       //
+// domain, while sorting of each subset ensures locality.                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  void transfernodes();
+
+  // Point sorting.
+  int  transgc[8][3][8], tsb1mod3[8];
+  void hilbert_init(int n);
+  int  hilbert_split(point* vertexarray, int arraysize, int gc0, int gc1,
+                     REAL, REAL, REAL, REAL, REAL, REAL);
+  void hilbert_sort3(point* vertexarray, int arraysize, int e, int d,
+                     REAL, REAL, REAL, REAL, REAL, REAL, int depth);
+  void brio_multiscale_sort(point*,int,int threshold,REAL ratio,int* depth);
+
+  // Point location.
+  unsigned long randomnation(unsigned int choices);
+  void randomsample(point searchpt, triface *searchtet);
+  enum locateresult locate(point searchpt, triface *searchtet);
+
+  // Incremental flips.
+  void flippush(badface*&, triface*);
+  int  incrementalflip(point newpt, int, flipconstraints *fc);
+
+  // Incremental Delaunay construction.
+  void initialdelaunay(point pa, point pb, point pc, point pd);
+  void incrementaldelaunay(clock_t&);
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Surface triangulation                                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  void flipshpush(face*);
+  void flip22(face*, int, int);
+  void flip31(face*, int);
+  long lawsonflip();
+  int sinsertvertex(point newpt, face*, face*, int iloc, int bowywat, int);
+  int sremovevertex(point delpt, face*, face*, int lawson);
+
+  enum locateresult slocate(point, face*, int, int, int);
+  enum interresult sscoutsegment(face*, point);
+  void scarveholes(int, REAL*);
+  void triangulate(int, arraypool*, arraypool*, int, REAL*);
+
+  void unifysubfaces(face*, face*);
+  void unifysegments();
+  void mergefacets();
+  void identifypscedges(point*);
+  void meshsurface();
+
+  void interecursive(shellface** subfacearray, int arraysize, int axis,
+                     REAL, REAL, REAL, REAL, REAL, REAL, int* internum);
+  void detectinterfaces();
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Constrained Delaunay tetrahedralization                                   //
+//                                                                           //
+// A constrained Delaunay tetrahedralization (CDT) is a variation of a Dela- //
+// unay tetrahedralization (DT) that is constrained to respect the boundary  //
+// of a 3D PLC (domain). In a CDT of a 3D PLC, every vertex or edge of the   //
+// PLC is also a vertex or an edge of the CDT, every polygon of the PLC is a //
+// union of triangles of the CDT. A crucial difference between a CDT and a   //
+// DT is that triangles in the PLC's polygons are not required to be locally //
+// Delaunay, which frees the CDT to better respect the PLC's polygons. CDTs  //
+// have optimal properties similar to those of DTs.                          //
+//                                                                           //
+// Steiner Points and Steiner CDTs. It is known that even a simple 3D polyh- //
+// edron may not have a tetrahedralization which only uses its own vertices. //
+// Some extra points, so-called "Steiner points" are needed in order to form //
+// a tetrahedralization of such polyhedron.  It is true for tetrahedralizing //
+// a 3D PLC as well. A Steiner CDT of a 3D PLC is a CDT containing Steiner   //
+// points. The CDT algorithms of TetGen in general create Steiner CDTs.      //
+// Almost all of the Steiner points are added in the edges of the PLC. They  //
+// guarantee the existence of a CDT of the modified PLC.                     //
+//                                                                           //
+// The routine constraineddelaunay() starts from a DT of the vertices of a   //
+// PLC and creates a (Steiner) CDT of the PLC (including Steiner points). It //
+// is constructed by two steps, (1) segment recovery and (2) facet (polygon) //
+// recovery. Each step is accomplished by its own algorithm.                 //
+//                                                                           //
+// The routine delaunizesegments() implements the segment recovery algorithm //
+// of Si, H. and Gaertner, K. "Meshing Piecewise Linear Complexes by Constr- //
+// ained Delaunay Tetrahedralizations," In Proceedings of the 14th Internat- //
+// ional Meshing Roundtable, 147--163, 2005.  It adds Steiner points into    //
+// non-Delaunay segments until all subsegments appear together in a DT. The  //
+// running time of this algorithm is proportional to the number of added     //
+// Steiner points.                                                           //
+//                                                                           //
+// There are two incremental facet recovery algorithms: the cavity re-trian- //
+// gulation algorithm of Si, H. and Gaertner, K. "3D Boundary Recovery by    //
+// Constrained Delaunay Tetrahedralization," International Journal for Numer-//
+// ical Methods in Engineering, 85:1341-1364, 2011, and the flip algorithm   //
+// of Shewchuk, J. "Updating and Constructing Constrained Delaunay and       //
+// Constrained Regular Triangulations by Flips." In Proceedings of the 19th  //
+// ACM Symposium on Computational Geometry, 86-95, 2003.                     //
+//                                                                           //
+// It is guaranteed in theory, no Steiner point is needed in both algorithms //
+// However, a facet with non-coplanar vertices might cause the  additions of //
+// Steiner points. It is discussed in the paper of Si, H., and  Shewchuk, J.,//
+// "Incrementally Constructing and Updating Constrained Delaunay             //
+// Tetrahedralizations with Finite Precision Coordinates." In Proceedings of //
+// the 21th International Meshing Roundtable, 2012.                          //
+//                                                                           //
+// Our implementation of the facet recovery algorithms recover a "missing    //
+// region" at a time. Each missing region is a subset of connected interiors //
+// of a polygon. The routine formcavity() creates the cavity of crossing     //
+// tetrahedra of the missing region.                                         //
+//                                                                           //
+// The cavity re-triangulation algorithm is implemented by three subroutines,//
+// delaunizecavity(), fillcavity(), and carvecavity(). Since it may fail due //
+// to non-coplanar vertices, the subroutine restorecavity() is used to rest- //
+// ore the original cavity.                                                  //
+//                                                                           //
+// The routine flipinsertfacet() implements the flip algorithm. The subrout- //
+// ine flipcertify() is used to maintain the priority queue of flips.        // 
+//                                                                           //
+// The routine refineregion() is called when the facet recovery algorithm    //
+// fail to recover a missing region. It inserts Steiner points to refine the //
+// missing region. In order to avoid inserting Steiner points very close to  //
+// existing segments.  The classical encroachment rules of the Delaunay      //
+// refinement algorithm are used to choose the Steiner points.               //
+//                                                                           //
+// The routine constrainedfacets() does the facet recovery by using either   //
+// the cavity re-triangulation algorithm (default) or the flip algorithm. It //
+// results a CDT of the (modified) PLC (including Steiner points).           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  void makesegmentendpointsmap();
+
+  enum interresult finddirection(triface* searchtet, point endpt);
+  enum interresult scoutsegment(point, point, triface*, point*, arraypool*);
+  int  getsteinerptonsegment(face* seg, point refpt, point steinpt);
+  void delaunizesegments();
+
+  enum interresult scoutsubface(face* searchsh, triface* searchtet);
+  void formregion(face*, arraypool*, arraypool*, arraypool*);
+  int  scoutcrossedge(triface& crosstet, arraypool*, arraypool*);
+  bool formcavity(triface*, arraypool*, arraypool*, arraypool*, arraypool*, 
+                  arraypool*, arraypool*);
+
+  // Facet recovery by cavity re-triangulation [Si and Gaertner 2011].
+  void delaunizecavity(arraypool*, arraypool*, arraypool*, arraypool*, 
+                       arraypool*, arraypool*);
+  bool fillcavity(arraypool*, arraypool*, arraypool*, arraypool*,
+                  arraypool*, arraypool*, triface* crossedge);
+  void carvecavity(arraypool*, arraypool*, arraypool*);
+  void restorecavity(arraypool*, arraypool*, arraypool*, arraypool*);
+
+  // Facet recovery by flips [Shewchuk 2003].
+  void flipcertify(triface *chkface, badface **pqueue, point, point, point);
+  void flipinsertfacet(arraypool*, arraypool*, arraypool*, arraypool*);
+
+  bool fillregion(arraypool* missingshs, arraypool*, arraypool* newshs);
+
+  int  insertpoint_cdt(point, triface*, face*, face*, insertvertexflags*,
+                       arraypool*, arraypool*, arraypool*, arraypool*,
+                       arraypool*, arraypool*);
+  void refineregion(face&, arraypool*, arraypool*, arraypool*, arraypool*,
+                    arraypool*, arraypool*);
+
+  void constrainedfacets();  
+
+  void constraineddelaunay(clock_t&);
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Constrained tetrahedralizations.                                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  int checkflipeligibility(int fliptype, point, point, point, point, point,
+                           int level, int edgepivot, flipconstraints* fc);
+
+  int removeedgebyflips(triface*, flipconstraints*);
+  int removefacebyflips(triface*, flipconstraints*);
+
+  int recoveredgebyflips(point, point, triface*, int fullsearch);
+  int add_steinerpt_in_schoenhardtpoly(triface*, int, int chkencflag);
+  int add_steinerpt_in_segment(face*, int searchlevel); 
+  int addsteiner4recoversegment(face*, int);
+  int recoversegments(arraypool*, int fullsearch, int steinerflag);
+
+  int recoverfacebyflips(point, point, point, face*, triface*);
+  int recoversubfaces(arraypool*, int steinerflag);
+
+  int getvertexstar(int, point searchpt, arraypool*, arraypool*, arraypool*);
+  int getedge(point, point, triface*);
+  int reduceedgesatvertex(point startpt, arraypool* endptlist);
+  int removevertexbyflips(point steinerpt);
+
+  int suppressbdrysteinerpoint(point steinerpt);
+  int suppresssteinerpoints();
+
+  void recoverboundary(clock_t&);
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh reconstruction                                                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  void carveholes();
+
+  void reconstructmesh();
+
+  int  scoutpoint(point, triface*, int randflag);
+  REAL getpointmeshsize(point, triface*, int iloc);
+  void interpolatemeshsize();
+
+  void insertconstrainedpoints(point *insertarray, int arylen, int rejflag);
+  void insertconstrainedpoints(tetgenio *addio);
+
+  void collectremovepoints(arraypool *remptlist);
+  void meshcoarsening();
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh refinement                                                           //
+//                                                                           //
+// The purpose of mesh refinement is to obtain a tetrahedral mesh with well- //
+// -shaped tetrahedra and appropriate mesh size.  It is necessary to insert  //
+// new Steiner points to achieve this property. The questions are (1) how to //
+// choose the Steiner points? and (2) how to insert them?                    //
+//                                                                           //
+// Delaunay refinement is a technique first developed by Chew [1989] and     //
+// Ruppert [1993, 1995] to generate quality triangular meshes in the plane.  //
+// It provides guarantee on the smallest angle of the triangles.  Rupper's   //
+// algorithm guarantees that the mesh is size-optimal (to within a constant  //
+// factor) among all meshes with the same quality.                           //
+//   Shewchuk generalized Ruppert's algorithm into 3D in his PhD thesis      //
+// [Shewchuk 1997]. A short version of his algorithm appears in "Tetrahedral //
+// Mesh Generation by Delaunay Refinement," In Proceedings of the 14th ACM   //
+// Symposium on Computational Geometry, 86-95, 1998.  It guarantees that all //
+// tetrahedra of the output mesh have a "radius-edge ratio" (equivalent to   //
+// the minimal face angle) bounded. However, it does not remove slivers, a   //
+// type of very flat tetrahedra which can have no small face angles but have //
+// very small (and large) dihedral angles. Moreover, it may not terminate if //
+// the input PLC contains "sharp features", e.g., two edges (or two facets)  //
+// meet at an acute angle (or dihedral angle).                               //
+//                                                                           //
+// TetGen uses the basic Delaunay refinement scheme to insert Steiner points.//
+// While it always maintains a constrained Delaunay mesh.  The algorithm is  //
+// described in Si, H., "Adaptive Constrained Delaunay Mesh Generation,"     //
+// International Journal for Numerical Methods in Engineering, 75:856-880.   //
+// This algorithm always terminates and sharp features are easily preserved. //
+// The mesh has good quality (same as Shewchuk's Delaunay refinement algori- //
+// thm) in the bulk of the mesh domain. Moreover, it supports the generation //
+// of adaptive mesh according to a (isotropic) mesh sizing function.         //   
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  void makefacetverticesmap();
+  int segsegadjacent(face *, face *);
+  int segfacetadjacent(face *checkseg, face *checksh);
+  int facetfacetadjacent(face *, face *);
+
+  int checkseg4encroach(point pa, point pb, point checkpt);
+  int checkseg4split(face *chkseg, point&, int&);
+  int splitsegment(face *splitseg, point encpt, REAL, point, point, int, int);
+  void repairencsegs(int chkencflag);
+
+  void enqueuesubface(memorypool*, face*);
+  int checkfac4encroach(point, point, point, point checkpt, REAL*, REAL*);
+  int checkfac4split(face *chkfac, point& encpt, int& qflag, REAL *ccent);
+  int splitsubface(face *splitfac, point, point, int qflag, REAL *ccent, int);
+  void repairencfacs(int chkencflag);
+
+  void enqueuetetrahedron(triface*);
+  int checktet4split(triface *chktet, int& qflag, REAL *ccent);
+  int splittetrahedron(triface* splittet,int qflag,REAL *ccent, int);
+  void repairbadtets(int chkencflag);
+
+  void delaunayrefinement();
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh optimization                                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  long lawsonflip3d(flipconstraints *fc);
+  void recoverdelaunay();
+
+  int  gettetrahedron(point, point, point, point, triface *);
+  long improvequalitybyflips();
+
+  int  smoothpoint(point smtpt, arraypool*, int ccw, optparameters *opm);
+  long improvequalitybysmoothing(optparameters *opm);
+
+  int  splitsliver(triface *, REAL, int);
+  long removeslivers(int);
+
+  void optimizemesh();
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh check and statistics                                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  // Mesh validations.
+  int checkmesh(int topoflag);
+  int checkshells();
+  int checksegments();
+  int checkdelaunay();
+  int checkregular(int);
+  int checkconforming(int);
+
+  //  Mesh statistics.
+  void printfcomma(unsigned long n);
+  void qualitystatistics();
+  void memorystatistics();
+  void statistics();
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Mesh output                                                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  void jettisonnodes();
+  void highorder();
+  void numberedges();
+  void outnodes(tetgenio*);
+  void outmetrics(tetgenio*);
+  void outelements(tetgenio*);
+  void outfaces(tetgenio*);
+  void outhullfaces(tetgenio*);
+  void outsubfaces(tetgenio*);
+  void outedges(tetgenio*);
+  void outsubsegments(tetgenio*);
+  void outneighbors(tetgenio*);
+  void outvoronoi(tetgenio*);
+  void outsmesh(char*);
+  void outmesh2medit(char*);
+  void outmesh2vtk(char*);
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Constructor & destructor                                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  tetgenmesh()
+  {
+    in  = addin = NULL;
+    b   = NULL;
+    bgm = NULL;
+
+    tetrahedrons = subfaces = subsegs = points = NULL;
+    badtetrahedrons = badsubfacs = badsubsegs = NULL;
+    tet2segpool = tet2subpool = NULL;
+    flippool = NULL;
+
+    dummypoint = NULL;
+    flipstack = NULL;
+    unflipqueue = NULL;
+
+    cavetetlist = cavebdrylist = caveoldtetlist = NULL;
+    cavetetshlist = cavetetseglist = cavetetvertlist = NULL;
+    caveencshlist = caveencseglist = NULL;
+    caveshlist = caveshbdlist = cavesegshlist = NULL;
+
+    subsegstack = subfacstack = subvertstack = NULL;
+    encseglist = encshlist = NULL;
+    idx2facetlist = NULL;
+    facetverticeslist = NULL;
+    segmentendpointslist = NULL;
+
+    highordertable = NULL;
+
+    numpointattrib = numelemattrib = 0;
+    sizeoftensor = 0;
+    pointmtrindex = 0;
+    pointparamindex = 0;
+    pointmarkindex = 0;
+    point2simindex = 0;
+    elemattribindex = 0;
+    volumeboundindex = 0;
+    shmarkindex = 0;
+    areaboundindex = 0;
+    checksubsegflag = 0;
+    checksubfaceflag = 0;
+    checkconstraints = 0;
+    nonconvex = 0;
+    autofliplinklevel = 1;
+    useinsertradius = 0;
+    samples = 0l;
+    randomseed = 1l;
+    minfaceang = minfacetdihed = PI;
+    tetprism_vol_sum = 0.0;
+    longest = 0.0;
+    xmax = xmin = ymax = ymin = zmax = zmin = 0.0; 
+
+    insegments = 0l;
+    hullsize = 0l;
+    meshedges = meshhulledges = 0l;
+    steinerleft = -1;
+    dupverts = 0l;
+    unuverts = 0l;
+    nonregularcount = 0l;
+    st_segref_count = st_facref_count = st_volref_count = 0l;
+    fillregioncount = cavitycount = cavityexpcount = 0l;
+    flip14count = flip26count = flipn2ncount = 0l;
+    flip23count = flip32count = flip44count = flip41count = 0l;
+    flip22count = flip31count = 0l;
+    totalworkmemory = 0l;
+
+
+  } // tetgenmesh()
+
+  void freememory()
+  {
+    if (bgm != NULL) {
+      delete bgm;
+    }
+
+    if (points != (memorypool *) NULL) {
+      delete points;
+      delete [] dummypoint;
+    }
+
+    if (tetrahedrons != (memorypool *) NULL) {
+      delete tetrahedrons;
+    }
+
+    if (subfaces != (memorypool *) NULL) {
+      delete subfaces;
+      delete subsegs;
+    }
+
+    if (tet2segpool != NULL) {
+      delete tet2segpool;
+      delete tet2subpool;
+    }
+
+    if (flippool != NULL) {
+      delete flippool;
+      delete unflipqueue;
+    }
+
+    if (cavetetlist != NULL) {
+      delete cavetetlist;
+      delete cavebdrylist;
+      delete caveoldtetlist;
+      delete cavetetvertlist;
+    }
+
+    if (caveshlist != NULL) {
+      delete caveshlist;
+      delete caveshbdlist;
+      delete cavesegshlist;
+      delete cavetetshlist;
+      delete cavetetseglist;
+      delete caveencshlist;
+      delete caveencseglist;
+    }
+
+    if (subsegstack != NULL) {
+      delete subsegstack;
+      delete subfacstack;
+      delete subvertstack;
+    }
+
+    if (idx2facetlist != NULL) {
+      delete [] idx2facetlist;
+      delete [] facetverticeslist;
+    }
+
+    if (segmentendpointslist != NULL) {
+      delete [] segmentendpointslist;
+    }
+
+    if (highordertable != NULL) {
+      delete [] highordertable;
+    }
+  }
+
+  ~tetgenmesh()
+  {
+    freememory();
+  } // ~tetgenmesh()
+
+};                                               // End of class tetgenmesh.
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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 function.                                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, 
+                    tetgenio *addin = NULL, tetgenio *bgmin = NULL);
+
+#ifdef TETLIBRARY
+void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
+                    tetgenio *addin = NULL, tetgenio *bgmin = NULL);
+#endif // #ifdef TETLIBRARY
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// terminatetetgen()    Terminate TetGen with a given exit code.             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+inline void terminatetetgen(tetgenmesh *m, int x)
+{
+  // Release the allocated memory.
+  if (m) {
+    m->freememory();
+  }
+#ifdef TETLIBRARY
+  throw x;
+#else
+  switch (x) {
+  case 1: // Out of memory.
+    printf("Error:  Out of memory.\n"); 
+    break;
+  case 2: // Encounter an internal error.
+    printf("Please report this bug to Hang.Si@wias-berlin.de. Include\n");
+    printf("  the message above, your input data set, and the exact\n");
+    printf("  command line you used to run this program, thank you.\n");
+    break;
+  case 3:
+    printf("A self-intersection was detected. Program stopped.\n");
+    printf("Hint: use -d option to detect all self-intersections.\n"); 
+    break;
+  case 4:
+    printf("A very small input feature size was detected. Program stopped.\n");
+    printf("Hint: use -T option to set a smaller tolerance.\n");
+    break;
+  case 5:
+    printf("Two very close input facets were detected. Program stopped.\n");
+    printf("Hint: use -Y option to avoid adding Steiner points in boundary.\n");
+    break;
+  case 10: 
+    printf("An input error was detected. Program stopped.\n"); 
+    break;
+  } // switch (x)
+  exit(x);
+#endif // #ifdef TETLIBRARY
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Primitives for tetrahedra                                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// encode()  compress a handle into a single pointer.  It relies on the 
+//   assumption that all addresses of tetrahedra are aligned to sixteen-
+//   byte boundaries, so that the last four significant bits are zero.
+
+inline tetgenmesh::tetrahedron tetgenmesh::encode(triface& t) {
+  return (tetrahedron) ((uintptr_t) (t).tet | (uintptr_t) (t).ver);
+}
+
+inline tetgenmesh::tetrahedron tetgenmesh::encode2(tetrahedron* ptr, int ver) {
+  return (tetrahedron) ((uintptr_t) (ptr) | (uintptr_t) (ver));
+}
+
+// decode()  converts a pointer to a handle. The version is extracted from
+//   the four least significant bits of the pointer.
+
+inline void tetgenmesh::decode(tetrahedron ptr, triface& t) {
+  (t).ver = (int) ((uintptr_t) (ptr) & (uintptr_t) 15);
+  (t).tet = (tetrahedron *) ((uintptr_t) (ptr) ^ (uintptr_t) (t).ver);
+}
+
+// bond()  connects two tetrahedra together. (t1,v1) and (t2,v2) must 
+//   refer to the same face and the same edge. 
+
+inline void tetgenmesh::bond(triface& t1, triface& t2) {
+  t1.tet[t1.ver & 3] = encode2(t2.tet, bondtbl[t1.ver][t2.ver]);
+  t2.tet[t2.ver & 3] = encode2(t1.tet, bondtbl[t2.ver][t1.ver]);
+}
+
+
+// dissolve()  a bond (from one side).
+
+inline void tetgenmesh::dissolve(triface& t) {
+  t.tet[t.ver & 3] = NULL;
+}
+
+// enext()  finds the next edge (counterclockwise) in the same face.
+
+inline void tetgenmesh::enext(triface& t1, triface& t2) {
+  t2.tet = t1.tet;
+  t2.ver = enexttbl[t1.ver];
+}
+
+inline void tetgenmesh::enextself(triface& t) {
+  t.ver = enexttbl[t.ver];
+}
+
+// eprev()   finds the next edge (clockwise) in the same face.
+
+inline void tetgenmesh::eprev(triface& t1, triface& t2) {
+  t2.tet = t1.tet;
+  t2.ver = eprevtbl[t1.ver];
+}
+
+inline void tetgenmesh::eprevself(triface& t) {
+  t.ver = eprevtbl[t.ver];
+}
+
+// esym()  finds the reversed edge.  It is in the other face of the
+//   same tetrahedron.
+
+inline void tetgenmesh::esym(triface& t1, triface& t2) {
+  (t2).tet = (t1).tet;
+  (t2).ver = esymtbl[(t1).ver];
+}
+
+inline void tetgenmesh::esymself(triface& t) {
+  (t).ver = esymtbl[(t).ver];
+}
+
+// enextesym()  finds the reversed edge of the next edge. It is in the other
+//   face of the same tetrahedron. It is the combination esym() * enext(). 
+
+inline void tetgenmesh::enextesym(triface& t1, triface& t2) {
+  t2.tet = t1.tet;
+  t2.ver = enextesymtbl[t1.ver];
+}
+
+inline void tetgenmesh::enextesymself(triface& t) {
+  t.ver = enextesymtbl[t.ver];
+}
+
+// eprevesym()  finds the reversed edge of the previous edge.
+
+inline void tetgenmesh::eprevesym(triface& t1, triface& t2) {
+  t2.tet = t1.tet;
+  t2.ver = eprevesymtbl[t1.ver];
+}
+
+inline void tetgenmesh::eprevesymself(triface& t) {
+  t.ver = eprevesymtbl[t.ver];
+}
+
+// eorgoppo()    Finds the opposite face of the origin of the current edge.
+//               Return the opposite edge of the current edge.
+
+inline void tetgenmesh::eorgoppo(triface& t1, triface& t2) {
+  t2.tet = t1.tet;
+  t2.ver = eorgoppotbl[t1.ver];
+}
+
+inline void tetgenmesh::eorgoppoself(triface& t) {
+  t.ver = eorgoppotbl[t.ver];
+}
+
+// edestoppo()    Finds the opposite face of the destination of the current 
+//                edge. Return the opposite edge of the current edge.
+
+inline void tetgenmesh::edestoppo(triface& t1, triface& t2) {
+  t2.tet = t1.tet;
+  t2.ver = edestoppotbl[t1.ver];
+}
+
+inline void tetgenmesh::edestoppoself(triface& t) {
+  t.ver = edestoppotbl[t.ver];
+}
+
+// fsym()  finds the adjacent tetrahedron at the same face and the same edge.
+
+inline void tetgenmesh::fsym(triface& t1, triface& t2) {
+  decode((t1).tet[(t1).ver & 3], t2);
+  t2.ver = fsymtbl[t1.ver][t2.ver];
+}
+
+
+#define fsymself(t) \
+  t1ver = (t).ver; \
+  decode((t).tet[(t).ver & 3], (t));\
+  (t).ver = fsymtbl[t1ver][(t).ver]
+
+// fnext()  finds the next face while rotating about an edge according to
+//   a right-hand rule. The face is in the adjacent tetrahedron.  It is
+//   the combination: fsym() * esym().
+
+inline void tetgenmesh::fnext(triface& t1, triface& t2) {
+  decode(t1.tet[facepivot1[t1.ver]], t2);
+  t2.ver = facepivot2[t1.ver][t2.ver];
+}
+
+
+#define fnextself(t) \
+  t1ver = (t).ver; \
+  decode((t).tet[facepivot1[(t).ver]], (t)); \
+  (t).ver = facepivot2[t1ver][(t).ver]
+
+
+// The following primtives get or set the origin, destination, face apex,
+//   or face opposite of an ordered tetrahedron.
+
+inline tetgenmesh::point tetgenmesh::org(triface& t) {
+  return (point) (t).tet[orgpivot[(t).ver]];
+}
+
+inline tetgenmesh::point tetgenmesh:: dest(triface& t) {
+  return (point) (t).tet[destpivot[(t).ver]];
+}
+
+inline tetgenmesh::point tetgenmesh:: apex(triface& t) {
+  return (point) (t).tet[apexpivot[(t).ver]];
+}
+
+inline tetgenmesh::point tetgenmesh:: oppo(triface& t) {
+  return (point) (t).tet[oppopivot[(t).ver]];
+}
+
+inline void tetgenmesh:: setorg(triface& t, point p) {
+  (t).tet[orgpivot[(t).ver]] = (tetrahedron) (p);
+}
+
+inline void tetgenmesh:: setdest(triface& t, point p) {
+  (t).tet[destpivot[(t).ver]] = (tetrahedron) (p);
+}
+
+inline void tetgenmesh:: setapex(triface& t, point p) {
+  (t).tet[apexpivot[(t).ver]] = (tetrahedron) (p);
+}
+
+inline void tetgenmesh:: setoppo(triface& t, point p) {
+  (t).tet[oppopivot[(t).ver]] = (tetrahedron) (p);
+}
+
+#define setvertices(t, torg, tdest, tapex, toppo) \
+  (t).tet[orgpivot[(t).ver]] = (tetrahedron) (torg);\
+  (t).tet[destpivot[(t).ver]] = (tetrahedron) (tdest); \
+  (t).tet[apexpivot[(t).ver]] = (tetrahedron) (tapex); \
+  (t).tet[oppopivot[(t).ver]] = (tetrahedron) (toppo)
+
+// Check or set a tetrahedron's attributes.
+
+inline REAL tetgenmesh::elemattribute(tetrahedron* ptr, int attnum) {
+  return ((REAL *) (ptr))[elemattribindex + attnum];
+}
+
+inline void tetgenmesh::setelemattribute(tetrahedron* ptr, int attnum, 
+  REAL value) {
+  ((REAL *) (ptr))[elemattribindex + attnum] = value;
+}
+
+// Check or set a tetrahedron's maximum volume bound.
+
+inline REAL tetgenmesh::volumebound(tetrahedron* ptr) {
+  return ((REAL *) (ptr))[volumeboundindex];
+}
+
+inline void tetgenmesh::setvolumebound(tetrahedron* ptr, REAL value) {
+  ((REAL *) (ptr))[volumeboundindex] = value;
+}
+
+// Get or set a tetrahedron's index (only used for output).
+//    These two routines use the reserved slot ptr[10].
+
+inline int tetgenmesh::elemindex(tetrahedron* ptr) {
+  int *iptr = (int *) &(ptr[10]);
+  return iptr[0];
+}
+
+inline void tetgenmesh::setelemindex(tetrahedron* ptr, int value) {
+  int *iptr = (int *) &(ptr[10]);
+  iptr[0] = value;
+}
+
+// Get or set a tetrahedron's marker. 
+//   Set 'value = 0' cleans all the face/edge flags.
+
+inline int tetgenmesh::elemmarker(tetrahedron* ptr) {
+  return ((int *) (ptr))[elemmarkerindex];
+}
+
+inline void tetgenmesh::setelemmarker(tetrahedron* ptr, int value) {
+  ((int *) (ptr))[elemmarkerindex] = value;
+}
+
+// infect(), infected(), uninfect() -- primitives to flag or unflag a
+//   tetrahedron. The last bit of the element marker is flagged (1)
+//   or unflagged (0).
+
+inline void tetgenmesh::infect(triface& t) {
+  ((int *) (t.tet))[elemmarkerindex] |= 1;
+}
+
+inline void tetgenmesh::uninfect(triface& t) {
+  ((int *) (t.tet))[elemmarkerindex] &= ~1;
+}
+
+inline bool tetgenmesh::infected(triface& t) {
+  return (((int *) (t.tet))[elemmarkerindex] & 1) != 0;
+}
+
+// marktest(), marktested(), unmarktest() -- primitives to flag or unflag a
+//   tetrahedron.  Use the second lowerest bit of the element marker.
+
+inline void tetgenmesh::marktest(triface& t) {
+  ((int *) (t.tet))[elemmarkerindex] |= 2;
+}
+
+inline void tetgenmesh::unmarktest(triface& t) {
+  ((int *) (t.tet))[elemmarkerindex] &= ~2;
+}
+    
+inline bool tetgenmesh::marktested(triface& t) {
+  return (((int *) (t.tet))[elemmarkerindex] & 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. 
+
+inline void tetgenmesh::markface(triface& t) {
+  ((int *) (t.tet))[elemmarkerindex] |= (4 << (t.ver & 3));
+}
+
+inline void tetgenmesh::unmarkface(triface& t) {
+  ((int *) (t.tet))[elemmarkerindex] &= ~(4 << (t.ver & 3));
+}
+
+inline bool tetgenmesh::facemarked(triface& t) {
+  return (((int *) (t.tet))[elemmarkerindex] & (4 << (t.ver & 3))) != 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.
+
+inline void tetgenmesh::markedge(triface& t) {
+  ((int *) (t.tet))[elemmarkerindex] |= (int) (64 << ver2edge[(t).ver]);
+}
+
+inline void tetgenmesh::unmarkedge(triface& t) {
+  ((int *) (t.tet))[elemmarkerindex] &= ~(int) (64 << ver2edge[(t).ver]);
+}
+
+inline bool tetgenmesh::edgemarked(triface& t) {
+  return (((int *) (t.tet))[elemmarkerindex] & 
+           (int) (64 << ver2edge[(t).ver])) != 0;
+}
+
+// marktest2(), unmarktest2(), marktest2ed() -- primitives to flag and unflag
+//   a tetrahedron. The 13th bit (2^12 = 4096) is used for this flag.
+
+inline void tetgenmesh::marktest2(triface& t) {
+  ((int *) (t.tet))[elemmarkerindex] |= (int) (4096);
+}
+
+inline void tetgenmesh::unmarktest2(triface& t) {
+  ((int *) (t.tet))[elemmarkerindex] &= ~(int) (4096);
+}
+
+inline bool tetgenmesh::marktest2ed(triface& t) {
+  return (((int *) (t.tet))[elemmarkerindex] & (int) (4096)) != 0;
+}
+
+// elemcounter(), setelemcounter() -- primitives to read or ser a (small)
+//   integer counter in this tet. It is saved from the 16th bit. On 32 bit
+//   system, the range of the counter is [0, 2^15 = 32768]. 
+
+inline int tetgenmesh::elemcounter(triface& t) {
+  return (((int *) (t.tet))[elemmarkerindex]) >> 16;
+}
+
+inline void tetgenmesh::setelemcounter(triface& t, int value) {
+  int c = ((int *) (t.tet))[elemmarkerindex];
+  // Clear the old counter while keep the other flags.
+  c &= 65535; // sum_{i=0^15} 2^i
+  c |= (value << 16);
+  ((int *) (t.tet))[elemmarkerindex] = c;
+}
+
+inline void tetgenmesh::increaseelemcounter(triface& t) {
+  int c = elemcounter(t);
+  setelemcounter(t, c + 1);
+}
+
+inline void tetgenmesh::decreaseelemcounter(triface& t) {
+  int c = elemcounter(t);
+  setelemcounter(t, c - 1);
+}
+
+// ishulltet()  tests if t is a hull tetrahedron.
+
+inline bool tetgenmesh::ishulltet(triface& t) {
+  return (point) (t).tet[7] == dummypoint;
+}
+
+// isdeadtet()  tests if t is a tetrahedron is dead.
+
+inline bool tetgenmesh::isdeadtet(triface& t) {
+  return ((t.tet == NULL) || (t.tet[4] == NULL));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Primitives for subfaces and subsegments                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// Each subface contains three pointers to its neighboring subfaces, with
+//   edge versions.  To save memory, both information are kept in a single
+//   pointer. To make this possible, all subfaces are aligned to eight-byte
+//   boundaries, so that the last three bits of each pointer are zeros. An
+//   edge version (in the range 0 to 5) is compressed into the last three
+//   bits of each pointer by 'sencode()'.  'sdecode()' decodes a pointer,
+//   extracting an edge version and a pointer to the beginning of a subface.
+
+inline void tetgenmesh::sdecode(shellface sptr, face& s) {
+  s.shver = (int) ((uintptr_t) (sptr) & (uintptr_t) 7);
+  s.sh = (shellface *) ((uintptr_t) (sptr) ^ (uintptr_t) (s.shver));
+}
+
+inline tetgenmesh::shellface tetgenmesh::sencode(face& s) {
+  return (shellface) ((uintptr_t) s.sh | (uintptr_t) s.shver);
+}
+
+inline tetgenmesh::shellface tetgenmesh::sencode2(shellface *sh, int shver) {
+  return (shellface) ((uintptr_t) sh | (uintptr_t) shver);
+}
+
+// sbond() bonds two subfaces (s1) and (s2) together. s1 and s2 must refer
+//   to the same edge. No requirement is needed on their orientations.
+
+inline void tetgenmesh::sbond(face& s1, face& s2) 
+{
+  s1.sh[s1.shver >> 1] = sencode(s2);
+  s2.sh[s2.shver >> 1] = sencode(s1);
+}
+
+// sbond1() bonds s1 <== s2, i.e., after bonding, s1 is pointing to s2,
+//   but s2 is not pointing to s1.  s1 and s2 must refer to the same edge.
+//   No requirement is needed on their orientations.
+
+inline void tetgenmesh::sbond1(face& s1, face& s2) 
+{
+  s1.sh[s1.shver >> 1] = sencode(s2);
+}
+
+// Dissolve a subface bond (from one side).  Note that the other subface
+//   will still think it's connected to this subface.
+
+inline void tetgenmesh::sdissolve(face& s)
+{
+  s.sh[s.shver >> 1] = NULL;
+}
+
+// spivot() finds the adjacent subface (s2) for a given subface (s1).
+//   s1 and s2 share at the same edge.
+
+inline void tetgenmesh::spivot(face& s1, face& s2) 
+{
+  shellface sptr = s1.sh[s1.shver >> 1];
+  sdecode(sptr, s2);
+}
+
+inline void tetgenmesh::spivotself(face& s) 
+{
+  shellface sptr = s.sh[s.shver >> 1];
+  sdecode(sptr, s);
+}
+
+// These primitives determine or set the origin, destination, or apex
+//   of a subface with respect to the edge version.
+
+inline tetgenmesh::point tetgenmesh::sorg(face& s) 
+{
+  return (point) s.sh[sorgpivot[s.shver]];
+}
+
+inline tetgenmesh::point tetgenmesh::sdest(face& s) 
+{
+  return (point) s.sh[sdestpivot[s.shver]];
+}
+
+inline tetgenmesh::point tetgenmesh::sapex(face& s) 
+{
+  return (point) s.sh[sapexpivot[s.shver]];
+}
+
+inline void tetgenmesh::setsorg(face& s, point pointptr) 
+{
+  s.sh[sorgpivot[s.shver]] = (shellface) pointptr;
+}
+
+inline void tetgenmesh::setsdest(face& s, point pointptr) 
+{
+  s.sh[sdestpivot[s.shver]] = (shellface) pointptr;
+}
+
+inline void tetgenmesh::setsapex(face& s, point pointptr) 
+{
+  s.sh[sapexpivot[s.shver]] = (shellface) pointptr;
+}
+
+#define setshvertices(s, pa, pb, pc)\
+  setsorg(s, pa);\
+  setsdest(s, pb);\
+  setsapex(s, pc)
+
+// sesym()  reserves the direction of the lead edge.
+
+inline void tetgenmesh::sesym(face& s1, face& s2) 
+{
+  s2.sh = s1.sh;
+  s2.shver = (s1.shver ^ 1);  // Inverse the last bit.
+}
+
+inline void tetgenmesh::sesymself(face& s) 
+{
+  s.shver ^= 1;
+}
+
+// senext()  finds the next edge (counterclockwise) in the same orientation
+//   of this face.
+
+inline void tetgenmesh::senext(face& s1, face& s2) 
+{
+  s2.sh = s1.sh;
+  s2.shver = snextpivot[s1.shver];
+}
+
+inline void tetgenmesh::senextself(face& s) 
+{
+  s.shver = snextpivot[s.shver];
+}
+
+inline void tetgenmesh::senext2(face& s1, face& s2) 
+{
+  s2.sh = s1.sh;
+  s2.shver = snextpivot[snextpivot[s1.shver]];
+}
+
+inline void tetgenmesh::senext2self(face& s) 
+{
+  s.shver = snextpivot[snextpivot[s.shver]];
+}
+
+
+// Check or set a subface's maximum area bound.
+
+inline REAL tetgenmesh::areabound(face& s) 
+{
+  return ((REAL *) (s.sh))[areaboundindex];
+}
+
+inline void tetgenmesh::setareabound(face& s, REAL value) 
+{
+  ((REAL *) (s.sh))[areaboundindex] = value;
+}
+
+// These two primitives read or set a shell marker.  Shell markers are used
+//   to hold user boundary information.
+
+inline int tetgenmesh::shellmark(face& s) 
+{
+  return ((int *) (s.sh))[shmarkindex];
+}
+
+inline void tetgenmesh::setshellmark(face& s, int value) 
+{
+  ((int *) (s.sh))[shmarkindex] = value;
+}
+
+
+
+// sinfect(), sinfected(), suninfect() -- primitives to flag or unflag a
+//   subface. The last bit of ((int *) ((s).sh))[shmarkindex+1] is flagged.
+
+inline void tetgenmesh::sinfect(face& s) 
+{
+  ((int *) ((s).sh))[shmarkindex+1] = 
+    (((int *) ((s).sh))[shmarkindex+1] | (int) 1);
+}
+
+inline void tetgenmesh::suninfect(face& s) 
+{
+  ((int *) ((s).sh))[shmarkindex+1] = 
+    (((int *) ((s).sh))[shmarkindex+1] & ~(int) 1);
+}
+
+// Test a subface for viral infection.
+
+inline bool tetgenmesh::sinfected(face& s) 
+{
+  return (((int *) ((s).sh))[shmarkindex+1] & (int) 1) != 0;
+}
+
+// smarktest(), smarktested(), sunmarktest() -- primitives to flag or unflag
+//   a subface. The last 2nd bit of the integer is flagged.
+
+inline void tetgenmesh::smarktest(face& s) 
+{
+  ((int *) ((s).sh))[shmarkindex+1] = 
+    (((int *)((s).sh))[shmarkindex+1] | (int) 2);
+}
+
+inline void tetgenmesh::sunmarktest(face& s) 
+{
+  ((int *) ((s).sh))[shmarkindex+1] = 
+    (((int *)((s).sh))[shmarkindex+1] & ~(int)2);
+}
+
+inline bool tetgenmesh::smarktested(face& s) 
+{
+  return ((((int *) ((s).sh))[shmarkindex+1] & (int) 2) != 0);
+}
+
+// smarktest2(), smarktest2ed(), sunmarktest2() -- primitives to flag or 
+//   unflag a subface. The last 3rd bit of the integer is flagged.
+
+inline void tetgenmesh::smarktest2(face& s) 
+{
+  ((int *) ((s).sh))[shmarkindex+1] = 
+    (((int *)((s).sh))[shmarkindex+1] | (int) 4);
+}
+
+inline void tetgenmesh::sunmarktest2(face& s) 
+{
+  ((int *) ((s).sh))[shmarkindex+1] = 
+    (((int *)((s).sh))[shmarkindex+1] & ~(int)4);
+}
+
+inline bool tetgenmesh::smarktest2ed(face& s) 
+{
+  return ((((int *) ((s).sh))[shmarkindex+1] & (int) 4) != 0);
+}
+
+// The last 4th bit of ((int *) ((s).sh))[shmarkindex+1] is flagged.
+
+inline void tetgenmesh::smarktest3(face& s) 
+{
+  ((int *) ((s).sh))[shmarkindex+1] = 
+    (((int *)((s).sh))[shmarkindex+1] | (int) 8);
+}
+
+inline void tetgenmesh::sunmarktest3(face& s) 
+{
+  ((int *) ((s).sh))[shmarkindex+1] = 
+    (((int *)((s).sh))[shmarkindex+1] & ~(int)8);
+}
+
+inline bool tetgenmesh::smarktest3ed(face& s) 
+{
+  return ((((int *) ((s).sh))[shmarkindex+1] & (int) 8) != 0);
+}
+
+
+// Each facet has a unique index (automatically indexed). Starting from '0'.
+// We save this index in the same field of the shell type. 
+
+inline void tetgenmesh::setfacetindex(face& s, int value)
+{
+  ((int *) (s.sh))[shmarkindex + 2] = value;
+}
+
+inline int tetgenmesh::getfacetindex(face& s)
+{
+  return ((int *) (s.sh))[shmarkindex + 2];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Primitives for interacting between tetrahedra and subfaces                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// tsbond() bond a tetrahedron (t) and a subface (s) together.
+// Note that t and s must be the same face and the same edge. Moreover,
+//   t and s have the same orientation. 
+// Since the edge number in t and in s can be any number in {0,1,2}. We bond
+//   the edge in s which corresponds to t's 0th edge, and vice versa.
+
+inline void tetgenmesh::tsbond(triface& t, face& s)
+{
+  if ((t).tet[9] == NULL) {
+    // Allocate space for this tet.
+    (t).tet[9] = (tetrahedron) tet2subpool->alloc();
+    // Initialize.
+    for (int i = 0; i < 4; i++) {
+      ((shellface *) (t).tet[9])[i] = NULL;
+    }
+  }
+  // Bond t <== s.
+  ((shellface *) (t).tet[9])[(t).ver & 3] = 
+    sencode2((s).sh, tsbondtbl[t.ver][s.shver]);
+  // Bond s <== t.
+  s.sh[9 + ((s).shver & 1)] = 
+    (shellface) encode2((t).tet, stbondtbl[t.ver][s.shver]);
+}
+
+// tspivot() finds a subface (s) abutting on the given tetrahdera (t).
+//   Return s.sh = NULL if there is no subface at t. Otherwise, return
+//   the subface s, and s and t must be at the same edge wth the same
+//   orientation.
+
+inline void tetgenmesh::tspivot(triface& t, face& s) 
+{
+  if ((t).tet[9] == NULL) {
+    (s).sh = NULL;
+    return;
+  }
+  // Get the attached subface s.
+  sdecode(((shellface *) (t).tet[9])[(t).ver & 3], (s));
+  (s).shver = tspivottbl[t.ver][s.shver];
+}
+
+// Quickly check if the handle (t, v) is a subface.
+#define issubface(t) \
+  ((t).tet[9] && ((t).tet[9])[(t).ver & 3])
+
+// stpivot() finds a tetrahedron (t) abutting a given subface (s).
+//   Return the t (if it exists) with the same edge and the same
+//   orientation of s.
+
+inline void tetgenmesh::stpivot(face& s, triface& t) 
+{
+  decode((tetrahedron) s.sh[9 + (s.shver & 1)], t);
+  if ((t).tet == NULL) {
+    return;
+  }
+  (t).ver = stpivottbl[t.ver][s.shver];
+}
+
+// Quickly check if this subface is attached to a tetrahedron.
+
+#define isshtet(s) \
+  ((s).sh[9 + ((s).shver & 1)])
+
+// tsdissolve() dissolve a bond (from the tetrahedron side).
+
+inline void tetgenmesh::tsdissolve(triface& t) 
+{
+  if ((t).tet[9] != NULL) {
+    ((shellface *) (t).tet[9])[(t).ver & 3] = NULL;
+  }
+}
+
+// stdissolve() dissolve a bond (from the subface side).
+
+inline void tetgenmesh::stdissolve(face& s) 
+{
+  (s).sh[9] = NULL;
+  (s).sh[10] = NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Primitives for interacting between subfaces and segments                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// ssbond() bond a subface to a subsegment.
+
+inline void tetgenmesh::ssbond(face& s, face& edge) 
+{
+  s.sh[6 + (s.shver >> 1)] = sencode(edge);
+  edge.sh[0] = sencode(s);
+}
+
+inline void tetgenmesh::ssbond1(face& s, face& edge) 
+{
+  s.sh[6 + (s.shver >> 1)] = sencode(edge);
+  //edge.sh[0] = sencode(s);
+}
+
+// ssdisolve() dissolve a bond (from the subface side)
+
+inline void tetgenmesh::ssdissolve(face& s) 
+{
+  s.sh[6 + (s.shver >> 1)] = NULL;
+}
+
+// sspivot() finds a subsegment abutting a subface.
+
+inline void tetgenmesh::sspivot(face& s, face& edge) 
+{
+  sdecode((shellface) s.sh[6 + (s.shver >> 1)], edge);
+}
+
+// Quickly check if the edge is a subsegment.
+
+#define isshsubseg(s) \
+  ((s).sh[6 + ((s).shver >> 1)])
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Primitives for interacting between tetrahedra and segments                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+inline void tetgenmesh::tssbond1(triface& t, face& s)
+{
+  if ((t).tet[8] == NULL) {
+    // Allocate space for this tet.
+    (t).tet[8] = (tetrahedron) tet2segpool->alloc();
+    // Initialization.
+    for (int i = 0; i < 6; i++) {
+      ((shellface *) (t).tet[8])[i] = NULL;
+    }
+  }
+  ((shellface *) (t).tet[8])[ver2edge[(t).ver]] = sencode((s)); 
+}
+
+inline void tetgenmesh::sstbond1(face& s, triface& t) 
+{
+  ((tetrahedron *) (s).sh)[9] = encode(t);
+}
+
+inline void tetgenmesh::tssdissolve1(triface& t)
+{
+  if ((t).tet[8] != NULL) {
+    ((shellface *) (t).tet[8])[ver2edge[(t).ver]] = NULL;
+  }
+}
+
+inline void tetgenmesh::sstdissolve1(face& s) 
+{
+  ((tetrahedron *) (s).sh)[9] = NULL;
+}
+
+inline void tetgenmesh::tsspivot1(triface& t, face& s)
+{
+  if ((t).tet[8] != NULL) {
+    sdecode(((shellface *) (t).tet[8])[ver2edge[(t).ver]], s);
+  } else {
+    (s).sh = NULL;
+  }
+}
+
+// Quickly check whether 't' is a segment or not.
+
+#define issubseg(t) \
+  ((t).tet[8] && ((t).tet[8])[ver2edge[(t).ver]])
+
+inline void tetgenmesh::sstpivot1(face& s, triface& t) 
+{
+  decode((tetrahedron) s.sh[9], t);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Primitives for points                                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+inline int tetgenmesh::pointmark(point pt) { 
+  return ((int *) (pt))[pointmarkindex]; 
+}
+
+inline void tetgenmesh::setpointmark(point pt, int value) {
+  ((int *) (pt))[pointmarkindex] = value;
+}
+
+
+// These two primitives set and read the type of the point.
+
+inline enum tetgenmesh::verttype tetgenmesh::pointtype(point pt) {
+  return (enum verttype) (((int *) (pt))[pointmarkindex + 1] >> (int) 8);
+}
+
+inline void tetgenmesh::setpointtype(point pt, enum verttype value) {
+  ((int *) (pt))[pointmarkindex + 1] = 
+    ((int) value << 8) + (((int *) (pt))[pointmarkindex + 1] & (int) 255);
+}
+
+// Read and set the geometry tag of the point (used by -s option).
+
+inline int tetgenmesh::pointgeomtag(point pt) { 
+  return ((int *) (pt))[pointmarkindex + 2]; 
+}
+
+inline void tetgenmesh::setpointgeomtag(point pt, int value) {
+  ((int *) (pt))[pointmarkindex + 2] = value;
+}
+
+// Read and set the u,v coordinates of the point (used by -s option).
+
+inline REAL tetgenmesh::pointgeomuv(point pt, int i) {
+  return pt[pointparamindex + i];
+}
+
+inline void tetgenmesh::setpointgeomuv(point pt, int i, REAL value) {
+  pt[pointparamindex + i] = value;
+}
+
+// pinfect(), puninfect(), pinfected() -- primitives to flag or unflag
+//   a point. The last bit of the integer '[pointindex+1]' is flagged.
+
+inline void tetgenmesh::pinfect(point pt) {
+  ((int *) (pt))[pointmarkindex + 1] |= (int) 1;
+}
+
+inline void tetgenmesh::puninfect(point pt) {
+  ((int *) (pt))[pointmarkindex + 1] &= ~(int) 1;
+}
+
+inline bool tetgenmesh::pinfected(point pt) {
+  return (((int *) (pt))[pointmarkindex + 1] & (int) 1) != 0;
+}
+
+// pmarktest(), punmarktest(), pmarktested() -- more primitives to 
+//   flag or unflag a point. 
+
+inline void tetgenmesh::pmarktest(point pt) {
+  ((int *) (pt))[pointmarkindex + 1] |= (int) 2;
+}
+
+inline void tetgenmesh::punmarktest(point pt) {
+  ((int *) (pt))[pointmarkindex + 1] &= ~(int) 2;
+}
+
+inline bool tetgenmesh::pmarktested(point pt) {
+  return (((int *) (pt))[pointmarkindex + 1] & (int) 2) != 0;
+}
+
+inline void tetgenmesh::pmarktest2(point pt) {
+  ((int *) (pt))[pointmarkindex + 1] |= (int) 4;
+}
+
+inline void tetgenmesh::punmarktest2(point pt) {
+  ((int *) (pt))[pointmarkindex + 1] &= ~(int) 4;
+}
+
+inline bool tetgenmesh::pmarktest2ed(point pt) {
+  return (((int *) (pt))[pointmarkindex + 1] & (int) 4) != 0;
+}
+
+inline void tetgenmesh::pmarktest3(point pt) {
+  ((int *) (pt))[pointmarkindex + 1] |= (int) 8;
+}
+
+inline void tetgenmesh::punmarktest3(point pt) {
+  ((int *) (pt))[pointmarkindex + 1] &= ~(int) 8;
+}
+
+inline bool tetgenmesh::pmarktest3ed(point pt) {
+  return (((int *) (pt))[pointmarkindex + 1] & (int) 8) != 0;
+}
+
+// These following primitives set and read a pointer to a tetrahedron
+//   a subface/subsegment, a point, or a tet of background mesh.
+
+inline tetgenmesh::tetrahedron tetgenmesh::point2tet(point pt) {
+  return ((tetrahedron *) (pt))[point2simindex];
+}
+
+inline void tetgenmesh::setpoint2tet(point pt, tetrahedron value) {
+  ((tetrahedron *) (pt))[point2simindex] = value;
+}
+
+inline tetgenmesh::point tetgenmesh::point2ppt(point pt) {
+  return (point) ((tetrahedron *) (pt))[point2simindex + 1];
+}
+
+inline void tetgenmesh::setpoint2ppt(point pt, point value) {
+  ((tetrahedron *) (pt))[point2simindex + 1] = (tetrahedron) value;
+}
+
+inline tetgenmesh::shellface tetgenmesh::point2sh(point pt) {
+  return (shellface) ((tetrahedron *) (pt))[point2simindex + 2];
+}
+
+inline void tetgenmesh::setpoint2sh(point pt, shellface value) {
+  ((tetrahedron *) (pt))[point2simindex + 2] = (tetrahedron) value;
+}
+
+
+inline tetgenmesh::tetrahedron tetgenmesh::point2bgmtet(point pt) {
+  return ((tetrahedron *) (pt))[point2simindex + 3];
+}
+
+inline void tetgenmesh::setpoint2bgmtet(point pt, tetrahedron value) {
+  ((tetrahedron *) (pt))[point2simindex + 3] = value;
+}
+
+
+// The primitives for saving and getting the insertion radius.
+inline void tetgenmesh::setpointinsradius(point pt, REAL value)
+{
+  pt[pointmtrindex + sizeoftensor - 1] = value;
+}
+
+inline REAL tetgenmesh::getpointinsradius(point pt)
+{
+  return pt[pointmtrindex + sizeoftensor - 1];
+}
+
+// point2tetorg()    Get the tetrahedron whose origin is the point.
+
+inline void tetgenmesh::point2tetorg(point pa, triface& searchtet)
+{
+  decode(point2tet(pa), searchtet);
+  if ((point) searchtet.tet[4] == pa) {
+    searchtet.ver = 11;
+  } else if ((point) searchtet.tet[5] == pa) {
+    searchtet.ver = 3;
+  } else if ((point) searchtet.tet[6] == pa) {
+    searchtet.ver = 7;
+  } else {
+    assert((point) searchtet.tet[7] == pa); // SELF_CHECK
+    searchtet.ver = 0;
+  }
+}
+
+// point2shorg()    Get the subface/segment whose origin is the point.
+
+inline void tetgenmesh::point2shorg(point pa, face& searchsh)
+{
+  sdecode(point2sh(pa), searchsh);
+  if ((point) searchsh.sh[3] == pa) {
+    searchsh.shver = 0;
+  } else if ((point) searchsh.sh[4] == pa) {
+    searchsh.shver = (searchsh.sh[5] != NULL ? 2 : 1); 
+  } else {
+    assert((point) searchsh.sh[5] == pa); // SELF_CHECK
+    searchsh.shver = 4;
+  }
+}
+
+// farsorg()    Return the origin of the subsegment.
+// farsdest()   Return the destination of the subsegment.
+
+inline tetgenmesh::point tetgenmesh::farsorg(face& s)
+{
+  face travesh, neighsh;
+
+  travesh = s;
+  while (1) {
+    senext2(travesh, neighsh);
+    spivotself(neighsh); 
+    if (neighsh.sh == NULL) break;
+    if (sorg(neighsh) != sorg(travesh)) sesymself(neighsh);
+    senext2(neighsh, travesh); 
+  }
+  return sorg(travesh);
+}
+
+inline tetgenmesh::point tetgenmesh::farsdest(face& s) 
+{
+  face travesh, neighsh;
+
+  travesh = s;
+  while (1) {
+    senext(travesh, neighsh);
+    spivotself(neighsh); 
+    if (neighsh.sh == NULL) break;
+    if (sdest(neighsh) != sdest(travesh)) sesymself(neighsh);
+    senext(neighsh, travesh); 
+  }
+  return sdest(travesh);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Linear algebra operators.                                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// dot() returns the dot product: v1 dot v2.
+inline REAL tetgenmesh::dot(REAL* v1, REAL* v2) 
+{
+  return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
+}
+
+// cross() computes the cross product: n = v1 cross v2.
+inline void tetgenmesh::cross(REAL* v1, REAL* v2, REAL* 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];
+}
+
+// distance() computes the Euclidean distance between two points.
+inline REAL tetgenmesh::distance(REAL* p1, REAL* p2)
+{
+  return sqrt((p2[0] - p1[0]) * (p2[0] - p1[0]) +
+              (p2[1] - p1[1]) * (p2[1] - p1[1]) +
+              (p2[2] - p1[2]) * (p2[2] - p1[2]));
+}
+
+inline REAL tetgenmesh::norm2(REAL x, REAL y, REAL z)
+{
+  return (x) * (x) + (y) * (y) + (z) * (z);
+}
+
+
+#endif // #ifndef tetgenH
+
diff --git a/meshpy/src/cpp/triangle.c b/meshpy/src/cpp/triangle.c
new file mode 100644
index 0000000000000000000000000000000000000000..d07556b1aa1b0945cad8ca3e9f9382e7346b445a
--- /dev/null
+++ b/meshpy/src/cpp/triangle.c
@@ -0,0 +1,16017 @@
+/*****************************************************************************/
+/*                                                                           */
+/*      888888888        ,o,                          / 888                  */
+/*         888    88o88o  "    o8888o  88o8888o o88888o 888  o88888o         */
+/*         888    888    888       88b 888  888 888 888 888 d888  88b        */
+/*         888    888    888  o88^o888 888  888 "88888" 888 8888oo888        */
+/*         888    888    888 C888  888 888  888  /      888 q888             */
+/*         888    888    888  "88o^888 888  888 Cb      888  "88oooo"        */
+/*                                              "8oo8D                       */
+/*                                                                           */
+/*  A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.      */
+/*  (triangle.c)                                                             */
+/*                                                                           */
+/*  Version 1.6                                                              */
+/*  July 28, 2005                                                            */
+/*                                                                           */
+/*  Copyright 1993, 1995, 1997, 1998, 2002, 2005                             */
+/*  Jonathan Richard Shewchuk                                                */
+/*  2360 Woolsey #H                                                          */
+/*  Berkeley, California  94705-1927                                         */
+/*  jrs@cs.berkeley.edu                                                      */
+/*                                                                           */
+/*  This program may be freely redistributed under the condition that the    */
+/*    copyright notices (including this entire header and the copyright      */
+/*    notice printed when the `-h' switch is selected) are not removed, and  */
+/*    no compensation is received.  Private, research, and institutional     */
+/*    use is free.  You may distribute modified versions of this code UNDER  */
+/*    THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE   */
+/*    SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE   */
+/*    AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR    */
+/*    NOTICE IS GIVEN OF THE MODIFICATIONS.  Distribution of this code as    */
+/*    part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT  */
+/*    WITH THE AUTHOR.  (If you are not directly supplying this code to a    */
+/*    customer, and you are instead telling them how they can obtain it for  */
+/*    free, then you are not required to make any arrangement with me.)      */
+/*                                                                           */
+/*  Hypertext instructions for Triangle are available on the Web at          */
+/*                                                                           */
+/*      http://www.cs.cmu.edu/~quake/triangle.html                           */
+/*                                                                           */
+/*  Disclaimer:  Neither I nor Carnegie Mellon warrant this code in any way  */
+/*    whatsoever.  This code is provided "as-is".  Use at your own risk.     */
+/*                                                                           */
+/*  Some of the references listed below are marked with an asterisk.  [*]    */
+/*    These references are available for downloading from the Web page       */
+/*                                                                           */
+/*      http://www.cs.cmu.edu/~quake/triangle.research.html                  */
+/*                                                                           */
+/*  Three papers discussing aspects of Triangle are available.  A short      */
+/*    overview appears in "Triangle:  Engineering a 2D Quality Mesh          */
+/*    Generator and Delaunay Triangulator," in Applied Computational         */
+/*    Geometry:  Towards Geometric Engineering, Ming C. Lin and Dinesh       */
+/*    Manocha, editors, Lecture Notes in Computer Science volume 1148,       */
+/*    pages 203-222, Springer-Verlag, Berlin, May 1996 (from the First ACM   */
+/*    Workshop on Applied Computational Geometry).  [*]                      */
+/*                                                                           */
+/*    The algorithms are discussed in the greatest detail in "Delaunay       */
+/*    Refinement Algorithms for Triangular Mesh Generation," Computational   */
+/*    Geometry:  Theory and Applications 22(1-3):21-74, May 2002.  [*]       */
+/*                                                                           */
+/*    More detail about the data structures may be found in my dissertation: */
+/*    "Delaunay Refinement Mesh Generation," Ph.D. thesis, Technical Report  */
+/*    CMU-CS-97-137, School of Computer Science, Carnegie Mellon University, */
+/*    Pittsburgh, Pennsylvania, 18 May 1997.  [*]                            */
+/*                                                                           */
+/*  Triangle was created as part of the Quake Project in the School of       */
+/*    Computer Science at Carnegie Mellon University.  For further           */
+/*    information, see Hesheng Bao, Jacobo Bielak, Omar Ghattas, Loukas F.   */
+/*    Kallivokas, David R. O'Hallaron, Jonathan R. Shewchuk, and Jifeng Xu,  */
+/*    "Large-scale Simulation of Elastic Wave Propagation in Heterogeneous   */
+/*    Media on Parallel Computers," Computer Methods in Applied Mechanics    */
+/*    and Engineering 152(1-2):85-102, 22 January 1998.                      */
+/*                                                                           */
+/*  Triangle's Delaunay refinement algorithm for quality mesh generation is  */
+/*    a hybrid of one due to Jim Ruppert, "A Delaunay Refinement Algorithm   */
+/*    for Quality 2-Dimensional Mesh Generation," Journal of Algorithms      */
+/*    18(3):548-585, May 1995 [*], and one due to L. Paul Chew, "Guaranteed- */
+/*    Quality Mesh Generation for Curved Surfaces," Proceedings of the Ninth */
+/*    Annual Symposium on Computational Geometry (San Diego, California),    */
+/*    pages 274-280, Association for Computing Machinery, May 1993,          */
+/*    http://portal.acm.org/citation.cfm?id=161150 .                         */
+/*                                                                           */
+/*  The Delaunay refinement algorithm has been modified so that it meshes    */
+/*    domains with small input angles well, as described in Gary L. Miller,  */
+/*    Steven E. Pav, and Noel J. Walkington, "When and Why Ruppert's         */
+/*    Algorithm Works," Twelfth International Meshing Roundtable, pages      */
+/*    91-102, Sandia National Laboratories, September 2003.  [*]             */
+/*                                                                           */
+/*  My implementation of the divide-and-conquer and incremental Delaunay     */
+/*    triangulation algorithms follows closely the presentation of Guibas    */
+/*    and Stolfi, even though I use a triangle-based data structure instead  */
+/*    of their quad-edge data structure.  (In fact, I originally implemented */
+/*    Triangle using the quad-edge data structure, but the switch to a       */
+/*    triangle-based data structure sped Triangle by a factor of two.)  The  */
+/*    mesh manipulation primitives and the two aforementioned Delaunay       */
+/*    triangulation algorithms are described by Leonidas J. Guibas and Jorge */
+/*    Stolfi, "Primitives for the Manipulation of General Subdivisions and   */
+/*    the Computation of Voronoi Diagrams," ACM Transactions on Graphics     */
+/*    4(2):74-123, April 1985, http://portal.acm.org/citation.cfm?id=282923 .*/
+/*                                                                           */
+/*  Their O(n log n) divide-and-conquer algorithm is adapted from Der-Tsai   */
+/*    Lee and Bruce J. Schachter, "Two Algorithms for Constructing the       */
+/*    Delaunay Triangulation," International Journal of Computer and         */
+/*    Information Science 9(3):219-242, 1980.  Triangle's improvement of the */
+/*    divide-and-conquer algorithm by alternating between vertical and       */
+/*    horizontal cuts was introduced by Rex A. Dwyer, "A Faster Divide-and-  */
+/*    Conquer Algorithm for Constructing Delaunay Triangulations,"           */
+/*    Algorithmica 2(2):137-151, 1987.                                       */
+/*                                                                           */
+/*  The incremental insertion algorithm was first proposed by C. L. Lawson,  */
+/*    "Software for C1 Surface Interpolation," in Mathematical Software III, */
+/*    John R. Rice, editor, Academic Press, New York, pp. 161-194, 1977.     */
+/*    For point location, I use the algorithm of Ernst P. Mucke, Isaac       */
+/*    Saias, and Binhai Zhu, "Fast Randomized Point Location Without         */
+/*    Preprocessing in Two- and Three-Dimensional Delaunay Triangulations,"  */
+/*    Proceedings of the Twelfth Annual Symposium on Computational Geometry, */
+/*    ACM, May 1996.  [*]  If I were to randomize the order of vertex        */
+/*    insertion (I currently don't bother), their result combined with the   */
+/*    result of Kenneth L. Clarkson and Peter W. Shor, "Applications of      */
+/*    Random Sampling in Computational Geometry II," Discrete &              */
+/*    Computational Geometry 4(1):387-421, 1989, would yield an expected     */
+/*    O(n^{4/3}) bound on running time.                                      */
+/*                                                                           */
+/*  The O(n log n) sweepline Delaunay triangulation algorithm is taken from  */
+/*    Steven Fortune, "A Sweepline Algorithm for Voronoi Diagrams",          */
+/*    Algorithmica 2(2):153-174, 1987.  A random sample of edges on the      */
+/*    boundary of the triangulation are maintained in a splay tree for the   */
+/*    purpose of point location.  Splay trees are described by Daniel        */
+/*    Dominic Sleator and Robert Endre Tarjan, "Self-Adjusting Binary Search */
+/*    Trees," Journal of the ACM 32(3):652-686, July 1985,                   */
+/*    http://portal.acm.org/citation.cfm?id=3835 .                           */
+/*                                                                           */
+/*  The algorithms for exact computation of the signs of determinants are    */
+/*    described in Jonathan Richard Shewchuk, "Adaptive Precision Floating-  */
+/*    Point Arithmetic and Fast Robust Geometric Predicates," Discrete &     */
+/*    Computational Geometry 18(3):305-363, October 1997.  (Also available   */
+/*    as Technical Report CMU-CS-96-140, School of Computer Science,         */
+/*    Carnegie Mellon University, Pittsburgh, Pennsylvania, May 1996.)  [*]  */
+/*    An abbreviated version appears as Jonathan Richard Shewchuk, "Robust   */
+/*    Adaptive Floating-Point Geometric Predicates," Proceedings of the      */
+/*    Twelfth Annual Symposium on Computational Geometry, ACM, May 1996. [*] */
+/*    Many of the ideas for my exact arithmetic routines originate with      */
+/*    Douglas M. Priest, "Algorithms for Arbitrary Precision Floating Point  */
+/*    Arithmetic," Tenth Symposium on Computer Arithmetic, pp. 132-143, IEEE */
+/*    Computer Society Press, 1991.  [*]  Many of the ideas for the correct  */
+/*    evaluation of the signs of determinants are taken from Steven Fortune  */
+/*    and Christopher J. Van Wyk, "Efficient Exact Arithmetic for Computa-   */
+/*    tional Geometry," Proceedings of the Ninth Annual Symposium on         */
+/*    Computational Geometry, ACM, pp. 163-172, May 1993, and from Steven    */
+/*    Fortune, "Numerical Stability of Algorithms for 2D Delaunay Triangu-   */
+/*    lations," International Journal of Computational Geometry & Applica-   */
+/*    tions 5(1-2):193-213, March-June 1995.                                 */
+/*                                                                           */
+/*  The method of inserting new vertices off-center (not precisely at the    */
+/*    circumcenter of every poor-quality triangle) is from Alper Ungor,      */
+/*    "Off-centers:  A New Type of Steiner Points for Computing Size-Optimal */
+/*    Quality-Guaranteed Delaunay Triangulations," Proceedings of LATIN      */
+/*    2004 (Buenos Aires, Argentina), April 2004.                            */
+/*                                                                           */
+/*  For definitions of and results involving Delaunay triangulations,        */
+/*    constrained and conforming versions thereof, and other aspects of      */
+/*    triangular mesh generation, see the excellent survey by Marshall Bern  */
+/*    and David Eppstein, "Mesh Generation and Optimal Triangulation," in    */
+/*    Computing and Euclidean Geometry, Ding-Zhu Du and Frank Hwang,         */
+/*    editors, World Scientific, Singapore, pp. 23-90, 1992.  [*]            */
+/*                                                                           */
+/*  The time for incrementally adding PSLG (planar straight line graph)      */
+/*    segments to create a constrained Delaunay triangulation is probably    */
+/*    O(t^2) per segment in the worst case and O(t) per segment in the       */
+/*    common case, where t is the number of triangles that intersect the     */
+/*    segment before it is inserted.  This doesn't count point location,     */
+/*    which can be much more expensive.  I could improve this to O(d log d)  */
+/*    time, but d is usually quite small, so it's not worth the bother.      */
+/*    (This note does not apply when the -s switch is used, invoking a       */
+/*    different method is used to insert segments.)                          */
+/*                                                                           */
+/*  The time for deleting a vertex from a Delaunay triangulation is O(d^2)   */
+/*    in the worst case and O(d) in the common case, where d is the degree   */
+/*    of the vertex being deleted.  I could improve this to O(d log d) time, */
+/*    but d is usually quite small, so it's not worth the bother.            */
+/*                                                                           */
+/*  Ruppert's Delaunay refinement algorithm typically generates triangles    */
+/*    at a linear rate (constant time per triangle) after the initial        */
+/*    triangulation is formed.  There may be pathological cases where        */
+/*    quadratic time is required, but these never arise in practice.         */
+/*                                                                           */
+/*  The geometric predicates (circumcenter calculations, segment             */
+/*    intersection formulae, etc.) appear in my "Lecture Notes on Geometric  */
+/*    Robustness" at http://www.cs.berkeley.edu/~jrs/mesh .                  */
+/*                                                                           */
+/*  If you make any improvements to this code, please please please let me   */
+/*    know, so that I may obtain the improvements.  Even if you don't change */
+/*    the code, I'd still love to hear what it's being used for.             */
+/*                                                                           */
+/*****************************************************************************/
+
+/* For single precision (which will save some memory and reduce paging),     */
+/*   define the symbol SINGLE by using the -DSINGLE compiler switch or by    */
+/*   writing "#define SINGLE" below.                                         */
+/*                                                                           */
+/* For double precision (which will allow you to refine meshes to a smaller  */
+/*   edge length), leave SINGLE undefined.                                   */
+/*                                                                           */
+/* Double precision uses more memory, but improves the resolution of the     */
+/*   meshes you can generate with Triangle.  It also reduces the likelihood  */
+/*   of a floating exception due to overflow.  Finally, it is much faster    */
+/*   than single precision on 64-bit architectures like the DEC Alpha.  I    */
+/*   recommend double precision unless you want to generate a mesh for which */
+/*   you do not have enough memory.                                          */
+
+/* #define SINGLE */
+
+#ifdef SINGLE
+#define REAL float
+#else /* not SINGLE */
+#define REAL double
+#endif /* not SINGLE */
+
+/* If yours is not a Unix system, define the NO_TIMER compiler switch to     */
+/*   remove the Unix-specific timing code.                                   */
+
+#define NO_TIMER
+
+/* To insert lots of self-checks for internal errors, define the SELF_CHECK  */
+/*   symbol.  This will slow down the program significantly.  It is best to  */
+/*   define the symbol using the -DSELF_CHECK compiler switch, but you could */
+/*   write "#define SELF_CHECK" below.  If you are modifying this code, I    */
+/*   recommend you turn self-checks on until your work is debugged.          */
+
+/* #define SELF_CHECK */
+
+/* To compile Triangle as a callable object library (triangle.o), define the */
+/*   TRILIBRARY symbol.  Read the file triangle.h for details on how to call */
+/*   the procedure triangulate() that results.                               */
+
+/* #define TRILIBRARY */
+
+/* It is possible to generate a smaller version of Triangle using one or     */
+/*   both of the following symbols.  Define the REDUCED symbol to eliminate  */
+/*   all features that are primarily of research interest; specifically, the */
+/*   -i, -F, -s, and -C switches.  Define the CDT_ONLY symbol to eliminate   */
+/*   all meshing algorithms above and beyond constrained Delaunay            */
+/*   triangulation; specifically, the -r, -q, -a, -u, -D, -S, and -s         */
+/*   switches.  These reductions are most likely to be useful when           */
+/*   generating an object library (triangle.o) by defining the TRILIBRARY    */
+/*   symbol.                                                                 */
+
+/* #define REDUCED */
+/* #define CDT_ONLY */
+
+/* On some machines, my exact arithmetic routines might be defeated by the   */
+/*   use of internal extended precision floating-point registers.  The best  */
+/*   way to solve this problem is to set the floating-point registers to use */
+/*   single or double precision internally.  On 80x86 processors, this may   */
+/*   be accomplished by setting the CPU86 symbol for the Microsoft C         */
+/*   compiler, or the LINUX symbol for the gcc compiler running on Linux.    */
+/*                                                                           */
+/* An inferior solution is to declare certain values as `volatile', thus     */
+/*   forcing them to be stored to memory and rounded off.  Unfortunately,    */
+/*   this solution might slow Triangle down quite a bit.  To use volatile    */
+/*   values, write "#define INEXACT volatile" below.  Normally, however,     */
+/*   INEXACT should be defined to be nothing.  ("#define INEXACT".)          */
+/*                                                                           */
+/* For more discussion, see http://www.cs.cmu.edu/~quake/robust.pc.html .    */
+/*   For yet more discussion, see Section 5 of my paper, "Adaptive Precision */
+/*   Floating-Point Arithmetic and Fast Robust Geometric Predicates" (also   */
+/*   available as Section 6.6 of my dissertation).                           */
+
+void exactdeinit(void);
+
+/* #define CPU86 */
+/* #define LINUX */
+
+#if defined(__linux__) && defined(__i386__)
+  #define LINUX 1
+#endif
+
+#define INEXACT /* Nothing */
+/* #define INEXACT volatile */
+
+/* Maximum number of characters in a file name (including the null).         */
+
+#define FILENAMESIZE 2048
+
+/* Maximum number of characters in a line read from a file (including the    */
+/*   null).                                                                  */
+
+#define INPUTLINESIZE 1024
+
+/* For efficiency, a variety of data structures are allocated in bulk.  The  */
+/*   following constants determine how many of each structure is allocated   */
+/*   at once.                                                                */
+
+#define TRIPERBLOCK 4092           /* Number of triangles allocated at once. */
+#define SUBSEGPERBLOCK 508       /* Number of subsegments allocated at once. */
+#define VERTEXPERBLOCK 4092         /* Number of vertices allocated at once. */
+#define VIRUSPERBLOCK 1020   /* Number of virus triangles allocated at once. */
+/* Number of encroached subsegments allocated at once. */
+#define BADSUBSEGPERBLOCK 252
+/* Number of skinny triangles allocated at once. */
+#define BADTRIPERBLOCK 4092
+/* Number of flipped triangles allocated at once. */
+#define FLIPSTACKERPERBLOCK 252
+/* Number of splay tree nodes allocated at once. */
+#define SPLAYNODEPERBLOCK 508
+
+/* The vertex types.   A DEADVERTEX has been deleted entirely.  An           */
+/*   UNDEADVERTEX is not part of the mesh, but is written to the output      */
+/*   .node file and affects the node indexing in the other output files.     */
+
+#define INPUTVERTEX 0
+#define SEGMENTVERTEX 1
+#define FREEVERTEX 2
+#define DEADVERTEX -32768
+#define UNDEADVERTEX -32767
+
+/* The next line is used to outsmart some very stupid compilers.  If your    */
+/*   compiler is smarter, feel free to replace the "int" with "void".        */
+/*   Not that it matters.                                                    */
+
+// #define VOID int
+
+/* Two constants for algorithms based on random sampling.  Both constants    */
+/*   have been chosen empirically to optimize their respective algorithms.   */
+
+/* Used for the point location scheme of Mucke, Saias, and Zhu, to decide    */
+/*   how large a random sample of triangles to inspect.                      */
+
+#define SAMPLEFACTOR 11
+
+/* Used in Fortune's sweepline Delaunay algorithm to determine what fraction */
+/*   of boundary edges should be maintained in the splay tree for point      */
+/*   location on the front.                                                  */
+
+#define SAMPLERATE 10
+
+/* A number that speaks for itself, every kissable digit.                    */
+
+#define PI 3.141592653589793238462643383279502884197169399375105820974944592308
+
+/* Another fave.                                                             */
+
+#define SQUAREROOTTWO 1.4142135623730950488016887242096980785696718753769480732
+
+/* And here's one for those of you who are intimidated by math.              */
+
+#define ONETHIRD 0.333333333333333333333333333333333333333333333333333333333333
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#ifndef NO_TIMER
+#include <sys/time.h>
+#endif /* not NO_TIMER */
+#ifdef CPU86
+#include <float.h>
+#endif /* CPU86 */
+#ifdef LINUX
+#include <fpu_control.h>
+#endif /* LINUX */
+#ifdef TRILIBRARY
+#include "triangle.h"
+#endif /* TRILIBRARY */
+
+/* A few forward declarations.                                               */
+
+#ifndef TRILIBRARY
+char *readline();
+char *findfield();
+#endif /* not TRILIBRARY */
+
+/* Labels that signify the result of point location.  The result of a        */
+/*   search indicates that the point falls in the interior of a triangle, on */
+/*   an edge, on a vertex, or outside the mesh.                              */
+
+enum locateresult {INTRIANGLE, ONEDGE, ONVERTEX, OUTSIDE};
+
+/* Labels that signify the result of vertex insertion.  The result indicates */
+/*   that the vertex was inserted with complete success, was inserted but    */
+/*   encroaches upon a subsegment, was not inserted because it lies on a     */
+/*   segment, or was not inserted because another vertex occupies the same   */
+/*   location.                                                               */
+
+enum insertvertexresult {SUCCESSFULVERTEX, ENCROACHINGVERTEX, VIOLATINGVERTEX,
+                         DUPLICATEVERTEX};
+
+/* Labels that signify the result of direction finding.  The result          */
+/*   indicates that a segment connecting the two query points falls within   */
+/*   the direction triangle, along the left edge of the direction triangle,  */
+/*   or along the right edge of the direction triangle.                      */
+
+enum finddirectionresult {WITHIN, LEFTCOLLINEAR, RIGHTCOLLINEAR};
+
+/*****************************************************************************/
+/*                                                                           */
+/*  The basic mesh data structures                                           */
+/*                                                                           */
+/*  There are three:  vertices, triangles, and subsegments (abbreviated      */
+/*  `subseg').  These three data structures, linked by pointers, comprise    */
+/*  the mesh.  A vertex simply represents a mesh vertex and its properties.  */
+/*  A triangle is a triangle.  A subsegment is a special data structure used */
+/*  to represent an impenetrable edge of the mesh (perhaps on the outer      */
+/*  boundary, on the boundary of a hole, or part of an internal boundary     */
+/*  separating two triangulated regions).  Subsegments represent boundaries, */
+/*  defined by the user, that triangles may not lie across.                  */
+/*                                                                           */
+/*  A triangle consists of a list of three vertices, a list of three         */
+/*  adjoining triangles, a list of three adjoining subsegments (when         */
+/*  segments exist), an arbitrary number of optional user-defined            */
+/*  floating-point attributes, and an optional area constraint.  The latter  */
+/*  is an upper bound on the permissible area of each triangle in a region,  */
+/*  used for mesh refinement.                                                */
+/*                                                                           */
+/*  For a triangle on a boundary of the mesh, some or all of the neighboring */
+/*  triangles may not be present.  For a triangle in the interior of the     */
+/*  mesh, often no neighboring subsegments are present.  Such absent         */
+/*  triangles and subsegments are never represented by NULL pointers; they   */
+/*  are represented by two special records:  `dummytri', the triangle that   */
+/*  fills "outer space", and `dummysub', the omnipresent subsegment.         */
+/*  `dummytri' and `dummysub' are used for several reasons; for instance,    */
+/*  they can be dereferenced and their contents examined without violating   */
+/*  protected memory.                                                        */
+/*                                                                           */
+/*  However, it is important to understand that a triangle includes other    */
+/*  information as well.  The pointers to adjoining vertices, triangles, and */
+/*  subsegments are ordered in a way that indicates their geometric relation */
+/*  to each other.  Furthermore, each of these pointers contains orientation */
+/*  information.  Each pointer to an adjoining triangle indicates which face */
+/*  of that triangle is contacted.  Similarly, each pointer to an adjoining  */
+/*  subsegment indicates which side of that subsegment is contacted, and how */
+/*  the subsegment is oriented relative to the triangle.                     */
+/*                                                                           */
+/*  The data structure representing a subsegment may be thought to be        */
+/*  abutting the edge of one or two triangle data structures:  either        */
+/*  sandwiched between two triangles, or resting against one triangle on an  */
+/*  exterior boundary or hole boundary.                                      */
+/*                                                                           */
+/*  A subsegment consists of a list of four vertices--the vertices of the    */
+/*  subsegment, and the vertices of the segment it is a part of--a list of   */
+/*  two adjoining subsegments, and a list of two adjoining triangles.  One   */
+/*  of the two adjoining triangles may not be present (though there should   */
+/*  always be one), and neighboring subsegments might not be present.        */
+/*  Subsegments also store a user-defined integer "boundary marker".         */
+/*  Typically, this integer is used to indicate what boundary conditions are */
+/*  to be applied at that location in a finite element simulation.           */
+/*                                                                           */
+/*  Like triangles, subsegments maintain information about the relative      */
+/*  orientation of neighboring objects.                                      */
+/*                                                                           */
+/*  Vertices are relatively simple.  A vertex is a list of floating-point    */
+/*  numbers, starting with the x, and y coordinates, followed by an          */
+/*  arbitrary number of optional user-defined floating-point attributes,     */
+/*  followed by an integer boundary marker.  During the segment insertion    */
+/*  phase, there is also a pointer from each vertex to a triangle that may   */
+/*  contain it.  Each pointer is not always correct, but when one is, it     */
+/*  speeds up segment insertion.  These pointers are assigned values once    */
+/*  at the beginning of the segment insertion phase, and are not used or     */
+/*  updated except during this phase.  Edge flipping during segment          */
+/*  insertion will render some of them incorrect.  Hence, don't rely upon    */
+/*  them for anything.                                                       */
+/*                                                                           */
+/*  Other than the exception mentioned above, vertices have no information   */
+/*  about what triangles, subfacets, or subsegments they are linked to.      */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  Handles                                                                  */
+/*                                                                           */
+/*  The oriented triangle (`otri') and oriented subsegment (`osub') data     */
+/*  structures defined below do not themselves store any part of the mesh.   */
+/*  The mesh itself is made of `triangle's, `subseg's, and `vertex's.        */
+/*                                                                           */
+/*  Oriented triangles and oriented subsegments will usually be referred to  */
+/*  as "handles."  A handle is essentially a pointer into the mesh; it       */
+/*  allows you to "hold" one particular part of the mesh.  Handles are used  */
+/*  to specify the regions in which one is traversing and modifying the mesh.*/
+/*  A single `triangle' may be held by many handles, or none at all.  (The   */
+/*  latter case is not a memory leak, because the triangle is still          */
+/*  connected to other triangles in the mesh.)                               */
+/*                                                                           */
+/*  An `otri' is a handle that holds a triangle.  It holds a specific edge   */
+/*  of the triangle.  An `osub' is a handle that holds a subsegment.  It     */
+/*  holds either the left or right side of the subsegment.                   */
+/*                                                                           */
+/*  Navigation about the mesh is accomplished through a set of mesh          */
+/*  manipulation primitives, further below.  Many of these primitives take   */
+/*  a handle and produce a new handle that holds the mesh near the first     */
+/*  handle.  Other primitives take two handles and glue the corresponding    */
+/*  parts of the mesh together.  The orientation of the handles is           */
+/*  important.  For instance, when two triangles are glued together by the   */
+/*  bond() primitive, they are glued at the edges on which the handles lie.  */
+/*                                                                           */
+/*  Because vertices have no information about which triangles they are      */
+/*  attached to, I commonly represent a vertex by use of a handle whose      */
+/*  origin is the vertex.  A single handle can simultaneously represent a    */
+/*  triangle, an edge, and a vertex.                                         */
+/*                                                                           */
+/*****************************************************************************/
+
+/* The triangle data structure.  Each triangle contains three pointers to    */
+/*   adjoining triangles, plus three pointers to vertices, plus three        */
+/*   pointers to subsegments (declared below; these pointers are usually     */
+/*   `dummysub').  It may or may not also contain user-defined attributes    */
+/*   and/or a floating-point "area constraint."  It may also contain extra   */
+/*   pointers for nodes, when the user asks for high-order elements.         */
+/*   Because the size and structure of a `triangle' is not decided until     */
+/*   runtime, I haven't simply declared the type `triangle' as a struct.     */
+
+typedef REAL **triangle;            /* Really:  typedef triangle *triangle   */
+
+/* An oriented triangle:  includes a pointer to a triangle and orientation.  */
+/*   The orientation denotes an edge of the triangle.  Hence, there are      */
+/*   three possible orientations.  By convention, each edge always points    */
+/*   counterclockwise about the corresponding triangle.                      */
+
+struct otri {
+  triangle *tri;
+  int orient;                                         /* Ranges from 0 to 2. */
+};
+
+/* The subsegment data structure.  Each subsegment contains two pointers to  */
+/*   adjoining subsegments, plus four pointers to vertices, plus two         */
+/*   pointers to adjoining triangles, plus one boundary marker, plus one     */
+/*   segment number.                                                         */
+
+typedef REAL **subseg;                  /* Really:  typedef subseg *subseg   */
+
+/* An oriented subsegment:  includes a pointer to a subsegment and an        */
+/*   orientation.  The orientation denotes a side of the edge.  Hence, there */
+/*   are two possible orientations.  By convention, the edge is always       */
+/*   directed so that the "side" denoted is the right side of the edge.      */
+
+struct osub {
+  subseg *ss;
+  int ssorient;                                       /* Ranges from 0 to 1. */
+};
+
+/* A queue used to store encroached subsegments.  Each subsegment's vertices */
+/*   are stored so that we can check whether a subsegment is still the same. */
+
+struct badsubseg {
+  subseg encsubseg;                             /* An encroached subsegment. */
+  vertex subsegorg, subsegdest;                         /* Its two vertices. */
+};
+
+/* A queue used to store bad triangles.  The key is the square of the cosine */
+/*   of the smallest angle of the triangle.  Each triangle's vertices are    */
+/*   stored so that one can check whether a triangle is still the same.      */
+
+struct badtriang {
+  triangle poortri;                       /* A skinny or too-large triangle. */
+  REAL key;                             /* cos^2 of smallest (apical) angle. */
+  vertex triangorg, triangdest, triangapex;           /* Its three vertices. */
+  struct badtriang *nexttriang;             /* Pointer to next bad triangle. */
+};
+
+/* A stack of triangles flipped during the most recent vertex insertion.     */
+/*   The stack is used to undo the vertex insertion if the vertex encroaches */
+/*   upon a subsegment.                                                      */
+
+struct flipstacker {
+  triangle flippedtri;                       /* A recently flipped triangle. */
+  struct flipstacker *prevflip;               /* Previous flip in the stack. */
+};
+
+/* A node in a heap used to store events for the sweepline Delaunay          */
+/*   algorithm.  Nodes do not point directly to their parents or children in */
+/*   the heap.  Instead, each node knows its position in the heap, and can   */
+/*   look up its parent and children in a separate array.  The `eventptr'    */
+/*   points either to a `vertex' or to a triangle (in encoded format, so     */
+/*   that an orientation is included).  In the latter case, the origin of    */
+/*   the oriented triangle is the apex of a "circle event" of the sweepline  */
+/*   algorithm.  To distinguish site events from circle events, all circle   */
+/*   events are given an invalid (smaller than `xmin') x-coordinate `xkey'.  */
+
+struct event {
+  REAL xkey, ykey;                              /* Coordinates of the event. */
+  VOID *eventptr;      /* Can be a vertex or the location of a circle event. */
+  int heapposition;              /* Marks this event's position in the heap. */
+};
+
+/* A node in the splay tree.  Each node holds an oriented ghost triangle     */
+/*   that represents a boundary edge of the growing triangulation.  When a   */
+/*   circle event covers two boundary edges with a triangle, so that they    */
+/*   are no longer boundary edges, those edges are not immediately deleted   */
+/*   from the tree; rather, they are lazily deleted when they are next       */
+/*   encountered.  (Since only a random sample of boundary edges are kept    */
+/*   in the tree, lazy deletion is faster.)  `keydest' is used to verify     */
+/*   that a triangle is still the same as when it entered the splay tree; if */
+/*   it has been rotated (due to a circle event), it no longer represents a  */
+/*   boundary edge and should be deleted.                                    */
+
+struct splaynode {
+  struct otri keyedge;                     /* Lprev of an edge on the front. */
+  vertex keydest;           /* Used to verify that splay node is still live. */
+  struct splaynode *lchild, *rchild;              /* Children in splay tree. */
+};
+
+/* A type used to allocate memory.  firstblock is the first block of items.  */
+/*   nowblock is the block from which items are currently being allocated.   */
+/*   nextitem points to the next slab of free memory for an item.            */
+/*   deaditemstack is the head of a linked list (stack) of deallocated items */
+/*   that can be recycled.  unallocateditems is the number of items that     */
+/*   remain to be allocated from nowblock.                                   */
+/*                                                                           */
+/* Traversal is the process of walking through the entire list of items, and */
+/*   is separate from allocation.  Note that a traversal will visit items on */
+/*   the "deaditemstack" stack as well as live items.  pathblock points to   */
+/*   the block currently being traversed.  pathitem points to the next item  */
+/*   to be traversed.  pathitemsleft is the number of items that remain to   */
+/*   be traversed in pathblock.                                              */
+/*                                                                           */
+/* alignbytes determines how new records should be aligned in memory.        */
+/*   itembytes is the length of a record in bytes (after rounding up).       */
+/*   itemsperblock is the number of items allocated at once in a single      */
+/*   block.  itemsfirstblock is the number of items in the first block,      */
+/*   which can vary from the others.  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.                                */
+
+struct memorypool {
+  VOID **firstblock, **nowblock;
+  VOID *nextitem;
+  VOID *deaditemstack;
+  VOID **pathblock;
+  VOID *pathitem;
+  int alignbytes;
+  int itembytes;
+  int itemsperblock;
+  int itemsfirstblock;
+  long items, maxitems;
+  int unallocateditems;
+  int pathitemsleft;
+};
+
+
+/* Global constants.                                                         */
+
+REAL splitter;       /* Used to split REAL factors for exact multiplication. */
+REAL epsilon;                             /* Floating-point machine epsilon. */
+REAL resulterrbound;
+REAL ccwerrboundA, ccwerrboundB, ccwerrboundC;
+REAL iccerrboundA, iccerrboundB, iccerrboundC;
+REAL o3derrboundA, o3derrboundB, o3derrboundC;
+
+/* Random number seed is not constant, but I've made it global anyway.       */
+
+unsigned long randomseed;                     /* Current random number seed. */
+
+
+/* Mesh data structure.  Triangle operates on only one mesh, but the mesh    */
+/*   structure is used (instead of global variables) to allow reentrancy.    */
+
+struct mesh {
+
+/* Variables used to allocate memory for triangles, subsegments, vertices,   */
+/*   viri (triangles being eaten), encroached segments, bad (skinny or too   */
+/*   large) triangles, and splay tree nodes.                                 */
+
+  struct memorypool triangles;
+  struct memorypool subsegs;
+  struct memorypool vertices;
+  struct memorypool viri;
+  struct memorypool badsubsegs;
+  struct memorypool badtriangles;
+  struct memorypool flipstackers;
+  struct memorypool splaynodes;
+
+/* Variables that maintain the bad triangle queues.  The queues are          */
+/*   ordered from 4095 (highest priority) to 0 (lowest priority).            */
+
+  struct badtriang *queuefront[4096];
+  struct badtriang *queuetail[4096];
+  int nextnonemptyq[4096];
+  int firstnonemptyq;
+
+/* Variable that maintains the stack of recently flipped triangles.          */
+
+  struct flipstacker *lastflip;
+
+/* Other variables. */
+
+  REAL xmin, xmax, ymin, ymax;                            /* x and y bounds. */
+  REAL xminextreme;      /* Nonexistent x value used as a flag in sweepline. */
+  int invertices;                               /* Number of input vertices. */
+  int inelements;                              /* Number of input triangles. */
+  int insegments;                               /* Number of input segments. */
+  int holes;                                       /* Number of input holes. */
+  int regions;                                   /* Number of input regions. */
+  int undeads;    /* Number of input vertices that don't appear in the mesh. */
+  long edges;                                     /* Number of output edges. */
+  int mesh_dim;                                /* Dimension (ought to be 2). */
+  int nextras;                           /* Number of attributes per vertex. */
+  int eextras;                         /* Number of attributes per triangle. */
+  long hullsize;                          /* Number of edges in convex hull. */
+  int steinerleft;                 /* Number of Steiner points not yet used. */
+  int vertexmarkindex;         /* Index to find boundary marker of a vertex. */
+  int vertex2triindex;     /* Index to find a triangle adjacent to a vertex. */
+  int highorderindex;  /* Index to find extra nodes for high-order elements. */
+  int elemattribindex;            /* Index to find attributes of a triangle. */
+  int areaboundindex;             /* Index to find area bound of a triangle. */
+  int checksegments;         /* Are there segments in the triangulation yet? */
+  int checkquality;                  /* Has quality triangulation begun yet? */
+  int readnodefile;                           /* Has a .node file been read? */
+  long samples;              /* Number of random samples for point location. */
+
+  long incirclecount;                 /* Number of incircle tests performed. */
+  long counterclockcount;     /* Number of counterclockwise tests performed. */
+  long orient3dcount;           /* Number of 3D orientation tests performed. */
+  long hyperbolacount;      /* Number of right-of-hyperbola tests performed. */
+  long circumcentercount;  /* Number of circumcenter calculations performed. */
+  long circletopcount;       /* Number of circle top calculations performed. */
+
+/* Triangular bounding box vertices.                                         */
+
+  vertex infvertex1, infvertex2, infvertex3;
+
+/* Pointer to the `triangle' that occupies all of "outer space."             */
+
+  triangle *dummytri;
+  triangle *dummytribase;    /* Keep base address so we can free() it later. */
+
+/* Pointer to the omnipresent subsegment.  Referenced by any triangle or     */
+/*   subsegment that isn't really connected to a subsegment at that          */
+/*   location.                                                               */
+
+  subseg *dummysub;
+  subseg *dummysubbase;      /* Keep base address so we can free() it later. */
+
+/* Pointer to a recently visited triangle.  Improves point location if       */
+/*   proximate vertices are inserted sequentially.                           */
+
+  struct otri recenttri;
+
+};                                                  /* End of `struct mesh'. */
+
+
+/* Data structure for command line switches and file names.  This structure  */
+/*   is used (instead of global variables) to allow reentrancy.              */
+
+struct behavior {
+
+/* Switches for the triangulator.                                            */
+/*   poly: -p switch.  refine: -r switch.                                    */
+/*   quality: -q switch.                                                     */
+/*     minangle: minimum angle bound, specified after -q switch.             */
+/*     goodangle: cosine squared of minangle.                                */
+/*     offconstant: constant used to place off-center Steiner points.        */
+/*   vararea: -a switch without number.                                      */
+/*   fixedarea: -a switch with number.                                       */
+/*     maxarea: maximum area bound, specified after -a switch.               */
+/*   usertest: -u switch.                                                    */
+/*   regionattrib: -A switch.  convex: -c switch.                            */
+/*   weighted: 1 for -w switch, 2 for -W switch.  jettison: -j switch        */
+/*   firstnumber: inverse of -z switch.  All items are numbered starting     */
+/*     from `firstnumber'.                                                   */
+/*   edgesout: -e switch.  voronoi: -v switch.                               */
+/*   neighbors: -n switch.  geomview: -g switch.                             */
+/*   nobound: -B switch.  nopolywritten: -P switch.                          */
+/*   nonodewritten: -N switch.  noelewritten: -E switch.                     */
+/*   noiterationnum: -I switch.  noholes: -O switch.                         */
+/*   noexact: -X switch.                                                     */
+/*   order: element order, specified after -o switch.                        */
+/*   nobisect: count of how often -Y switch is selected.                     */
+/*   steiner: maximum number of Steiner points, specified after -S switch.   */
+/*   incremental: -i switch.  sweepline: -F switch.                          */
+/*   dwyer: inverse of -l switch.                                            */
+/*   splitseg: -s switch.                                                    */
+/*   conformdel: -D switch.  docheck: -C switch.                             */
+/*   quiet: -Q switch.  verbose: count of how often -V switch is selected.   */
+/*   usesegments: -p, -r, -q, or -c switch; determines whether segments are  */
+/*     used at all.                                                          */
+/*                                                                           */
+/* Read the instructions to find out the meaning of these switches.          */
+
+  int poly, refine, quality, vararea, fixedarea, usertest;
+  int regionattrib, convex, weighted, jettison;
+  int firstnumber;
+  int edgesout, voronoi, neighbors, geomview;
+  int nobound, nopolywritten, nonodewritten, noelewritten, noiterationnum;
+  int noholes, noexact, conformdel;
+  int incremental, sweepline, dwyer;
+  int splitseg;
+  int docheck;
+  int quiet, verbose;
+  int usesegments;
+  int order;
+  int nobisect;
+  int steiner;
+  REAL minangle, goodangle, offconstant;
+  REAL maxarea;
+
+/* Variables for file names.                                                 */
+
+#ifndef TRILIBRARY
+  char innodefilename[FILENAMESIZE];
+  char inelefilename[FILENAMESIZE];
+  char inpolyfilename[FILENAMESIZE];
+  char areafilename[FILENAMESIZE];
+  char outnodefilename[FILENAMESIZE];
+  char outelefilename[FILENAMESIZE];
+  char outpolyfilename[FILENAMESIZE];
+  char edgefilename[FILENAMESIZE];
+  char vnodefilename[FILENAMESIZE];
+  char vedgefilename[FILENAMESIZE];
+  char neighborfilename[FILENAMESIZE];
+  char offfilename[FILENAMESIZE];
+#endif /* not TRILIBRARY */
+
+};                                              /* End of `struct behavior'. */
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*  Mesh manipulation primitives.  Each triangle contains three pointers to  */
+/*  other triangles, with orientations.  Each pointer points not to the      */
+/*  first byte of a triangle, but to one of the first three bytes of a       */
+/*  triangle.  It is necessary to extract both the triangle itself and the   */
+/*  orientation.  To save memory, I keep both pieces of information in one   */
+/*  pointer.  To make this possible, I assume that all triangles are aligned */
+/*  to four-byte boundaries.  The decode() routine below decodes a pointer,  */
+/*  extracting an orientation (in the range 0 to 2) and a pointer to the     */
+/*  beginning of a triangle.  The encode() routine compresses a pointer to a */
+/*  triangle and an orientation into a single pointer.  My assumptions that  */
+/*  triangles are four-byte-aligned and that the `unsigned long' type is     */
+/*  long enough to hold a pointer are two of the few kludges in this program.*/
+/*                                                                           */
+/*  Subsegments are manipulated similarly.  A pointer to a subsegment        */
+/*  carries both an address and an orientation in the range 0 to 1.          */
+/*                                                                           */
+/*  The other primitives take an oriented triangle or oriented subsegment,   */
+/*  and return an oriented triangle or oriented subsegment or vertex; or     */
+/*  they change the connections in the data structure.                       */
+/*                                                                           */
+/*  Below, triangles and subsegments are denoted by their vertices.  The     */
+/*  triangle abc has origin (org) a, destination (dest) b, and apex (apex)   */
+/*  c.  These vertices occur in counterclockwise order about the triangle.   */
+/*  The handle abc may simultaneously denote vertex a, edge ab, and triangle */
+/*  abc.                                                                     */
+/*                                                                           */
+/*  Similarly, the subsegment ab has origin (sorg) a and destination (sdest) */
+/*  b.  If ab is thought to be directed upward (with b directly above a),    */
+/*  then the handle ab is thought to grasp the right side of ab, and may     */
+/*  simultaneously denote vertex a and edge ab.                              */
+/*                                                                           */
+/*  An asterisk (*) denotes a vertex whose identity is unknown.              */
+/*                                                                           */
+/*  Given this notation, a partial list of mesh manipulation primitives      */
+/*  follows.                                                                 */
+/*                                                                           */
+/*                                                                           */
+/*  For triangles:                                                           */
+/*                                                                           */
+/*  sym:  Find the abutting triangle; same edge.                             */
+/*  sym(abc) -> ba*                                                          */
+/*                                                                           */
+/*  lnext:  Find the next edge (counterclockwise) of a triangle.             */
+/*  lnext(abc) -> bca                                                        */
+/*                                                                           */
+/*  lprev:  Find the previous edge (clockwise) of a triangle.                */
+/*  lprev(abc) -> cab                                                        */
+/*                                                                           */
+/*  onext:  Find the next edge counterclockwise with the same origin.        */
+/*  onext(abc) -> ac*                                                        */
+/*                                                                           */
+/*  oprev:  Find the next edge clockwise with the same origin.               */
+/*  oprev(abc) -> a*b                                                        */
+/*                                                                           */
+/*  dnext:  Find the next edge counterclockwise with the same destination.   */
+/*  dnext(abc) -> *ba                                                        */
+/*                                                                           */
+/*  dprev:  Find the next edge clockwise with the same destination.          */
+/*  dprev(abc) -> cb*                                                        */
+/*                                                                           */
+/*  rnext:  Find the next edge (counterclockwise) of the adjacent triangle.  */
+/*  rnext(abc) -> *a*                                                        */
+/*                                                                           */
+/*  rprev:  Find the previous edge (clockwise) of the adjacent triangle.     */
+/*  rprev(abc) -> b**                                                        */
+/*                                                                           */
+/*  org:  Origin          dest:  Destination          apex:  Apex            */
+/*  org(abc) -> a         dest(abc) -> b              apex(abc) -> c         */
+/*                                                                           */
+/*  bond:  Bond two triangles together at the resepective handles.           */
+/*  bond(abc, bad)                                                           */
+/*                                                                           */
+/*                                                                           */
+/*  For subsegments:                                                         */
+/*                                                                           */
+/*  ssym:  Reverse the orientation of a subsegment.                          */
+/*  ssym(ab) -> ba                                                           */
+/*                                                                           */
+/*  spivot:  Find adjoining subsegment with the same origin.                 */
+/*  spivot(ab) -> a*                                                         */
+/*                                                                           */
+/*  snext:  Find next subsegment in sequence.                                */
+/*  snext(ab) -> b*                                                          */
+/*                                                                           */
+/*  sorg:  Origin                      sdest:  Destination                   */
+/*  sorg(ab) -> a                      sdest(ab) -> b                        */
+/*                                                                           */
+/*  sbond:  Bond two subsegments together at the respective origins.         */
+/*  sbond(ab, ac)                                                            */
+/*                                                                           */
+/*                                                                           */
+/*  For interacting tetrahedra and subfacets:                                */
+/*                                                                           */
+/*  tspivot:  Find a subsegment abutting a triangle.                         */
+/*  tspivot(abc) -> ba                                                       */
+/*                                                                           */
+/*  stpivot:  Find a triangle abutting a subsegment.                         */
+/*  stpivot(ab) -> ba*                                                       */
+/*                                                                           */
+/*  tsbond:  Bond a triangle to a subsegment.                                */
+/*  tsbond(abc, ba)                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+/********* Mesh manipulation primitives begin here                   *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/* Fast lookup arrays to speed some of the mesh manipulation primitives.     */
+
+int plus1mod3[3] = {1, 2, 0};
+int minus1mod3[3] = {2, 0, 1};
+
+/********* Primitives for triangles                                  *********/
+/*                                                                           */
+/*                                                                           */
+
+/* decode() converts a pointer to an oriented triangle.  The orientation is  */
+/*   extracted from the two least significant bits of the pointer.           */
+
+#define decode(ptr, otri)                                                     \
+  (otri).orient = (int) ((size_t) (ptr) & (size_t) 3l);         \
+  (otri).tri = (triangle *)                                                   \
+                  ((size_t) (ptr) ^ (size_t) (otri).orient)
+
+/* encode() compresses an oriented triangle into a single pointer.  It       */
+/*   relies on the assumption that all triangles are aligned to four-byte    */
+/*   boundaries, so the two least significant bits of (otri).tri are zero.   */
+
+#define encode(otri)                                                          \
+  (triangle) ((size_t) (otri).tri | (size_t) (otri).orient)
+
+/* The following handle manipulation primitives are all described by Guibas  */
+/*   and Stolfi.  However, Guibas and Stolfi use an edge-based data          */
+/*   structure, whereas I use a triangle-based data structure.               */
+
+/* sym() finds the abutting triangle, on the same edge.  Note that the edge  */
+/*   direction is necessarily reversed, because the handle specified by an   */
+/*   oriented triangle is directed counterclockwise around the triangle.     */
+
+#define sym(otri1, otri2)                                                     \
+  ptr = (otri1).tri[(otri1).orient];                                          \
+  decode(ptr, otri2);
+
+#define symself(otri)                                                         \
+  ptr = (otri).tri[(otri).orient];                                            \
+  decode(ptr, otri);
+
+/* lnext() finds the next edge (counterclockwise) of a triangle.             */
+
+#define lnext(otri1, otri2)                                                   \
+  (otri2).tri = (otri1).tri;                                                  \
+  (otri2).orient = plus1mod3[(otri1).orient]
+
+#define lnextself(otri)                                                       \
+  (otri).orient = plus1mod3[(otri).orient]
+
+/* lprev() finds the previous edge (clockwise) of a triangle.                */
+
+#define lprev(otri1, otri2)                                                   \
+  (otri2).tri = (otri1).tri;                                                  \
+  (otri2).orient = minus1mod3[(otri1).orient]
+
+#define lprevself(otri)                                                       \
+  (otri).orient = minus1mod3[(otri).orient]
+
+/* onext() spins counterclockwise around a vertex; that is, it finds the     */
+/*   next edge with the same origin in the counterclockwise direction.  This */
+/*   edge is part of a different triangle.                                   */
+
+#define onext(otri1, otri2)                                                   \
+  lprev(otri1, otri2);                                                        \
+  symself(otri2);
+
+#define onextself(otri)                                                       \
+  lprevself(otri);                                                            \
+  symself(otri);
+
+/* oprev() spins clockwise around a vertex; that is, it finds the next edge  */
+/*   with the same origin in the clockwise direction.  This edge is part of  */
+/*   a different triangle.                                                   */
+
+#define oprev(otri1, otri2)                                                   \
+  sym(otri1, otri2);                                                          \
+  lnextself(otri2);
+
+#define oprevself(otri)                                                       \
+  symself(otri);                                                              \
+  lnextself(otri);
+
+/* dnext() spins counterclockwise around a vertex; that is, it finds the     */
+/*   next edge with the same destination in the counterclockwise direction.  */
+/*   This edge is part of a different triangle.                              */
+
+#define dnext(otri1, otri2)                                                   \
+  sym(otri1, otri2);                                                          \
+  lprevself(otri2);
+
+#define dnextself(otri)                                                       \
+  symself(otri);                                                              \
+  lprevself(otri);
+
+/* dprev() spins clockwise around a vertex; that is, it finds the next edge  */
+/*   with the same destination in the clockwise direction.  This edge is     */
+/*   part of a different triangle.                                           */
+
+#define dprev(otri1, otri2)                                                   \
+  lnext(otri1, otri2);                                                        \
+  symself(otri2);
+
+#define dprevself(otri)                                                       \
+  lnextself(otri);                                                            \
+  symself(otri);
+
+/* rnext() moves one edge counterclockwise about the adjacent triangle.      */
+/*   (It's best understood by reading Guibas and Stolfi.  It involves        */
+/*   changing triangles twice.)                                              */
+
+#define rnext(otri1, otri2)                                                   \
+  sym(otri1, otri2);                                                          \
+  lnextself(otri2);                                                           \
+  symself(otri2);
+
+#define rnextself(otri)                                                       \
+  symself(otri);                                                              \
+  lnextself(otri);                                                            \
+  symself(otri);
+
+/* rprev() moves one edge clockwise about the adjacent triangle.             */
+/*   (It's best understood by reading Guibas and Stolfi.  It involves        */
+/*   changing triangles twice.)                                              */
+
+#define rprev(otri1, otri2)                                                   \
+  sym(otri1, otri2);                                                          \
+  lprevself(otri2);                                                           \
+  symself(otri2);
+
+#define rprevself(otri)                                                       \
+  symself(otri);                                                              \
+  lprevself(otri);                                                            \
+  symself(otri);
+
+/* These primitives determine or set the origin, destination, or apex of a   */
+/* triangle.                                                                 */
+
+#define org(otri, vertexptr)                                                  \
+  vertexptr = (vertex) (otri).tri[plus1mod3[(otri).orient] + 3]
+
+#define dest(otri, vertexptr)                                                 \
+  vertexptr = (vertex) (otri).tri[minus1mod3[(otri).orient] + 3]
+
+#define apex(otri, vertexptr)                                                 \
+  vertexptr = (vertex) (otri).tri[(otri).orient + 3]
+
+#define setorg(otri, vertexptr)                                               \
+  (otri).tri[plus1mod3[(otri).orient] + 3] = (triangle) vertexptr
+
+#define setdest(otri, vertexptr)                                              \
+  (otri).tri[minus1mod3[(otri).orient] + 3] = (triangle) vertexptr
+
+#define setapex(otri, vertexptr)                                              \
+  (otri).tri[(otri).orient + 3] = (triangle) vertexptr
+
+/* Bond two triangles together.                                              */
+
+#define bond(otri1, otri2)                                                    \
+  (otri1).tri[(otri1).orient] = encode(otri2);                                \
+  (otri2).tri[(otri2).orient] = encode(otri1)
+
+/* Dissolve a bond (from one side).  Note that the other triangle will still */
+/*   think it's connected to this triangle.  Usually, however, the other     */
+/*   triangle is being deleted entirely, or bonded to another triangle, so   */
+/*   it doesn't matter.                                                      */
+
+#define dissolve(otri)                                                        \
+  (otri).tri[(otri).orient] = (triangle) m->dummytri
+
+/* Copy an oriented triangle.                                                */
+
+#define otricopy(otri1, otri2)                                                \
+  (otri2).tri = (otri1).tri;                                                  \
+  (otri2).orient = (otri1).orient
+
+/* Test for equality of oriented triangles.                                  */
+
+#define otriequal(otri1, otri2)                                               \
+  (((otri1).tri == (otri2).tri) &&                                            \
+   ((otri1).orient == (otri2).orient))
+
+/* Primitives to infect or cure a triangle with the virus.  These rely on    */
+/*   the assumption that all subsegments are aligned to four-byte boundaries.*/
+
+#define infect(otri)                                                          \
+  (otri).tri[6] = (triangle)                                                  \
+                    ((size_t) (otri).tri[6] | (size_t) 2l)
+
+#define uninfect(otri)                                                        \
+  (otri).tri[6] = (triangle)                                                  \
+                    ((size_t) (otri).tri[6] & ~ (size_t) 2l)
+
+/* Test a triangle for viral infection.                                      */
+
+#define infected(otri)                                                        \
+  (((size_t) (otri).tri[6] & (size_t) 2l) != 0l)
+
+/* Check or set a triangle's attributes.                                     */
+
+#define elemattribute(otri, attnum)                                           \
+  ((REAL *) (otri).tri)[m->elemattribindex + (attnum)]
+
+#define setelemattribute(otri, attnum, value)                                 \
+  ((REAL *) (otri).tri)[m->elemattribindex + (attnum)] = value
+
+/* Check or set a triangle's maximum area bound.                             */
+
+#define areabound(otri)  ((REAL *) (otri).tri)[m->areaboundindex]
+
+#define setareabound(otri, value)                                             \
+  ((REAL *) (otri).tri)[m->areaboundindex] = value
+
+/* Check or set a triangle's deallocation.  Its second pointer is set to     */
+/*   NULL to indicate that it is not allocated.  (Its first pointer is used  */
+/*   for the stack of dead items.)  Its fourth pointer (its first vertex)    */
+/*   is set to NULL in case a `badtriang' structure points to it.            */
+
+#define deadtri(tria)  ((tria)[1] == (triangle) NULL)
+
+#define killtri(tria)                                                         \
+  (tria)[1] = (triangle) NULL;                                                \
+  (tria)[3] = (triangle) NULL
+
+/********* Primitives for subsegments                                *********/
+/*                                                                           */
+/*                                                                           */
+
+/* sdecode() converts a pointer to an oriented subsegment.  The orientation  */
+/*   is extracted from the least significant bit of the pointer.  The two    */
+/*   least significant bits (one for orientation, one for viral infection)   */
+/*   are masked out to produce the real pointer.                             */
+
+#define sdecode(sptr, osub)                                                   \
+  (osub).ssorient = (int) ((size_t) (sptr) & (size_t) 1l);      \
+  (osub).ss = (subseg *)                                                      \
+              ((size_t) (sptr) & ~ (size_t) 3l)
+
+/* sencode() compresses an oriented subsegment into a single pointer.  It    */
+/*   relies on the assumption that all subsegments are aligned to two-byte   */
+/*   boundaries, so the least significant bit of (osub).ss is zero.          */
+
+#define sencode(osub)                                                         \
+  (subseg) ((size_t) (osub).ss | (size_t) (osub).ssorient)
+
+/* ssym() toggles the orientation of a subsegment.                           */
+
+#define ssym(osub1, osub2)                                                    \
+  (osub2).ss = (osub1).ss;                                                    \
+  (osub2).ssorient = 1 - (osub1).ssorient
+
+#define ssymself(osub)                                                        \
+  (osub).ssorient = 1 - (osub).ssorient
+
+/* spivot() finds the other subsegment (from the same segment) that shares   */
+/*   the same origin.                                                        */
+
+#define spivot(osub1, osub2)                                                  \
+  sptr = (osub1).ss[(osub1).ssorient];                                        \
+  sdecode(sptr, osub2)
+
+#define spivotself(osub)                                                      \
+  sptr = (osub).ss[(osub).ssorient];                                          \
+  sdecode(sptr, osub)
+
+/* snext() finds the next subsegment (from the same segment) in sequence;    */
+/*   one whose origin is the input subsegment's destination.                 */
+
+#define snext(osub1, osub2)                                                   \
+  sptr = (osub1).ss[1 - (osub1).ssorient];                                    \
+  sdecode(sptr, osub2)
+
+#define snextself(osub)                                                       \
+  sptr = (osub).ss[1 - (osub).ssorient];                                      \
+  sdecode(sptr, osub)
+
+/* These primitives determine or set the origin or destination of a          */
+/*   subsegment or the segment that includes it.                             */
+
+#define sorg(osub, vertexptr)                                                 \
+  vertexptr = (vertex) (osub).ss[2 + (osub).ssorient]
+
+#define sdest(osub, vertexptr)                                                \
+  vertexptr = (vertex) (osub).ss[3 - (osub).ssorient]
+
+#define setsorg(osub, vertexptr)                                              \
+  (osub).ss[2 + (osub).ssorient] = (subseg) vertexptr
+
+#define setsdest(osub, vertexptr)                                             \
+  (osub).ss[3 - (osub).ssorient] = (subseg) vertexptr
+
+#define segorg(osub, vertexptr)                                               \
+  vertexptr = (vertex) (osub).ss[4 + (osub).ssorient]
+
+#define segdest(osub, vertexptr)                                              \
+  vertexptr = (vertex) (osub).ss[5 - (osub).ssorient]
+
+#define setsegorg(osub, vertexptr)                                            \
+  (osub).ss[4 + (osub).ssorient] = (subseg) vertexptr
+
+#define setsegdest(osub, vertexptr)                                           \
+  (osub).ss[5 - (osub).ssorient] = (subseg) vertexptr
+
+/* These primitives read or set a boundary marker.  Boundary markers are     */
+/*   used to hold user-defined tags for setting boundary conditions in       */
+/*   finite element solvers.                                                 */
+
+#define mark(osub)  (* (int *) ((osub).ss + 8))
+
+#define setmark(osub, value)                                                  \
+  * (int *) ((osub).ss + 8) = value
+
+/* Bond two subsegments together.                                            */
+
+#define sbond(osub1, osub2)                                                   \
+  (osub1).ss[(osub1).ssorient] = sencode(osub2);                              \
+  (osub2).ss[(osub2).ssorient] = sencode(osub1)
+
+/* Dissolve a subsegment bond (from one side).  Note that the other          */
+/*   subsegment will still think it's connected to this subsegment.          */
+
+#define sdissolve(osub)                                                       \
+  (osub).ss[(osub).ssorient] = (subseg) m->dummysub
+
+/* Copy a subsegment.                                                        */
+
+#define subsegcopy(osub1, osub2)                                              \
+  (osub2).ss = (osub1).ss;                                                    \
+  (osub2).ssorient = (osub1).ssorient
+
+/* Test for equality of subsegments.                                         */
+
+#define subsegequal(osub1, osub2)                                             \
+  (((osub1).ss == (osub2).ss) &&                                              \
+   ((osub1).ssorient == (osub2).ssorient))
+
+/* Check or set a subsegment's deallocation.  Its second pointer is set to   */
+/*   NULL to indicate that it is not allocated.  (Its first pointer is used  */
+/*   for the stack of dead items.)  Its third pointer (its first vertex)     */
+/*   is set to NULL in case a `badsubseg' structure points to it.            */
+
+#define deadsubseg(sub)  ((sub)[1] == (subseg) NULL)
+
+#define killsubseg(sub)                                                       \
+  (sub)[1] = (subseg) NULL;                                                   \
+  (sub)[2] = (subseg) NULL
+
+/********* Primitives for interacting triangles and subsegments      *********/
+/*                                                                           */
+/*                                                                           */
+
+/* tspivot() finds a subsegment abutting a triangle.                         */
+
+#define tspivot(otri, osub)                                                   \
+  sptr = (subseg) (otri).tri[6 + (otri).orient];                              \
+  sdecode(sptr, osub)
+
+/* stpivot() finds a triangle abutting a subsegment.  It requires that the   */
+/*   variable `ptr' of type `triangle' be defined.                           */
+
+#define stpivot(osub, otri)                                                   \
+  ptr = (triangle) (osub).ss[6 + (osub).ssorient];                            \
+  decode(ptr, otri)
+
+/* Bond a triangle to a subsegment.                                          */
+
+#define tsbond(otri, osub)                                                    \
+  (otri).tri[6 + (otri).orient] = (triangle) sencode(osub);                   \
+  (osub).ss[6 + (osub).ssorient] = (subseg) encode(otri)
+
+/* Dissolve a bond (from the triangle side).                                 */
+
+#define tsdissolve(otri)                                                      \
+  (otri).tri[6 + (otri).orient] = (triangle) m->dummysub
+
+/* Dissolve a bond (from the subsegment side).                               */
+
+#define stdissolve(osub)                                                      \
+  (osub).ss[6 + (osub).ssorient] = (subseg) m->dummytri
+
+/********* Primitives for vertices                                   *********/
+/*                                                                           */
+/*                                                                           */
+
+#define vertexmark(vx)  ((int *) (vx))[m->vertexmarkindex]
+
+#define setvertexmark(vx, value)                                              \
+  ((int *) (vx))[m->vertexmarkindex] = value
+
+#define vertextype(vx)  ((int *) (vx))[m->vertexmarkindex + 1]
+
+#define setvertextype(vx, value)                                              \
+  ((int *) (vx))[m->vertexmarkindex + 1] = value
+
+#define vertex2tri(vx)  ((triangle *) (vx))[m->vertex2triindex]
+
+#define setvertex2tri(vx, value)                                              \
+  ((triangle *) (vx))[m->vertex2triindex] = value
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Mesh manipulation primitives end here                     *********/
+
+/********* User-defined triangle evaluation routine begins here      *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  triunsuitable()   Determine if a triangle is unsuitable, and thus must   */
+/*                    be further refined.                                    */
+/*                                                                           */
+/*  You may write your own procedure that decides whether or not a selected  */
+/*  triangle is too big (and needs to be refined).  There are two ways to do */
+/*  this.                                                                    */
+/*                                                                           */
+/*  (1)  Modify the procedure `triunsuitable' below, then recompile          */
+/*  Triangle.                                                                */
+/*                                                                           */
+/*  (2)  Define the symbol EXTERNAL_TEST (either by adding the definition    */
+/*  to this file, or by using the appropriate compiler switch).  This way,   */
+/*  you can compile triangle.c separately from your test.  Write your own    */
+/*  `triunsuitable' procedure in a separate C file (using the same prototype */
+/*  as below).  Compile it and link the object code with triangle.o.         */
+/*                                                                           */
+/*  This procedure returns 1 if the triangle is too large and should be      */
+/*  refined; 0 otherwise.                                                    */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef EXTERNAL_TEST
+
+//int triunsuitable(void);
+
+#else /* not EXTERNAL_TEST */
+
+#ifdef ANSI_DECLARATORS
+int triunsuitable(vertex triorg, vertex tridest, vertex triapex, REAL area)
+#else /* not ANSI_DECLARATORS */
+int triunsuitable(triorg, tridest, triapex, area)
+vertex triorg;                              /* The triangle's origin vertex. */
+vertex tridest;                        /* The triangle's destination vertex. */
+vertex triapex;                               /* The triangle's apex vertex. */
+REAL area;                                      /* The area of the triangle. */
+#endif /* not ANSI_DECLARATORS */
+
+{
+  REAL dxoa, dxda, dxod;
+  REAL dyoa, dyda, dyod;
+  REAL oalen, dalen, odlen;
+  REAL maxlen;
+
+  dxoa = triorg[0] - triapex[0];
+  dyoa = triorg[1] - triapex[1];
+  dxda = tridest[0] - triapex[0];
+  dyda = tridest[1] - triapex[1];
+  dxod = triorg[0] - tridest[0];
+  dyod = triorg[1] - tridest[1];
+  /* Find the squares of the lengths of the triangle's three edges. */
+  oalen = dxoa * dxoa + dyoa * dyoa;
+  dalen = dxda * dxda + dyda * dyda;
+  odlen = dxod * dxod + dyod * dyod;
+  /* Find the square of the length of the longest edge. */
+  maxlen = (dalen > oalen) ? dalen : oalen;
+  maxlen = (odlen > maxlen) ? odlen : maxlen;
+
+  if (maxlen > 0.05 * (triorg[0] * triorg[0] + triorg[1] * triorg[1]) + 0.02) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+#endif /* not EXTERNAL_TEST */
+
+/**                                                                         **/
+/**                                                                         **/
+/********* User-defined triangle evaluation routine ends here        *********/
+
+/********* Memory allocation and program exit wrappers begin here    *********/
+/**                                                                         **/
+/**                                                                         **/
+
+#ifdef ANSI_DECLARATORS
+void triexit(int status)
+#else /* not ANSI_DECLARATORS */
+void triexit(status)
+int status;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  exit(status);
+}
+
+#ifdef ANSI_DECLARATORS
+VOID *trimalloc(int size)
+#else /* not ANSI_DECLARATORS */
+VOID *trimalloc(size)
+int size;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  VOID *memptr;
+
+  memptr = (VOID *) malloc((unsigned int) size);
+  if (memptr == (VOID *) NULL) {
+    printf("Error:  Out of memory.\n");
+    triexit(1);
+  }
+  return(memptr);
+}
+
+#ifdef ANSI_DECLARATORS
+void trifree(VOID *memptr)
+#else /* not ANSI_DECLARATORS */
+void trifree(memptr)
+VOID *memptr;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  free(memptr);
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Memory allocation and program exit wrappers end here      *********/
+
+/********* User interaction routines begin here                      *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  syntax()   Print list of command line switches.                          */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef TRILIBRARY
+
+void syntax()
+{
+#ifdef CDT_ONLY
+#ifdef REDUCED
+  printf("triangle [-pAcjevngBPNEIOXzo_lQVh] input_file\n");
+#else /* not REDUCED */
+  printf("triangle [-pAcjevngBPNEIOXzo_iFlCQVh] input_file\n");
+#endif /* not REDUCED */
+#else /* not CDT_ONLY */
+#ifdef REDUCED
+  printf("triangle [-prq__a__uAcDjevngBPNEIOXzo_YS__lQVh] input_file\n");
+#else /* not REDUCED */
+  printf("triangle [-prq__a__uAcDjevngBPNEIOXzo_YS__iFlsCQVh] input_file\n");
+#endif /* not REDUCED */
+#endif /* not CDT_ONLY */
+
+  printf("    -p  Triangulates a Planar Straight Line Graph (.poly file).\n");
+#ifndef CDT_ONLY
+  printf("    -r  Refines a previously generated mesh.\n");
+  printf(
+    "    -q  Quality mesh generation.  A minimum angle may be specified.\n");
+  printf("    -a  Applies a maximum triangle area constraint.\n");
+  printf("    -u  Applies a user-defined triangle constraint.\n");
+#endif /* not CDT_ONLY */
+  printf(
+    "    -A  Applies attributes to identify triangles in certain regions.\n");
+  printf("    -c  Encloses the convex hull with segments.\n");
+#ifndef CDT_ONLY
+  printf("    -D  Conforming Delaunay:  all triangles are truly Delaunay.\n");
+#endif /* not CDT_ONLY */
+/*
+  printf("    -w  Weighted Delaunay triangulation.\n");
+  printf("    -W  Regular triangulation (lower hull of a height field).\n");
+*/
+  printf("    -j  Jettison unused vertices from output .node file.\n");
+  printf("    -e  Generates an edge list.\n");
+  printf("    -v  Generates a Voronoi diagram.\n");
+  printf("    -n  Generates a list of triangle neighbors.\n");
+  printf("    -g  Generates an .off file for Geomview.\n");
+  printf("    -B  Suppresses output of boundary information.\n");
+  printf("    -P  Suppresses output of .poly file.\n");
+  printf("    -N  Suppresses output of .node file.\n");
+  printf("    -E  Suppresses output of .ele file.\n");
+  printf("    -I  Suppresses mesh iteration numbers.\n");
+  printf("    -O  Ignores holes in .poly file.\n");
+  printf("    -X  Suppresses use of exact arithmetic.\n");
+  printf("    -z  Numbers all items starting from zero (rather than one).\n");
+  printf("    -o2 Generates second-order subparametric elements.\n");
+#ifndef CDT_ONLY
+  printf("    -Y  Suppresses boundary segment splitting.\n");
+  printf("    -S  Specifies maximum number of added Steiner points.\n");
+#endif /* not CDT_ONLY */
+#ifndef REDUCED
+  printf("    -i  Uses incremental method, rather than divide-and-conquer.\n");
+  printf("    -F  Uses Fortune's sweepline algorithm, rather than d-and-c.\n");
+#endif /* not REDUCED */
+  printf("    -l  Uses vertical cuts only, rather than alternating cuts.\n");
+#ifndef REDUCED
+#ifndef CDT_ONLY
+  printf(
+    "    -s  Force segments into mesh by splitting (instead of using CDT).\n");
+#endif /* not CDT_ONLY */
+  printf("    -C  Check consistency of final mesh.\n");
+#endif /* not REDUCED */
+  printf("    -Q  Quiet:  No terminal output except errors.\n");
+  printf("    -V  Verbose:  Detailed information on what I'm doing.\n");
+  printf("    -h  Help:  Detailed instructions for Triangle.\n");
+  triexit(0);
+}
+
+#endif /* not TRILIBRARY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  info()   Print out complete instructions.                                */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef TRILIBRARY
+
+void info()
+{
+  printf("Triangle\n");
+  printf(
+"A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.\n");
+  printf("Version 1.6\n\n");
+  printf(
+"Copyright 1993, 1995, 1997, 1998, 2002, 2005 Jonathan Richard Shewchuk\n");
+  printf("2360 Woolsey #H / Berkeley, California 94705-1927\n");
+  printf("Bugs/comments to jrs@cs.berkeley.edu\n");
+  printf(
+"Created as part of the Quake project (tools for earthquake simulation).\n");
+  printf(
+"Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.\n");
+  printf("There is no warranty whatsoever.  Use at your own risk.\n");
+#ifdef SINGLE
+  printf("This executable is compiled for single precision arithmetic.\n\n\n");
+#else /* not SINGLE */
+  printf("This executable is compiled for double precision arithmetic.\n\n\n");
+#endif /* not SINGLE */
+  printf(
+"Triangle generates exact Delaunay triangulations, constrained Delaunay\n");
+  printf(
+"triangulations, conforming Delaunay triangulations, Voronoi diagrams, and\n");
+  printf(
+"high-quality triangular meshes.  The latter can be generated with no small\n"
+);
+  printf(
+"or large angles, and are thus suitable for finite element analysis.  If no\n"
+);
+  printf(
+"command line switch is specified, your .node input file is read, and the\n");
+  printf(
+"Delaunay triangulation is returned in .node and .ele output files.  The\n");
+  printf("command syntax is:\n\n");
+  printf("triangle [-prq__a__uAcDjevngBPNEIOXzo_YS__iFlsCQVh] input_file\n\n");
+  printf(
+"Underscores indicate that numbers may optionally follow certain switches.\n");
+  printf(
+"Do not leave any space between a switch and its numeric parameter.\n");
+  printf(
+"input_file must be a file with extension .node, or extension .poly if the\n");
+  printf(
+"-p switch is used.  If -r is used, you must supply .node and .ele files,\n");
+  printf(
+"and possibly a .poly file and an .area file as well.  The formats of these\n"
+);
+  printf("files are described below.\n\n");
+  printf("Command Line Switches:\n\n");
+  printf(
+"    -p  Reads a Planar Straight Line Graph (.poly file), which can specify\n"
+);
+  printf(
+"        vertices, segments, holes, regional attributes, and regional area\n");
+  printf(
+"        constraints.  Generates a constrained Delaunay triangulation (CDT)\n"
+);
+  printf(
+"        fitting the input; or, if -s, -q, -a, or -u is used, a conforming\n");
+  printf(
+"        constrained Delaunay triangulation (CCDT).  If you want a truly\n");
+  printf(
+"        Delaunay (not just constrained Delaunay) triangulation, use -D as\n");
+  printf(
+"        well.  When -p is not used, Triangle reads a .node file by default.\n"
+);
+  printf(
+"    -r  Refines a previously generated mesh.  The mesh is read from a .node\n"
+);
+  printf(
+"        file and an .ele file.  If -p is also used, a .poly file is read\n");
+  printf(
+"        and used to constrain segments in the mesh.  If -a is also used\n");
+  printf(
+"        (with no number following), an .area file is read and used to\n");
+  printf(
+"        impose area constraints on the mesh.  Further details on refinement\n"
+);
+  printf("        appear below.\n");
+  printf(
+"    -q  Quality mesh generation by Delaunay refinement (a hybrid of Paul\n");
+  printf(
+"        Chew's and Jim Ruppert's algorithms).  Adds vertices to the mesh to\n"
+);
+  printf(
+"        ensure that all angles are between 20 and 140 degrees.  An\n");
+  printf(
+"        alternative bound on the minimum angle, replacing 20 degrees, may\n");
+  printf(
+"        be specified after the `q'.  The specified angle may include a\n");
+  printf(
+"        decimal point, but not exponential notation.  Note that a bound of\n"
+);
+  printf(
+"        theta degrees on the smallest angle also implies a bound of\n");
+  printf(
+"        (180 - 2 theta) on the largest angle.  If the minimum angle is 28.6\n"
+);
+  printf(
+"        degrees or smaller, Triangle is mathematically guaranteed to\n");
+  printf(
+"        terminate (assuming infinite precision arithmetic--Triangle may\n");
+  printf(
+"        fail to terminate if you run out of precision).  In practice,\n");
+  printf(
+"        Triangle often succeeds for minimum angles up to 34 degrees.  For\n");
+  printf(
+"        some meshes, however, you might need to reduce the minimum angle to\n"
+);
+  printf(
+"        avoid problems associated with insufficient floating-point\n");
+  printf("        precision.\n");
+  printf(
+"    -a  Imposes a maximum triangle area.  If a number follows the `a', no\n");
+  printf(
+"        triangle is generated whose area is larger than that number.  If no\n"
+);
+  printf(
+"        number is specified, an .area file (if -r is used) or .poly file\n");
+  printf(
+"        (if -r is not used) specifies a set of maximum area constraints.\n");
+  printf(
+"        An .area file contains a separate area constraint for each\n");
+  printf(
+"        triangle, and is useful for refining a finite element mesh based on\n"
+);
+  printf(
+"        a posteriori error estimates.  A .poly file can optionally contain\n"
+);
+  printf(
+"        an area constraint for each segment-bounded region, thereby\n");
+  printf(
+"        controlling triangle densities in a first triangulation of a PSLG.\n"
+);
+  printf(
+"        You can impose both a fixed area constraint and a varying area\n");
+  printf(
+"        constraint by invoking the -a switch twice, once with and once\n");
+  printf(
+"        without a number following.  Each area specified may include a\n");
+  printf("        decimal point.\n");
+  printf(
+"    -u  Imposes a user-defined constraint on triangle size.  There are two\n"
+);
+  printf(
+"        ways to use this feature.  One is to edit the triunsuitable()\n");
+  printf(
+"        procedure in triangle.c to encode any constraint you like, then\n");
+  printf(
+"        recompile Triangle.  The other is to compile triangle.c with the\n");
+  printf(
+"        EXTERNAL_TEST symbol set (compiler switch -DEXTERNAL_TEST), then\n");
+  printf(
+"        link Triangle with a separate object file that implements\n");
+  printf(
+"        triunsuitable().  In either case, the -u switch causes the user-\n");
+  printf("        defined test to be applied to every triangle.\n");
+  printf(
+"    -A  Assigns an additional floating-point attribute to each triangle\n");
+  printf(
+"        that identifies what segment-bounded region each triangle belongs\n");
+  printf(
+"        to.  Attributes are assigned to regions by the .poly file.  If a\n");
+  printf(
+"        region is not explicitly marked by the .poly file, triangles in\n");
+  printf(
+"        that region are assigned an attribute of zero.  The -A switch has\n");
+  printf(
+"        an effect only when the -p switch is used and the -r switch is not.\n"
+);
+  printf(
+"    -c  Creates segments on the convex hull of the triangulation.  If you\n");
+  printf(
+"        are triangulating a vertex set, this switch causes a .poly file to\n"
+);
+  printf(
+"        be written, containing all edges of the convex hull.  If you are\n");
+  printf(
+"        triangulating a PSLG, this switch specifies that the whole convex\n");
+  printf(
+"        hull of the PSLG should be triangulated, regardless of what\n");
+  printf(
+"        segments the PSLG has.  If you do not use this switch when\n");
+  printf(
+"        triangulating a PSLG, Triangle assumes that you have identified the\n"
+);
+  printf(
+"        region to be triangulated by surrounding it with segments of the\n");
+  printf(
+"        input PSLG.  Beware:  if you are not careful, this switch can cause\n"
+);
+  printf(
+"        the introduction of an extremely thin angle between a PSLG segment\n"
+);
+  printf(
+"        and a convex hull segment, which can cause overrefinement (and\n");
+  printf(
+"        possibly failure if Triangle runs out of precision).  If you are\n");
+  printf(
+"        refining a mesh, the -c switch works differently:  it causes a\n");
+  printf(
+"        .poly file to be written containing the boundary edges of the mesh\n"
+);
+  printf("        (useful if no .poly file was read).\n");
+  printf(
+"    -D  Conforming Delaunay triangulation:  use this switch if you want to\n"
+);
+  printf(
+"        ensure that all the triangles in the mesh are Delaunay, and not\n");
+  printf(
+"        merely constrained Delaunay; or if you want to ensure that all the\n"
+);
+  printf(
+"        Voronoi vertices lie within the triangulation.  (Some finite volume\n"
+);
+  printf(
+"        methods have this requirement.)  This switch invokes Ruppert's\n");
+  printf(
+"        original algorithm, which splits every subsegment whose diametral\n");
+  printf(
+"        circle is encroached.  It usually increases the number of vertices\n"
+);
+  printf("        and triangles.\n");
+  printf(
+"    -j  Jettisons vertices that are not part of the final triangulation\n");
+  printf(
+"        from the output .node file.  By default, Triangle copies all\n");
+  printf(
+"        vertices in the input .node file to the output .node file, in the\n");
+  printf(
+"        same order, so their indices do not change.  The -j switch prevents\n"
+);
+  printf(
+"        duplicated input vertices, or vertices `eaten' by holes, from\n");
+  printf(
+"        appearing in the output .node file.  Thus, if two input vertices\n");
+  printf(
+"        have exactly the same coordinates, only the first appears in the\n");
+  printf(
+"        output.  If any vertices are jettisoned, the vertex numbering in\n");
+  printf(
+"        the output .node file differs from that of the input .node file.\n");
+  printf(
+"    -e  Outputs (to an .edge file) a list of edges of the triangulation.\n");
+  printf(
+"    -v  Outputs the Voronoi diagram associated with the triangulation.\n");
+  printf(
+"        Does not attempt to detect degeneracies, so some Voronoi vertices\n");
+  printf(
+"        may be duplicated.  See the discussion of Voronoi diagrams below.\n");
+  printf(
+"    -n  Outputs (to a .neigh file) a list of triangles neighboring each\n");
+  printf("        triangle.\n");
+  printf(
+"    -g  Outputs the mesh to an Object File Format (.off) file, suitable for\n"
+);
+  printf("        viewing with the Geometry Center's Geomview package.\n");
+  printf(
+"    -B  No boundary markers in the output .node, .poly, and .edge output\n");
+  printf(
+"        files.  See the detailed discussion of boundary markers below.\n");
+  printf(
+"    -P  No output .poly file.  Saves disk space, but you lose the ability\n");
+  printf(
+"        to maintain constraining segments on later refinements of the mesh.\n"
+);
+  printf("    -N  No output .node file.\n");
+  printf("    -E  No output .ele file.\n");
+  printf(
+"    -I  No iteration numbers.  Suppresses the output of .node and .poly\n");
+  printf(
+"        files, so your input files won't be overwritten.  (If your input is\n"
+);
+  printf(
+"        a .poly file only, a .node file is written.)  Cannot be used with\n");
+  printf(
+"        the -r switch, because that would overwrite your input .ele file.\n");
+  printf(
+"        Shouldn't be used with the -q, -a, -u, or -s switch if you are\n");
+  printf(
+"        using a .node file for input, because no .node file is written, so\n"
+);
+  printf("        there is no record of any added Steiner points.\n");
+  printf("    -O  No holes.  Ignores the holes in the .poly file.\n");
+  printf(
+"    -X  No exact arithmetic.  Normally, Triangle uses exact floating-point\n"
+);
+  printf(
+"        arithmetic for certain tests if it thinks the inexact tests are not\n"
+);
+  printf(
+"        accurate enough.  Exact arithmetic ensures the robustness of the\n");
+  printf(
+"        triangulation algorithms, despite floating-point roundoff error.\n");
+  printf(
+"        Disabling exact arithmetic with the -X switch causes a small\n");
+  printf(
+"        improvement in speed and creates the possibility that Triangle will\n"
+);
+  printf("        fail to produce a valid mesh.  Not recommended.\n");
+  printf(
+"    -z  Numbers all items starting from zero (rather than one).  Note that\n"
+);
+  printf(
+"        this switch is normally overridden by the value used to number the\n"
+);
+  printf(
+"        first vertex of the input .node or .poly file.  However, this\n");
+  printf(
+"        switch is useful when calling Triangle from another program.\n");
+  printf(
+"    -o2 Generates second-order subparametric elements with six nodes each.\n"
+);
+  printf(
+"    -Y  No new vertices on the boundary.  This switch is useful when the\n");
+  printf(
+"        mesh boundary must be preserved so that it conforms to some\n");
+  printf(
+"        adjacent mesh.  Be forewarned that you will probably sacrifice much\n"
+);
+  printf(
+"        of the quality of the mesh; Triangle will try, but the resulting\n");
+  printf(
+"        mesh may contain poorly shaped triangles.  Works well if all the\n");
+  printf(
+"        boundary vertices are closely spaced.  Specify this switch twice\n");
+  printf(
+"        (`-YY') to prevent all segment splitting, including internal\n");
+  printf("        boundaries.\n");
+  printf(
+"    -S  Specifies the maximum number of Steiner points (vertices that are\n");
+  printf(
+"        not in the input, but are added to meet the constraints on minimum\n"
+);
+  printf(
+"        angle and maximum area).  The default is to allow an unlimited\n");
+  printf(
+"        number.  If you specify this switch with no number after it,\n");
+  printf(
+"        the limit is set to zero.  Triangle always adds vertices at segment\n"
+);
+  printf(
+"        intersections, even if it needs to use more vertices than the limit\n"
+);
+  printf(
+"        you set.  When Triangle inserts segments by splitting (-s), it\n");
+  printf(
+"        always adds enough vertices to ensure that all the segments of the\n"
+);
+  printf("        PLSG are recovered, ignoring the limit if necessary.\n");
+  printf(
+"    -i  Uses an incremental rather than a divide-and-conquer algorithm to\n");
+  printf(
+"        construct a Delaunay triangulation.  Try it if the divide-and-\n");
+  printf("        conquer algorithm fails.\n");
+  printf(
+"    -F  Uses Steven Fortune's sweepline algorithm to construct a Delaunay\n");
+  printf(
+"        triangulation.  Warning:  does not use exact arithmetic for all\n");
+  printf("        calculations.  An exact result is not guaranteed.\n");
+  printf(
+"    -l  Uses only vertical cuts in the divide-and-conquer algorithm.  By\n");
+  printf(
+"        default, Triangle alternates between vertical and horizontal cuts,\n"
+);
+  printf(
+"        which usually improve the speed except with vertex sets that are\n");
+  printf(
+"        small or short and wide.  This switch is primarily of theoretical\n");
+  printf("        interest.\n");
+  printf(
+"    -s  Specifies that segments should be forced into the triangulation by\n"
+);
+  printf(
+"        recursively splitting them at their midpoints, rather than by\n");
+  printf(
+"        generating a constrained Delaunay triangulation.  Segment splitting\n"
+);
+  printf(
+"        is true to Ruppert's original algorithm, but can create needlessly\n"
+);
+  printf(
+"        small triangles.  This switch is primarily of theoretical interest.\n"
+);
+  printf(
+"    -C  Check the consistency of the final mesh.  Uses exact arithmetic for\n"
+);
+  printf(
+"        checking, even if the -X switch is used.  Useful if you suspect\n");
+  printf("        Triangle is buggy.\n");
+  printf(
+"    -Q  Quiet:  Suppresses all explanation of what Triangle is doing,\n");
+  printf("        unless an error occurs.\n");
+  printf(
+"    -V  Verbose:  Gives detailed information about what Triangle is doing.\n"
+);
+  printf(
+"        Add more `V's for increasing amount of detail.  `-V' is most\n");
+  printf(
+"        useful; itgives information on algorithmic progress and much more\n");
+  printf(
+"        detailed statistics.  `-VV' gives vertex-by-vertex details, and\n");
+  printf(
+"        prints so much that Triangle runs much more slowly.  `-VVVV' gives\n"
+);
+  printf("        information only a debugger could love.\n");
+  printf("    -h  Help:  Displays these instructions.\n");
+  printf("\n");
+  printf("Definitions:\n");
+  printf("\n");
+  printf(
+"  A Delaunay triangulation of a vertex set is a triangulation whose\n");
+  printf(
+"  vertices are the vertex set, that covers the convex hull of the vertex\n");
+  printf(
+"  set.  A Delaunay triangulation has the property that no vertex lies\n");
+  printf(
+"  inside the circumscribing circle (circle that passes through all three\n");
+  printf("  vertices) of any triangle in the triangulation.\n\n");
+  printf(
+"  A Voronoi diagram of a vertex set is a subdivision of the plane into\n");
+  printf(
+"  polygonal cells (some of which may be unbounded, meaning infinitely\n");
+  printf(
+"  large), where each cell is the set of points in the plane that are closer\n"
+);
+  printf(
+"  to some input vertex than to any other input vertex.  The Voronoi diagram\n"
+);
+  printf("  is a geometric dual of the Delaunay triangulation.\n\n");
+  printf(
+"  A Planar Straight Line Graph (PSLG) is a set of vertices and segments.\n");
+  printf(
+"  Segments are simply edges, whose endpoints are all vertices in the PSLG.\n"
+);
+  printf(
+"  Segments may intersect each other only at their endpoints.  The file\n");
+  printf("  format for PSLGs (.poly files) is described below.\n\n");
+  printf(
+"  A constrained Delaunay triangulation (CDT) of a PSLG is similar to a\n");
+  printf(
+"  Delaunay triangulation, but each PSLG segment is present as a single edge\n"
+);
+  printf(
+"  of the CDT.  (A constrained Delaunay triangulation is not truly a\n");
+  printf(
+"  Delaunay triangulation, because some of its triangles might not be\n");
+  printf(
+"  Delaunay.)  By definition, a CDT does not have any vertices other than\n");
+  printf(
+"  those specified in the input PSLG.  Depending on context, a CDT might\n");
+  printf(
+"  cover the convex hull of the PSLG, or it might cover only a segment-\n");
+  printf("  bounded region (e.g. a polygon).\n\n");
+  printf(
+"  A conforming Delaunay triangulation of a PSLG is a triangulation in which\n"
+);
+  printf(
+"  each triangle is truly Delaunay, and each PSLG segment is represented by\n"
+);
+  printf(
+"  a linear contiguous sequence of edges of the triangulation.  New vertices\n"
+);
+  printf(
+"  (not part of the PSLG) may appear, and each input segment may have been\n");
+  printf(
+"  subdivided into shorter edges (subsegments) by these additional vertices.\n"
+);
+  printf(
+"  The new vertices are frequently necessary to maintain the Delaunay\n");
+  printf("  property while ensuring that every segment is represented.\n\n");
+  printf(
+"  A conforming constrained Delaunay triangulation (CCDT) of a PSLG is a\n");
+  printf(
+"  triangulation of a PSLG whose triangles are constrained Delaunay.  New\n");
+  printf("  vertices may appear, and input segments may be subdivided into\n");
+  printf(
+"  subsegments, but not to guarantee that segments are respected; rather, to\n"
+);
+  printf(
+"  improve the quality of the triangles.  The high-quality meshes produced\n");
+  printf(
+"  by the -q switch are usually CCDTs, but can be made conforming Delaunay\n");
+  printf("  with the -D switch.\n\n");
+  printf("File Formats:\n\n");
+  printf(
+"  All files may contain comments prefixed by the character '#'.  Vertices,\n"
+);
+  printf(
+"  triangles, edges, holes, and maximum area constraints must be numbered\n");
+  printf(
+"  consecutively, starting from either 1 or 0.  Whichever you choose, all\n");
+  printf(
+"  input files must be consistent; if the vertices are numbered from 1, so\n");
+  printf(
+"  must be all other objects.  Triangle automatically detects your choice\n");
+  printf(
+"  while reading the .node (or .poly) file.  (When calling Triangle from\n");
+  printf(
+"  another program, use the -z switch if you wish to number objects from\n");
+  printf("  zero.)  Examples of these file formats are given below.\n\n");
+  printf("  .node files:\n");
+  printf(
+"    First line:  <# of vertices> <dimension (must be 2)> <# of attributes>\n"
+);
+  printf(
+"                                           <# of boundary markers (0 or 1)>\n"
+);
+  printf(
+"    Remaining lines:  <vertex #> <x> <y> [attributes] [boundary marker]\n");
+  printf("\n");
+  printf(
+"    The attributes, which are typically floating-point values of physical\n");
+  printf(
+"    quantities (such as mass or conductivity) associated with the nodes of\n"
+);
+  printf(
+"    a finite element mesh, are copied unchanged to the output mesh.  If -q,\n"
+);
+  printf(
+"    -a, -u, -D, or -s is selected, each new Steiner point added to the mesh\n"
+);
+  printf("    has attributes assigned to it by linear interpolation.\n\n");
+  printf(
+"    If the fourth entry of the first line is `1', the last column of the\n");
+  printf(
+"    remainder of the file is assumed to contain boundary markers.  Boundary\n"
+);
+  printf(
+"    markers are used to identify boundary vertices and vertices resting on\n"
+);
+  printf(
+"    PSLG segments; a complete description appears in a section below.  The\n"
+);
+  printf(
+"    .node file produced by Triangle contains boundary markers in the last\n");
+  printf("    column unless they are suppressed by the -B switch.\n\n");
+  printf("  .ele files:\n");
+  printf(
+"    First line:  <# of triangles> <nodes per triangle> <# of attributes>\n");
+  printf(
+"    Remaining lines:  <triangle #> <node> <node> <node> ... [attributes]\n");
+  printf("\n");
+  printf(
+"    Nodes are indices into the corresponding .node file.  The first three\n");
+  printf(
+"    nodes are the corner vertices, and are listed in counterclockwise order\n"
+);
+  printf(
+"    around each triangle.  (The remaining nodes, if any, depend on the type\n"
+);
+  printf("    of finite element used.)\n\n");
+  printf(
+"    The attributes are just like those of .node files.  Because there is no\n"
+);
+  printf(
+"    simple mapping from input to output triangles, Triangle attempts to\n");
+  printf(
+"    interpolate attributes, and may cause a lot of diffusion of attributes\n"
+);
+  printf(
+"    among nearby triangles as the triangulation is refined.  Attributes do\n"
+);
+  printf("    not diffuse across segments, so attributes used to identify\n");
+  printf("    segment-bounded regions remain intact.\n\n");
+  printf(
+"    In .ele files produced by Triangle, each triangular element has three\n");
+  printf(
+"    nodes (vertices) unless the -o2 switch is used, in which case\n");
+  printf(
+"    subparametric quadratic elements with six nodes each are generated.\n");
+  printf(
+"    The first three nodes are the corners in counterclockwise order, and\n");
+  printf(
+"    the fourth, fifth, and sixth nodes lie on the midpoints of the edges\n");
+  printf(
+"    opposite the first, second, and third vertices, respectively.\n");
+  printf("\n");
+  printf("  .poly files:\n");
+  printf(
+"    First line:  <# of vertices> <dimension (must be 2)> <# of attributes>\n"
+);
+  printf(
+"                                           <# of boundary markers (0 or 1)>\n"
+);
+  printf(
+"    Following lines:  <vertex #> <x> <y> [attributes] [boundary marker]\n");
+  printf("    One line:  <# of segments> <# of boundary markers (0 or 1)>\n");
+  printf(
+"    Following lines:  <segment #> <endpoint> <endpoint> [boundary marker]\n");
+  printf("    One line:  <# of holes>\n");
+  printf("    Following lines:  <hole #> <x> <y>\n");
+  printf(
+"    Optional line:  <# of regional attributes and/or area constraints>\n");
+  printf(
+"    Optional following lines:  <region #> <x> <y> <attribute> <max area>\n");
+  printf("\n");
+  printf(
+"    A .poly file represents a PSLG, as well as some additional information.\n"
+);
+  printf(
+"    The first section lists all the vertices, and is identical to the\n");
+  printf(
+"    format of .node files.  <# of vertices> may be set to zero to indicate\n"
+);
+  printf(
+"    that the vertices are listed in a separate .node file; .poly files\n");
+  printf(
+"    produced by Triangle always have this format.  A vertex set represented\n"
+);
+  printf(
+"    this way has the advantage that it may easily be triangulated with or\n");
+  printf(
+"    without segments (depending on whether the -p switch is invoked).\n");
+  printf("\n");
+  printf(
+"    The second section lists the segments.  Segments are edges whose\n");
+  printf(
+"    presence in the triangulation is enforced.  (Depending on the choice of\n"
+);
+  printf(
+"    switches, segment might be subdivided into smaller edges).  Each\n");
+  printf(
+"    segment is specified by listing the indices of its two endpoints.  This\n"
+);
+  printf(
+"    means that you must include its endpoints in the vertex list.  Each\n");
+  printf("    segment, like each point, may have a boundary marker.\n\n");
+  printf(
+"    If -q, -a, -u, and -s are not selected, Triangle produces a constrained\n"
+);
+  printf(
+"    Delaunay triangulation (CDT), in which each segment appears as a single\n"
+);
+  printf(
+"    edge in the triangulation.  If -q, -a, -u, or -s is selected, Triangle\n"
+);
+  printf(
+"    produces a conforming constrained Delaunay triangulation (CCDT), in\n");
+  printf(
+"    which segments may be subdivided into smaller edges.  If -D is\n");
+  printf(
+"    selected, Triangle produces a conforming Delaunay triangulation, so\n");
+  printf(
+"    that every triangle is Delaunay, and not just constrained Delaunay.\n");
+  printf("\n");
+  printf(
+"    The third section lists holes (and concavities, if -c is selected) in\n");
+  printf(
+"    the triangulation.  Holes are specified by identifying a point inside\n");
+  printf(
+"    each hole.  After the triangulation is formed, Triangle creates holes\n");
+  printf(
+"    by eating triangles, spreading out from each hole point until its\n");
+  printf(
+"    progress is blocked by segments in the PSLG.  You must be careful to\n");
+  printf(
+"    enclose each hole in segments, or your whole triangulation might be\n");
+  printf(
+"    eaten away.  If the two triangles abutting a segment are eaten, the\n");
+  printf(
+"    segment itself is also eaten.  Do not place a hole directly on a\n");
+  printf("    segment; if you do, Triangle chooses one side of the segment\n");
+  printf("    arbitrarily.\n\n");
+  printf(
+"    The optional fourth section lists regional attributes (to be assigned\n");
+  printf(
+"    to all triangles in a region) and regional constraints on the maximum\n");
+  printf(
+"    triangle area.  Triangle reads this section only if the -A switch is\n");
+  printf(
+"    used or the -a switch is used without a number following it, and the -r\n"
+);
+  printf(
+"    switch is not used.  Regional attributes and area constraints are\n");
+  printf(
+"    propagated in the same manner as holes:  you specify a point for each\n");
+  printf(
+"    attribute and/or constraint, and the attribute and/or constraint\n");
+  printf(
+"    affects the whole region (bounded by segments) containing the point.\n");
+  printf(
+"    If two values are written on a line after the x and y coordinate, the\n");
+  printf(
+"    first such value is assumed to be a regional attribute (but is only\n");
+  printf(
+"    applied if the -A switch is selected), and the second value is assumed\n"
+);
+  printf(
+"    to be a regional area constraint (but is only applied if the -a switch\n"
+);
+  printf(
+"    is selected).  You may specify just one value after the coordinates,\n");
+  printf(
+"    which can serve as both an attribute and an area constraint, depending\n"
+);
+  printf(
+"    on the choice of switches.  If you are using the -A and -a switches\n");
+  printf(
+"    simultaneously and wish to assign an attribute to some region without\n");
+  printf("    imposing an area constraint, use a negative maximum area.\n\n");
+  printf(
+"    When a triangulation is created from a .poly file, you must either\n");
+  printf(
+"    enclose the entire region to be triangulated in PSLG segments, or\n");
+  printf(
+"    use the -c switch, which automatically creates extra segments that\n");
+  printf(
+"    enclose the convex hull of the PSLG.  If you do not use the -c switch,\n"
+);
+  printf(
+"    Triangle eats all triangles that are not enclosed by segments; if you\n");
+  printf(
+"    are not careful, your whole triangulation may be eaten away.  If you do\n"
+);
+  printf(
+"    use the -c switch, you can still produce concavities by the appropriate\n"
+);
+  printf(
+"    placement of holes just inside the boundary of the convex hull.\n");
+  printf("\n");
+  printf(
+"    An ideal PSLG has no intersecting segments, nor any vertices that lie\n");
+  printf(
+"    upon segments (except, of course, the endpoints of each segment).  You\n"
+);
+  printf(
+"    aren't required to make your .poly files ideal, but you should be aware\n"
+);
+  printf(
+"    of what can go wrong.  Segment intersections are relatively safe--\n");
+  printf(
+"    Triangle calculates the intersection points for you and adds them to\n");
+  printf(
+"    the triangulation--as long as your machine's floating-point precision\n");
+  printf(
+"    doesn't become a problem.  You are tempting the fates if you have three\n"
+);
+  printf(
+"    segments that cross at the same location, and expect Triangle to figure\n"
+);
+  printf(
+"    out where the intersection point is.  Thanks to floating-point roundoff\n"
+);
+  printf(
+"    error, Triangle will probably decide that the three segments intersect\n"
+);
+  printf(
+"    at three different points, and you will find a minuscule triangle in\n");
+  printf(
+"    your output--unless Triangle tries to refine the tiny triangle, uses\n");
+  printf(
+"    up the last bit of machine precision, and fails to terminate at all.\n");
+  printf(
+"    You're better off putting the intersection point in the input files,\n");
+  printf(
+"    and manually breaking up each segment into two.  Similarly, if you\n");
+  printf(
+"    place a vertex at the middle of a segment, and hope that Triangle will\n"
+);
+  printf(
+"    break up the segment at that vertex, you might get lucky.  On the other\n"
+);
+  printf(
+"    hand, Triangle might decide that the vertex doesn't lie precisely on\n");
+  printf(
+"    the segment, and you'll have a needle-sharp triangle in your output--or\n"
+);
+  printf("    a lot of tiny triangles if you're generating a quality mesh.\n");
+  printf("\n");
+  printf(
+"    When Triangle reads a .poly file, it also writes a .poly file, which\n");
+  printf(
+"    includes all the subsegments--the edges that are parts of input\n");
+  printf(
+"    segments.  If the -c switch is used, the output .poly file also\n");
+  printf(
+"    includes all of the edges on the convex hull.  Hence, the output .poly\n"
+);
+  printf(
+"    file is useful for finding edges associated with input segments and for\n"
+);
+  printf(
+"    setting boundary conditions in finite element simulations.  Moreover,\n");
+  printf(
+"    you will need the output .poly file if you plan to refine the output\n");
+  printf(
+"    mesh, and don't want segments to be missing in later triangulations.\n");
+  printf("\n");
+  printf("  .area files:\n");
+  printf("    First line:  <# of triangles>\n");
+  printf("    Following lines:  <triangle #> <maximum area>\n");
+  printf("\n");
+  printf(
+"    An .area file associates with each triangle a maximum area that is used\n"
+);
+  printf(
+"    for mesh refinement.  As with other file formats, every triangle must\n");
+  printf(
+"    be represented, and the triangles must be numbered consecutively.  A\n");
+  printf(
+"    triangle may be left unconstrained by assigning it a negative maximum\n");
+  printf("    area.\n\n");
+  printf("  .edge files:\n");
+  printf("    First line:  <# of edges> <# of boundary markers (0 or 1)>\n");
+  printf(
+"    Following lines:  <edge #> <endpoint> <endpoint> [boundary marker]\n");
+  printf("\n");
+  printf(
+"    Endpoints are indices into the corresponding .node file.  Triangle can\n"
+);
+  printf(
+"    produce .edge files (use the -e switch), but cannot read them.  The\n");
+  printf(
+"    optional column of boundary markers is suppressed by the -B switch.\n");
+  printf("\n");
+  printf(
+"    In Voronoi diagrams, one also finds a special kind of edge that is an\n");
+  printf(
+"    infinite ray with only one endpoint.  For these edges, a different\n");
+  printf("    format is used:\n\n");
+  printf("        <edge #> <endpoint> -1 <direction x> <direction y>\n\n");
+  printf(
+"    The `direction' is a floating-point vector that indicates the direction\n"
+);
+  printf("    of the infinite ray.\n\n");
+  printf("  .neigh files:\n");
+  printf(
+"    First line:  <# of triangles> <# of neighbors per triangle (always 3)>\n"
+);
+  printf(
+"    Following lines:  <triangle #> <neighbor> <neighbor> <neighbor>\n");
+  printf("\n");
+  printf(
+"    Neighbors are indices into the corresponding .ele file.  An index of -1\n"
+);
+  printf(
+"    indicates no neighbor (because the triangle is on an exterior\n");
+  printf(
+"    boundary).  The first neighbor of triangle i is opposite the first\n");
+  printf("    corner of triangle i, and so on.\n\n");
+  printf(
+"    Triangle can produce .neigh files (use the -n switch), but cannot read\n"
+);
+  printf("    them.\n\n");
+  printf("Boundary Markers:\n\n");
+  printf(
+"  Boundary markers are tags used mainly to identify which output vertices\n");
+  printf(
+"  and edges are associated with which PSLG segment, and to identify which\n");
+  printf(
+"  vertices and edges occur on a boundary of the triangulation.  A common\n");
+  printf(
+"  use is to determine where boundary conditions should be applied to a\n");
+  printf(
+"  finite element mesh.  You can prevent boundary markers from being written\n"
+);
+  printf("  into files produced by Triangle by using the -B switch.\n\n");
+  printf(
+"  The boundary marker associated with each segment in an output .poly file\n"
+);
+  printf("  and each edge in an output .edge file is chosen as follows:\n");
+  printf(
+"    - If an output edge is part or all of a PSLG segment with a nonzero\n");
+  printf(
+"      boundary marker, then the edge is assigned the same marker.\n");
+  printf(
+"    - Otherwise, if the edge lies on a boundary of the triangulation\n");
+  printf(
+"      (even the boundary of a hole), then the edge is assigned the marker\n");
+  printf("      one (1).\n");
+  printf("    - Otherwise, the edge is assigned the marker zero (0).\n");
+  printf(
+"  The boundary marker associated with each vertex in an output .node file\n");
+  printf("  is chosen as follows:\n");
+  printf(
+"    - If a vertex is assigned a nonzero boundary marker in the input file,\n"
+);
+  printf(
+"      then it is assigned the same marker in the output .node file.\n");
+  printf(
+"    - Otherwise, if the vertex lies on a PSLG segment (even if it is an\n");
+  printf(
+"      endpoint of the segment) with a nonzero boundary marker, then the\n");
+  printf(
+"      vertex is assigned the same marker.  If the vertex lies on several\n");
+  printf("      such segments, one of the markers is chosen arbitrarily.\n");
+  printf(
+"    - Otherwise, if the vertex occurs on a boundary of the triangulation,\n");
+  printf("      then the vertex is assigned the marker one (1).\n");
+  printf("    - Otherwise, the vertex is assigned the marker zero (0).\n");
+  printf("\n");
+  printf(
+"  If you want Triangle to determine for you which vertices and edges are on\n"
+);
+  printf(
+"  the boundary, assign them the boundary marker zero (or use no markers at\n"
+);
+  printf(
+"  all) in your input files.  In the output files, all boundary vertices,\n");
+  printf("  edges, and segments will be assigned the value one.\n\n");
+  printf("Triangulation Iteration Numbers:\n\n");
+  printf(
+"  Because Triangle can read and refine its own triangulations, input\n");
+  printf(
+"  and output files have iteration numbers.  For instance, Triangle might\n");
+  printf(
+"  read the files mesh.3.node, mesh.3.ele, and mesh.3.poly, refine the\n");
+  printf(
+"  triangulation, and output the files mesh.4.node, mesh.4.ele, and\n");
+  printf("  mesh.4.poly.  Files with no iteration number are treated as if\n");
+  printf(
+"  their iteration number is zero; hence, Triangle might read the file\n");
+  printf(
+"  points.node, triangulate it, and produce the files points.1.node and\n");
+  printf("  points.1.ele.\n\n");
+  printf(
+"  Iteration numbers allow you to create a sequence of successively finer\n");
+  printf(
+"  meshes suitable for multigrid methods.  They also allow you to produce a\n"
+);
+  printf(
+"  sequence of meshes using error estimate-driven mesh refinement.\n");
+  printf("\n");
+  printf(
+"  If you're not using refinement or quality meshing, and you don't like\n");
+  printf(
+"  iteration numbers, use the -I switch to disable them.  This switch also\n");
+  printf(
+"  disables output of .node and .poly files to prevent your input files from\n"
+);
+  printf(
+"  being overwritten.  (If the input is a .poly file that contains its own\n");
+  printf(
+"  points, a .node file is written.  This can be quite convenient for\n");
+  printf("  computing CDTs or quality meshes.)\n\n");
+  printf("Examples of How to Use Triangle:\n\n");
+  printf(
+"  `triangle dots' reads vertices from dots.node, and writes their Delaunay\n"
+);
+  printf(
+"  triangulation to dots.1.node and dots.1.ele.  (dots.1.node is identical\n");
+  printf(
+"  to dots.node.)  `triangle -I dots' writes the triangulation to dots.ele\n");
+  printf(
+"  instead.  (No additional .node file is needed, so none is written.)\n");
+  printf("\n");
+  printf(
+"  `triangle -pe object.1' reads a PSLG from object.1.poly (and possibly\n");
+  printf(
+"  object.1.node, if the vertices are omitted from object.1.poly) and writes\n"
+);
+  printf(
+"  its constrained Delaunay triangulation to object.2.node and object.2.ele.\n"
+);
+  printf(
+"  The segments are copied to object.2.poly, and all edges are written to\n");
+  printf("  object.2.edge.\n\n");
+  printf(
+"  `triangle -pq31.5a.1 object' reads a PSLG from object.poly (and possibly\n"
+);
+  printf(
+"  object.node), generates a mesh whose angles are all between 31.5 and 117\n"
+);
+  printf(
+"  degrees and whose triangles all have areas of 0.1 or less, and writes the\n"
+);
+  printf(
+"  mesh to object.1.node and object.1.ele.  Each segment may be broken up\n");
+  printf("  into multiple subsegments; these are written to object.1.poly.\n");
+  printf("\n");
+  printf(
+"  Here is a sample file `box.poly' describing a square with a square hole:\n"
+);
+  printf("\n");
+  printf(
+"    # A box with eight vertices in 2D, no attributes, one boundary marker.\n"
+);
+  printf("    8 2 0 1\n");
+  printf("     # Outer box has these vertices:\n");
+  printf("     1   0 0   0\n");
+  printf("     2   0 3   0\n");
+  printf("     3   3 0   0\n");
+  printf("     4   3 3   33     # A special marker for this vertex.\n");
+  printf("     # Inner square has these vertices:\n");
+  printf("     5   1 1   0\n");
+  printf("     6   1 2   0\n");
+  printf("     7   2 1   0\n");
+  printf("     8   2 2   0\n");
+  printf("    # Five segments with boundary markers.\n");
+  printf("    5 1\n");
+  printf("     1   1 2   5      # Left side of outer box.\n");
+  printf("     # Square hole has these segments:\n");
+  printf("     2   5 7   0\n");
+  printf("     3   7 8   0\n");
+  printf("     4   8 6   10\n");
+  printf("     5   6 5   0\n");
+  printf("    # One hole in the middle of the inner square.\n");
+  printf("    1\n");
+  printf("     1   1.5 1.5\n");
+  printf("\n");
+  printf(
+"  Note that some segments are missing from the outer square, so you must\n");
+  printf(
+"  use the `-c' switch.  After `triangle -pqc box.poly', here is the output\n"
+);
+  printf(
+"  file `box.1.node', with twelve vertices.  The last four vertices were\n");
+  printf(
+"  added to meet the angle constraint.  Vertices 1, 2, and 9 have markers\n");
+  printf(
+"  from segment 1.  Vertices 6 and 8 have markers from segment 4.  All the\n");
+  printf(
+"  other vertices but 4 have been marked to indicate that they lie on a\n");
+  printf("  boundary.\n\n");
+  printf("    12  2  0  1\n");
+  printf("       1    0   0      5\n");
+  printf("       2    0   3      5\n");
+  printf("       3    3   0      1\n");
+  printf("       4    3   3     33\n");
+  printf("       5    1   1      1\n");
+  printf("       6    1   2     10\n");
+  printf("       7    2   1      1\n");
+  printf("       8    2   2     10\n");
+  printf("       9    0   1.5    5\n");
+  printf("      10    1.5   0    1\n");
+  printf("      11    3   1.5    1\n");
+  printf("      12    1.5   3    1\n");
+  printf("    # Generated by triangle -pqc box.poly\n");
+  printf("\n");
+  printf("  Here is the output file `box.1.ele', with twelve triangles.\n");
+  printf("\n");
+  printf("    12  3  0\n");
+  printf("       1     5   6   9\n");
+  printf("       2    10   3   7\n");
+  printf("       3     6   8  12\n");
+  printf("       4     9   1   5\n");
+  printf("       5     6   2   9\n");
+  printf("       6     7   3  11\n");
+  printf("       7    11   4   8\n");
+  printf("       8     7   5  10\n");
+  printf("       9    12   2   6\n");
+  printf("      10     8   7  11\n");
+  printf("      11     5   1  10\n");
+  printf("      12     8   4  12\n");
+  printf("    # Generated by triangle -pqc box.poly\n\n");
+  printf(
+"  Here is the output file `box.1.poly'.  Note that segments have been added\n"
+);
+  printf(
+"  to represent the convex hull, and some segments have been subdivided by\n");
+  printf(
+"  newly added vertices.  Note also that <# of vertices> is set to zero to\n");
+  printf("  indicate that the vertices should be read from the .node file.\n");
+  printf("\n");
+  printf("    0  2  0  1\n");
+  printf("    12  1\n");
+  printf("       1     1   9     5\n");
+  printf("       2     5   7     1\n");
+  printf("       3     8   7     1\n");
+  printf("       4     6   8    10\n");
+  printf("       5     5   6     1\n");
+  printf("       6     3  10     1\n");
+  printf("       7     4  11     1\n");
+  printf("       8     2  12     1\n");
+  printf("       9     9   2     5\n");
+  printf("      10    10   1     1\n");
+  printf("      11    11   3     1\n");
+  printf("      12    12   4     1\n");
+  printf("    1\n");
+  printf("       1   1.5 1.5\n");
+  printf("    # Generated by triangle -pqc box.poly\n");
+  printf("\n");
+  printf("Refinement and Area Constraints:\n");
+  printf("\n");
+  printf(
+"  The -r switch causes a mesh (.node and .ele files) to be read and\n");
+  printf(
+"  refined.  If the -p switch is also used, a .poly file is read and used to\n"
+);
+  printf(
+"  specify edges that are constrained and cannot be eliminated (although\n");
+  printf(
+"  they can be subdivided into smaller edges) by the refinement process.\n");
+  printf("\n");
+  printf(
+"  When you refine a mesh, you generally want to impose tighter constraints.\n"
+);
+  printf(
+"  One way to accomplish this is to use -q with a larger angle, or -a\n");
+  printf(
+"  followed by a smaller area than you used to generate the mesh you are\n");
+  printf(
+"  refining.  Another way to do this is to create an .area file, which\n");
+  printf(
+"  specifies a maximum area for each triangle, and use the -a switch\n");
+  printf(
+"  (without a number following).  Each triangle's area constraint is applied\n"
+);
+  printf(
+"  to that triangle.  Area constraints tend to diffuse as the mesh is\n");
+  printf(
+"  refined, so if there are large variations in area constraint between\n");
+  printf(
+"  adjacent triangles, you may not get the results you want.  In that case,\n"
+);
+  printf(
+"  consider instead using the -u switch and writing a C procedure that\n");
+  printf("  determines which triangles are too large.\n\n");
+  printf(
+"  If you are refining a mesh composed of linear (three-node) elements, the\n"
+);
+  printf(
+"  output mesh contains all the nodes present in the input mesh, in the same\n"
+);
+  printf(
+"  order, with new nodes added at the end of the .node file.  However, the\n");
+  printf(
+"  refinement is not hierarchical: there is no guarantee that each output\n");
+  printf(
+"  element is contained in a single input element.  Often, an output element\n"
+);
+  printf(
+"  can overlap two or three input elements, and some input edges are not\n");
+  printf(
+"  present in the output mesh.  Hence, a sequence of refined meshes forms a\n"
+);
+  printf(
+"  hierarchy of nodes, but not a hierarchy of elements.  If you refine a\n");
+  printf(
+"  mesh of higher-order elements, the hierarchical property applies only to\n"
+);
+  printf(
+"  the nodes at the corners of an element; the midpoint nodes on each edge\n");
+  printf("  are discarded before the mesh is refined.\n\n");
+  printf(
+"  Maximum area constraints in .poly files operate differently from those in\n"
+);
+  printf(
+"  .area files.  A maximum area in a .poly file applies to the whole\n");
+  printf(
+"  (segment-bounded) region in which a point falls, whereas a maximum area\n");
+  printf(
+"  in an .area file applies to only one triangle.  Area constraints in .poly\n"
+);
+  printf(
+"  files are used only when a mesh is first generated, whereas area\n");
+  printf(
+"  constraints in .area files are used only to refine an existing mesh, and\n"
+);
+  printf(
+"  are typically based on a posteriori error estimates resulting from a\n");
+  printf("  finite element simulation on that mesh.\n\n");
+  printf(
+"  `triangle -rq25 object.1' reads object.1.node and object.1.ele, then\n");
+  printf(
+"  refines the triangulation to enforce a 25 degree minimum angle, and then\n"
+);
+  printf(
+"  writes the refined triangulation to object.2.node and object.2.ele.\n");
+  printf("\n");
+  printf(
+"  `triangle -rpaa6.2 z.3' reads z.3.node, z.3.ele, z.3.poly, and z.3.area.\n"
+);
+  printf(
+"  After reconstructing the mesh and its subsegments, Triangle refines the\n");
+  printf(
+"  mesh so that no triangle has area greater than 6.2, and furthermore the\n");
+  printf(
+"  triangles satisfy the maximum area constraints in z.3.area.  No angle\n");
+  printf(
+"  bound is imposed at all.  The output is written to z.4.node, z.4.ele, and\n"
+);
+  printf("  z.4.poly.\n\n");
+  printf(
+"  The sequence `triangle -qa1 x', `triangle -rqa.3 x.1', `triangle -rqa.1\n");
+  printf(
+"  x.2' creates a sequence of successively finer meshes x.1, x.2, and x.3,\n");
+  printf("  suitable for multigrid.\n\n");
+  printf("Convex Hulls and Mesh Boundaries:\n\n");
+  printf(
+"  If the input is a vertex set (not a PSLG), Triangle produces its convex\n");
+  printf(
+"  hull as a by-product in the output .poly file if you use the -c switch.\n");
+  printf(
+"  There are faster algorithms for finding a two-dimensional convex hull\n");
+  printf("  than triangulation, of course, but this one comes for free.\n\n");
+  printf(
+"  If the input is an unconstrained mesh (you are using the -r switch but\n");
+  printf(
+"  not the -p switch), Triangle produces a list of its boundary edges\n");
+  printf(
+"  (including hole boundaries) as a by-product when you use the -c switch.\n");
+  printf(
+"  If you also use the -p switch, the output .poly file contains all the\n");
+  printf("  segments from the input .poly file as well.\n\n");
+  printf("Voronoi Diagrams:\n\n");
+  printf(
+"  The -v switch produces a Voronoi diagram, in files suffixed .v.node and\n");
+  printf(
+"  .v.edge.  For example, `triangle -v points' reads points.node, produces\n");
+  printf(
+"  its Delaunay triangulation in points.1.node and points.1.ele, and\n");
+  printf(
+"  produces its Voronoi diagram in points.1.v.node and points.1.v.edge.  The\n"
+);
+  printf(
+"  .v.node file contains a list of all Voronoi vertices, and the .v.edge\n");
+  printf(
+"  file contains a list of all Voronoi edges, some of which may be infinite\n"
+);
+  printf(
+"  rays.  (The choice of filenames makes it easy to run the set of Voronoi\n");
+  printf("  vertices through Triangle, if so desired.)\n\n");
+  printf(
+"  This implementation does not use exact arithmetic to compute the Voronoi\n"
+);
+  printf(
+"  vertices, and does not check whether neighboring vertices are identical.\n"
+);
+  printf(
+"  Be forewarned that if the Delaunay triangulation is degenerate or\n");
+  printf(
+"  near-degenerate, the Voronoi diagram may have duplicate vertices or\n");
+  printf("  crossing edges.\n\n");
+  printf(
+"  The result is a valid Voronoi diagram only if Triangle's output is a true\n"
+);
+  printf(
+"  Delaunay triangulation.  The Voronoi output is usually meaningless (and\n");
+  printf(
+"  may contain crossing edges and other pathology) if the output is a CDT or\n"
+);
+  printf(
+"  CCDT, or if it has holes or concavities.  If the triangulated domain is\n");
+  printf(
+"  convex and has no holes, you can use -D switch to force Triangle to\n");
+  printf(
+"  construct a conforming Delaunay triangulation instead of a CCDT, so the\n");
+  printf("  Voronoi diagram will be valid.\n\n");
+  printf("Mesh Topology:\n\n");
+  printf(
+"  You may wish to know which triangles are adjacent to a certain Delaunay\n");
+  printf(
+"  edge in an .edge file, which Voronoi cells are adjacent to a certain\n");
+  printf(
+"  Voronoi edge in a .v.edge file, or which Voronoi cells are adjacent to\n");
+  printf(
+"  each other.  All of this information can be found by cross-referencing\n");
+  printf(
+"  output files with the recollection that the Delaunay triangulation and\n");
+  printf("  the Voronoi diagram are planar duals.\n\n");
+  printf(
+"  Specifically, edge i of an .edge file is the dual of Voronoi edge i of\n");
+  printf(
+"  the corresponding .v.edge file, and is rotated 90 degrees counterclock-\n");
+  printf(
+"  wise from the Voronoi edge.  Triangle j of an .ele file is the dual of\n");
+  printf(
+"  vertex j of the corresponding .v.node file.  Voronoi cell k is the dual\n");
+  printf("  of vertex k of the corresponding .node file.\n\n");
+  printf(
+"  Hence, to find the triangles adjacent to a Delaunay edge, look at the\n");
+  printf(
+"  vertices of the corresponding Voronoi edge.  If the endpoints of a\n");
+  printf(
+"  Voronoi edge are Voronoi vertices 2 and 6 respectively, then triangles 2\n"
+);
+  printf(
+"  and 6 adjoin the left and right sides of the corresponding Delaunay edge,\n"
+);
+  printf(
+"  respectively.  To find the Voronoi cells adjacent to a Voronoi edge, look\n"
+);
+  printf(
+"  at the endpoints of the corresponding Delaunay edge.  If the endpoints of\n"
+);
+  printf(
+"  a Delaunay edge are input vertices 7 and 12, then Voronoi cells 7 and 12\n"
+);
+  printf(
+"  adjoin the right and left sides of the corresponding Voronoi edge,\n");
+  printf(
+"  respectively.  To find which Voronoi cells are adjacent to each other,\n");
+  printf("  just read the list of Delaunay edges.\n\n");
+  printf(
+"  Triangle does not write a list of the edges adjoining each Voronoi cell,\n"
+);
+  printf(
+"  but you can reconstructed it straightforwardly.  For instance, to find\n");
+  printf(
+"  all the edges of Voronoi cell 1, search the output .edge file for every\n");
+  printf(
+"  edge that has input vertex 1 as an endpoint.  The corresponding dual\n");
+  printf(
+"  edges in the output .v.edge file form the boundary of Voronoi cell 1.\n");
+  printf("\n");
+  printf(
+"  For each Voronoi vertex, the .neigh file gives a list of the three\n");
+  printf(
+"  Voronoi vertices attached to it.  You might find this more convenient\n");
+  printf("  than the .v.edge file.\n\n");
+  printf("Quadratic Elements:\n\n");
+  printf(
+"  Triangle generates meshes with subparametric quadratic elements if the\n");
+  printf(
+"  -o2 switch is specified.  Quadratic elements have six nodes per element,\n"
+);
+  printf(
+"  rather than three.  `Subparametric' means that the edges of the triangles\n"
+);
+  printf(
+"  are always straight, so that subparametric quadratic elements are\n");
+  printf(
+"  geometrically identical to linear elements, even though they can be used\n"
+);
+  printf(
+"  with quadratic interpolating functions.  The three extra nodes of an\n");
+  printf(
+"  element fall at the midpoints of the three edges, with the fourth, fifth,\n"
+);
+  printf(
+"  and sixth nodes appearing opposite the first, second, and third corners\n");
+  printf("  respectively.\n\n");
+  printf("Domains with Small Angles:\n\n");
+  printf(
+"  If two input segments adjoin each other at a small angle, clearly the -q\n"
+);
+  printf(
+"  switch cannot remove the small angle.  Moreover, Triangle may have no\n");
+  printf(
+"  choice but to generate additional triangles whose smallest angles are\n");
+  printf(
+"  smaller than the specified bound.  However, these triangles only appear\n");
+  printf(
+"  between input segments separated by small angles.  Moreover, if you\n");
+  printf(
+"  request a minimum angle of theta degrees, Triangle will generally produce\n"
+);
+  printf(
+"  no angle larger than 180 - 2 theta, even if it is forced to compromise on\n"
+);
+  printf("  the minimum angle.\n\n");
+  printf("Statistics:\n\n");
+  printf(
+"  After generating a mesh, Triangle prints a count of entities in the\n");
+  printf(
+"  output mesh, including the number of vertices, triangles, edges, exterior\n"
+);
+  printf(
+"  boundary edges (i.e. subsegments on the boundary of the triangulation,\n");
+  printf(
+"  including hole boundaries), interior boundary edges (i.e. subsegments of\n"
+);
+  printf(
+"  input segments not on the boundary), and total subsegments.  If you've\n");
+  printf(
+"  forgotten the statistics for an existing mesh, run Triangle on that mesh\n"
+);
+  printf(
+"  with the -rNEP switches to read the mesh and print the statistics without\n"
+);
+  printf(
+"  writing any files.  Use -rpNEP if you've got a .poly file for the mesh.\n");
+  printf("\n");
+  printf(
+"  The -V switch produces extended statistics, including a rough estimate\n");
+  printf(
+"  of memory use, the number of calls to geometric predicates, and\n");
+  printf(
+"  histograms of the angles and the aspect ratios of the triangles in the\n");
+  printf("  mesh.\n\n");
+  printf("Exact Arithmetic:\n\n");
+  printf(
+"  Triangle uses adaptive exact arithmetic to perform what computational\n");
+  printf(
+"  geometers call the `orientation' and `incircle' tests.  If the floating-\n"
+);
+  printf(
+"  point arithmetic of your machine conforms to the IEEE 754 standard (as\n");
+  printf(
+"  most workstations do), and does not use extended precision internal\n");
+  printf(
+"  floating-point registers, then your output is guaranteed to be an\n");
+  printf(
+"  absolutely true Delaunay or constrained Delaunay triangulation, roundoff\n"
+);
+  printf(
+"  error notwithstanding.  The word `adaptive' implies that these arithmetic\n"
+);
+  printf(
+"  routines compute the result only to the precision necessary to guarantee\n"
+);
+  printf(
+"  correctness, so they are usually nearly as fast as their approximate\n");
+  printf("  counterparts.\n\n");
+  printf(
+"  May CPUs, including Intel x86 processors, have extended precision\n");
+  printf(
+"  floating-point registers.  These must be reconfigured so their precision\n"
+);
+  printf(
+"  is reduced to memory precision.  Triangle does this if it is compiled\n");
+  printf("  correctly.  See the makefile for details.\n\n");
+  printf(
+"  The exact tests can be disabled with the -X switch.  On most inputs, this\n"
+);
+  printf(
+"  switch reduces the computation time by about eight percent--it's not\n");
+  printf(
+"  worth the risk.  There are rare difficult inputs (having many collinear\n");
+  printf(
+"  and cocircular vertices), however, for which the difference in speed\n");
+  printf(
+"  could be a factor of two.  Be forewarned that these are precisely the\n");
+  printf(
+"  inputs most likely to cause errors if you use the -X switch.  Hence, the\n"
+);
+  printf("  -X switch is not recommended.\n\n");
+  printf(
+"  Unfortunately, the exact tests don't solve every numerical problem.\n");
+  printf(
+"  Exact arithmetic is not used to compute the positions of new vertices,\n");
+  printf(
+"  because the bit complexity of vertex coordinates would grow without\n");
+  printf(
+"  bound.  Hence, segment intersections aren't computed exactly; in very\n");
+  printf(
+"  unusual cases, roundoff error in computing an intersection point might\n");
+  printf(
+"  actually lead to an inverted triangle and an invalid triangulation.\n");
+  printf(
+"  (This is one reason to specify your own intersection points in your .poly\n"
+);
+  printf(
+"  files.)  Similarly, exact arithmetic is not used to compute the vertices\n"
+);
+  printf("  of the Voronoi diagram.\n\n");
+  printf(
+"  Another pair of problems not solved by the exact arithmetic routines is\n");
+  printf(
+"  underflow and overflow.  If Triangle is compiled for double precision\n");
+  printf(
+"  arithmetic, I believe that Triangle's geometric predicates work correctly\n"
+);
+  printf(
+"  if the exponent of every input coordinate falls in the range [-148, 201].\n"
+);
+  printf(
+"  Underflow can silently prevent the orientation and incircle tests from\n");
+  printf(
+"  being performed exactly, while overflow typically causes a floating\n");
+  printf("  exception.\n\n");
+  printf("Calling Triangle from Another Program:\n\n");
+  printf("  Read the file triangle.h for details.\n\n");
+  printf("Troubleshooting:\n\n");
+  printf("  Please read this section before mailing me bugs.\n\n");
+  printf("  `My output mesh has no triangles!'\n\n");
+  printf(
+"    If you're using a PSLG, you've probably failed to specify a proper set\n"
+);
+  printf(
+"    of bounding segments, or forgotten to use the -c switch.  Or you may\n");
+  printf(
+"    have placed a hole badly, thereby eating all your triangles.  To test\n");
+  printf("    these possibilities, try again with the -c and -O switches.\n");
+  printf(
+"    Alternatively, all your input vertices may be collinear, in which case\n"
+);
+  printf("    you can hardly expect to triangulate them.\n\n");
+  printf("  `Triangle doesn't terminate, or just crashes.'\n\n");
+  printf(
+"    Bad things can happen when triangles get so small that the distance\n");
+  printf(
+"    between their vertices isn't much larger than the precision of your\n");
+  printf(
+"    machine's arithmetic.  If you've compiled Triangle for single-precision\n"
+);
+  printf(
+"    arithmetic, you might do better by recompiling it for double-precision.\n"
+);
+  printf(
+"    Then again, you might just have to settle for more lenient constraints\n"
+);
+  printf(
+"    on the minimum angle and the maximum area than you had planned.\n");
+  printf("\n");
+  printf(
+"    You can minimize precision problems by ensuring that the origin lies\n");
+  printf(
+"    inside your vertex set, or even inside the densest part of your\n");
+  printf(
+"    mesh.  If you're triangulating an object whose x-coordinates all fall\n");
+  printf(
+"    between 6247133 and 6247134, you're not leaving much floating-point\n");
+  printf("    precision for Triangle to work with.\n\n");
+  printf(
+"    Precision problems can occur covertly if the input PSLG contains two\n");
+  printf(
+"    segments that meet (or intersect) at an extremely small angle, or if\n");
+  printf(
+"    such an angle is introduced by the -c switch.  If you don't realize\n");
+  printf(
+"    that a tiny angle is being formed, you might never discover why\n");
+  printf(
+"    Triangle is crashing.  To check for this possibility, use the -S switch\n"
+);
+  printf(
+"    (with an appropriate limit on the number of Steiner points, found by\n");
+  printf(
+"    trial-and-error) to stop Triangle early, and view the output .poly file\n"
+);
+  printf(
+"    with Show Me (described below).  Look carefully for regions where dense\n"
+);
+  printf(
+"    clusters of vertices are forming and for small angles between segments.\n"
+);
+  printf(
+"    Zoom in closely, as such segments might look like a single segment from\n"
+);
+  printf("    a distance.\n\n");
+  printf(
+"    If some of the input values are too large, Triangle may suffer a\n");
+  printf(
+"    floating exception due to overflow when attempting to perform an\n");
+  printf(
+"    orientation or incircle test.  (Read the section on exact arithmetic\n");
+  printf(
+"    above.)  Again, I recommend compiling Triangle for double (rather\n");
+  printf("    than single) precision arithmetic.\n\n");
+  printf(
+"    Unexpected problems can arise if you use quality meshing (-q, -a, or\n");
+  printf(
+"    -u) with an input that is not segment-bounded--that is, if your input\n");
+  printf(
+"    is a vertex set, or you're using the -c switch.  If the convex hull of\n"
+);
+  printf(
+"    your input vertices has collinear vertices on its boundary, an input\n");
+  printf(
+"    vertex that you think lies on the convex hull might actually lie just\n");
+  printf(
+"    inside the convex hull.  If so, the vertex and the nearby convex hull\n");
+  printf(
+"    edge form an extremely thin triangle.  When Triangle tries to refine\n");
+  printf(
+"    the mesh to enforce angle and area constraints, Triangle might generate\n"
+);
+  printf(
+"    extremely tiny triangles, or it might fail because of insufficient\n");
+  printf("    floating-point precision.\n\n");
+  printf(
+"  `The numbering of the output vertices doesn't match the input vertices.'\n"
+);
+  printf("\n");
+  printf(
+"    You may have had duplicate input vertices, or you may have eaten some\n");
+  printf(
+"    of your input vertices with a hole, or by placing them outside the area\n"
+);
+  printf(
+"    enclosed by segments.  In any case, you can solve the problem by not\n");
+  printf("    using the -j switch.\n\n");
+  printf(
+"  `Triangle executes without incident, but when I look at the resulting\n");
+  printf(
+"  mesh, it has overlapping triangles or other geometric inconsistencies.'\n");
+  printf("\n");
+  printf(
+"    If you select the -X switch, Triangle occasionally makes mistakes due\n");
+  printf(
+"    to floating-point roundoff error.  Although these errors are rare,\n");
+  printf(
+"    don't use the -X switch.  If you still have problems, please report the\n"
+);
+  printf("    bug.\n\n");
+  printf(
+"  `Triangle executes without incident, but when I look at the resulting\n");
+  printf("  Voronoi diagram, it has overlapping edges or other geometric\n");
+  printf("  inconsistencies.'\n");
+  printf("\n");
+  printf(
+"    If your input is a PSLG (-p), you can only expect a meaningful Voronoi\n"
+);
+  printf(
+"    diagram if the domain you are triangulating is convex and free of\n");
+  printf(
+"    holes, and you use the -D switch to construct a conforming Delaunay\n");
+  printf("    triangulation (instead of a CDT or CCDT).\n\n");
+  printf(
+"  Strange things can happen if you've taken liberties with your PSLG.  Do\n");
+  printf(
+"  you have a vertex lying in the middle of a segment?  Triangle sometimes\n");
+  printf(
+"  copes poorly with that sort of thing.  Do you want to lay out a collinear\n"
+);
+  printf(
+"  row of evenly spaced, segment-connected vertices?  Have you simply\n");
+  printf(
+"  defined one long segment connecting the leftmost vertex to the rightmost\n"
+);
+  printf(
+"  vertex, and a bunch of vertices lying along it?  This method occasionally\n"
+);
+  printf(
+"  works, especially with horizontal and vertical lines, but often it\n");
+  printf(
+"  doesn't, and you'll have to connect each adjacent pair of vertices with a\n"
+);
+  printf("  separate segment.  If you don't like it, tough.\n\n");
+  printf(
+"  Furthermore, if you have segments that intersect other than at their\n");
+  printf(
+"  endpoints, try not to let the intersections fall extremely close to PSLG\n"
+);
+  printf("  vertices or each other.\n\n");
+  printf(
+"  If you have problems refining a triangulation not produced by Triangle:\n");
+  printf(
+"  Are you sure the triangulation is geometrically valid?  Is it formatted\n");
+  printf(
+"  correctly for Triangle?  Are the triangles all listed so the first three\n"
+);
+  printf(
+"  vertices are their corners in counterclockwise order?  Are all of the\n");
+  printf(
+"  triangles constrained Delaunay?  Triangle's Delaunay refinement algorithm\n"
+);
+  printf("  assumes that it starts with a CDT.\n\n");
+  printf("Show Me:\n\n");
+  printf(
+"  Triangle comes with a separate program named `Show Me', whose primary\n");
+  printf(
+"  purpose is to draw meshes on your screen or in PostScript.  Its secondary\n"
+);
+  printf(
+"  purpose is to check the validity of your input files, and do so more\n");
+  printf(
+"  thoroughly than Triangle does.  Unlike Triangle, Show Me requires that\n");
+  printf(
+"  you have the X Windows system.  Sorry, Microsoft Windows users.\n");
+  printf("\n");
+  printf("Triangle on the Web:\n");
+  printf("\n");
+  printf("  To see an illustrated version of these instructions, check out\n");
+  printf("\n");
+  printf("    http://www.cs.cmu.edu/~quake/triangle.html\n");
+  printf("\n");
+  printf("A Brief Plea:\n");
+  printf("\n");
+  printf(
+"  If you use Triangle, and especially if you use it to accomplish real\n");
+  printf(
+"  work, I would like very much to hear from you.  A short letter or email\n");
+  printf(
+"  (to jrs@cs.berkeley.edu) describing how you use Triangle will mean a lot\n"
+);
+  printf(
+"  to me.  The more people I know are using this program, the more easily I\n"
+);
+  printf(
+"  can justify spending time on improvements, which in turn will benefit\n");
+  printf(
+"  you.  Also, I can put you on a list to receive email whenever a new\n");
+  printf("  version of Triangle is available.\n\n");
+  printf(
+"  If you use a mesh generated by Triangle in a publication, please include\n"
+);
+  printf(
+"  an acknowledgment as well.  And please spell Triangle with a capital `T'!\n"
+);
+  printf(
+"  If you want to include a citation, use `Jonathan Richard Shewchuk,\n");
+  printf(
+"  ``Triangle: Engineering a 2D Quality Mesh Generator and Delaunay\n");
+  printf(
+"  Triangulator,'' in Applied Computational Geometry:  Towards Geometric\n");
+  printf(
+"  Engineering (Ming C. Lin and Dinesh Manocha, editors), volume 1148 of\n");
+  printf(
+"  Lecture Notes in Computer Science, pages 203-222, Springer-Verlag,\n");
+  printf(
+"  Berlin, May 1996.  (From the First ACM Workshop on Applied Computational\n"
+);
+  printf("  Geometry.)'\n\n");
+  printf("Research credit:\n\n");
+  printf(
+"  Of course, I can take credit for only a fraction of the ideas that made\n");
+  printf(
+"  this mesh generator possible.  Triangle owes its existence to the efforts\n"
+);
+  printf(
+"  of many fine computational geometers and other researchers, including\n");
+  printf(
+"  Marshall Bern, L. Paul Chew, Kenneth L. Clarkson, Boris Delaunay, Rex A.\n"
+);
+  printf(
+"  Dwyer, David Eppstein, Steven Fortune, Leonidas J. Guibas, Donald E.\n");
+  printf(
+"  Knuth, Charles L. Lawson, Der-Tsai Lee, Gary L. Miller, Ernst P. Mucke,\n");
+  printf(
+"  Steven E. Pav, Douglas M. Priest, Jim Ruppert, Isaac Saias, Bruce J.\n");
+  printf(
+"  Schachter, Micha Sharir, Peter W. Shor, Daniel D. Sleator, Jorge Stolfi,\n"
+);
+  printf("  Robert E. Tarjan, Alper Ungor, Christopher J. Van Wyk, Noel J.\n");
+  printf(
+"  Walkington, and Binhai Zhu.  See the comments at the beginning of the\n");
+  printf("  source code for references.\n\n");
+  triexit(0);
+}
+
+#endif /* not TRILIBRARY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  internalerror()   Ask the user to send me the defective product.  Exit.  */
+/*                                                                           */
+/*****************************************************************************/
+
+void internalerror(void)
+{
+  printf("  Please report this bug to jrs@cs.berkeley.edu\n");
+  printf("  Include the message above, your input data set, and the exact\n");
+  printf("    command line you used to run Triangle.\n");
+  triexit(1);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  parsecommandline()   Read the command line, identify switches, and set   */
+/*                       up options and file names.                          */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void parsecommandline(int argc, char **argv, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void parsecommandline(argc, argv, b)
+int argc;
+char **argv;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+#ifdef TRILIBRARY
+#define STARTINDEX 0
+#else /* not TRILIBRARY */
+#define STARTINDEX 1
+  int increment;
+  int meshnumber;
+#endif /* not TRILIBRARY */
+  int i, j, k;
+  char workstring[FILENAMESIZE];
+
+  b->poly = b->refine = b->quality = 0;
+  b->vararea = b->fixedarea = b->usertest = 0;
+  b->regionattrib = b->convex = b->weighted = b->jettison = 0;
+  b->firstnumber = 1;
+  b->edgesout = b->voronoi = b->neighbors = b->geomview = 0;
+  b->nobound = b->nopolywritten = b->nonodewritten = b->noelewritten = 0;
+  b->noiterationnum = 0;
+  b->noholes = b->noexact = 0;
+  b->incremental = b->sweepline = 0;
+  b->dwyer = 1;
+  b->splitseg = 0;
+  b->docheck = 0;
+  b->nobisect = 0;
+  b->conformdel = 0;
+  b->steiner = -1;
+  b->order = 1;
+  b->minangle = 0.0;
+  b->maxarea = -1.0;
+  b->quiet = b->verbose = 0;
+#ifndef TRILIBRARY
+  b->innodefilename[0] = '\0';
+#endif /* not TRILIBRARY */
+
+  for (i = STARTINDEX; i < argc; i++) {
+#ifndef TRILIBRARY
+    if (argv[i][0] == '-') {
+#endif /* not TRILIBRARY */
+      for (j = STARTINDEX; argv[i][j] != '\0'; j++) {
+        if (argv[i][j] == 'p') {
+          b->poly = 1;
+	}
+#ifndef CDT_ONLY
+        if (argv[i][j] == 'r') {
+          b->refine = 1;
+	}
+        if (argv[i][j] == 'q') {
+          b->quality = 1;
+          if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+              (argv[i][j + 1] == '.')) {
+            k = 0;
+            while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+                   (argv[i][j + 1] == '.')) {
+              j++;
+              workstring[k] = argv[i][j];
+              k++;
+            }
+            workstring[k] = '\0';
+            b->minangle = (REAL) strtod(workstring, (char **) NULL);
+	  } else {
+            b->minangle = 20.0;
+	  }
+	}
+        if (argv[i][j] == 'a') {
+          b->quality = 1;
+          if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+              (argv[i][j + 1] == '.')) {
+            b->fixedarea = 1;
+            k = 0;
+            while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+                   (argv[i][j + 1] == '.')) {
+              j++;
+              workstring[k] = argv[i][j];
+              k++;
+            }
+            workstring[k] = '\0';
+            b->maxarea = (REAL) strtod(workstring, (char **) NULL);
+            if (b->maxarea <= 0.0) {
+              printf("Error:  Maximum area must be greater than zero.\n");
+              triexit(1);
+	    }
+	  } else {
+            b->vararea = 1;
+	  }
+	}
+        if (argv[i][j] == 'u') {
+          b->quality = 1;
+          b->usertest = 1;
+        }
+#endif /* not CDT_ONLY */
+        if (argv[i][j] == 'A') {
+          b->regionattrib = 1;
+        }
+        if (argv[i][j] == 'c') {
+          b->convex = 1;
+        }
+        if (argv[i][j] == 'w') {
+          b->weighted = 1;
+        }
+        if (argv[i][j] == 'W') {
+          b->weighted = 2;
+        }
+        if (argv[i][j] == 'j') {
+          b->jettison = 1;
+        }
+        if (argv[i][j] == 'z') {
+          b->firstnumber = 0;
+        }
+        if (argv[i][j] == 'e') {
+          b->edgesout = 1;
+	}
+        if (argv[i][j] == 'v') {
+          b->voronoi = 1;
+	}
+        if (argv[i][j] == 'n') {
+          b->neighbors = 1;
+	}
+        if (argv[i][j] == 'g') {
+          b->geomview = 1;
+	}
+        if (argv[i][j] == 'B') {
+          b->nobound = 1;
+	}
+        if (argv[i][j] == 'P') {
+          b->nopolywritten = 1;
+	}
+        if (argv[i][j] == 'N') {
+          b->nonodewritten = 1;
+	}
+        if (argv[i][j] == 'E') {
+          b->noelewritten = 1;
+	}
+#ifndef TRILIBRARY
+        if (argv[i][j] == 'I') {
+          b->noiterationnum = 1;
+	}
+#endif /* not TRILIBRARY */
+        if (argv[i][j] == 'O') {
+          b->noholes = 1;
+	}
+        if (argv[i][j] == 'X') {
+          b->noexact = 1;
+	}
+        if (argv[i][j] == 'o') {
+          if (argv[i][j + 1] == '2') {
+            j++;
+            b->order = 2;
+          }
+	}
+#ifndef CDT_ONLY
+        if (argv[i][j] == 'Y') {
+          b->nobisect++;
+	}
+        if (argv[i][j] == 'S') {
+          b->steiner = 0;
+          while ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
+            j++;
+            b->steiner = b->steiner * 10 + (int) (argv[i][j] - '0');
+          }
+        }
+#endif /* not CDT_ONLY */
+#ifndef REDUCED
+        if (argv[i][j] == 'i') {
+          b->incremental = 1;
+        }
+        if (argv[i][j] == 'F') {
+          b->sweepline = 1;
+        }
+#endif /* not REDUCED */
+        if (argv[i][j] == 'l') {
+          b->dwyer = 0;
+        }
+#ifndef REDUCED
+#ifndef CDT_ONLY
+        if (argv[i][j] == 's') {
+          b->splitseg = 1;
+        }
+        if ((argv[i][j] == 'D') || (argv[i][j] == 'L')) {
+          b->quality = 1;
+          b->conformdel = 1;
+        }
+#endif /* not CDT_ONLY */
+        if (argv[i][j] == 'C') {
+          b->docheck = 1;
+        }
+#endif /* not REDUCED */
+        if (argv[i][j] == 'Q') {
+          b->quiet = 1;
+        }
+        if (argv[i][j] == 'V') {
+          b->verbose++;
+        }
+#ifndef TRILIBRARY
+        if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
+            (argv[i][j] == '?')) {
+          info();
+	}
+#endif /* not TRILIBRARY */
+      }
+#ifndef TRILIBRARY
+    } else {
+      strncpy(b->innodefilename, argv[i], FILENAMESIZE - 1);
+      b->innodefilename[FILENAMESIZE - 1] = '\0';
+    }
+#endif /* not TRILIBRARY */
+  }
+#ifndef TRILIBRARY
+  if (b->innodefilename[0] == '\0') {
+    syntax();
+  }
+  if (!strcmp(&b->innodefilename[strlen(b->innodefilename) - 5], ".node")) {
+    b->innodefilename[strlen(b->innodefilename) - 5] = '\0';
+  }
+  if (!strcmp(&b->innodefilename[strlen(b->innodefilename) - 5], ".poly")) {
+    b->innodefilename[strlen(b->innodefilename) - 5] = '\0';
+    b->poly = 1;
+  }
+#ifndef CDT_ONLY
+  if (!strcmp(&b->innodefilename[strlen(b->innodefilename) - 4], ".ele")) {
+    b->innodefilename[strlen(b->innodefilename) - 4] = '\0';
+    b->refine = 1;
+  }
+  if (!strcmp(&b->innodefilename[strlen(b->innodefilename) - 5], ".area")) {
+    b->innodefilename[strlen(b->innodefilename) - 5] = '\0';
+    b->refine = 1;
+    b->quality = 1;
+    b->vararea = 1;
+  }
+#endif /* not CDT_ONLY */
+#endif /* not TRILIBRARY */
+  b->usesegments = b->poly || b->refine || b->quality || b->convex;
+  b->goodangle = cos(b->minangle * PI / 180.0);
+  if (b->goodangle == 1.0) {
+    b->offconstant = 0.0;
+  } else {
+    b->offconstant = 0.475 * sqrt((1.0 + b->goodangle) / (1.0 - b->goodangle));
+  }
+  b->goodangle *= b->goodangle;
+  if (b->refine && b->noiterationnum) {
+    printf(
+      "Error:  You cannot use the -I switch when refining a triangulation.\n");
+    triexit(1);
+  }
+  /* Be careful not to allocate space for element area constraints that */
+  /*   will never be assigned any value (other than the default -1.0).  */
+  if (!b->refine && !b->poly) {
+    b->vararea = 0;
+  }
+  /* Be careful not to add an extra attribute to each element unless the */
+  /*   input supports it (PSLG in, but not refining a preexisting mesh). */
+  if (b->refine || !b->poly) {
+    b->regionattrib = 0;
+  }
+  /* Regular/weighted triangulations are incompatible with PSLGs */
+  /*   and meshing.                                              */
+  if (b->weighted && (b->poly || b->quality)) {
+    b->weighted = 0;
+    if (!b->quiet) {
+      printf("Warning:  weighted triangulations (-w, -W) are incompatible\n");
+      printf("  with PSLGs (-p) and meshing (-q, -a, -u).  Weights ignored.\n"
+             );
+    }
+  }
+  if (b->jettison && b->nonodewritten && !b->quiet) {
+    printf("Warning:  -j and -N switches are somewhat incompatible.\n");
+    printf("  If any vertices are jettisoned, you will need the output\n");
+    printf("  .node file to reconstruct the new node indices.");
+  }
+
+#ifndef TRILIBRARY
+  strcpy(b->inpolyfilename, b->innodefilename);
+  strcpy(b->inelefilename, b->innodefilename);
+  strcpy(b->areafilename, b->innodefilename);
+  increment = 0;
+  strcpy(workstring, b->innodefilename);
+  j = 1;
+  while (workstring[j] != '\0') {
+    if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) {
+      increment = j + 1;
+    }
+    j++;
+  }
+  meshnumber = 0;
+  if (increment > 0) {
+    j = increment;
+    do {
+      if ((workstring[j] >= '0') && (workstring[j] <= '9')) {
+        meshnumber = meshnumber * 10 + (int) (workstring[j] - '0');
+      } else {
+        increment = 0;
+      }
+      j++;
+    } while (workstring[j] != '\0');
+  }
+  if (b->noiterationnum) {
+    strcpy(b->outnodefilename, b->innodefilename);
+    strcpy(b->outelefilename, b->innodefilename);
+    strcpy(b->edgefilename, b->innodefilename);
+    strcpy(b->vnodefilename, b->innodefilename);
+    strcpy(b->vedgefilename, b->innodefilename);
+    strcpy(b->neighborfilename, b->innodefilename);
+    strcpy(b->offfilename, b->innodefilename);
+    strcat(b->outnodefilename, ".node");
+    strcat(b->outelefilename, ".ele");
+    strcat(b->edgefilename, ".edge");
+    strcat(b->vnodefilename, ".v.node");
+    strcat(b->vedgefilename, ".v.edge");
+    strcat(b->neighborfilename, ".neigh");
+    strcat(b->offfilename, ".off");
+  } else if (increment == 0) {
+    strcpy(b->outnodefilename, b->innodefilename);
+    strcpy(b->outpolyfilename, b->innodefilename);
+    strcpy(b->outelefilename, b->innodefilename);
+    strcpy(b->edgefilename, b->innodefilename);
+    strcpy(b->vnodefilename, b->innodefilename);
+    strcpy(b->vedgefilename, b->innodefilename);
+    strcpy(b->neighborfilename, b->innodefilename);
+    strcpy(b->offfilename, b->innodefilename);
+    strcat(b->outnodefilename, ".1.node");
+    strcat(b->outpolyfilename, ".1.poly");
+    strcat(b->outelefilename, ".1.ele");
+    strcat(b->edgefilename, ".1.edge");
+    strcat(b->vnodefilename, ".1.v.node");
+    strcat(b->vedgefilename, ".1.v.edge");
+    strcat(b->neighborfilename, ".1.neigh");
+    strcat(b->offfilename, ".1.off");
+  } else {
+    workstring[increment] = '%';
+    workstring[increment + 1] = 'd';
+    workstring[increment + 2] = '\0';
+    sprintf(b->outnodefilename, workstring, meshnumber + 1);
+    strcpy(b->outpolyfilename, b->outnodefilename);
+    strcpy(b->outelefilename, b->outnodefilename);
+    strcpy(b->edgefilename, b->outnodefilename);
+    strcpy(b->vnodefilename, b->outnodefilename);
+    strcpy(b->vedgefilename, b->outnodefilename);
+    strcpy(b->neighborfilename, b->outnodefilename);
+    strcpy(b->offfilename, b->outnodefilename);
+    strcat(b->outnodefilename, ".node");
+    strcat(b->outpolyfilename, ".poly");
+    strcat(b->outelefilename, ".ele");
+    strcat(b->edgefilename, ".edge");
+    strcat(b->vnodefilename, ".v.node");
+    strcat(b->vedgefilename, ".v.edge");
+    strcat(b->neighborfilename, ".neigh");
+    strcat(b->offfilename, ".off");
+  }
+  strcat(b->innodefilename, ".node");
+  strcat(b->inpolyfilename, ".poly");
+  strcat(b->inelefilename, ".ele");
+  strcat(b->areafilename, ".area");
+#endif /* not TRILIBRARY */
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* User interaction routines begin here                      *********/
+
+/********* Debugging routines begin here                             *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  printtriangle()   Print out the details of an oriented triangle.         */
+/*                                                                           */
+/*  I originally wrote this procedure to simplify debugging; it can be       */
+/*  called directly from the debugger, and presents information about an     */
+/*  oriented triangle in digestible form.  It's also used when the           */
+/*  highest level of verbosity (`-VVV') is specified.                        */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void printtriangle(struct mesh *m, struct behavior *b, struct otri *t)
+#else /* not ANSI_DECLARATORS */
+void printtriangle(m, b, t)
+struct mesh *m;
+struct behavior *b;
+struct otri *t;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri printtri;
+  struct osub printsh;
+  vertex printvertex;
+
+  printf("triangle x%zx with orientation %d:\n", (size_t) t->tri,
+         t->orient);
+  decode(t->tri[0], printtri);
+  if (printtri.tri == m->dummytri) {
+    printf("    [0] = Outer space\n");
+  } else {
+    printf("    [0] = x%zx  %d\n", (size_t) printtri.tri,
+           printtri.orient);
+  }
+  decode(t->tri[1], printtri);
+  if (printtri.tri == m->dummytri) {
+    printf("    [1] = Outer space\n");
+  } else {
+    printf("    [1] = x%zx  %d\n", (size_t) printtri.tri,
+           printtri.orient);
+  }
+  decode(t->tri[2], printtri);
+  if (printtri.tri == m->dummytri) {
+    printf("    [2] = Outer space\n");
+  } else {
+    printf("    [2] = x%zx  %d\n", (size_t) printtri.tri,
+           printtri.orient);
+  }
+
+  org(*t, printvertex);
+  if (printvertex == (vertex) NULL)
+    printf("    Origin[%d] = NULL\n", (t->orient + 1) % 3 + 3);
+  else
+    printf("    Origin[%d] = x%zx  (%.12g, %.12g)\n",
+           (t->orient + 1) % 3 + 3, (size_t) printvertex,
+           printvertex[0], printvertex[1]);
+  dest(*t, printvertex);
+  if (printvertex == (vertex) NULL)
+    printf("    Dest  [%d] = NULL\n", (t->orient + 2) % 3 + 3);
+  else
+    printf("    Dest  [%d] = x%zx  (%.12g, %.12g)\n",
+           (t->orient + 2) % 3 + 3, (size_t) printvertex,
+           printvertex[0], printvertex[1]);
+  apex(*t, printvertex);
+  if (printvertex == (vertex) NULL)
+    printf("    Apex  [%d] = NULL\n", t->orient + 3);
+  else
+    printf("    Apex  [%d] = x%zx  (%.12g, %.12g)\n",
+           t->orient + 3, (size_t) printvertex,
+           printvertex[0], printvertex[1]);
+
+  if (b->usesegments) {
+    sdecode(t->tri[6], printsh);
+    if (printsh.ss != m->dummysub) {
+      printf("    [6] = x%zx  %d\n", (size_t) printsh.ss,
+             printsh.ssorient);
+    }
+    sdecode(t->tri[7], printsh);
+    if (printsh.ss != m->dummysub) {
+      printf("    [7] = x%zx  %d\n", (size_t) printsh.ss,
+             printsh.ssorient);
+    }
+    sdecode(t->tri[8], printsh);
+    if (printsh.ss != m->dummysub) {
+      printf("    [8] = x%zx  %d\n", (size_t) printsh.ss,
+             printsh.ssorient);
+    }
+  }
+
+  if (b->vararea) {
+    printf("    Area constraint:  %.4g\n", areabound(*t));
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  printsubseg()   Print out the details of an oriented subsegment.         */
+/*                                                                           */
+/*  I originally wrote this procedure to simplify debugging; it can be       */
+/*  called directly from the debugger, and presents information about an     */
+/*  oriented subsegment in digestible form.  It's also used when the highest */
+/*  level of verbosity (`-VVV') is specified.                                */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void printsubseg(struct mesh *m, struct behavior *b, struct osub *s)
+#else /* not ANSI_DECLARATORS */
+void printsubseg(m, b, s)
+struct mesh *m;
+struct behavior *b;
+struct osub *s;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct osub printsh;
+  struct otri printtri;
+  vertex printvertex;
+
+  printf("subsegment x%zx with orientation %d and mark %d:\n",
+         (size_t) s->ss, s->ssorient, mark(*s));
+  sdecode(s->ss[0], printsh);
+  if (printsh.ss == m->dummysub) {
+    printf("    [0] = No subsegment\n");
+  } else {
+    printf("    [0] = x%zx  %d\n", (size_t) printsh.ss,
+           printsh.ssorient);
+  }
+  sdecode(s->ss[1], printsh);
+  if (printsh.ss == m->dummysub) {
+    printf("    [1] = No subsegment\n");
+  } else {
+    printf("    [1] = x%zx  %d\n", (size_t) printsh.ss,
+           printsh.ssorient);
+  }
+
+  sorg(*s, printvertex);
+  if (printvertex == (vertex) NULL)
+    printf("    Origin[%d] = NULL\n", 2 + s->ssorient);
+  else
+    printf("    Origin[%d] = x%zx  (%.12g, %.12g)\n",
+           2 + s->ssorient, (size_t) printvertex,
+           printvertex[0], printvertex[1]);
+  sdest(*s, printvertex);
+  if (printvertex == (vertex) NULL)
+    printf("    Dest  [%d] = NULL\n", 3 - s->ssorient);
+  else
+    printf("    Dest  [%d] = x%zx  (%.12g, %.12g)\n",
+           3 - s->ssorient, (size_t) printvertex,
+           printvertex[0], printvertex[1]);
+
+  decode(s->ss[6], printtri);
+  if (printtri.tri == m->dummytri) {
+    printf("    [6] = Outer space\n");
+  } else {
+    printf("    [6] = x%zx  %d\n", (size_t) printtri.tri,
+           printtri.orient);
+  }
+  decode(s->ss[7], printtri);
+  if (printtri.tri == m->dummytri) {
+    printf("    [7] = Outer space\n");
+  } else {
+    printf("    [7] = x%zx  %d\n", (size_t) printtri.tri,
+           printtri.orient);
+  }
+
+  segorg(*s, printvertex);
+  if (printvertex == (vertex) NULL)
+    printf("    Segment origin[%d] = NULL\n", 4 + s->ssorient);
+  else
+    printf("    Segment origin[%d] = x%zx  (%.12g, %.12g)\n",
+           4 + s->ssorient, (size_t) printvertex,
+           printvertex[0], printvertex[1]);
+  segdest(*s, printvertex);
+  if (printvertex == (vertex) NULL)
+    printf("    Segment dest  [%d] = NULL\n", 5 - s->ssorient);
+  else
+    printf("    Segment dest  [%d] = x%zx  (%.12g, %.12g)\n",
+           5 - s->ssorient, (size_t) printvertex,
+           printvertex[0], printvertex[1]);
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Debugging routines end here                               *********/
+
+/********* Memory management routines begin here                     *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  poolzero()   Set all of a pool's fields to zero.                         */
+/*                                                                           */
+/*  This procedure should never be called on a pool that has any memory      */
+/*  allocated to it, as that memory would leak.                              */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void poolzero(struct memorypool *pool)
+#else /* not ANSI_DECLARATORS */
+void poolzero(pool)
+struct memorypool *pool;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  pool->firstblock = (VOID **) NULL;
+  pool->nowblock = (VOID **) NULL;
+  pool->nextitem = (VOID *) NULL;
+  pool->deaditemstack = (VOID *) NULL;
+  pool->pathblock = (VOID **) NULL;
+  pool->pathitem = (VOID *) NULL;
+  pool->alignbytes = 0;
+  pool->itembytes = 0;
+  pool->itemsperblock = 0;
+  pool->itemsfirstblock = 0;
+  pool->items = 0;
+  pool->maxitems = 0;
+  pool->unallocateditems = 0;
+  pool->pathitemsleft = 0;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  poolrestart()   Deallocate all items in a pool.                          */
+/*                                                                           */
+/*  The pool is returned to its starting state, except that no memory is     */
+/*  freed to the operating system.  Rather, the previously allocated blocks  */
+/*  are ready to be reused.                                                  */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void poolrestart(struct memorypool *pool)
+#else /* not ANSI_DECLARATORS */
+void poolrestart(pool)
+struct memorypool *pool;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  size_t alignptr;
+
+  pool->items = 0;
+  pool->maxitems = 0;
+
+  /* Set the currently active block. */
+  pool->nowblock = pool->firstblock;
+  /* Find the first item in the pool.  Increment by the size of (VOID *). */
+  alignptr = (size_t) (pool->nowblock + 1);
+  /* Align the item on an `alignbytes'-byte boundary. */
+  pool->nextitem = (VOID *)
+    (alignptr + (size_t) pool->alignbytes -
+     (alignptr % (size_t) pool->alignbytes));
+  /* There are lots of unallocated items left in this block. */
+  pool->unallocateditems = pool->itemsfirstblock;
+  /* The stack of deallocated items is empty. */
+  pool->deaditemstack = (VOID *) NULL;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  poolinit()   Initialize a pool of memory for allocation of items.        */
+/*                                                                           */
+/*  This routine initializes the machinery for allocating items.  A `pool'   */
+/*  is created whose records have size at least `bytecount'.  Items will be  */
+/*  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.              */
+/*                                                                           */
+/*  Don't change this routine unless you understand it.                      */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void poolinit(struct memorypool *pool, int bytecount, int itemcount,
+              int firstitemcount, int alignment)
+#else /* not ANSI_DECLARATORS */
+void poolinit(pool, bytecount, itemcount, firstitemcount, alignment)
+struct memorypool *pool;
+int bytecount;
+int itemcount;
+int firstitemcount;
+int alignment;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  /* Find the proper alignment, which must be at least as large as:   */
+  /*   - The parameter `alignment'.                                   */
+  /*   - sizeof(VOID *), so the stack of dead items can be maintained */
+  /*       without unaligned accesses.                                */
+  if (alignment > sizeof(VOID *)) {
+    pool->alignbytes = alignment;
+  } else {
+    pool->alignbytes = sizeof(VOID *);
+  }
+  pool->itembytes = ((bytecount - 1) / pool->alignbytes + 1) *
+                    pool->alignbytes;
+  pool->itemsperblock = itemcount;
+  if (firstitemcount == 0) {
+    pool->itemsfirstblock = itemcount;
+  } else {
+    pool->itemsfirstblock = firstitemcount;
+  }
+
+  /* Allocate a block of items.  Space for `itemsfirstblock' items and one  */
+  /*   pointer (to point to the next block) are allocated, as well as space */
+  /*   to ensure alignment of the items.                                    */
+  pool->firstblock = (VOID **)
+    trimalloc(pool->itemsfirstblock * pool->itembytes + (int) sizeof(VOID *) +
+              pool->alignbytes);
+  /* Set the next block pointer to NULL. */
+  *(pool->firstblock) = (VOID *) NULL;
+  poolrestart(pool);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  pooldeinit()   Free to the operating system all memory taken by a pool.  */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void pooldeinit(struct memorypool *pool)
+#else /* not ANSI_DECLARATORS */
+void pooldeinit(pool)
+struct memorypool *pool;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  while (pool->firstblock != (VOID **) NULL) {
+    pool->nowblock = (VOID **) *(pool->firstblock);
+    trifree((VOID *) pool->firstblock);
+    pool->firstblock = pool->nowblock;
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  poolalloc()   Allocate space for an item.                                */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+VOID *poolalloc(struct memorypool *pool)
+#else /* not ANSI_DECLARATORS */
+VOID *poolalloc(pool)
+struct memorypool *pool;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  VOID *newitem;
+  VOID **newblock;
+  size_t 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 (pool->deaditemstack != (VOID *) NULL) {
+    newitem = pool->deaditemstack;               /* Take first item in list. */
+    pool->deaditemstack = * (VOID **) pool->deaditemstack;
+  } else {
+    /* Check if there are any free items left in the current block. */
+    if (pool->unallocateditems == 0) {
+      /* Check if another block must be allocated. */
+      if (*(pool->nowblock) == (VOID *) NULL) {
+        /* Allocate a new block of items, pointed to by the previous block. */
+        newblock = (VOID **) trimalloc(pool->itemsperblock * pool->itembytes +
+                                       (int) sizeof(VOID *) +
+                                       pool->alignbytes);
+        *(pool->nowblock) = (VOID *) newblock;
+        /* The next block pointer is NULL. */
+        *newblock = (VOID *) NULL;
+      }
+
+      /* Move to the new block. */
+      pool->nowblock = (VOID **) *(pool->nowblock);
+      /* Find the first item in the block.    */
+      /*   Increment by the size of (VOID *). */
+      alignptr = (size_t) (pool->nowblock + 1);
+      /* Align the item on an `alignbytes'-byte boundary. */
+      pool->nextitem = (VOID *)
+        (alignptr + (size_t) pool->alignbytes -
+         (alignptr % (size_t) pool->alignbytes));
+      /* There are lots of unallocated items left in this block. */
+      pool->unallocateditems = pool->itemsperblock;
+    }
+
+    /* Allocate a new item. */
+    newitem = pool->nextitem;
+    /* Advance `nextitem' pointer to next free item in block. */
+    pool->nextitem = (VOID *) ((char *) pool->nextitem + pool->itembytes);
+    pool->unallocateditems--;
+    pool->maxitems++;
+  }
+  pool->items++;
+  return newitem;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  pooldealloc()   Deallocate space for an item.                            */
+/*                                                                           */
+/*  The deallocated space is stored in a queue for later reuse.              */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void pooldealloc(struct memorypool *pool, VOID *dyingitem)
+#else /* not ANSI_DECLARATORS */
+void pooldealloc(pool, dyingitem)
+struct memorypool *pool;
+VOID *dyingitem;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  /* Push freshly killed item onto stack. */
+  *((VOID **) dyingitem) = pool->deaditemstack;
+  pool->deaditemstack = dyingitem;
+  pool->items--;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  traversalinit()   Prepare to traverse the entire list of items.          */
+/*                                                                           */
+/*  This routine is used in conjunction with traverse().                     */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void traversalinit(struct memorypool *pool)
+#else /* not ANSI_DECLARATORS */
+void traversalinit(pool)
+struct memorypool *pool;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  size_t alignptr;
+
+  /* Begin the traversal in the first block. */
+  pool->pathblock = pool->firstblock;
+  /* Find the first item in the block.  Increment by the size of (VOID *). */
+  alignptr = (size_t) (pool->pathblock + 1);
+  /* Align with item on an `alignbytes'-byte boundary. */
+  pool->pathitem = (VOID *)
+    (alignptr + (size_t) pool->alignbytes -
+     (alignptr % (size_t) pool->alignbytes));
+  /* Set the number of items left in the current block. */
+  pool->pathitemsleft = pool->itemsfirstblock;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  traverse()   Find the next item in the list.                             */
+/*                                                                           */
+/*  This routine is used in conjunction with traversalinit().  Be forewarned */
+/*  that this routine successively returns all items in the list, including  */
+/*  deallocated ones on the deaditemqueue.  It's up to you to figure out     */
+/*  which ones are actually dead.  Why?  I don't want to allocate extra      */
+/*  space just to demarcate dead items.  It can usually be done more         */
+/*  space-efficiently by a routine that knows something about the structure  */
+/*  of the item.                                                             */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+VOID *traverse(struct memorypool *pool)
+#else /* not ANSI_DECLARATORS */
+VOID *traverse(pool)
+struct memorypool *pool;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  VOID *newitem;
+  size_t alignptr;
+
+  /* Stop upon exhausting the list of items. */
+  if (pool->pathitem == pool->nextitem) {
+    return (VOID *) NULL;
+  }
+
+  /* Check whether any untraversed items remain in the current block. */
+  if (pool->pathitemsleft == 0) {
+    /* Find the next block. */
+    pool->pathblock = (VOID **) *(pool->pathblock);
+    /* Find the first item in the block.  Increment by the size of (VOID *). */
+    alignptr = (size_t) (pool->pathblock + 1);
+    /* Align with item on an `alignbytes'-byte boundary. */
+    pool->pathitem = (VOID *)
+      (alignptr + (size_t) pool->alignbytes -
+       (alignptr % (size_t) pool->alignbytes));
+    /* Set the number of items left in the current block. */
+    pool->pathitemsleft = pool->itemsperblock;
+  }
+
+  newitem = pool->pathitem;
+  /* Find the next item in the block. */
+  pool->pathitem = (VOID *) ((char *) pool->pathitem + pool->itembytes);
+  pool->pathitemsleft--;
+  return newitem;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  dummyinit()   Initialize the triangle that fills "outer space" and the   */
+/*                omnipresent subsegment.                                    */
+/*                                                                           */
+/*  The triangle that fills "outer space," called `dummytri', is pointed to  */
+/*  by every triangle and subsegment on a boundary (be it outer or inner) of */
+/*  the triangulation.  Also, `dummytri' points to one of the triangles on   */
+/*  the convex hull (until the holes and concavities are carved), making it  */
+/*  possible to find a starting triangle for point location.                 */
+/*                                                                           */
+/*  The omnipresent subsegment, `dummysub', is pointed to by every triangle  */
+/*  or subsegment that doesn't have a full complement of real subsegments    */
+/*  to point to.                                                             */
+/*                                                                           */
+/*  `dummytri' and `dummysub' are generally required to fulfill only a few   */
+/*  invariants:  their vertices must remain NULL and `dummytri' must always  */
+/*  be bonded (at offset zero) to some triangle on the convex hull of the    */
+/*  mesh, via a boundary edge.  Otherwise, the connections of `dummytri' and */
+/*  `dummysub' may change willy-nilly.  This makes it possible to avoid      */
+/*  writing a good deal of special-case code (in the edge flip, for example) */
+/*  for dealing with the boundary of the mesh, places where no subsegment is */
+/*  present, and so forth.  Other entities are frequently bonded to          */
+/*  `dummytri' and `dummysub' as if they were real mesh entities, with no    */
+/*  harm done.                                                               */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void dummyinit(struct mesh *m, struct behavior *b, int trianglebytes,
+               int subsegbytes)
+#else /* not ANSI_DECLARATORS */
+void dummyinit(m, b, trianglebytes, subsegbytes)
+struct mesh *m;
+struct behavior *b;
+int trianglebytes;
+int subsegbytes;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  size_t alignptr;
+
+  /* Set up `dummytri', the `triangle' that occupies "outer space." */
+  m->dummytribase = (triangle *) trimalloc(trianglebytes +
+                                           m->triangles.alignbytes);
+  /* Align `dummytri' on a `triangles.alignbytes'-byte boundary. */
+  alignptr = (size_t) m->dummytribase;
+  m->dummytri = (triangle *)
+    (alignptr + (size_t) m->triangles.alignbytes -
+     (alignptr % (size_t) m->triangles.alignbytes));
+  /* Initialize the three adjoining triangles to be "outer space."  These  */
+  /*   will eventually be changed by various bonding operations, but their */
+  /*   values don't really matter, as long as they can legally be          */
+  /*   dereferenced.                                                       */
+  m->dummytri[0] = (triangle) m->dummytri;
+  m->dummytri[1] = (triangle) m->dummytri;
+  m->dummytri[2] = (triangle) m->dummytri;
+  /* Three NULL vertices. */
+  m->dummytri[3] = (triangle) NULL;
+  m->dummytri[4] = (triangle) NULL;
+  m->dummytri[5] = (triangle) NULL;
+
+  if (b->usesegments) {
+    /* Set up `dummysub', the omnipresent subsegment pointed to by any */
+    /*   triangle side or subsegment end that isn't attached to a real */
+    /*   subsegment.                                                   */
+    m->dummysubbase = (subseg *) trimalloc(subsegbytes +
+                                           m->subsegs.alignbytes);
+    /* Align `dummysub' on a `subsegs.alignbytes'-byte boundary. */
+    alignptr = (size_t) m->dummysubbase;
+    m->dummysub = (subseg *)
+      (alignptr + (size_t) m->subsegs.alignbytes -
+       (alignptr % (size_t) m->subsegs.alignbytes));
+    /* Initialize the two adjoining subsegments to be the omnipresent      */
+    /*   subsegment.  These will eventually be changed by various bonding  */
+    /*   operations, but their values don't really matter, as long as they */
+    /*   can legally be dereferenced.                                      */
+    m->dummysub[0] = (subseg) m->dummysub;
+    m->dummysub[1] = (subseg) m->dummysub;
+    /* Four NULL vertices. */
+    m->dummysub[2] = (subseg) NULL;
+    m->dummysub[3] = (subseg) NULL;
+    m->dummysub[4] = (subseg) NULL;
+    m->dummysub[5] = (subseg) NULL;
+    /* Initialize the two adjoining triangles to be "outer space." */
+    m->dummysub[6] = (subseg) m->dummytri;
+    m->dummysub[7] = (subseg) m->dummytri;
+    /* Set the boundary marker to zero. */
+    * (int *) (m->dummysub + 8) = 0;
+
+    /* Initialize the three adjoining subsegments of `dummytri' to be */
+    /*   the omnipresent subsegment.                                  */
+    m->dummytri[6] = (triangle) m->dummysub;
+    m->dummytri[7] = (triangle) m->dummysub;
+    m->dummytri[8] = (triangle) m->dummysub;
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  initializevertexpool()   Calculate the size of the vertex data structure */
+/*                           and initialize its memory pool.                 */
+/*                                                                           */
+/*  This routine also computes the `vertexmarkindex' and `vertex2triindex'   */
+/*  indices used to find values within each vertex.                          */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void initializevertexpool(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void initializevertexpool(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  int vertexsize;
+
+  /* The index within each vertex at which the boundary marker is found,    */
+  /*   followed by the vertex type.  Ensure the vertex marker is aligned to */
+  /*   a sizeof(int)-byte address.                                          */
+  m->vertexmarkindex = ((m->mesh_dim + m->nextras) * sizeof(REAL) +
+                        sizeof(int) - 1) /
+                       sizeof(int);
+  vertexsize = (m->vertexmarkindex + 2) * sizeof(int);
+  if (b->poly) {
+    /* The index within each vertex at which a triangle pointer is found.  */
+    /*   Ensure the pointer is aligned to a sizeof(triangle)-byte address. */
+    m->vertex2triindex = (vertexsize + sizeof(triangle) - 1) /
+                         sizeof(triangle);
+    vertexsize = (m->vertex2triindex + 1) * sizeof(triangle);
+  }
+
+  /* Initialize the pool of vertices. */
+  poolinit(&m->vertices, vertexsize, VERTEXPERBLOCK,
+           m->invertices > VERTEXPERBLOCK ? m->invertices : VERTEXPERBLOCK,
+           sizeof(REAL));
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  initializetrisubpools()   Calculate the sizes of the triangle and        */
+/*                            subsegment data structures and initialize      */
+/*                            their memory pools.                            */
+/*                                                                           */
+/*  This routine also computes the `highorderindex', `elemattribindex', and  */
+/*  `areaboundindex' indices used to find values within each triangle.       */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void initializetrisubpools(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void initializetrisubpools(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  int trisize;
+
+  /* The index within each triangle at which the extra nodes (above three)  */
+  /*   associated with high order elements are found.  There are three      */
+  /*   pointers to other triangles, three pointers to corners, and possibly */
+  /*   three pointers to subsegments before the extra nodes.                */
+  m->highorderindex = 6 + (b->usesegments * 3);
+  /* The number of bytes occupied by a triangle. */
+  trisize = ((b->order + 1) * (b->order + 2) / 2 + (m->highorderindex - 3)) *
+            sizeof(triangle);
+  /* The index within each triangle at which its attributes are found, */
+  /*   where the index is measured in REALs.                           */
+  m->elemattribindex = (trisize + sizeof(REAL) - 1) / sizeof(REAL);
+  /* The index within each triangle at which the maximum area constraint  */
+  /*   is found, where the index is measured in REALs.  Note that if the  */
+  /*   `regionattrib' flag is set, an additional attribute will be added. */
+  m->areaboundindex = m->elemattribindex + m->eextras + b->regionattrib;
+  /* If triangle attributes or an area bound are needed, increase the number */
+  /*   of bytes occupied by a triangle.                                      */
+  if (b->vararea) {
+    trisize = (m->areaboundindex + 1) * sizeof(REAL);
+  } else if (m->eextras + b->regionattrib > 0) {
+    trisize = m->areaboundindex * sizeof(REAL);
+  }
+  /* If a Voronoi diagram or triangle neighbor graph is requested, make    */
+  /*   sure there's room to store an integer index in each triangle.  This */
+  /*   integer index can occupy the same space as the subsegment pointers  */
+  /*   or attributes or area constraint or extra nodes.                    */
+  if ((b->voronoi || b->neighbors) &&
+      (trisize < 6 * sizeof(triangle) + sizeof(int))) {
+    trisize = 6 * sizeof(triangle) + sizeof(int);
+  }
+
+  /* Having determined the memory size of a triangle, initialize the pool. */
+  poolinit(&m->triangles, trisize, TRIPERBLOCK,
+           (2 * m->invertices - 2) > TRIPERBLOCK ? (2 * m->invertices - 2) :
+           TRIPERBLOCK, 4);
+
+  if (b->usesegments) {
+    /* Initialize the pool of subsegments.  Take into account all eight */
+    /*   pointers and one boundary marker.                              */
+    poolinit(&m->subsegs, 8 * sizeof(triangle) + sizeof(int),
+             SUBSEGPERBLOCK, SUBSEGPERBLOCK, 4);
+
+    /* Initialize the "outer space" triangle and omnipresent subsegment. */
+    dummyinit(m, b, m->triangles.itembytes, m->subsegs.itembytes);
+  } else {
+    /* Initialize the "outer space" triangle. */
+    dummyinit(m, b, m->triangles.itembytes, 0);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  triangledealloc()   Deallocate space for a triangle, marking it dead.    */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void triangledealloc(struct mesh *m, triangle *dyingtriangle)
+#else /* not ANSI_DECLARATORS */
+void triangledealloc(m, dyingtriangle)
+struct mesh *m;
+triangle *dyingtriangle;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  /* Mark the triangle as dead.  This makes it possible to detect dead */
+  /*   triangles when traversing the list of all triangles.            */
+  killtri(dyingtriangle);
+  pooldealloc(&m->triangles, (VOID *) dyingtriangle);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  triangletraverse()   Traverse the triangles, skipping dead ones.         */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+triangle *triangletraverse(struct mesh *m)
+#else /* not ANSI_DECLARATORS */
+triangle *triangletraverse(m)
+struct mesh *m;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  triangle *newtriangle;
+
+  do {
+    newtriangle = (triangle *) traverse(&m->triangles);
+    if (newtriangle == (triangle *) NULL) {
+      return (triangle *) NULL;
+    }
+  } while (deadtri(newtriangle));                         /* Skip dead ones. */
+  return newtriangle;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  subsegdealloc()   Deallocate space for a subsegment, marking it dead.    */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void subsegdealloc(struct mesh *m, subseg *dyingsubseg)
+#else /* not ANSI_DECLARATORS */
+void subsegdealloc(m, dyingsubseg)
+struct mesh *m;
+subseg *dyingsubseg;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  /* Mark the subsegment as dead.  This makes it possible to detect dead */
+  /*   subsegments when traversing the list of all subsegments.          */
+  killsubseg(dyingsubseg);
+  pooldealloc(&m->subsegs, (VOID *) dyingsubseg);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  subsegtraverse()   Traverse the subsegments, skipping dead ones.         */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+subseg *subsegtraverse(struct mesh *m)
+#else /* not ANSI_DECLARATORS */
+subseg *subsegtraverse(m)
+struct mesh *m;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  subseg *newsubseg;
+
+  do {
+    newsubseg = (subseg *) traverse(&m->subsegs);
+    if (newsubseg == (subseg *) NULL) {
+      return (subseg *) NULL;
+    }
+  } while (deadsubseg(newsubseg));                        /* Skip dead ones. */
+  return newsubseg;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  vertexdealloc()   Deallocate space for a vertex, marking it dead.        */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void vertexdealloc(struct mesh *m, vertex dyingvertex)
+#else /* not ANSI_DECLARATORS */
+void vertexdealloc(m, dyingvertex)
+struct mesh *m;
+vertex dyingvertex;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  /* Mark the vertex as dead.  This makes it possible to detect dead */
+  /*   vertices when traversing the list of all vertices.            */
+  setvertextype(dyingvertex, DEADVERTEX);
+  pooldealloc(&m->vertices, (VOID *) dyingvertex);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  vertextraverse()   Traverse the vertices, skipping dead ones.            */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+vertex vertextraverse(struct mesh *m)
+#else /* not ANSI_DECLARATORS */
+vertex vertextraverse(m)
+struct mesh *m;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  vertex newvertex;
+
+  do {
+    newvertex = (vertex) traverse(&m->vertices);
+    if (newvertex == (vertex) NULL) {
+      return (vertex) NULL;
+    }
+  } while (vertextype(newvertex) == DEADVERTEX);          /* Skip dead ones. */
+  return newvertex;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  badsubsegdealloc()   Deallocate space for a bad subsegment, marking it   */
+/*                       dead.                                               */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef CDT_ONLY
+
+#ifdef ANSI_DECLARATORS
+void badsubsegdealloc(struct mesh *m, struct badsubseg *dyingseg)
+#else /* not ANSI_DECLARATORS */
+void badsubsegdealloc(m, dyingseg)
+struct mesh *m;
+struct badsubseg *dyingseg;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  /* Set subsegment's origin to NULL.  This makes it possible to detect dead */
+  /*   badsubsegs when traversing the list of all badsubsegs             .   */
+  dyingseg->subsegorg = (vertex) NULL;
+  pooldealloc(&m->badsubsegs, (VOID *) dyingseg);
+}
+
+#endif /* not CDT_ONLY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  badsubsegtraverse()   Traverse the bad subsegments, skipping dead ones.  */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef CDT_ONLY
+
+#ifdef ANSI_DECLARATORS
+struct badsubseg *badsubsegtraverse(struct mesh *m)
+#else /* not ANSI_DECLARATORS */
+struct badsubseg *badsubsegtraverse(m)
+struct mesh *m;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct badsubseg *newseg;
+
+  do {
+    newseg = (struct badsubseg *) traverse(&m->badsubsegs);
+    if (newseg == (struct badsubseg *) NULL) {
+      return (struct badsubseg *) NULL;
+    }
+  } while (newseg->subsegorg == (vertex) NULL);           /* Skip dead ones. */
+  return newseg;
+}
+
+#endif /* not CDT_ONLY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  getvertex()   Get a specific vertex, by number, from the list.           */
+/*                                                                           */
+/*  The first vertex is number 'firstnumber'.                                */
+/*                                                                           */
+/*  Note that this takes O(n) time (with a small constant, if VERTEXPERBLOCK */
+/*  is large).  I don't care to take the trouble to make it work in constant */
+/*  time.                                                                    */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+vertex getvertex(struct mesh *m, struct behavior *b, int number)
+#else /* not ANSI_DECLARATORS */
+vertex getvertex(m, b, number)
+struct mesh *m;
+struct behavior *b;
+int number;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  VOID **getblock;
+  char *foundvertex;
+  size_t alignptr;
+  int current;
+
+  getblock = m->vertices.firstblock;
+  current = b->firstnumber;
+
+  /* Find the right block. */
+  if (current + m->vertices.itemsfirstblock <= number) {
+    getblock = (VOID **) *getblock;
+    current += m->vertices.itemsfirstblock;
+    while (current + m->vertices.itemsperblock <= number) {
+      getblock = (VOID **) *getblock;
+      current += m->vertices.itemsperblock;
+    }
+  }
+
+  /* Now find the right vertex. */
+  alignptr = (size_t) (getblock + 1);
+  foundvertex = (char *) (alignptr + (size_t) m->vertices.alignbytes -
+                          (alignptr % (size_t) m->vertices.alignbytes));
+  return (vertex) (foundvertex + m->vertices.itembytes * (number - current));
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  triangledeinit()   Free all remaining allocated memory.                  */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void triangledeinit(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void triangledeinit(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  pooldeinit(&m->triangles);
+  trifree((VOID *) m->dummytribase);
+  if (b->usesegments) {
+    pooldeinit(&m->subsegs);
+    trifree((VOID *) m->dummysubbase);
+  }
+  pooldeinit(&m->vertices);
+#ifndef CDT_ONLY
+  if (b->quality) {
+    pooldeinit(&m->badsubsegs);
+    if ((b->minangle > 0.0) || b->vararea || b->fixedarea || b->usertest) {
+      pooldeinit(&m->badtriangles);
+      pooldeinit(&m->flipstackers);
+    }
+  }
+#endif /* not CDT_ONLY */
+  exactdeinit();
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Memory management routines end here                       *********/
+
+/********* Constructors begin here                                   *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  maketriangle()   Create a new triangle with orientation zero.            */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void maketriangle(struct mesh *m, struct behavior *b, struct otri *newotri)
+#else /* not ANSI_DECLARATORS */
+void maketriangle(m, b, newotri)
+struct mesh *m;
+struct behavior *b;
+struct otri *newotri;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  int i;
+
+  newotri->tri = (triangle *) poolalloc(&m->triangles);
+  /* Initialize the three adjoining triangles to be "outer space". */
+  newotri->tri[0] = (triangle) m->dummytri;
+  newotri->tri[1] = (triangle) m->dummytri;
+  newotri->tri[2] = (triangle) m->dummytri;
+  /* Three NULL vertices. */
+  newotri->tri[3] = (triangle) NULL;
+  newotri->tri[4] = (triangle) NULL;
+  newotri->tri[5] = (triangle) NULL;
+  if (b->usesegments) {
+    /* Initialize the three adjoining subsegments to be the omnipresent */
+    /*   subsegment.                                                    */
+    newotri->tri[6] = (triangle) m->dummysub;
+    newotri->tri[7] = (triangle) m->dummysub;
+    newotri->tri[8] = (triangle) m->dummysub;
+  }
+  for (i = 0; i < m->eextras; i++) {
+    setelemattribute(*newotri, i, 0.0);
+  }
+  if (b->vararea) {
+    setareabound(*newotri, -1.0);
+  }
+
+  newotri->orient = 0;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  makesubseg()   Create a new subsegment with orientation zero.            */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void makesubseg(struct mesh *m, struct osub *newsubseg)
+#else /* not ANSI_DECLARATORS */
+void makesubseg(m, newsubseg)
+struct mesh *m;
+struct osub *newsubseg;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  newsubseg->ss = (subseg *) poolalloc(&m->subsegs);
+  /* Initialize the two adjoining subsegments to be the omnipresent */
+  /*   subsegment.                                                  */
+  newsubseg->ss[0] = (subseg) m->dummysub;
+  newsubseg->ss[1] = (subseg) m->dummysub;
+  /* Four NULL vertices. */
+  newsubseg->ss[2] = (subseg) NULL;
+  newsubseg->ss[3] = (subseg) NULL;
+  newsubseg->ss[4] = (subseg) NULL;
+  newsubseg->ss[5] = (subseg) NULL;
+  /* Initialize the two adjoining triangles to be "outer space." */
+  newsubseg->ss[6] = (subseg) m->dummytri;
+  newsubseg->ss[7] = (subseg) m->dummytri;
+  /* Set the boundary marker to zero. */
+  setmark(*newsubseg, 0);
+
+  newsubseg->ssorient = 0;
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Constructors end here                                     *********/
+
+/********* Geometric primitives begin here                           *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/* The adaptive exact arithmetic geometric predicates implemented herein are */
+/*   described in detail in my paper, "Adaptive Precision Floating-Point     */
+/*   Arithmetic and Fast Robust Geometric Predicates."  See the header for a */
+/*   full citation.                                                          */
+
+/* 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 without       */
+/*   forcing the value to be stored to memory (rather than be kept in the    */
+/*   register to which the optimizer assigned it).                           */
+
+#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 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
+
+/* 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)
+
+/* Macro for multiplying a two-component expansion by a single component.    */
+
+#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)
+
+/*****************************************************************************/
+/*                                                                           */
+/*  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.                */
+/*                                                                           */
+/*****************************************************************************/
+
+static int previous_cword;
+
+void exactinit(void)
+{
+  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
+  _FPU_GETCW(previous_cword);
+#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 these routines will work on such machines.)       */
+  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;
+  iccerrboundA = (10.0 + 96.0 * epsilon) * epsilon;
+  iccerrboundB = (4.0 + 48.0 * epsilon) * epsilon;
+  iccerrboundC = (44.0 + 576.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;
+}
+
+void exactdeinit()
+{
+#ifdef LINUX
+  _FPU_SETCW(previous_cword);
+#endif /* LINUX */
+}
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*  fast_expansion_sum_zeroelim()   Sum two expansions, eliminating zero     */
+/*                                  components from the output expansion.    */
+/*                                                                           */
+/*  Sets h = e + f.  See my Robust Predicates 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.                                                              */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+int fast_expansion_sum_zeroelim(int elen, REAL *e, int flen, REAL *f, REAL *h)
+#else /* not ANSI_DECLARATORS */
+int fast_expansion_sum_zeroelim(elen, e, flen, f, h)  /* h cannot be e or f. */
+int elen;
+REAL *e;
+int flen;
+REAL *f;
+REAL *h;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  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;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  scale_expansion_zeroelim()   Multiply an expansion by a scalar,          */
+/*                               eliminating zero components from the        */
+/*                               output expansion.                           */
+/*                                                                           */
+/*  Sets h = be.  See my Robust Predicates 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.)                                                                 */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+int scale_expansion_zeroelim(int elen, REAL *e, REAL b, REAL *h)
+#else /* not ANSI_DECLARATORS */
+int scale_expansion_zeroelim(elen, e, b, h)   /* e and h cannot be the same. */
+int elen;
+REAL *e;
+REAL b;
+REAL *h;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  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;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  estimate()   Produce a one-word estimate of an expansion's value.        */
+/*                                                                           */
+/*  See my Robust Predicates paper for details.                              */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+REAL estimate(int elen, REAL *e)
+#else /* not ANSI_DECLARATORS */
+REAL estimate(elen, e)
+int elen;
+REAL *e;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  REAL Q;
+  int eindex;
+
+  Q = e[0];
+  for (eindex = 1; eindex < elen; eindex++) {
+    Q += e[eindex];
+  }
+  return Q;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  counterclockwise()   Return a positive value if the points pa, pb, and   */
+/*                       pc occur in counterclockwise order; a negative      */
+/*                       value if they occur in clockwise order; and zero    */
+/*                       if they are collinear.  The result is also a rough  */
+/*                       approximation of twice the signed area of the       */
+/*                       triangle defined by the three points.               */
+/*                                                                           */
+/*  Uses exact arithmetic if necessary to ensure a correct answer.  The      */
+/*  result returned is the determinant of a matrix.  This determinant is     */
+/*  computed adaptively, in the sense that exact arithmetic is used only to  */
+/*  the degree it is needed to ensure that the returned value has the        */
+/*  correct sign.  Hence, this function is usually quite fast, but will run  */
+/*  more slowly when the input points are collinear or nearly so.            */
+/*                                                                           */
+/*  See my Robust Predicates paper for details.                              */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+REAL counterclockwiseadapt(vertex pa, vertex pb, vertex pc, REAL detsum)
+#else /* not ANSI_DECLARATORS */
+REAL counterclockwiseadapt(pa, pb, pc, detsum)
+vertex pa;
+vertex pb;
+vertex pc;
+REAL detsum;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  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]);
+}
+
+#ifdef ANSI_DECLARATORS
+REAL counterclockwise(struct mesh *m, struct behavior *b,
+                      vertex pa, vertex pb, vertex pc)
+#else /* not ANSI_DECLARATORS */
+REAL counterclockwise(m, b, pa, pb, pc)
+struct mesh *m;
+struct behavior *b;
+vertex pa;
+vertex pb;
+vertex pc;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  REAL detleft, detright, det;
+  REAL detsum, errbound;
+
+  m->counterclockcount++;
+
+  detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]);
+  detright = (pa[1] - pc[1]) * (pb[0] - pc[0]);
+  det = detleft - detright;
+
+  if (b->noexact) {
+    return det;
+  }
+
+  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 counterclockwiseadapt(pa, pb, pc, detsum);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  incircle()   Return a positive value if the point pd lies inside the     */
+/*               circle passing through pa, pb, and pc; a negative value if  */
+/*               it lies outside; and zero if the four points are cocircular.*/
+/*               The points pa, pb, and pc must be in counterclockwise       */
+/*               order, or the sign of the result will be reversed.          */
+/*                                                                           */
+/*  Uses exact arithmetic if necessary to ensure a correct answer.  The      */
+/*  result returned is the determinant of a matrix.  This determinant is     */
+/*  computed adaptively, in the sense that exact arithmetic is used only to  */
+/*  the degree it is needed to ensure that the returned value has the        */
+/*  correct sign.  Hence, this function is usually quite fast, but will run  */
+/*  more slowly when the input points are cocircular or nearly so.           */
+/*                                                                           */
+/*  See my Robust Predicates paper for details.                              */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+REAL incircleadapt(vertex pa, vertex pb, vertex pc, vertex pd, REAL permanent)
+#else /* not ANSI_DECLARATORS */
+REAL incircleadapt(pa, pb, pc, pd, permanent)
+vertex pa;
+vertex pb;
+vertex pc;
+vertex pd;
+REAL permanent;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  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];
+}
+
+#ifdef ANSI_DECLARATORS
+REAL incircle(struct mesh *m, struct behavior *b,
+              vertex pa, vertex pb, vertex pc, vertex pd)
+#else /* not ANSI_DECLARATORS */
+REAL incircle(m, b, pa, pb, pc, pd)
+struct mesh *m;
+struct behavior *b;
+vertex pa;
+vertex pb;
+vertex pc;
+vertex pd;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  REAL adx, bdx, cdx, ady, bdy, cdy;
+  REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
+  REAL alift, blift, clift;
+  REAL det;
+  REAL permanent, errbound;
+
+  m->incirclecount++;
+
+  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);
+
+  if (b->noexact) {
+    return det;
+  }
+
+  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);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  orient3d()   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.                                                */
+/*                                                                           */
+/*  Uses exact arithmetic if necessary to ensure a correct answer.  The      */
+/*  result returned is the determinant of a matrix.  This determinant is     */
+/*  computed adaptively, in the sense that exact arithmetic is used only to  */
+/*  the degree it is needed to ensure that the returned value has the        */
+/*  correct sign.  Hence, this function is usually quite fast, but will run  */
+/*  more slowly when the input points are coplanar or nearly so.             */
+/*                                                                           */
+/*  See my Robust Predicates paper for details.                              */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+REAL orient3dadapt(vertex pa, vertex pb, vertex pc, vertex pd,
+                   REAL aheight, REAL bheight, REAL cheight, REAL dheight,
+                   REAL permanent)
+#else /* not ANSI_DECLARATORS */
+REAL orient3dadapt(pa, pb, pc, pd,
+                   aheight, bheight, cheight, dheight, permanent)
+vertex pa;
+vertex pb;
+vertex pc;
+vertex pd;
+REAL aheight;
+REAL bheight;
+REAL cheight;
+REAL dheight;
+REAL permanent;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  INEXACT REAL adx, bdx, cdx, ady, bdy, cdy, adheight, bdheight, cdheight;
+  REAL det, errbound;
+
+  INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1;
+  REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0;
+  REAL bc[4], ca[4], ab[4];
+  INEXACT REAL bc3, ca3, ab3;
+  REAL adet[8], bdet[8], cdet[8];
+  int alen, blen, clen;
+  REAL abdet[16];
+  int ablen;
+  REAL *finnow, *finother, *finswap;
+  REAL fin1[192], fin2[192];
+  int finlength;
+
+  REAL adxtail, bdxtail, cdxtail;
+  REAL adytail, bdytail, cdytail;
+  REAL adheighttail, bdheighttail, cdheighttail;
+  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]);
+  adheight = (REAL) (aheight - dheight);
+  bdheight = (REAL) (bheight - dheight);
+  cdheight = (REAL) (cheight - dheight);
+
+  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, adheight, 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, bdheight, 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, cdheight, 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(aheight, dheight, adheight, adheighttail);
+  Two_Diff_Tail(bheight, dheight, bdheight, bdheighttail);
+  Two_Diff_Tail(cheight, dheight, cdheight, cdheighttail);
+
+  if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) &&
+      (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0) &&
+      (adheighttail == 0.0) &&
+      (bdheighttail == 0.0) &&
+      (cdheighttail == 0.0)) {
+    return det;
+  }
+
+  errbound = o3derrboundC * permanent + resulterrbound * Absolute(det);
+  det += (adheight * ((bdx * cdytail + cdy * bdxtail) -
+                      (bdy * cdxtail + cdx * bdytail)) +
+          adheighttail * (bdx * cdy - bdy * cdx)) +
+         (bdheight * ((cdx * adytail + ady * cdxtail) -
+                      (cdy * adxtail + adx * cdytail)) +
+          bdheighttail * (cdx * ady - cdy * adx)) +
+         (cdheight * ((adx * bdytail + bdy * adxtail) -
+                      (ady * bdxtail + bdx * adytail)) +
+          cdheighttail * (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, adheight, 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, bdheight, 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, cdheight, w);
+  finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
+                                          finother);
+  finswap = finnow; finnow = finother; finother = finswap;
+
+  if (adheighttail != 0.0) {
+    vlength = scale_expansion_zeroelim(4, bc, adheighttail, v);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v,
+                                            finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+  if (bdheighttail != 0.0) {
+    vlength = scale_expansion_zeroelim(4, ca, bdheighttail, v);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v,
+                                            finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+  if (cdheighttail != 0.0) {
+    vlength = scale_expansion_zeroelim(4, ab, cdheighttail, 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, cdheight, 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 (cdheighttail != 0.0) {
+        Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdheighttail,
+                        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, bdheight, 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 (bdheighttail != 0.0) {
+        Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdheighttail,
+                        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, adheight, 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 (adheighttail != 0.0) {
+        Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adheighttail,
+                        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, cdheight, 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 (cdheighttail != 0.0) {
+        Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdheighttail,
+                        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, bdheight, 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 (bdheighttail != 0.0) {
+        Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdheighttail,
+                        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, adheight, 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 (adheighttail != 0.0) {
+        Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adheighttail,
+                        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 (adheighttail != 0.0) {
+    wlength = scale_expansion_zeroelim(bctlen, bct, adheighttail, w);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
+                                            finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+  if (bdheighttail != 0.0) {
+    wlength = scale_expansion_zeroelim(catlen, cat, bdheighttail, w);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
+                                            finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+  if (cdheighttail != 0.0) {
+    wlength = scale_expansion_zeroelim(abtlen, abt, cdheighttail, w);
+    finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
+                                            finother);
+    finswap = finnow; finnow = finother; finother = finswap;
+  }
+
+  return finnow[finlength - 1];
+}
+
+#ifdef ANSI_DECLARATORS
+REAL orient3d(struct mesh *m, struct behavior *b,
+              vertex pa, vertex pb, vertex pc, vertex pd,
+              REAL aheight, REAL bheight, REAL cheight, REAL dheight)
+#else /* not ANSI_DECLARATORS */
+REAL orient3d(m, b, pa, pb, pc, pd, aheight, bheight, cheight, dheight)
+struct mesh *m;
+struct behavior *b;
+vertex pa;
+vertex pb;
+vertex pc;
+vertex pd;
+REAL aheight;
+REAL bheight;
+REAL cheight;
+REAL dheight;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  REAL adx, bdx, cdx, ady, bdy, cdy, adheight, bdheight, cdheight;
+  REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
+  REAL det;
+  REAL permanent, errbound;
+
+  m->orient3dcount++;
+
+  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];
+  adheight = aheight - dheight;
+  bdheight = bheight - dheight;
+  cdheight = cheight - dheight;
+
+  bdxcdy = bdx * cdy;
+  cdxbdy = cdx * bdy;
+
+  cdxady = cdx * ady;
+  adxcdy = adx * cdy;
+
+  adxbdy = adx * bdy;
+  bdxady = bdx * ady;
+
+  det = adheight * (bdxcdy - cdxbdy) 
+      + bdheight * (cdxady - adxcdy)
+      + cdheight * (adxbdy - bdxady);
+
+  if (b->noexact) {
+    return det;
+  }
+
+  permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * Absolute(adheight)
+            + (Absolute(cdxady) + Absolute(adxcdy)) * Absolute(bdheight)
+            + (Absolute(adxbdy) + Absolute(bdxady)) * Absolute(cdheight);
+  errbound = o3derrboundA * permanent;
+  if ((det > errbound) || (-det > errbound)) {
+    return det;
+  }
+
+  return orient3dadapt(pa, pb, pc, pd, aheight, bheight, cheight, dheight,
+                       permanent);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  nonregular()   Return a positive value if the point pd is incompatible   */
+/*                 with the circle or plane passing through pa, pb, and pc   */
+/*                 (meaning that pd is inside the circle or below the        */
+/*                 plane); a negative value if it is compatible; and zero if */
+/*                 the four points are cocircular/coplanar.  The points pa,  */
+/*                 pb, and pc must be in counterclockwise order, or the sign */
+/*                 of the result will be reversed.                           */
+/*                                                                           */
+/*  If the -w switch is used, the points are lifted onto the parabolic       */
+/*  lifting map, then they are dropped according to their weights, then the  */
+/*  3D orientation test is applied.  If the -W switch is used, the points'   */
+/*  heights are already provided, so the 3D orientation test is applied      */
+/*  directly.  If neither switch is used, the incircle test is applied.      */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+REAL nonregular(struct mesh *m, struct behavior *b,
+                vertex pa, vertex pb, vertex pc, vertex pd)
+#else /* not ANSI_DECLARATORS */
+REAL nonregular(m, b, pa, pb, pc, pd)
+struct mesh *m;
+struct behavior *b;
+vertex pa;
+vertex pb;
+vertex pc;
+vertex pd;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  if (b->weighted == 0) {
+    return incircle(m, b, pa, pb, pc, pd);
+  } else if (b->weighted == 1) {
+    return orient3d(m, b, pa, pb, pc, pd,
+                    pa[0] * pa[0] + pa[1] * pa[1] - pa[2],
+                    pb[0] * pb[0] + pb[1] * pb[1] - pb[2],
+                    pc[0] * pc[0] + pc[1] * pc[1] - pc[2],
+                    pd[0] * pd[0] + pd[1] * pd[1] - pd[2]);
+  } else {
+    return orient3d(m, b, pa, pb, pc, pd, pa[2], pb[2], pc[2], pd[2]);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  findcircumcenter()   Find the circumcenter of a triangle.                */
+/*                                                                           */
+/*  The result is returned both in terms of x-y coordinates and xi-eta       */
+/*  (barycentric) coordinates.  The xi-eta coordinate system is defined in   */
+/*  terms of the triangle:  the origin of the triangle is the origin of the  */
+/*  coordinate system; the destination of the triangle is one unit along the */
+/*  xi axis; and the apex of the triangle is one unit along the eta axis.    */
+/*  This procedure also returns the square of the length of the triangle's   */
+/*  shortest edge.                                                           */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void findcircumcenter(struct mesh *m, struct behavior *b,
+                      vertex torg, vertex tdest, vertex tapex,
+                      vertex circumcenter, REAL *xi, REAL *eta, int offcenter)
+#else /* not ANSI_DECLARATORS */
+void findcircumcenter(m, b, torg, tdest, tapex, circumcenter, xi, eta,
+                      offcenter)
+struct mesh *m;
+struct behavior *b;
+vertex torg;
+vertex tdest;
+vertex tapex;
+vertex circumcenter;
+REAL *xi;
+REAL *eta;
+int offcenter;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  REAL xdo, ydo, xao, yao;
+  REAL dodist, aodist, dadist;
+  REAL denominator;
+  REAL dx, dy, dxoff, dyoff;
+
+  m->circumcentercount++;
+
+  /* Compute the circumcenter of the triangle. */
+  xdo = tdest[0] - torg[0];
+  ydo = tdest[1] - torg[1];
+  xao = tapex[0] - torg[0];
+  yao = tapex[1] - torg[1];
+  dodist = xdo * xdo + ydo * ydo;
+  aodist = xao * xao + yao * yao;
+  dadist = (tdest[0] - tapex[0]) * (tdest[0] - tapex[0]) +
+           (tdest[1] - tapex[1]) * (tdest[1] - tapex[1]);
+  if (b->noexact) {
+    denominator = 0.5 / (xdo * yao - xao * ydo);
+  } else {
+    /* Use the counterclockwise() routine to ensure a positive (and */
+    /*   reasonably accurate) result, avoiding any possibility of   */
+    /*   division by zero.                                          */
+    denominator = 0.5 / counterclockwise(m, b, tdest, tapex, torg);
+    /* Don't count the above as an orientation test. */
+    m->counterclockcount--;
+  }
+  dx = (yao * dodist - ydo * aodist) * denominator;
+  dy = (xdo * aodist - xao * dodist) * denominator;
+
+  /* Find the (squared) length of the triangle's shortest edge.  This   */
+  /*   serves as a conservative estimate of the insertion radius of the */
+  /*   circumcenter's parent.  The estimate is used to ensure that      */
+  /*   the algorithm terminates even if very small angles appear in     */
+  /*   the input PSLG.                                                  */
+  if ((dodist < aodist) && (dodist < dadist)) {
+    if (offcenter && (b->offconstant > 0.0)) {
+      /* Find the position of the off-center, as described by Alper Ungor. */
+      dxoff = 0.5 * xdo - b->offconstant * ydo;
+      dyoff = 0.5 * ydo + b->offconstant * xdo;
+      /* If the off-center is closer to the origin than the */
+      /*   circumcenter, use the off-center instead.        */
+      if (dxoff * dxoff + dyoff * dyoff < dx * dx + dy * dy) {
+        dx = dxoff;
+        dy = dyoff;
+      }
+    }
+  } else if (aodist < dadist) {
+    if (offcenter && (b->offconstant > 0.0)) {
+      dxoff = 0.5 * xao + b->offconstant * yao;
+      dyoff = 0.5 * yao - b->offconstant * xao;
+      /* If the off-center is closer to the origin than the */
+      /*   circumcenter, use the off-center instead.        */
+      if (dxoff * dxoff + dyoff * dyoff < dx * dx + dy * dy) {
+        dx = dxoff;
+        dy = dyoff;
+      }
+    }
+  } else {
+    if (offcenter && (b->offconstant > 0.0)) {
+      dxoff = 0.5 * (tapex[0] - tdest[0]) -
+              b->offconstant * (tapex[1] - tdest[1]);
+      dyoff = 0.5 * (tapex[1] - tdest[1]) +
+              b->offconstant * (tapex[0] - tdest[0]);
+      /* If the off-center is closer to the destination than the */
+      /*   circumcenter, use the off-center instead.             */
+      if (dxoff * dxoff + dyoff * dyoff <
+          (dx - xdo) * (dx - xdo) + (dy - ydo) * (dy - ydo)) {
+        dx = xdo + dxoff;
+        dy = ydo + dyoff;
+      }
+    }
+  }
+
+  circumcenter[0] = torg[0] + dx;
+  circumcenter[1] = torg[1] + dy;
+
+  /* To interpolate vertex attributes for the new vertex inserted at */
+  /*   the circumcenter, define a coordinate system with a xi-axis,  */
+  /*   directed from the triangle's origin to its destination, and   */
+  /*   an eta-axis, directed from its origin to its apex.            */
+  /*   Calculate the xi and eta coordinates of the circumcenter.     */
+  *xi = (yao * dx - xao * dy) * (2.0 * denominator);
+  *eta = (xdo * dy - ydo * dx) * (2.0 * denominator);
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Geometric primitives end here                             *********/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  triangleinit()   Initialize some variables.                              */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void triangleinit(struct mesh *m)
+#else /* not ANSI_DECLARATORS */
+void triangleinit(m)
+struct mesh *m;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  poolzero(&m->vertices);
+  poolzero(&m->triangles);
+  poolzero(&m->subsegs);
+  poolzero(&m->viri);
+  poolzero(&m->badsubsegs);
+  poolzero(&m->badtriangles);
+  poolzero(&m->flipstackers);
+  poolzero(&m->splaynodes);
+
+  m->recenttri.tri = (triangle *) NULL; /* No triangle has been visited yet. */
+  m->undeads = 0;                       /* No eliminated input vertices yet. */
+  m->samples = 1;         /* Point location should take at least one sample. */
+  m->checksegments = 0;   /* There are no segments in the triangulation yet. */
+  m->checkquality = 0;     /* The quality triangulation stage has not begun. */
+  m->incirclecount = m->counterclockcount = m->orient3dcount = 0;
+  m->hyperbolacount = m->circletopcount = m->circumcentercount = 0;
+  randomseed = 1;
+
+  exactinit();                     /* Initialize exact arithmetic constants. */
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  randomnation()   Generate a random number between 0 and `choices' - 1.   */
+/*                                                                           */
+/*  This is a simple linear congruential random number generator.  Hence, it */
+/*  is a bad random number generator, but good enough for most randomized    */
+/*  geometric algorithms.                                                    */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+unsigned long randomnation(unsigned int choices)
+#else /* not ANSI_DECLARATORS */
+unsigned long randomnation(choices)
+unsigned int choices;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  randomseed = (randomseed * 1366l + 150889l) % 714025l;
+  return randomseed / (714025l / choices + 1);
+}
+
+/********* Mesh quality testing routines begin here                  *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  checkmesh()   Test the mesh for topological consistency.                 */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+void checkmesh(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void checkmesh(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri triangleloop;
+  struct otri oppotri, oppooppotri;
+  vertex triorg, tridest, triapex;
+  vertex oppoorg, oppodest;
+  int horrors;
+  int saveexact;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+  /* Temporarily turn on exact arithmetic if it's off. */
+  saveexact = b->noexact;
+  b->noexact = 0;
+  if (!b->quiet) {
+    printf("  Checking consistency of mesh...\n");
+  }
+  horrors = 0;
+  /* Run through the list of triangles, checking each one. */
+  traversalinit(&m->triangles);
+  triangleloop.tri = triangletraverse(m);
+  while (triangleloop.tri != (triangle *) NULL) {
+    /* Check all three edges of the triangle. */
+    for (triangleloop.orient = 0; triangleloop.orient < 3;
+         triangleloop.orient++) {
+      org(triangleloop, triorg);
+      dest(triangleloop, tridest);
+      if (triangleloop.orient == 0) {       /* Only test for inversion once. */
+        /* Test if the triangle is flat or inverted. */
+        apex(triangleloop, triapex);
+        if (counterclockwise(m, b, triorg, tridest, triapex) <= 0.0) {
+          printf("  !! !! Inverted ");
+          printtriangle(m, b, &triangleloop);
+          horrors++;
+        }
+      }
+      /* Find the neighboring triangle on this edge. */
+      sym(triangleloop, oppotri);
+      if (oppotri.tri != m->dummytri) {
+        /* Check that the triangle's neighbor knows it's a neighbor. */
+        sym(oppotri, oppooppotri);
+        if ((triangleloop.tri != oppooppotri.tri)
+            || (triangleloop.orient != oppooppotri.orient)) {
+          printf("  !! !! Asymmetric triangle-triangle bond:\n");
+          if (triangleloop.tri == oppooppotri.tri) {
+            printf("   (Right triangle, wrong orientation)\n");
+          }
+          printf("    First ");
+          printtriangle(m, b, &triangleloop);
+          printf("    Second (nonreciprocating) ");
+          printtriangle(m, b, &oppotri);
+          horrors++;
+        }
+        /* Check that both triangles agree on the identities */
+        /*   of their shared vertices.                       */
+        org(oppotri, oppoorg);
+        dest(oppotri, oppodest);
+        if ((triorg != oppodest) || (tridest != oppoorg)) {
+          printf("  !! !! Mismatched edge coordinates between two triangles:\n"
+                 );
+          printf("    First mismatched ");
+          printtriangle(m, b, &triangleloop);
+          printf("    Second mismatched ");
+          printtriangle(m, b, &oppotri);
+          horrors++;
+        }
+      }
+    }
+    triangleloop.tri = triangletraverse(m);
+  }
+  if (horrors == 0) {
+    if (!b->quiet) {
+      printf("  In my studied opinion, the mesh appears to be consistent.\n");
+    }
+  } else if (horrors == 1) {
+    printf("  !! !! !! !! Precisely one festering wound discovered.\n");
+  } else {
+    printf("  !! !! !! !! %d abominations witnessed.\n", horrors);
+  }
+  /* Restore the status of exact arithmetic. */
+  b->noexact = saveexact;
+}
+
+#endif /* not REDUCED */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  checkdelaunay()   Ensure that the mesh is (constrained) Delaunay.        */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+void checkdelaunay(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void checkdelaunay(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri triangleloop;
+  struct otri oppotri;
+  struct osub opposubseg;
+  vertex triorg, tridest, triapex;
+  vertex oppoapex;
+  int shouldbedelaunay;
+  int horrors;
+  int saveexact;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+
+  /* Temporarily turn on exact arithmetic if it's off. */
+  saveexact = b->noexact;
+  b->noexact = 0;
+  if (!b->quiet) {
+    printf("  Checking Delaunay property of mesh...\n");
+  }
+  horrors = 0;
+  /* Run through the list of triangles, checking each one. */
+  traversalinit(&m->triangles);
+  triangleloop.tri = triangletraverse(m);
+  while (triangleloop.tri != (triangle *) NULL) {
+    /* Check all three edges of the triangle. */
+    for (triangleloop.orient = 0; triangleloop.orient < 3;
+         triangleloop.orient++) {
+      org(triangleloop, triorg);
+      dest(triangleloop, tridest);
+      apex(triangleloop, triapex);
+      sym(triangleloop, oppotri);
+      apex(oppotri, oppoapex);
+      /* Only test that the edge is locally Delaunay if there is an   */
+      /*   adjoining triangle whose pointer is larger (to ensure that */
+      /*   each pair isn't tested twice).                             */
+      shouldbedelaunay = (oppotri.tri != m->dummytri) &&
+            !deadtri(oppotri.tri) && (triangleloop.tri < oppotri.tri) &&
+            (triorg != m->infvertex1) && (triorg != m->infvertex2) &&
+            (triorg != m->infvertex3) &&
+            (tridest != m->infvertex1) && (tridest != m->infvertex2) &&
+            (tridest != m->infvertex3) &&
+            (triapex != m->infvertex1) && (triapex != m->infvertex2) &&
+            (triapex != m->infvertex3) &&
+            (oppoapex != m->infvertex1) && (oppoapex != m->infvertex2) &&
+            (oppoapex != m->infvertex3);
+      if (m->checksegments && shouldbedelaunay) {
+        /* If a subsegment separates the triangles, then the edge is */
+        /*   constrained, so no local Delaunay test should be done.  */
+        tspivot(triangleloop, opposubseg);
+        if (opposubseg.ss != m->dummysub){
+          shouldbedelaunay = 0;
+        }
+      }
+      if (shouldbedelaunay) {
+        if (nonregular(m, b, triorg, tridest, triapex, oppoapex) > 0.0) {
+          if (!b->weighted) {
+            printf("  !! !! Non-Delaunay pair of triangles:\n");
+            printf("    First non-Delaunay ");
+            printtriangle(m, b, &triangleloop);
+            printf("    Second non-Delaunay ");
+          } else {
+            printf("  !! !! Non-regular pair of triangles:\n");
+            printf("    First non-regular ");
+            printtriangle(m, b, &triangleloop);
+            printf("    Second non-regular ");
+          }
+          printtriangle(m, b, &oppotri);
+          horrors++;
+        }
+      }
+    }
+    triangleloop.tri = triangletraverse(m);
+  }
+  if (horrors == 0) {
+    if (!b->quiet) {
+      printf(
+  "  By virtue of my perceptive intelligence, I declare the mesh Delaunay.\n");
+    }
+  } else if (horrors == 1) {
+    printf(
+         "  !! !! !! !! Precisely one terrifying transgression identified.\n");
+  } else {
+    printf("  !! !! !! !! %d obscenities viewed with horror.\n", horrors);
+  }
+  /* Restore the status of exact arithmetic. */
+  b->noexact = saveexact;
+}
+
+#endif /* not REDUCED */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  enqueuebadtriang()   Add a bad triangle data structure to the end of a   */
+/*                       queue.                                              */
+/*                                                                           */
+/*  The queue is actually a set of 4096 queues.  I use multiple queues to    */
+/*  give priority to smaller angles.  I originally implemented a heap, but   */
+/*  the queues are faster by a larger margin than I'd suspected.             */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef CDT_ONLY
+
+#ifdef ANSI_DECLARATORS
+void enqueuebadtriang(struct mesh *m, struct behavior *b,
+                      struct badtriang *badtri)
+#else /* not ANSI_DECLARATORS */
+void enqueuebadtriang(m, b, badtri)
+struct mesh *m;
+struct behavior *b;
+struct badtriang *badtri;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  REAL length, multiplier;
+  int exponent, expincrement;
+  int queuenumber;
+  int posexponent;
+  int i;
+
+  if (b->verbose > 2) {
+    printf("  Queueing bad triangle:\n");
+    printf("    (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
+           badtri->triangorg[0], badtri->triangorg[1],
+           badtri->triangdest[0], badtri->triangdest[1],
+           badtri->triangapex[0], badtri->triangapex[1]);
+  }
+
+  /* Determine the appropriate queue to put the bad triangle into.    */
+  /*   Recall that the key is the square of its shortest edge length. */
+  if (badtri->key >= 1.0) {
+    length = badtri->key;
+    posexponent = 1;
+  } else {
+    /* `badtri->key' is 2.0 to a negative exponent, so we'll record that */
+    /*   fact and use the reciprocal of `badtri->key', which is > 1.0.   */
+    length = 1.0 / badtri->key;
+    posexponent = 0;
+  }
+  /* `length' is approximately 2.0 to what exponent?  The following code */
+  /*   determines the answer in time logarithmic in the exponent.        */
+  exponent = 0;
+  while (length > 2.0) {
+    /* Find an approximation by repeated squaring of two. */
+    expincrement = 1;
+    multiplier = 0.5;
+    while (length * multiplier * multiplier > 1.0) {
+      expincrement *= 2;
+      multiplier *= multiplier;
+    }
+    /* Reduce the value of `length', then iterate if necessary. */
+    exponent += expincrement;
+    length *= multiplier;
+  }
+  /* `length' is approximately squareroot(2.0) to what exponent? */
+  exponent = 2.0 * exponent + (length > SQUAREROOTTWO);
+  /* `exponent' is now in the range 0...2047 for IEEE double precision.   */
+  /*   Choose a queue in the range 0...4095.  The shortest edges have the */
+  /*   highest priority (queue 4095).                                     */
+  if (posexponent) {
+    queuenumber = 2047 - exponent;
+  } else {
+    queuenumber = 2048 + exponent;
+  }
+
+  /* Are we inserting into an empty queue? */
+  if (m->queuefront[queuenumber] == (struct badtriang *) NULL) {
+    /* Yes, we are inserting into an empty queue.     */
+    /*   Will this become the highest-priority queue? */
+    if (queuenumber > m->firstnonemptyq) {
+      /* Yes, this is the highest-priority queue. */
+      m->nextnonemptyq[queuenumber] = m->firstnonemptyq;
+      m->firstnonemptyq = queuenumber;
+    } else {
+      /* No, this is not the highest-priority queue. */
+      /*   Find the queue with next higher priority. */
+      i = queuenumber + 1;
+      while (m->queuefront[i] == (struct badtriang *) NULL) {
+        i++;
+      }
+      /* Mark the newly nonempty queue as following a higher-priority queue. */
+      m->nextnonemptyq[queuenumber] = m->nextnonemptyq[i];
+      m->nextnonemptyq[i] = queuenumber;
+    }
+    /* Put the bad triangle at the beginning of the (empty) queue. */
+    m->queuefront[queuenumber] = badtri;
+  } else {
+    /* Add the bad triangle to the end of an already nonempty queue. */
+    m->queuetail[queuenumber]->nexttriang = badtri;
+  }
+  /* Maintain a pointer to the last triangle of the queue. */
+  m->queuetail[queuenumber] = badtri;
+  /* Newly enqueued bad triangle has no successor in the queue. */
+  badtri->nexttriang = (struct badtriang *) NULL;
+}
+
+#endif /* not CDT_ONLY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  enqueuebadtri()   Add a bad triangle to the end of a queue.              */
+/*                                                                           */
+/*  Allocates a badtriang data structure for the triangle, then passes it to */
+/*  enqueuebadtriang().                                                      */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef CDT_ONLY
+
+#ifdef ANSI_DECLARATORS
+void enqueuebadtri(struct mesh *m, struct behavior *b, struct otri *enqtri,
+                   REAL minedge, vertex enqapex, vertex enqorg, vertex enqdest)
+#else /* not ANSI_DECLARATORS */
+void enqueuebadtri(m, b, enqtri, minedge, enqapex, enqorg, enqdest)
+struct mesh *m;
+struct behavior *b;
+struct otri *enqtri;
+REAL minedge;
+vertex enqapex;
+vertex enqorg;
+vertex enqdest;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct badtriang *newbad;
+
+  /* Allocate space for the bad triangle. */
+  newbad = (struct badtriang *) poolalloc(&m->badtriangles);
+  newbad->poortri = encode(*enqtri);
+  newbad->key = minedge;
+  newbad->triangapex = enqapex;
+  newbad->triangorg = enqorg;
+  newbad->triangdest = enqdest;
+  enqueuebadtriang(m, b, newbad);
+}
+
+#endif /* not CDT_ONLY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  dequeuebadtriang()   Remove a triangle from the front of the queue.      */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef CDT_ONLY
+
+#ifdef ANSI_DECLARATORS
+struct badtriang *dequeuebadtriang(struct mesh *m)
+#else /* not ANSI_DECLARATORS */
+struct badtriang *dequeuebadtriang(m)
+struct mesh *m;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct badtriang *result;
+
+  /* If no queues are nonempty, return NULL. */
+  if (m->firstnonemptyq < 0) {
+    return (struct badtriang *) NULL;
+  }
+  /* Find the first triangle of the highest-priority queue. */
+  result = m->queuefront[m->firstnonemptyq];
+  /* Remove the triangle from the queue. */
+  m->queuefront[m->firstnonemptyq] = result->nexttriang;
+  /* If this queue is now empty, note the new highest-priority */
+  /*   nonempty queue.                                         */
+  if (result == m->queuetail[m->firstnonemptyq]) {
+    m->firstnonemptyq = m->nextnonemptyq[m->firstnonemptyq];
+  }
+  return result;
+}
+
+#endif /* not CDT_ONLY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  checkseg4encroach()   Check a subsegment to see if it is encroached; add */
+/*                        it to the list if it is.                           */
+/*                                                                           */
+/*  A subsegment is encroached if there is a vertex in its diametral lens.   */
+/*  For Ruppert's algorithm (-D switch), the "diametral lens" is the         */
+/*  diametral circle.  For Chew's algorithm (default), the diametral lens is */
+/*  just big enough to enclose two isosceles triangles whose bases are the   */
+/*  subsegment.  Each of the two isosceles triangles has two angles equal    */
+/*  to `b->minangle'.                                                        */
+/*                                                                           */
+/*  Chew's algorithm does not require diametral lenses at all--but they save */
+/*  time.  Any vertex inside a subsegment's diametral lens implies that the  */
+/*  triangle adjoining the subsegment will be too skinny, so it's only a     */
+/*  matter of time before the encroaching vertex is deleted by Chew's        */
+/*  algorithm.  It's faster to simply not insert the doomed vertex in the    */
+/*  first place, which is why I use diametral lenses with Chew's algorithm.  */
+/*                                                                           */
+/*  Returns a nonzero value if the subsegment is encroached.                 */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef CDT_ONLY
+
+#ifdef ANSI_DECLARATORS
+int checkseg4encroach(struct mesh *m, struct behavior *b,
+                      struct osub *testsubseg)
+#else /* not ANSI_DECLARATORS */
+int checkseg4encroach(m, b, testsubseg)
+struct mesh *m;
+struct behavior *b;
+struct osub *testsubseg;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri neighbortri;
+  struct osub testsym;
+  struct badsubseg *encroachedseg;
+  REAL dotproduct;
+  int encroached;
+  int sides;
+  vertex eorg, edest, eapex;
+  triangle ptr;                     /* Temporary variable used by stpivot(). */
+
+  encroached = 0;
+  sides = 0;
+
+  sorg(*testsubseg, eorg);
+  sdest(*testsubseg, edest);
+  /* Check one neighbor of the subsegment. */
+  stpivot(*testsubseg, neighbortri);
+  /* Does the neighbor exist, or is this a boundary edge? */
+  if (neighbortri.tri != m->dummytri) {
+    sides++;
+    /* Find a vertex opposite this subsegment. */
+    apex(neighbortri, eapex);
+    /* Check whether the apex is in the diametral lens of the subsegment */
+    /*   (the diametral circle if `conformdel' is set).  A dot product   */
+    /*   of two sides of the triangle is used to check whether the angle */
+    /*   at the apex is greater than (180 - 2 `minangle') degrees (for   */
+    /*   lenses; 90 degrees for diametral circles).                      */
+    dotproduct = (eorg[0] - eapex[0]) * (edest[0] - eapex[0]) +
+                 (eorg[1] - eapex[1]) * (edest[1] - eapex[1]);
+    if (dotproduct < 0.0) {
+      if (b->conformdel ||
+          (dotproduct * dotproduct >=
+           (2.0 * b->goodangle - 1.0) * (2.0 * b->goodangle - 1.0) *
+           ((eorg[0] - eapex[0]) * (eorg[0] - eapex[0]) +
+            (eorg[1] - eapex[1]) * (eorg[1] - eapex[1])) *
+           ((edest[0] - eapex[0]) * (edest[0] - eapex[0]) +
+            (edest[1] - eapex[1]) * (edest[1] - eapex[1])))) {
+        encroached = 1;
+      }
+    }
+  }
+  /* Check the other neighbor of the subsegment. */
+  ssym(*testsubseg, testsym);
+  stpivot(testsym, neighbortri);
+  /* Does the neighbor exist, or is this a boundary edge? */
+  if (neighbortri.tri != m->dummytri) {
+    sides++;
+    /* Find the other vertex opposite this subsegment. */
+    apex(neighbortri, eapex);
+    /* Check whether the apex is in the diametral lens of the subsegment */
+    /*   (or the diametral circle, if `conformdel' is set).              */
+    dotproduct = (eorg[0] - eapex[0]) * (edest[0] - eapex[0]) +
+                 (eorg[1] - eapex[1]) * (edest[1] - eapex[1]);
+    if (dotproduct < 0.0) {
+      if (b->conformdel ||
+          (dotproduct * dotproduct >=
+           (2.0 * b->goodangle - 1.0) * (2.0 * b->goodangle - 1.0) *
+           ((eorg[0] - eapex[0]) * (eorg[0] - eapex[0]) +
+            (eorg[1] - eapex[1]) * (eorg[1] - eapex[1])) *
+           ((edest[0] - eapex[0]) * (edest[0] - eapex[0]) +
+            (edest[1] - eapex[1]) * (edest[1] - eapex[1])))) {
+        encroached += 2;
+      }
+    }
+  }
+
+  if (encroached && (!b->nobisect || ((b->nobisect == 1) && (sides == 2)))) {
+    if (b->verbose > 2) {
+      printf(
+        "  Queueing encroached subsegment (%.12g, %.12g) (%.12g, %.12g).\n",
+        eorg[0], eorg[1], edest[0], edest[1]);
+    }
+    /* Add the subsegment to the list of encroached subsegments. */
+    /*   Be sure to get the orientation right.                   */
+    encroachedseg = (struct badsubseg *) poolalloc(&m->badsubsegs);
+    if (encroached == 1) {
+      encroachedseg->encsubseg = sencode(*testsubseg);
+      encroachedseg->subsegorg = eorg;
+      encroachedseg->subsegdest = edest;
+    } else {
+      encroachedseg->encsubseg = sencode(testsym);
+      encroachedseg->subsegorg = edest;
+      encroachedseg->subsegdest = eorg;
+    }
+  }
+
+  return encroached;
+}
+
+#endif /* not CDT_ONLY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  testtriangle()   Test a triangle for quality and size.                   */
+/*                                                                           */
+/*  Tests a triangle to see if it satisfies the minimum angle condition and  */
+/*  the maximum area condition.  Triangles that aren't up to spec are added  */
+/*  to the bad triangle queue.                                               */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef CDT_ONLY
+
+#ifdef ANSI_DECLARATORS
+void testtriangle(struct mesh *m, struct behavior *b, struct otri *testtri)
+#else /* not ANSI_DECLARATORS */
+void testtriangle(m, b, testtri)
+struct mesh *m;
+struct behavior *b;
+struct otri *testtri;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri tri1, tri2;
+  struct osub testsub;
+  vertex torg, tdest, tapex;
+  vertex base1, base2;
+  vertex org1, dest1, org2, dest2;
+  vertex joinvertex;
+  REAL dxod, dyod, dxda, dyda, dxao, dyao;
+  REAL dxod2, dyod2, dxda2, dyda2, dxao2, dyao2;
+  REAL apexlen, orglen, destlen, minedge;
+  REAL angle;
+  REAL area;
+  REAL dist1, dist2;
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+  triangle ptr;           /* Temporary variable used by oprev() and dnext(). */
+
+  org(*testtri, torg);
+  dest(*testtri, tdest);
+  apex(*testtri, tapex);
+  dxod = torg[0] - tdest[0];
+  dyod = torg[1] - tdest[1];
+  dxda = tdest[0] - tapex[0];
+  dyda = tdest[1] - tapex[1];
+  dxao = tapex[0] - torg[0];
+  dyao = tapex[1] - torg[1];
+  dxod2 = dxod * dxod;
+  dyod2 = dyod * dyod;
+  dxda2 = dxda * dxda;
+  dyda2 = dyda * dyda;
+  dxao2 = dxao * dxao;
+  dyao2 = dyao * dyao;
+  /* Find the lengths of the triangle's three edges. */
+  apexlen = dxod2 + dyod2;
+  orglen = dxda2 + dyda2;
+  destlen = dxao2 + dyao2;
+
+  if ((apexlen < orglen) && (apexlen < destlen)) {
+    /* The edge opposite the apex is shortest. */
+    minedge = apexlen;
+    /* Find the square of the cosine of the angle at the apex. */
+    angle = dxda * dxao + dyda * dyao;
+    angle = angle * angle / (orglen * destlen);
+    base1 = torg;
+    base2 = tdest;
+    otricopy(*testtri, tri1);
+  } else if (orglen < destlen) {
+    /* The edge opposite the origin is shortest. */
+    minedge = orglen;
+    /* Find the square of the cosine of the angle at the origin. */
+    angle = dxod * dxao + dyod * dyao;
+    angle = angle * angle / (apexlen * destlen);
+    base1 = tdest;
+    base2 = tapex;
+    lnext(*testtri, tri1);
+  } else {
+    /* The edge opposite the destination is shortest. */
+    minedge = destlen;
+    /* Find the square of the cosine of the angle at the destination. */
+    angle = dxod * dxda + dyod * dyda;
+    angle = angle * angle / (apexlen * orglen);
+    base1 = tapex;
+    base2 = torg;
+    lprev(*testtri, tri1);
+  }
+
+  if (b->vararea || b->fixedarea || b->usertest) {
+    /* Check whether the area is larger than permitted. */
+    area = 0.5 * (dxod * dyda - dyod * dxda);
+    if (b->fixedarea && (area > b->maxarea)) {
+      /* Add this triangle to the list of bad triangles. */
+      enqueuebadtri(m, b, testtri, minedge, tapex, torg, tdest);
+      return;
+    }
+
+    /* Nonpositive area constraints are treated as unconstrained. */
+    if ((b->vararea) && (area > areabound(*testtri)) &&
+        (areabound(*testtri) > 0.0)) {
+      /* Add this triangle to the list of bad triangles. */
+      enqueuebadtri(m, b, testtri, minedge, tapex, torg, tdest);
+      return;
+    }
+
+    if (b->usertest) {
+      /* Check whether the user thinks this triangle is too large. */
+      if (triunsuitable(torg, tdest, tapex, area)) {
+        enqueuebadtri(m, b, testtri, minedge, tapex, torg, tdest);
+        return;
+      }
+    }
+  }
+
+  /* Check whether the angle is smaller than permitted. */
+  if (angle > b->goodangle) {
+    /* Use the rules of Miller, Pav, and Walkington to decide that certain */
+    /*   triangles should not be split, even if they have bad angles.      */
+    /*   A skinny triangle is not split if its shortest edge subtends a    */
+    /*   small input angle, and both endpoints of the edge lie on a        */
+    /*   concentric circular shell.  For convenience, I make a small       */
+    /*   adjustment to that rule:  I check if the endpoints of the edge    */
+    /*   both lie in segment interiors, equidistant from the apex where    */
+    /*   the two segments meet.                                            */
+    /* First, check if both points lie in segment interiors.               */
+    if ((vertextype(base1) == SEGMENTVERTEX) &&
+        (vertextype(base2) == SEGMENTVERTEX)) {
+      /* Check if both points lie in a common segment.  If they do, the */
+      /*   skinny triangle is enqueued to be split as usual.            */
+      tspivot(tri1, testsub);
+      if (testsub.ss == m->dummysub) {
+        /* No common segment.  Find a subsegment that contains `torg'. */
+        otricopy(tri1, tri2);
+        do {
+          oprevself(tri1);
+          tspivot(tri1, testsub);
+        } while (testsub.ss == m->dummysub);
+        /* Find the endpoints of the containing segment. */
+        segorg(testsub, org1);
+        segdest(testsub, dest1);
+        /* Find a subsegment that contains `tdest'. */
+        do {
+          dnextself(tri2);
+          tspivot(tri2, testsub);
+        } while (testsub.ss == m->dummysub);
+        /* Find the endpoints of the containing segment. */
+        segorg(testsub, org2);
+        segdest(testsub, dest2);
+        /* Check if the two containing segments have an endpoint in common. */
+        joinvertex = (vertex) NULL;
+        if ((dest1[0] == org2[0]) && (dest1[1] == org2[1])) {
+          joinvertex = dest1;
+        } else if ((org1[0] == dest2[0]) && (org1[1] == dest2[1])) {
+          joinvertex = org1;
+        }
+        if (joinvertex != (vertex) NULL) {
+          /* Compute the distance from the common endpoint (of the two  */
+          /*   segments) to each of the endpoints of the shortest edge. */
+          dist1 = ((base1[0] - joinvertex[0]) * (base1[0] - joinvertex[0]) +
+                   (base1[1] - joinvertex[1]) * (base1[1] - joinvertex[1]));
+          dist2 = ((base2[0] - joinvertex[0]) * (base2[0] - joinvertex[0]) +
+                   (base2[1] - joinvertex[1]) * (base2[1] - joinvertex[1]));
+          /* If the two distances are equal, don't split the triangle. */
+          if ((dist1 < 1.001 * dist2) && (dist1 > 0.999 * dist2)) {
+            /* Return now to avoid enqueueing the bad triangle. */
+            return;
+          }
+        }
+      }
+    }
+
+    /* Add this triangle to the list of bad triangles. */
+    enqueuebadtri(m, b, testtri, minedge, tapex, torg, tdest);
+  }
+}
+
+#endif /* not CDT_ONLY */
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Mesh quality testing routines end here                    *********/
+
+/********* Point location routines begin here                        *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  makevertexmap()   Construct a mapping from vertices to triangles to      */
+/*                    improve the speed of point location for segment        */
+/*                    insertion.                                             */
+/*                                                                           */
+/*  Traverses all the triangles, and provides each corner of each triangle   */
+/*  with a pointer to that triangle.  Of course, pointers will be            */
+/*  overwritten by other pointers because (almost) each vertex is a corner   */
+/*  of several triangles, but in the end every vertex will point to some     */
+/*  triangle that contains it.                                               */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void makevertexmap(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void makevertexmap(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri triangleloop;
+  vertex triorg;
+
+  if (b->verbose) {
+    printf("    Constructing mapping from vertices to triangles.\n");
+  }
+  traversalinit(&m->triangles);
+  triangleloop.tri = triangletraverse(m);
+  while (triangleloop.tri != (triangle *) NULL) {
+    /* Check all three vertices of the triangle. */
+    for (triangleloop.orient = 0; triangleloop.orient < 3;
+         triangleloop.orient++) {
+      org(triangleloop, triorg);
+      setvertex2tri(triorg, encode(triangleloop));
+    }
+    triangleloop.tri = triangletraverse(m);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  preciselocate()   Find a triangle or edge containing a given point.      */
+/*                                                                           */
+/*  Begins its search from `searchtri'.  It is important that `searchtri'    */
+/*  be a handle with the property that `searchpoint' is strictly to the left */
+/*  of the edge denoted by `searchtri', or is collinear with that edge and   */
+/*  does not intersect that edge.  (In particular, `searchpoint' should not  */
+/*  be the origin or destination of that edge.)                              */
+/*                                                                           */
+/*  These conditions are imposed because preciselocate() is normally used in */
+/*  one of two situations:                                                   */
+/*                                                                           */
+/*  (1)  To try to find the location to insert a new point.  Normally, we    */
+/*       know an edge that the point is strictly to the left of.  In the     */
+/*       incremental Delaunay algorithm, that edge is a bounding box edge.   */
+/*       In Ruppert's Delaunay refinement algorithm for quality meshing,     */
+/*       that edge is the shortest edge of the triangle whose circumcenter   */
+/*       is being inserted.                                                  */
+/*                                                                           */
+/*  (2)  To try to find an existing point.  In this case, any edge on the    */
+/*       convex hull is a good starting edge.  You must screen out the       */
+/*       possibility that the vertex sought is an endpoint of the starting   */
+/*       edge before you call preciselocate().                               */
+/*                                                                           */
+/*  On completion, `searchtri' is a triangle that contains `searchpoint'.    */
+/*                                                                           */
+/*  This implementation differs from that given by Guibas and Stolfi.  It    */
+/*  walks from triangle to triangle, crossing an edge only if `searchpoint'  */
+/*  is on the other side of the line containing that edge.  After entering   */
+/*  a triangle, there are two edges by which one can leave that triangle.    */
+/*  If both edges are valid (`searchpoint' is on the other side of both      */
+/*  edges), one of the two is chosen by drawing a line perpendicular to      */
+/*  the entry edge (whose endpoints are `forg' and `fdest') passing through  */
+/*  `fapex'.  Depending on which side of this perpendicular `searchpoint'    */
+/*  falls on, an exit edge is chosen.                                        */
+/*                                                                           */
+/*  This implementation is empirically faster than the Guibas and Stolfi     */
+/*  point location routine (which I originally used), which tends to spiral  */
+/*  in toward its target.                                                    */
+/*                                                                           */
+/*  Returns ONVERTEX if the point lies on an existing vertex.  `searchtri'   */
+/*  is a handle whose origin is the existing vertex.                         */
+/*                                                                           */
+/*  Returns ONEDGE if the point lies on a mesh edge.  `searchtri' is a       */
+/*  handle whose primary edge is the edge on which the point lies.           */
+/*                                                                           */
+/*  Returns INTRIANGLE if the point lies strictly within a triangle.         */
+/*  `searchtri' is a handle on the triangle that contains the point.         */
+/*                                                                           */
+/*  Returns OUTSIDE if the point lies outside the mesh.  `searchtri' is a    */
+/*  handle whose primary edge the point is to the right of.  This might      */
+/*  occur when the circumcenter of a triangle falls just slightly outside    */
+/*  the mesh due to floating-point roundoff error.  It also occurs when      */
+/*  seeking a hole or region point that a foolish user has placed outside    */
+/*  the mesh.                                                                */
+/*                                                                           */
+/*  If `stopatsubsegment' is nonzero, the search will stop if it tries to    */
+/*  walk through a subsegment, and will return OUTSIDE.                      */
+/*                                                                           */
+/*  WARNING:  This routine is designed for convex triangulations, and will   */
+/*  not generally work after the holes and concavities have been carved.     */
+/*  However, it can still be used to find the circumcenter of a triangle, as */
+/*  long as the search is begun from the triangle in question.               */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+enum locateresult preciselocate(struct mesh *m, struct behavior *b,
+                                vertex searchpoint, struct otri *searchtri,
+                                int stopatsubsegment)
+#else /* not ANSI_DECLARATORS */
+enum locateresult preciselocate(m, b, searchpoint, searchtri, stopatsubsegment)
+struct mesh *m;
+struct behavior *b;
+vertex searchpoint;
+struct otri *searchtri;
+int stopatsubsegment;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri backtracktri;
+  struct osub checkedge;
+  vertex forg, fdest, fapex;
+  REAL orgorient, destorient;
+  int moveleft;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+
+  if (b->verbose > 2) {
+    printf("  Searching for point (%.12g, %.12g).\n",
+           searchpoint[0], searchpoint[1]);
+  }
+  /* Where are we? */
+  org(*searchtri, forg);
+  dest(*searchtri, fdest);
+  apex(*searchtri, fapex);
+  while (1) {
+    if (b->verbose > 2) {
+      printf("    At (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
+             forg[0], forg[1], fdest[0], fdest[1], fapex[0], fapex[1]);
+    }
+    /* Check whether the apex is the point we seek. */
+    if ((fapex[0] == searchpoint[0]) && (fapex[1] == searchpoint[1])) {
+      lprevself(*searchtri);
+      return ONVERTEX;
+    }
+    /* Does the point lie on the other side of the line defined by the */
+    /*   triangle edge opposite the triangle's destination?            */
+    destorient = counterclockwise(m, b, forg, fapex, searchpoint);
+    /* Does the point lie on the other side of the line defined by the */
+    /*   triangle edge opposite the triangle's origin?                 */
+    orgorient = counterclockwise(m, b, fapex, fdest, searchpoint);
+    if (destorient > 0.0) {
+      if (orgorient > 0.0) {
+        /* Move left if the inner product of (fapex - searchpoint) and  */
+        /*   (fdest - forg) is positive.  This is equivalent to drawing */
+        /*   a line perpendicular to the line (forg, fdest) and passing */
+        /*   through `fapex', and determining which side of this line   */
+        /*   `searchpoint' falls on.                                    */
+        moveleft = (fapex[0] - searchpoint[0]) * (fdest[0] - forg[0]) +
+                   (fapex[1] - searchpoint[1]) * (fdest[1] - forg[1]) > 0.0;
+      } else {
+        moveleft = 1;
+      }
+    } else {
+      if (orgorient > 0.0) {
+        moveleft = 0;
+      } else {
+        /* The point we seek must be on the boundary of or inside this */
+        /*   triangle.                                                 */
+        if (destorient == 0.0) {
+          lprevself(*searchtri);
+          return ONEDGE;
+        }
+        if (orgorient == 0.0) {
+          lnextself(*searchtri);
+          return ONEDGE;
+        }
+        return INTRIANGLE;
+      }
+    }
+
+    /* Move to another triangle.  Leave a trace `backtracktri' in case */
+    /*   floating-point roundoff or some such bogey causes us to walk  */
+    /*   off a boundary of the triangulation.                          */
+    if (moveleft) {
+      lprev(*searchtri, backtracktri);
+      fdest = fapex;
+    } else {
+      lnext(*searchtri, backtracktri);
+      forg = fapex;
+    }
+    sym(backtracktri, *searchtri);
+
+    if (m->checksegments && stopatsubsegment) {
+      /* Check for walking through a subsegment. */
+      tspivot(backtracktri, checkedge);
+      if (checkedge.ss != m->dummysub) {
+        /* Go back to the last triangle. */
+        otricopy(backtracktri, *searchtri);
+        return OUTSIDE;
+      }
+    }
+    /* Check for walking right out of the triangulation. */
+    if (searchtri->tri == m->dummytri) {
+      /* Go back to the last triangle. */
+      otricopy(backtracktri, *searchtri);
+      return OUTSIDE;
+    }
+
+    apex(*searchtri, fapex);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  locate()   Find a triangle or edge containing a given point.             */
+/*                                                                           */
+/*  Searching begins from one of:  the input `searchtri', a recently         */
+/*  encountered triangle `recenttri', or from a triangle chosen from a       */
+/*  random sample.  The choice is made by determining which triangle's       */
+/*  origin is closest to the point we are searching for.  Normally,          */
+/*  `searchtri' should be a handle on the convex hull of the triangulation.  */
+/*                                                                           */
+/*  Details on the random sampling method can be found in the Mucke, Saias,  */
+/*  and Zhu paper cited in the header of this code.                          */
+/*                                                                           */
+/*  On completion, `searchtri' is a triangle that contains `searchpoint'.    */
+/*                                                                           */
+/*  Returns ONVERTEX if the point lies on an existing vertex.  `searchtri'   */
+/*  is a handle whose origin is the existing vertex.                         */
+/*                                                                           */
+/*  Returns ONEDGE if the point lies on a mesh edge.  `searchtri' is a       */
+/*  handle whose primary edge is the edge on which the point lies.           */
+/*                                                                           */
+/*  Returns INTRIANGLE if the point lies strictly within a triangle.         */
+/*  `searchtri' is a handle on the triangle that contains the point.         */
+/*                                                                           */
+/*  Returns OUTSIDE if the point lies outside the mesh.  `searchtri' is a    */
+/*  handle whose primary edge the point is to the right of.  This might      */
+/*  occur when the circumcenter of a triangle falls just slightly outside    */
+/*  the mesh due to floating-point roundoff error.  It also occurs when      */
+/*  seeking a hole or region point that a foolish user has placed outside    */
+/*  the mesh.                                                                */
+/*                                                                           */
+/*  WARNING:  This routine is designed for convex triangulations, and will   */
+/*  not generally work after the holes and concavities have been carved.     */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+enum locateresult locate(struct mesh *m, struct behavior *b,
+                         vertex searchpoint, struct otri *searchtri)
+#else /* not ANSI_DECLARATORS */
+enum locateresult locate(m, b, searchpoint, searchtri)
+struct mesh *m;
+struct behavior *b;
+vertex searchpoint;
+struct otri *searchtri;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  VOID **sampleblock;
+  char *firsttri;
+  struct otri sampletri;
+  vertex torg, tdest;
+  size_t alignptr;
+  REAL searchdist, dist;
+  REAL ahead;
+  long samplesperblock, totalsamplesleft, samplesleft;
+  long population, totalpopulation;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+  if (b->verbose > 2) {
+    printf("  Randomly sampling for a triangle near point (%.12g, %.12g).\n",
+           searchpoint[0], searchpoint[1]);
+  }
+  /* Record the distance from the suggested starting triangle to the */
+  /*   point we seek.                                                */
+  org(*searchtri, torg);
+  searchdist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) +
+               (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]);
+  if (b->verbose > 2) {
+    printf("    Boundary triangle has origin (%.12g, %.12g).\n",
+           torg[0], torg[1]);
+  }
+
+  /* If a recently encountered triangle has been recorded and has not been */
+  /*   deallocated, test it as a good starting point.                      */
+  if (m->recenttri.tri != (triangle *) NULL) {
+    if (!deadtri(m->recenttri.tri)) {
+      org(m->recenttri, torg);
+      if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) {
+        otricopy(m->recenttri, *searchtri);
+        return ONVERTEX;
+      }
+      dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) +
+             (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]);
+      if (dist < searchdist) {
+        otricopy(m->recenttri, *searchtri);
+        searchdist = dist;
+        if (b->verbose > 2) {
+          printf("    Choosing recent triangle with origin (%.12g, %.12g).\n",
+                 torg[0], torg[1]);
+        }
+      }
+    }
+  }
+
+  /* The number of random samples taken is proportional to the cube root of */
+  /*   the number of triangles in the mesh.  The next bit of code assumes   */
+  /*   that the number of triangles increases monotonically (or at least    */
+  /*   doesn't decrease enough to matter).                                  */
+  while (SAMPLEFACTOR * m->samples * m->samples * m->samples <
+         m->triangles.items) {
+    m->samples++;
+  }
+
+  /* We'll draw ceiling(samples * TRIPERBLOCK / maxitems) random samples  */
+  /*   from each block of triangles (except the first)--until we meet the */
+  /*   sample quota.  The ceiling means that blocks at the end might be   */
+  /*   neglected, but I don't care.                                       */
+  samplesperblock = (m->samples * TRIPERBLOCK - 1) / m->triangles.maxitems + 1;
+  /* We'll draw ceiling(samples * itemsfirstblock / maxitems) random samples */
+  /*   from the first block of triangles.                                    */
+  samplesleft = (m->samples * m->triangles.itemsfirstblock - 1) /
+                m->triangles.maxitems + 1;
+  totalsamplesleft = m->samples;
+  population = m->triangles.itemsfirstblock;
+  totalpopulation = m->triangles.maxitems;
+  sampleblock = m->triangles.firstblock;
+  sampletri.orient = 0;
+  while (totalsamplesleft > 0) {
+    /* If we're in the last block, `population' needs to be corrected. */
+    if (population > totalpopulation) {
+      population = totalpopulation;
+    }
+    /* Find a pointer to the first triangle in the block. */
+    alignptr = (size_t) (sampleblock + 1);
+    firsttri = (char *) (alignptr +
+                         (size_t) m->triangles.alignbytes -
+                         (alignptr %
+                          (size_t) m->triangles.alignbytes));
+
+    /* Choose `samplesleft' randomly sampled triangles in this block. */
+    do {
+      sampletri.tri = (triangle *) (firsttri +
+                                    (randomnation((unsigned int) population) *
+                                     m->triangles.itembytes));
+      if (!deadtri(sampletri.tri)) {
+        org(sampletri, torg);
+        dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) +
+               (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]);
+        if (dist < searchdist) {
+          otricopy(sampletri, *searchtri);
+          searchdist = dist;
+          if (b->verbose > 2) {
+            printf("    Choosing triangle with origin (%.12g, %.12g).\n",
+                   torg[0], torg[1]);
+          }
+        }
+      }
+
+      samplesleft--;
+      totalsamplesleft--;
+    } while ((samplesleft > 0) && (totalsamplesleft > 0));
+
+    if (totalsamplesleft > 0) {
+      sampleblock = (VOID **) *sampleblock;
+      samplesleft = samplesperblock;
+      totalpopulation -= population;
+      population = TRIPERBLOCK;
+    }
+  }
+
+  /* Where are we? */
+  org(*searchtri, torg);
+  dest(*searchtri, tdest);
+  /* Check the starting triangle's vertices. */
+  if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) {
+    return ONVERTEX;
+  }
+  if ((tdest[0] == searchpoint[0]) && (tdest[1] == searchpoint[1])) {
+    lnextself(*searchtri);
+    return ONVERTEX;
+  }
+  /* Orient `searchtri' to fit the preconditions of calling preciselocate(). */
+  ahead = counterclockwise(m, b, torg, tdest, searchpoint);
+  if (ahead < 0.0) {
+    /* Turn around so that `searchpoint' is to the left of the */
+    /*   edge specified by `searchtri'.                        */
+    symself(*searchtri);
+  } else if (ahead == 0.0) {
+    /* Check if `searchpoint' is between `torg' and `tdest'. */
+    if (((torg[0] < searchpoint[0]) == (searchpoint[0] < tdest[0])) &&
+        ((torg[1] < searchpoint[1]) == (searchpoint[1] < tdest[1]))) {
+      return ONEDGE;
+    }
+  }
+  return preciselocate(m, b, searchpoint, searchtri, 0);
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Point location routines end here                          *********/
+
+/********* Mesh transformation routines begin here                   *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  insertsubseg()   Create a new subsegment and insert it between two       */
+/*                   triangles.                                              */
+/*                                                                           */
+/*  The new subsegment is inserted at the edge described by the handle       */
+/*  `tri'.  Its vertices are properly initialized.  The marker `subsegmark'  */
+/*  is applied to the subsegment and, if appropriate, its vertices.          */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void insertsubseg(struct mesh *m, struct behavior *b, struct otri *tri,
+                  int subsegmark)
+#else /* not ANSI_DECLARATORS */
+void insertsubseg(m, b, tri, subsegmark)
+struct mesh *m;
+struct behavior *b;
+struct otri *tri;             /* Edge at which to insert the new subsegment. */
+int subsegmark;                            /* Marker for the new subsegment. */
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri oppotri;
+  struct osub newsubseg;
+  vertex triorg, tridest;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+
+  org(*tri, triorg);
+  dest(*tri, tridest);
+  /* Mark vertices if possible. */
+  if (vertexmark(triorg) == 0) {
+    setvertexmark(triorg, subsegmark);
+  }
+  if (vertexmark(tridest) == 0) {
+    setvertexmark(tridest, subsegmark);
+  }
+  /* Check if there's already a subsegment here. */
+  tspivot(*tri, newsubseg);
+  if (newsubseg.ss == m->dummysub) {
+    /* Make new subsegment and initialize its vertices. */
+    makesubseg(m, &newsubseg);
+    setsorg(newsubseg, tridest);
+    setsdest(newsubseg, triorg);
+    setsegorg(newsubseg, tridest);
+    setsegdest(newsubseg, triorg);
+    /* Bond new subsegment to the two triangles it is sandwiched between. */
+    /*   Note that the facing triangle `oppotri' might be equal to        */
+    /*   `dummytri' (outer space), but the new subsegment is bonded to it */
+    /*   all the same.                                                    */
+    tsbond(*tri, newsubseg);
+    sym(*tri, oppotri);
+    ssymself(newsubseg);
+    tsbond(oppotri, newsubseg);
+    setmark(newsubseg, subsegmark);
+    if (b->verbose > 2) {
+      printf("  Inserting new ");
+      printsubseg(m, b, &newsubseg);
+    }
+  } else {
+    if (mark(newsubseg) == 0) {
+      setmark(newsubseg, subsegmark);
+    }
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  Terminology                                                              */
+/*                                                                           */
+/*  A "local transformation" replaces a small set of triangles with another  */
+/*  set of triangles.  This may or may not involve inserting or deleting a   */
+/*  vertex.                                                                  */
+/*                                                                           */
+/*  The term "casing" is used to describe the set of triangles that are      */
+/*  attached to the triangles being transformed, but are not transformed     */
+/*  themselves.  Think of the casing as a fixed hollow structure inside      */
+/*  which all the action happens.  A "casing" is only defined relative to    */
+/*  a single transformation; each occurrence of a transformation will        */
+/*  involve a different casing.                                              */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  flip()   Transform two triangles to two different triangles by flipping  */
+/*           an edge counterclockwise within a quadrilateral.                */
+/*                                                                           */
+/*  Imagine the original triangles, abc and bad, oriented so that the        */
+/*  shared edge ab lies in a horizontal plane, with the vertex b on the left */
+/*  and the vertex a on the right.  The vertex c lies below the edge, and    */
+/*  the vertex d lies above the edge.  The `flipedge' handle holds the edge  */
+/*  ab of triangle abc, and is directed left, from vertex a to vertex b.     */
+/*                                                                           */
+/*  The triangles abc and bad are deleted and replaced by the triangles cdb  */
+/*  and dca.  The triangles that represent abc and bad are NOT deallocated;  */
+/*  they are reused for dca and cdb, respectively.  Hence, any handles that  */
+/*  may have held the original triangles are still valid, although not       */
+/*  directed as they were before.                                            */
+/*                                                                           */
+/*  Upon completion of this routine, the `flipedge' handle holds the edge    */
+/*  dc of triangle dca, and is directed down, from vertex d to vertex c.     */
+/*  (Hence, the two triangles have rotated counterclockwise.)                */
+/*                                                                           */
+/*  WARNING:  This transformation is geometrically valid only if the         */
+/*  quadrilateral adbc is convex.  Furthermore, this transformation is       */
+/*  valid only if there is not a subsegment between the triangles abc and    */
+/*  bad.  This routine does not check either of these preconditions, and     */
+/*  it is the responsibility of the calling routine to ensure that they are  */
+/*  met.  If they are not, the streets shall be filled with wailing and      */
+/*  gnashing of teeth.                                                       */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void flip(struct mesh *m, struct behavior *b, struct otri *flipedge)
+#else /* not ANSI_DECLARATORS */
+void flip(m, b, flipedge)
+struct mesh *m;
+struct behavior *b;
+struct otri *flipedge;                    /* Handle for the triangle abc. */
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri botleft, botright;
+  struct otri topleft, topright;
+  struct otri top;
+  struct otri botlcasing, botrcasing;
+  struct otri toplcasing, toprcasing;
+  struct osub botlsubseg, botrsubseg;
+  struct osub toplsubseg, toprsubseg;
+  vertex leftvertex, rightvertex, botvertex;
+  vertex farvertex;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+
+  /* Identify the vertices of the quadrilateral. */
+  org(*flipedge, rightvertex);
+  dest(*flipedge, leftvertex);
+  apex(*flipedge, botvertex);
+  sym(*flipedge, top);
+#ifdef SELF_CHECK
+  if (top.tri == m->dummytri) {
+    printf("Internal error in flip():  Attempt to flip on boundary.\n");
+    lnextself(*flipedge);
+    return;
+  }
+  if (m->checksegments) {
+    tspivot(*flipedge, toplsubseg);
+    if (toplsubseg.ss != m->dummysub) {
+      printf("Internal error in flip():  Attempt to flip a segment.\n");
+      lnextself(*flipedge);
+      return;
+    }
+  }
+#endif /* SELF_CHECK */
+  apex(top, farvertex);
+
+  /* Identify the casing of the quadrilateral. */
+  lprev(top, topleft);
+  sym(topleft, toplcasing);
+  lnext(top, topright);
+  sym(topright, toprcasing);
+  lnext(*flipedge, botleft);
+  sym(botleft, botlcasing);
+  lprev(*flipedge, botright);
+  sym(botright, botrcasing);
+  /* Rotate the quadrilateral one-quarter turn counterclockwise. */
+  bond(topleft, botlcasing);
+  bond(botleft, botrcasing);
+  bond(botright, toprcasing);
+  bond(topright, toplcasing);
+
+  if (m->checksegments) {
+    /* Check for subsegments and rebond them to the quadrilateral. */
+    tspivot(topleft, toplsubseg);
+    tspivot(botleft, botlsubseg);
+    tspivot(botright, botrsubseg);
+    tspivot(topright, toprsubseg);
+    if (toplsubseg.ss == m->dummysub) {
+      tsdissolve(topright);
+    } else {
+      tsbond(topright, toplsubseg);
+    }
+    if (botlsubseg.ss == m->dummysub) {
+      tsdissolve(topleft);
+    } else {
+      tsbond(topleft, botlsubseg);
+    }
+    if (botrsubseg.ss == m->dummysub) {
+      tsdissolve(botleft);
+    } else {
+      tsbond(botleft, botrsubseg);
+    }
+    if (toprsubseg.ss == m->dummysub) {
+      tsdissolve(botright);
+    } else {
+      tsbond(botright, toprsubseg);
+    }
+  }
+
+  /* New vertex assignments for the rotated quadrilateral. */
+  setorg(*flipedge, farvertex);
+  setdest(*flipedge, botvertex);
+  setapex(*flipedge, rightvertex);
+  setorg(top, botvertex);
+  setdest(top, farvertex);
+  setapex(top, leftvertex);
+  if (b->verbose > 2) {
+    printf("  Edge flip results in left ");
+    printtriangle(m, b, &top);
+    printf("  and right ");
+    printtriangle(m, b, flipedge);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  unflip()   Transform two triangles to two different triangles by         */
+/*             flipping an edge clockwise within a quadrilateral.  Reverses  */
+/*             the flip() operation so that the data structures representing */
+/*             the triangles are back where they were before the flip().     */
+/*                                                                           */
+/*  Imagine the original triangles, abc and bad, oriented so that the        */
+/*  shared edge ab lies in a horizontal plane, with the vertex b on the left */
+/*  and the vertex a on the right.  The vertex c lies below the edge, and    */
+/*  the vertex d lies above the edge.  The `flipedge' handle holds the edge  */
+/*  ab of triangle abc, and is directed left, from vertex a to vertex b.     */
+/*                                                                           */
+/*  The triangles abc and bad are deleted and replaced by the triangles cdb  */
+/*  and dca.  The triangles that represent abc and bad are NOT deallocated;  */
+/*  they are reused for cdb and dca, respectively.  Hence, any handles that  */
+/*  may have held the original triangles are still valid, although not       */
+/*  directed as they were before.                                            */
+/*                                                                           */
+/*  Upon completion of this routine, the `flipedge' handle holds the edge    */
+/*  cd of triangle cdb, and is directed up, from vertex c to vertex d.       */
+/*  (Hence, the two triangles have rotated clockwise.)                       */
+/*                                                                           */
+/*  WARNING:  This transformation is geometrically valid only if the         */
+/*  quadrilateral adbc is convex.  Furthermore, this transformation is       */
+/*  valid only if there is not a subsegment between the triangles abc and    */
+/*  bad.  This routine does not check either of these preconditions, and     */
+/*  it is the responsibility of the calling routine to ensure that they are  */
+/*  met.  If they are not, the streets shall be filled with wailing and      */
+/*  gnashing of teeth.                                                       */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void unflip(struct mesh *m, struct behavior *b, struct otri *flipedge)
+#else /* not ANSI_DECLARATORS */
+void unflip(m, b, flipedge)
+struct mesh *m;
+struct behavior *b;
+struct otri *flipedge;                    /* Handle for the triangle abc. */
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri botleft, botright;
+  struct otri topleft, topright;
+  struct otri top;
+  struct otri botlcasing, botrcasing;
+  struct otri toplcasing, toprcasing;
+  struct osub botlsubseg, botrsubseg;
+  struct osub toplsubseg, toprsubseg;
+  vertex leftvertex, rightvertex, botvertex;
+  vertex farvertex;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+
+  /* Identify the vertices of the quadrilateral. */
+  org(*flipedge, rightvertex);
+  dest(*flipedge, leftvertex);
+  apex(*flipedge, botvertex);
+  sym(*flipedge, top);
+#ifdef SELF_CHECK
+  if (top.tri == m->dummytri) {
+    printf("Internal error in unflip():  Attempt to flip on boundary.\n");
+    lnextself(*flipedge);
+    return;
+  }
+  if (m->checksegments) {
+    tspivot(*flipedge, toplsubseg);
+    if (toplsubseg.ss != m->dummysub) {
+      printf("Internal error in unflip():  Attempt to flip a subsegment.\n");
+      lnextself(*flipedge);
+      return;
+    }
+  }
+#endif /* SELF_CHECK */
+  apex(top, farvertex);
+
+  /* Identify the casing of the quadrilateral. */
+  lprev(top, topleft);
+  sym(topleft, toplcasing);
+  lnext(top, topright);
+  sym(topright, toprcasing);
+  lnext(*flipedge, botleft);
+  sym(botleft, botlcasing);
+  lprev(*flipedge, botright);
+  sym(botright, botrcasing);
+  /* Rotate the quadrilateral one-quarter turn clockwise. */
+  bond(topleft, toprcasing);
+  bond(botleft, toplcasing);
+  bond(botright, botlcasing);
+  bond(topright, botrcasing);
+
+  if (m->checksegments) {
+    /* Check for subsegments and rebond them to the quadrilateral. */
+    tspivot(topleft, toplsubseg);
+    tspivot(botleft, botlsubseg);
+    tspivot(botright, botrsubseg);
+    tspivot(topright, toprsubseg);
+    if (toplsubseg.ss == m->dummysub) {
+      tsdissolve(botleft);
+    } else {
+      tsbond(botleft, toplsubseg);
+    }
+    if (botlsubseg.ss == m->dummysub) {
+      tsdissolve(botright);
+    } else {
+      tsbond(botright, botlsubseg);
+    }
+    if (botrsubseg.ss == m->dummysub) {
+      tsdissolve(topright);
+    } else {
+      tsbond(topright, botrsubseg);
+    }
+    if (toprsubseg.ss == m->dummysub) {
+      tsdissolve(topleft);
+    } else {
+      tsbond(topleft, toprsubseg);
+    }
+  }
+
+  /* New vertex assignments for the rotated quadrilateral. */
+  setorg(*flipedge, botvertex);
+  setdest(*flipedge, farvertex);
+  setapex(*flipedge, leftvertex);
+  setorg(top, farvertex);
+  setdest(top, botvertex);
+  setapex(top, rightvertex);
+  if (b->verbose > 2) {
+    printf("  Edge unflip results in left ");
+    printtriangle(m, b, flipedge);
+    printf("  and right ");
+    printtriangle(m, b, &top);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  insertvertex()   Insert a vertex into a Delaunay triangulation,          */
+/*                   performing flips as necessary to maintain the Delaunay  */
+/*                   property.                                               */
+/*                                                                           */
+/*  The point `insertvertex' is located.  If `searchtri.tri' is not NULL,    */
+/*  the search for the containing triangle begins from `searchtri'.  If      */
+/*  `searchtri.tri' is NULL, a full point location procedure is called.      */
+/*  If `insertvertex' is found inside a triangle, the triangle is split into */
+/*  three; if `insertvertex' lies on an edge, the edge is split in two,      */
+/*  thereby splitting the two adjacent triangles into four.  Edge flips are  */
+/*  used to restore the Delaunay property.  If `insertvertex' lies on an     */
+/*  existing vertex, no action is taken, and the value DUPLICATEVERTEX is    */
+/*  returned.  On return, `searchtri' is set to a handle whose origin is the */
+/*  existing vertex.                                                         */
+/*                                                                           */
+/*  Normally, the parameter `splitseg' is set to NULL, implying that no      */
+/*  subsegment should be split.  In this case, if `insertvertex' is found to */
+/*  lie on a segment, no action is taken, and the value VIOLATINGVERTEX is   */
+/*  returned.  On return, `searchtri' is set to a handle whose primary edge  */
+/*  is the violated subsegment.                                              */
+/*                                                                           */
+/*  If the calling routine wishes to split a subsegment by inserting a       */
+/*  vertex in it, the parameter `splitseg' should be that subsegment.  In    */
+/*  this case, `searchtri' MUST be the triangle handle reached by pivoting   */
+/*  from that subsegment; no point location is done.                         */
+/*                                                                           */
+/*  `segmentflaws' and `triflaws' are flags that indicate whether or not     */
+/*  there should be checks for the creation of encroached subsegments or bad */
+/*  quality triangles.  If a newly inserted vertex encroaches upon           */
+/*  subsegments, these subsegments are added to the list of subsegments to   */
+/*  be split if `segmentflaws' is set.  If bad triangles are created, these  */
+/*  are added to the queue if `triflaws' is set.                             */
+/*                                                                           */
+/*  If a duplicate vertex or violated segment does not prevent the vertex    */
+/*  from being inserted, the return value will be ENCROACHINGVERTEX if the   */
+/*  vertex encroaches upon a subsegment (and checking is enabled), or        */
+/*  SUCCESSFULVERTEX otherwise.  In either case, `searchtri' is set to a     */
+/*  handle whose origin is the newly inserted vertex.                        */
+/*                                                                           */
+/*  insertvertex() does not use flip() for reasons of speed; some            */
+/*  information can be reused from edge flip to edge flip, like the          */
+/*  locations of subsegments.                                                */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+enum insertvertexresult insertvertex(struct mesh *m, struct behavior *b,
+                                     vertex newvertex, struct otri *searchtri,
+                                     struct osub *splitseg,
+                                     int segmentflaws, int triflaws)
+#else /* not ANSI_DECLARATORS */
+enum insertvertexresult insertvertex(m, b, newvertex, searchtri, splitseg,
+                                     segmentflaws, triflaws)
+struct mesh *m;
+struct behavior *b;
+vertex newvertex;
+struct otri *searchtri;
+struct osub *splitseg;
+int segmentflaws;
+int triflaws;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri horiz;
+  struct otri top;
+  struct otri botleft, botright;
+  struct otri topleft, topright;
+  struct otri newbotleft, newbotright;
+  struct otri newtopright;
+  struct otri botlcasing, botrcasing;
+  struct otri toplcasing, toprcasing;
+  struct otri testtri;
+  struct osub botlsubseg, botrsubseg;
+  struct osub toplsubseg, toprsubseg;
+  struct osub brokensubseg;
+  struct osub checksubseg;
+  struct osub rightsubseg;
+  struct osub newsubseg;
+  struct badsubseg *encroached;
+  struct flipstacker *newflip;
+  vertex first;
+  vertex leftvertex, rightvertex, botvertex, topvertex, farvertex;
+  vertex segmentorg, segmentdest;
+  REAL attrib;
+  REAL area;
+  enum insertvertexresult success;
+  enum locateresult intersect;
+  int doflip;
+  int mirrorflag;
+  int enq;
+  int i;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  subseg sptr;         /* Temporary variable used by spivot() and tspivot(). */
+
+  if (b->verbose > 1) {
+    printf("  Inserting (%.12g, %.12g).\n", newvertex[0], newvertex[1]);
+  }
+
+  if (splitseg == (struct osub *) NULL) {
+    /* Find the location of the vertex to be inserted.  Check if a good */
+    /*   starting triangle has already been provided by the caller.     */
+    if (searchtri->tri == m->dummytri) {
+      /* Find a boundary triangle. */
+      horiz.tri = m->dummytri;
+      horiz.orient = 0;
+      symself(horiz);
+      /* Search for a triangle containing `newvertex'. */
+      intersect = locate(m, b, newvertex, &horiz);
+    } else {
+      /* Start searching from the triangle provided by the caller. */
+      otricopy(*searchtri, horiz);
+      intersect = preciselocate(m, b, newvertex, &horiz, 1);
+    }
+  } else {
+    /* The calling routine provides the subsegment in which */
+    /*   the vertex is inserted.                             */
+    otricopy(*searchtri, horiz);
+    intersect = ONEDGE;
+  }
+
+  if (intersect == ONVERTEX) {
+    /* There's already a vertex there.  Return in `searchtri' a triangle */
+    /*   whose origin is the existing vertex.                            */
+    otricopy(horiz, *searchtri);
+    otricopy(horiz, m->recenttri);
+    return DUPLICATEVERTEX;
+  }
+  if ((intersect == ONEDGE) || (intersect == OUTSIDE)) {
+    /* The vertex falls on an edge or boundary. */
+    if (m->checksegments && (splitseg == (struct osub *) NULL)) {
+      /* Check whether the vertex falls on a subsegment. */
+      tspivot(horiz, brokensubseg);
+      if (brokensubseg.ss != m->dummysub) {
+        /* The vertex falls on a subsegment, and hence will not be inserted. */
+        if (segmentflaws) {
+          enq = b->nobisect != 2;
+          if (enq && (b->nobisect == 1)) {
+            /* This subsegment may be split only if it is an */
+            /*   internal boundary.                          */
+            sym(horiz, testtri);
+            enq = testtri.tri != m->dummytri;
+          }
+          if (enq) {
+            /* Add the subsegment to the list of encroached subsegments. */
+            encroached = (struct badsubseg *) poolalloc(&m->badsubsegs);
+            encroached->encsubseg = sencode(brokensubseg);
+            sorg(brokensubseg, encroached->subsegorg);
+            sdest(brokensubseg, encroached->subsegdest);
+            if (b->verbose > 2) {
+              printf(
+          "  Queueing encroached subsegment (%.12g, %.12g) (%.12g, %.12g).\n",
+                     encroached->subsegorg[0], encroached->subsegorg[1],
+                     encroached->subsegdest[0], encroached->subsegdest[1]);
+            }
+          }
+        }
+        /* Return a handle whose primary edge contains the vertex, */
+        /*   which has not been inserted.                          */
+        otricopy(horiz, *searchtri);
+        otricopy(horiz, m->recenttri);
+        return VIOLATINGVERTEX;
+      }
+    }
+
+    /* Insert the vertex on an edge, dividing one triangle into two (if */
+    /*   the edge lies on a boundary) or two triangles into four.       */
+    lprev(horiz, botright);
+    sym(botright, botrcasing);
+    sym(horiz, topright);
+    /* Is there a second triangle?  (Or does this edge lie on a boundary?) */
+    mirrorflag = topright.tri != m->dummytri;
+    if (mirrorflag) {
+      lnextself(topright);
+      sym(topright, toprcasing);
+      maketriangle(m, b, &newtopright);
+    } else {
+      /* Splitting a boundary edge increases the number of boundary edges. */
+      m->hullsize++;
+    }
+    maketriangle(m, b, &newbotright);
+
+    /* Set the vertices of changed and new triangles. */
+    org(horiz, rightvertex);
+    dest(horiz, leftvertex);
+    apex(horiz, botvertex);
+    setorg(newbotright, botvertex);
+    setdest(newbotright, rightvertex);
+    setapex(newbotright, newvertex);
+    setorg(horiz, newvertex);
+    for (i = 0; i < m->eextras; i++) {
+      /* Set the element attributes of a new triangle. */
+      setelemattribute(newbotright, i, elemattribute(botright, i));
+    }
+    if (b->vararea) {
+      /* Set the area constraint of a new triangle. */
+      setareabound(newbotright, areabound(botright));
+    }
+    if (mirrorflag) {
+      dest(topright, topvertex);
+      setorg(newtopright, rightvertex);
+      setdest(newtopright, topvertex);
+      setapex(newtopright, newvertex);
+      setorg(topright, newvertex);
+      for (i = 0; i < m->eextras; i++) {
+        /* Set the element attributes of another new triangle. */
+        setelemattribute(newtopright, i, elemattribute(topright, i));
+      }
+      if (b->vararea) {
+        /* Set the area constraint of another new triangle. */
+        setareabound(newtopright, areabound(topright));
+      }
+    }
+
+    /* There may be subsegments that need to be bonded */
+    /*   to the new triangle(s).                       */
+    if (m->checksegments) {
+      tspivot(botright, botrsubseg);
+      if (botrsubseg.ss != m->dummysub) {
+        tsdissolve(botright);
+        tsbond(newbotright, botrsubseg);
+      }
+      if (mirrorflag) {
+        tspivot(topright, toprsubseg);
+        if (toprsubseg.ss != m->dummysub) {
+          tsdissolve(topright);
+          tsbond(newtopright, toprsubseg);
+        }
+      }
+    }
+
+    /* Bond the new triangle(s) to the surrounding triangles. */
+    bond(newbotright, botrcasing);
+    lprevself(newbotright);
+    bond(newbotright, botright);
+    lprevself(newbotright);
+    if (mirrorflag) {
+      bond(newtopright, toprcasing);
+      lnextself(newtopright);
+      bond(newtopright, topright);
+      lnextself(newtopright);
+      bond(newtopright, newbotright);
+    }
+
+    if (splitseg != (struct osub *) NULL) {
+      /* Split the subsegment into two. */
+      setsdest(*splitseg, newvertex);
+      segorg(*splitseg, segmentorg);
+      segdest(*splitseg, segmentdest);
+      ssymself(*splitseg);
+      spivot(*splitseg, rightsubseg);
+      insertsubseg(m, b, &newbotright, mark(*splitseg));
+      tspivot(newbotright, newsubseg);
+      setsegorg(newsubseg, segmentorg);
+      setsegdest(newsubseg, segmentdest);
+      sbond(*splitseg, newsubseg);
+      ssymself(newsubseg);
+      sbond(newsubseg, rightsubseg);
+      ssymself(*splitseg);
+      /* Transfer the subsegment's boundary marker to the vertex */
+      /*   if required.                                          */
+      if (vertexmark(newvertex) == 0) {
+        setvertexmark(newvertex, mark(*splitseg));
+      }
+    }
+
+    if (m->checkquality) {
+      poolrestart(&m->flipstackers);
+      m->lastflip = (struct flipstacker *) poolalloc(&m->flipstackers);
+      m->lastflip->flippedtri = encode(horiz);
+      m->lastflip->prevflip = (struct flipstacker *) &insertvertex;
+    }
+
+#ifdef SELF_CHECK
+    if (counterclockwise(m, b, rightvertex, leftvertex, botvertex) < 0.0) {
+      printf("Internal error in insertvertex():\n");
+      printf(
+            "  Clockwise triangle prior to edge vertex insertion (bottom).\n");
+    }
+    if (mirrorflag) {
+      if (counterclockwise(m, b, leftvertex, rightvertex, topvertex) < 0.0) {
+        printf("Internal error in insertvertex():\n");
+        printf("  Clockwise triangle prior to edge vertex insertion (top).\n");
+      }
+      if (counterclockwise(m, b, rightvertex, topvertex, newvertex) < 0.0) {
+        printf("Internal error in insertvertex():\n");
+        printf(
+            "  Clockwise triangle after edge vertex insertion (top right).\n");
+      }
+      if (counterclockwise(m, b, topvertex, leftvertex, newvertex) < 0.0) {
+        printf("Internal error in insertvertex():\n");
+        printf(
+            "  Clockwise triangle after edge vertex insertion (top left).\n");
+      }
+    }
+    if (counterclockwise(m, b, leftvertex, botvertex, newvertex) < 0.0) {
+      printf("Internal error in insertvertex():\n");
+      printf(
+          "  Clockwise triangle after edge vertex insertion (bottom left).\n");
+    }
+    if (counterclockwise(m, b, botvertex, rightvertex, newvertex) < 0.0) {
+      printf("Internal error in insertvertex():\n");
+      printf(
+        "  Clockwise triangle after edge vertex insertion (bottom right).\n");
+    }
+#endif /* SELF_CHECK */
+    if (b->verbose > 2) {
+      printf("  Updating bottom left ");
+      printtriangle(m, b, &botright);
+      if (mirrorflag) {
+        printf("  Updating top left ");
+        printtriangle(m, b, &topright);
+        printf("  Creating top right ");
+        printtriangle(m, b, &newtopright);
+      }
+      printf("  Creating bottom right ");
+      printtriangle(m, b, &newbotright);
+    }
+
+    /* Position `horiz' on the first edge to check for */
+    /*   the Delaunay property.                        */
+    lnextself(horiz);
+  } else {
+    /* Insert the vertex in a triangle, splitting it into three. */
+    lnext(horiz, botleft);
+    lprev(horiz, botright);
+    sym(botleft, botlcasing);
+    sym(botright, botrcasing);
+    maketriangle(m, b, &newbotleft);
+    maketriangle(m, b, &newbotright);
+
+    /* Set the vertices of changed and new triangles. */
+    org(horiz, rightvertex);
+    dest(horiz, leftvertex);
+    apex(horiz, botvertex);
+    setorg(newbotleft, leftvertex);
+    setdest(newbotleft, botvertex);
+    setapex(newbotleft, newvertex);
+    setorg(newbotright, botvertex);
+    setdest(newbotright, rightvertex);
+    setapex(newbotright, newvertex);
+    setapex(horiz, newvertex);
+    for (i = 0; i < m->eextras; i++) {
+      /* Set the element attributes of the new triangles. */
+      attrib = elemattribute(horiz, i);
+      setelemattribute(newbotleft, i, attrib);
+      setelemattribute(newbotright, i, attrib);
+    }
+    if (b->vararea) {
+      /* Set the area constraint of the new triangles. */
+      area = areabound(horiz);
+      setareabound(newbotleft, area);
+      setareabound(newbotright, area);
+    }
+
+    /* There may be subsegments that need to be bonded */
+    /*   to the new triangles.                         */
+    if (m->checksegments) {
+      tspivot(botleft, botlsubseg);
+      if (botlsubseg.ss != m->dummysub) {
+        tsdissolve(botleft);
+        tsbond(newbotleft, botlsubseg);
+      }
+      tspivot(botright, botrsubseg);
+      if (botrsubseg.ss != m->dummysub) {
+        tsdissolve(botright);
+        tsbond(newbotright, botrsubseg);
+      }
+    }
+
+    /* Bond the new triangles to the surrounding triangles. */
+    bond(newbotleft, botlcasing);
+    bond(newbotright, botrcasing);
+    lnextself(newbotleft);
+    lprevself(newbotright);
+    bond(newbotleft, newbotright);
+    lnextself(newbotleft);
+    bond(botleft, newbotleft);
+    lprevself(newbotright);
+    bond(botright, newbotright);
+
+    if (m->checkquality) {
+      poolrestart(&m->flipstackers);
+      m->lastflip = (struct flipstacker *) poolalloc(&m->flipstackers);
+      m->lastflip->flippedtri = encode(horiz);
+      m->lastflip->prevflip = (struct flipstacker *) NULL;
+    }
+
+#ifdef SELF_CHECK
+    if (counterclockwise(m, b, rightvertex, leftvertex, botvertex) < 0.0) {
+      printf("Internal error in insertvertex():\n");
+      printf("  Clockwise triangle prior to vertex insertion.\n");
+    }
+    if (counterclockwise(m, b, rightvertex, leftvertex, newvertex) < 0.0) {
+      printf("Internal error in insertvertex():\n");
+      printf("  Clockwise triangle after vertex insertion (top).\n");
+    }
+    if (counterclockwise(m, b, leftvertex, botvertex, newvertex) < 0.0) {
+      printf("Internal error in insertvertex():\n");
+      printf("  Clockwise triangle after vertex insertion (left).\n");
+    }
+    if (counterclockwise(m, b, botvertex, rightvertex, newvertex) < 0.0) {
+      printf("Internal error in insertvertex():\n");
+      printf("  Clockwise triangle after vertex insertion (right).\n");
+    }
+#endif /* SELF_CHECK */
+    if (b->verbose > 2) {
+      printf("  Updating top ");
+      printtriangle(m, b, &horiz);
+      printf("  Creating left ");
+      printtriangle(m, b, &newbotleft);
+      printf("  Creating right ");
+      printtriangle(m, b, &newbotright);
+    }
+  }
+
+  /* The insertion is successful by default, unless an encroached */
+  /*   subsegment is found.                                       */
+  success = SUCCESSFULVERTEX;
+  /* Circle around the newly inserted vertex, checking each edge opposite */
+  /*   it for the Delaunay property.  Non-Delaunay edges are flipped.     */
+  /*   `horiz' is always the edge being checked.  `first' marks where to  */
+  /*   stop circling.                                                     */
+  org(horiz, first);
+  rightvertex = first;
+  dest(horiz, leftvertex);
+  /* Circle until finished. */
+  while (1) {
+    /* By default, the edge will be flipped. */
+    doflip = 1;
+
+    if (m->checksegments) {
+      /* Check for a subsegment, which cannot be flipped. */
+      tspivot(horiz, checksubseg);
+      if (checksubseg.ss != m->dummysub) {
+        /* The edge is a subsegment and cannot be flipped. */
+        doflip = 0;
+#ifndef CDT_ONLY
+        if (segmentflaws) {
+          /* Does the new vertex encroach upon this subsegment? */
+          if (checkseg4encroach(m, b, &checksubseg)) {
+            success = ENCROACHINGVERTEX;
+          }
+        }
+#endif /* not CDT_ONLY */
+      }
+    }
+
+    if (doflip) {
+      /* Check if the edge is a boundary edge. */
+      sym(horiz, top);
+      if (top.tri == m->dummytri) {
+        /* The edge is a boundary edge and cannot be flipped. */
+        doflip = 0;
+      } else {
+        /* Find the vertex on the other side of the edge. */
+        apex(top, farvertex);
+        /* In the incremental Delaunay triangulation algorithm, any of      */
+        /*   `leftvertex', `rightvertex', and `farvertex' could be vertices */
+        /*   of the triangular bounding box.  These vertices must be        */
+        /*   treated as if they are infinitely distant, even though their   */
+        /*   "coordinates" are not.                                         */
+        if ((leftvertex == m->infvertex1) || (leftvertex == m->infvertex2) ||
+            (leftvertex == m->infvertex3)) {
+          /* `leftvertex' is infinitely distant.  Check the convexity of  */
+          /*   the boundary of the triangulation.  'farvertex' might be   */
+          /*   infinite as well, but trust me, this same condition should */
+          /*   be applied.                                                */
+          doflip = counterclockwise(m, b, newvertex, rightvertex, farvertex)
+                   > 0.0;
+        } else if ((rightvertex == m->infvertex1) ||
+                   (rightvertex == m->infvertex2) ||
+                   (rightvertex == m->infvertex3)) {
+          /* `rightvertex' is infinitely distant.  Check the convexity of */
+          /*   the boundary of the triangulation.  'farvertex' might be   */
+          /*   infinite as well, but trust me, this same condition should */
+          /*   be applied.                                                */
+          doflip = counterclockwise(m, b, farvertex, leftvertex, newvertex)
+                   > 0.0;
+        } else if ((farvertex == m->infvertex1) ||
+                   (farvertex == m->infvertex2) ||
+                   (farvertex == m->infvertex3)) {
+          /* `farvertex' is infinitely distant and cannot be inside */
+          /*   the circumcircle of the triangle `horiz'.            */
+          doflip = 0;
+        } else {
+          /* Test whether the edge is locally Delaunay. */
+          doflip = incircle(m, b, leftvertex, newvertex, rightvertex,
+                            farvertex) > 0.0;
+        }
+        if (doflip) {
+          /* We made it!  Flip the edge `horiz' by rotating its containing */
+          /*   quadrilateral (the two triangles adjacent to `horiz').      */
+          /* Identify the casing of the quadrilateral. */
+          lprev(top, topleft);
+          sym(topleft, toplcasing);
+          lnext(top, topright);
+          sym(topright, toprcasing);
+          lnext(horiz, botleft);
+          sym(botleft, botlcasing);
+          lprev(horiz, botright);
+          sym(botright, botrcasing);
+          /* Rotate the quadrilateral one-quarter turn counterclockwise. */
+          bond(topleft, botlcasing);
+          bond(botleft, botrcasing);
+          bond(botright, toprcasing);
+          bond(topright, toplcasing);
+          if (m->checksegments) {
+            /* Check for subsegments and rebond them to the quadrilateral. */
+            tspivot(topleft, toplsubseg);
+            tspivot(botleft, botlsubseg);
+            tspivot(botright, botrsubseg);
+            tspivot(topright, toprsubseg);
+            if (toplsubseg.ss == m->dummysub) {
+              tsdissolve(topright);
+            } else {
+              tsbond(topright, toplsubseg);
+            }
+            if (botlsubseg.ss == m->dummysub) {
+              tsdissolve(topleft);
+            } else {
+              tsbond(topleft, botlsubseg);
+            }
+            if (botrsubseg.ss == m->dummysub) {
+              tsdissolve(botleft);
+            } else {
+              tsbond(botleft, botrsubseg);
+            }
+            if (toprsubseg.ss == m->dummysub) {
+              tsdissolve(botright);
+            } else {
+              tsbond(botright, toprsubseg);
+            }
+          }
+          /* New vertex assignments for the rotated quadrilateral. */
+          setorg(horiz, farvertex);
+          setdest(horiz, newvertex);
+          setapex(horiz, rightvertex);
+          setorg(top, newvertex);
+          setdest(top, farvertex);
+          setapex(top, leftvertex);
+          for (i = 0; i < m->eextras; i++) {
+            /* Take the average of the two triangles' attributes. */
+            attrib = 0.5 * (elemattribute(top, i) + elemattribute(horiz, i));
+            setelemattribute(top, i, attrib);
+            setelemattribute(horiz, i, attrib);
+          }
+          if (b->vararea) {
+            if ((areabound(top) <= 0.0) || (areabound(horiz) <= 0.0)) {
+              area = -1.0;
+            } else {
+              /* Take the average of the two triangles' area constraints.    */
+              /*   This prevents small area constraints from migrating a     */
+              /*   long, long way from their original location due to flips. */
+              area = 0.5 * (areabound(top) + areabound(horiz));
+            }
+            setareabound(top, area);
+            setareabound(horiz, area);
+          }
+
+          if (m->checkquality) {
+            newflip = (struct flipstacker *) poolalloc(&m->flipstackers);
+            newflip->flippedtri = encode(horiz);
+            newflip->prevflip = m->lastflip;
+            m->lastflip = newflip;
+          }
+
+#ifdef SELF_CHECK
+          if (newvertex != (vertex) NULL) {
+            if (counterclockwise(m, b, leftvertex, newvertex, rightvertex) <
+                0.0) {
+              printf("Internal error in insertvertex():\n");
+              printf("  Clockwise triangle prior to edge flip (bottom).\n");
+            }
+            /* The following test has been removed because constrainededge() */
+            /*   sometimes generates inverted triangles that insertvertex()  */
+            /*   removes.                                                    */
+/*
+            if (counterclockwise(m, b, rightvertex, farvertex, leftvertex) <
+                0.0) {
+              printf("Internal error in insertvertex():\n");
+              printf("  Clockwise triangle prior to edge flip (top).\n");
+            }
+*/
+            if (counterclockwise(m, b, farvertex, leftvertex, newvertex) <
+                0.0) {
+              printf("Internal error in insertvertex():\n");
+              printf("  Clockwise triangle after edge flip (left).\n");
+            }
+            if (counterclockwise(m, b, newvertex, rightvertex, farvertex) <
+                0.0) {
+              printf("Internal error in insertvertex():\n");
+              printf("  Clockwise triangle after edge flip (right).\n");
+            }
+          }
+#endif /* SELF_CHECK */
+          if (b->verbose > 2) {
+            printf("  Edge flip results in left ");
+            lnextself(topleft);
+            printtriangle(m, b, &topleft);
+            printf("  and right ");
+            printtriangle(m, b, &horiz);
+          }
+          /* On the next iterations, consider the two edges that were  */
+          /*   exposed (this is, are now visible to the newly inserted */
+          /*   vertex) by the edge flip.                               */
+          lprevself(horiz);
+          leftvertex = farvertex;
+        }
+      }
+    }
+    if (!doflip) {
+      /* The handle `horiz' is accepted as locally Delaunay. */
+#ifndef CDT_ONLY
+      if (triflaws) {
+        /* Check the triangle `horiz' for quality. */
+        testtriangle(m, b, &horiz);
+      }
+#endif /* not CDT_ONLY */
+      /* Look for the next edge around the newly inserted vertex. */
+      lnextself(horiz);
+      sym(horiz, testtri);
+      /* Check for finishing a complete revolution about the new vertex, or */
+      /*   falling outside  of the triangulation.  The latter will happen   */
+      /*   when a vertex is inserted at a boundary.                         */
+      if ((leftvertex == first) || (testtri.tri == m->dummytri)) {
+        /* We're done.  Return a triangle whose origin is the new vertex. */
+        lnext(horiz, *searchtri);
+        lnext(horiz, m->recenttri);
+        return success;
+      }
+      /* Finish finding the next edge around the newly inserted vertex. */
+      lnext(testtri, horiz);
+      rightvertex = leftvertex;
+      dest(horiz, leftvertex);
+    }
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  triangulatepolygon()   Find the Delaunay triangulation of a polygon that */
+/*                         has a certain "nice" shape.  This includes the    */
+/*                         polygons that result from deletion of a vertex or */
+/*                         insertion of a segment.                           */
+/*                                                                           */
+/*  This is a conceptually difficult routine.  The starting assumption is    */
+/*  that we have a polygon with n sides.  n - 1 of these sides are currently */
+/*  represented as edges in the mesh.  One side, called the "base", need not */
+/*  be.                                                                      */
+/*                                                                           */
+/*  Inside the polygon is a structure I call a "fan", consisting of n - 1    */
+/*  triangles that share a common origin.  For each of these triangles, the  */
+/*  edge opposite the origin is one of the sides of the polygon.  The        */
+/*  primary edge of each triangle is the edge directed from the origin to    */
+/*  the destination; note that this is not the same edge that is a side of   */
+/*  the polygon.  `firstedge' is the primary edge of the first triangle.     */
+/*  From there, the triangles follow in counterclockwise order about the     */
+/*  polygon, until `lastedge', the primary edge of the last triangle.        */
+/*  `firstedge' and `lastedge' are probably connected to other triangles     */
+/*  beyond the extremes of the fan, but their identity is not important, as  */
+/*  long as the fan remains connected to them.                               */
+/*                                                                           */
+/*  Imagine the polygon oriented so that its base is at the bottom.  This    */
+/*  puts `firstedge' on the far right, and `lastedge' on the far left.       */
+/*  The right vertex of the base is the destination of `firstedge', and the  */
+/*  left vertex of the base is the apex of `lastedge'.                       */
+/*                                                                           */
+/*  The challenge now is to find the right sequence of edge flips to         */
+/*  transform the fan into a Delaunay triangulation of the polygon.  Each    */
+/*  edge flip effectively removes one triangle from the fan, committing it   */
+/*  to the polygon.  The resulting polygon has one fewer edge.  If `doflip'  */
+/*  is set, the final flip will be performed, resulting in a fan of one      */
+/*  (useless?) triangle.  If `doflip' is not set, the final flip is not      */
+/*  performed, resulting in a fan of two triangles, and an unfinished        */
+/*  triangular polygon that is not yet filled out with a single triangle.    */
+/*  On completion of the routine, `lastedge' is the last remaining triangle, */
+/*  or the leftmost of the last two.                                         */
+/*                                                                           */
+/*  Although the flips are performed in the order described above, the       */
+/*  decisions about what flips to perform are made in precisely the reverse  */
+/*  order.  The recursive triangulatepolygon() procedure makes a decision,   */
+/*  uses up to two recursive calls to triangulate the "subproblems"          */
+/*  (polygons with fewer edges), and then performs an edge flip.             */
+/*                                                                           */
+/*  The "decision" it makes is which vertex of the polygon should be         */
+/*  connected to the base.  This decision is made by testing every possible  */
+/*  vertex.  Once the best vertex is found, the two edges that connect this  */
+/*  vertex to the base become the bases for two smaller polygons.  These     */
+/*  are triangulated recursively.  Unfortunately, this approach can take     */
+/*  O(n^2) time not only in the worst case, but in many common cases.  It's  */
+/*  rarely a big deal for vertex deletion, where n is rarely larger than     */
+/*  ten, but it could be a big deal for segment insertion, especially if     */
+/*  there's a lot of long segments that each cut many triangles.  I ought to */
+/*  code a faster algorithm some day.                                        */
+/*                                                                           */
+/*  The `edgecount' parameter is the number of sides of the polygon,         */
+/*  including its base.  `triflaws' is a flag that determines whether the    */
+/*  new triangles should be tested for quality, and enqueued if they are     */
+/*  bad.                                                                     */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void triangulatepolygon(struct mesh *m, struct behavior *b,
+                        struct otri *firstedge, struct otri *lastedge,
+                        int edgecount, int doflip, int triflaws)
+#else /* not ANSI_DECLARATORS */
+void triangulatepolygon(m, b, firstedge, lastedge, edgecount, doflip, triflaws)
+struct mesh *m;
+struct behavior *b;
+struct otri *firstedge;
+struct otri *lastedge;
+int edgecount;
+int doflip;
+int triflaws;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri testtri;
+  struct otri besttri;
+  struct otri tempedge;
+  vertex leftbasevertex, rightbasevertex;
+  vertex testvertex;
+  vertex bestvertex;
+  int bestnumber;
+  int i;
+  triangle ptr;   /* Temporary variable used by sym(), onext(), and oprev(). */
+
+  /* Identify the base vertices. */
+  apex(*lastedge, leftbasevertex);
+  dest(*firstedge, rightbasevertex);
+  if (b->verbose > 2) {
+    printf("  Triangulating interior polygon at edge\n");
+    printf("    (%.12g, %.12g) (%.12g, %.12g)\n", leftbasevertex[0],
+           leftbasevertex[1], rightbasevertex[0], rightbasevertex[1]);
+  }
+  /* Find the best vertex to connect the base to. */
+  onext(*firstedge, besttri);
+  dest(besttri, bestvertex);
+  otricopy(besttri, testtri);
+  bestnumber = 1;
+  for (i = 2; i <= edgecount - 2; i++) {
+    onextself(testtri);
+    dest(testtri, testvertex);
+    /* Is this a better vertex? */
+    if (incircle(m, b, leftbasevertex, rightbasevertex, bestvertex,
+                 testvertex) > 0.0) {
+      otricopy(testtri, besttri);
+      bestvertex = testvertex;
+      bestnumber = i;
+    }
+  }
+  if (b->verbose > 2) {
+    printf("    Connecting edge to (%.12g, %.12g)\n", bestvertex[0],
+           bestvertex[1]);
+  }
+  if (bestnumber > 1) {
+    /* Recursively triangulate the smaller polygon on the right. */
+    oprev(besttri, tempedge);
+    triangulatepolygon(m, b, firstedge, &tempedge, bestnumber + 1, 1,
+                       triflaws);
+  }
+  if (bestnumber < edgecount - 2) {
+    /* Recursively triangulate the smaller polygon on the left. */
+    sym(besttri, tempedge);
+    triangulatepolygon(m, b, &besttri, lastedge, edgecount - bestnumber, 1,
+                       triflaws);
+    /* Find `besttri' again; it may have been lost to edge flips. */
+    sym(tempedge, besttri);
+  }
+  if (doflip) {
+    /* Do one final edge flip. */
+    flip(m, b, &besttri);
+#ifndef CDT_ONLY
+    if (triflaws) {
+      /* Check the quality of the newly committed triangle. */
+      sym(besttri, testtri);
+      testtriangle(m, b, &testtri);
+    }
+#endif /* not CDT_ONLY */
+  }
+  /* Return the base triangle. */
+  otricopy(besttri, *lastedge);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  deletevertex()   Delete a vertex from a Delaunay triangulation, ensuring */
+/*                   that the triangulation remains Delaunay.                */
+/*                                                                           */
+/*  The origin of `deltri' is deleted.  The union of the triangles adjacent  */
+/*  to this vertex is a polygon, for which the Delaunay triangulation is     */
+/*  found.  Two triangles are removed from the mesh.                         */
+/*                                                                           */
+/*  Only interior vertices that do not lie on segments or boundaries may be  */
+/*  deleted.                                                                 */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef CDT_ONLY
+
+#ifdef ANSI_DECLARATORS
+void deletevertex(struct mesh *m, struct behavior *b, struct otri *deltri)
+#else /* not ANSI_DECLARATORS */
+void deletevertex(m, b, deltri)
+struct mesh *m;
+struct behavior *b;
+struct otri *deltri;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri countingtri;
+  struct otri firstedge, lastedge;
+  struct otri deltriright;
+  struct otri lefttri, righttri;
+  struct otri leftcasing, rightcasing;
+  struct osub leftsubseg, rightsubseg;
+  vertex delvertex;
+  vertex neworg;
+  int edgecount;
+  triangle ptr;   /* Temporary variable used by sym(), onext(), and oprev(). */
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+
+  org(*deltri, delvertex);
+  if (b->verbose > 1) {
+    printf("  Deleting (%.12g, %.12g).\n", delvertex[0], delvertex[1]);
+  }
+  vertexdealloc(m, delvertex);
+
+  /* Count the degree of the vertex being deleted. */
+  onext(*deltri, countingtri);
+  edgecount = 1;
+  while (!otriequal(*deltri, countingtri)) {
+#ifdef SELF_CHECK
+    if (countingtri.tri == m->dummytri) {
+      printf("Internal error in deletevertex():\n");
+      printf("  Attempt to delete boundary vertex.\n");
+      internalerror();
+    }
+#endif /* SELF_CHECK */
+    edgecount++;
+    onextself(countingtri);
+  }
+
+#ifdef SELF_CHECK
+  if (edgecount < 3) {
+    printf("Internal error in deletevertex():\n  Vertex has degree %d.\n",
+           edgecount);
+    internalerror();
+  }
+#endif /* SELF_CHECK */
+  if (edgecount > 3) {
+    /* Triangulate the polygon defined by the union of all triangles */
+    /*   adjacent to the vertex being deleted.  Check the quality of */
+    /*   the resulting triangles.                                    */
+    onext(*deltri, firstedge);
+    oprev(*deltri, lastedge);
+    triangulatepolygon(m, b, &firstedge, &lastedge, edgecount, 0,
+                       !b->nobisect);
+  }
+  /* Splice out two triangles. */
+  lprev(*deltri, deltriright);
+  dnext(*deltri, lefttri);
+  sym(lefttri, leftcasing);
+  oprev(deltriright, righttri);
+  sym(righttri, rightcasing);
+  bond(*deltri, leftcasing);
+  bond(deltriright, rightcasing);
+  tspivot(lefttri, leftsubseg);
+  if (leftsubseg.ss != m->dummysub) {
+    tsbond(*deltri, leftsubseg);
+  }
+  tspivot(righttri, rightsubseg);
+  if (rightsubseg.ss != m->dummysub) {
+    tsbond(deltriright, rightsubseg);
+  }
+
+  /* Set the new origin of `deltri' and check its quality. */
+  org(lefttri, neworg);
+  setorg(*deltri, neworg);
+  if (!b->nobisect) {
+    testtriangle(m, b, deltri);
+  }
+
+  /* Delete the two spliced-out triangles. */
+  triangledealloc(m, lefttri.tri);
+  triangledealloc(m, righttri.tri);
+}
+
+#endif /* not CDT_ONLY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  undovertex()   Undo the most recent vertex insertion.                    */
+/*                                                                           */
+/*  Walks through the list of transformations (flips and a vertex insertion) */
+/*  in the reverse of the order in which they were done, and undoes them.    */
+/*  The inserted vertex is removed from the triangulation and deallocated.   */
+/*  Two triangles (possibly just one) are also deallocated.                  */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef CDT_ONLY
+
+#ifdef ANSI_DECLARATORS
+void undovertex(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void undovertex(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri fliptri;
+  struct otri botleft, botright, topright;
+  struct otri botlcasing, botrcasing, toprcasing;
+  struct otri gluetri;
+  struct osub botlsubseg, botrsubseg, toprsubseg;
+  vertex botvertex, rightvertex;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+
+  /* Walk through the list of transformations (flips and a vertex insertion) */
+  /*   in the reverse of the order in which they were done, and undo them.   */
+  while (m->lastflip != (struct flipstacker *) NULL) {
+    /* Find a triangle involved in the last unreversed transformation. */
+    decode(m->lastflip->flippedtri, fliptri);
+
+    /* We are reversing one of three transformations:  a trisection of one */
+    /*   triangle into three (by inserting a vertex in the triangle), a    */
+    /*   bisection of two triangles into four (by inserting a vertex in an */
+    /*   edge), or an edge flip.                                           */
+    if (m->lastflip->prevflip == (struct flipstacker *) NULL) {
+      /* Restore a triangle that was split into three triangles, */
+      /*   so it is again one triangle.                          */
+      dprev(fliptri, botleft);
+      lnextself(botleft);
+      onext(fliptri, botright);
+      lprevself(botright);
+      sym(botleft, botlcasing);
+      sym(botright, botrcasing);
+      dest(botleft, botvertex);
+
+      setapex(fliptri, botvertex);
+      lnextself(fliptri);
+      bond(fliptri, botlcasing);
+      tspivot(botleft, botlsubseg);
+      tsbond(fliptri, botlsubseg);
+      lnextself(fliptri);
+      bond(fliptri, botrcasing);
+      tspivot(botright, botrsubseg);
+      tsbond(fliptri, botrsubseg);
+
+      /* Delete the two spliced-out triangles. */
+      triangledealloc(m, botleft.tri);
+      triangledealloc(m, botright.tri);
+    } else if (m->lastflip->prevflip == (struct flipstacker *) &insertvertex) {
+      /* Restore two triangles that were split into four triangles, */
+      /*   so they are again two triangles.                         */
+      lprev(fliptri, gluetri);
+      sym(gluetri, botright);
+      lnextself(botright);
+      sym(botright, botrcasing);
+      dest(botright, rightvertex);
+
+      setorg(fliptri, rightvertex);
+      bond(gluetri, botrcasing);
+      tspivot(botright, botrsubseg);
+      tsbond(gluetri, botrsubseg);
+
+      /* Delete the spliced-out triangle. */
+      triangledealloc(m, botright.tri);
+
+      sym(fliptri, gluetri);
+      if (gluetri.tri != m->dummytri) {
+        lnextself(gluetri);
+        dnext(gluetri, topright);
+        sym(topright, toprcasing);
+
+        setorg(gluetri, rightvertex);
+        bond(gluetri, toprcasing);
+        tspivot(topright, toprsubseg);
+        tsbond(gluetri, toprsubseg);
+
+        /* Delete the spliced-out triangle. */
+        triangledealloc(m, topright.tri);
+      }
+
+      /* This is the end of the list, sneakily encoded. */
+      m->lastflip->prevflip = (struct flipstacker *) NULL;
+    } else {
+      /* Undo an edge flip. */
+      unflip(m, b, &fliptri);
+    }
+
+    /* Go on and process the next transformation. */
+    m->lastflip = m->lastflip->prevflip;
+  }
+}
+
+#endif /* not CDT_ONLY */
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Mesh transformation routines end here                     *********/
+
+/********* Divide-and-conquer Delaunay triangulation begins here     *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  The divide-and-conquer bounding box                                      */
+/*                                                                           */
+/*  I originally implemented the divide-and-conquer and incremental Delaunay */
+/*  triangulations using the edge-based data structure presented by Guibas   */
+/*  and Stolfi.  Switching to a triangle-based data structure doubled the    */
+/*  speed.  However, I had to think of a few extra tricks to maintain the    */
+/*  elegance of the original algorithms.                                     */
+/*                                                                           */
+/*  The "bounding box" used by my variant of the divide-and-conquer          */
+/*  algorithm uses one triangle for each edge of the convex hull of the      */
+/*  triangulation.  These bounding triangles all share a common apical       */
+/*  vertex, which is represented by NULL and which represents nothing.       */
+/*  The bounding triangles are linked in a circular fan about this NULL      */
+/*  vertex, and the edges on the convex hull of the triangulation appear     */
+/*  opposite the NULL vertex.  You might find it easiest to imagine that     */
+/*  the NULL vertex is a point in 3D space behind the center of the          */
+/*  triangulation, and that the bounding triangles form a sort of cone.      */
+/*                                                                           */
+/*  This bounding box makes it easy to represent degenerate cases.  For      */
+/*  instance, the triangulation of two vertices is a single edge.  This edge */
+/*  is represented by two bounding box triangles, one on each "side" of the  */
+/*  edge.  These triangles are also linked together in a fan about the NULL  */
+/*  vertex.                                                                  */
+/*                                                                           */
+/*  The bounding box also makes it easy to traverse the convex hull, as the  */
+/*  divide-and-conquer algorithm needs to do.                                */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  vertexsort()   Sort an array of vertices by x-coordinate, using the      */
+/*                 y-coordinate as a secondary key.                          */
+/*                                                                           */
+/*  Uses quicksort.  Randomized O(n log n) time.  No, I did not make any of  */
+/*  the usual quicksort mistakes.                                            */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void vertexsort(vertex *sortarray, int arraysize)
+#else /* not ANSI_DECLARATORS */
+void vertexsort(sortarray, arraysize)
+vertex *sortarray;
+int arraysize;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  int left, right;
+  int pivot;
+  REAL pivotx, pivoty;
+  vertex temp;
+
+  if (arraysize == 2) {
+    /* Recursive base case. */
+    if ((sortarray[0][0] > sortarray[1][0]) ||
+        ((sortarray[0][0] == sortarray[1][0]) &&
+         (sortarray[0][1] > sortarray[1][1]))) {
+      temp = sortarray[1];
+      sortarray[1] = sortarray[0];
+      sortarray[0] = temp;
+    }
+    return;
+  }
+  /* Choose a random pivot to split the array. */
+  pivot = (int) randomnation((unsigned int) arraysize);
+  pivotx = sortarray[pivot][0];
+  pivoty = sortarray[pivot][1];
+  /* Split the array. */
+  left = -1;
+  right = arraysize;
+  while (left < right) {
+    /* Search for a vertex whose x-coordinate is too large for the left. */
+    do {
+      left++;
+    } while ((left <= right) && ((sortarray[left][0] < pivotx) ||
+                                 ((sortarray[left][0] == pivotx) &&
+                                  (sortarray[left][1] < pivoty))));
+    /* Search for a vertex whose x-coordinate is too small for the right. */
+    do {
+      right--;
+    } while ((left <= right) && ((sortarray[right][0] > pivotx) ||
+                                 ((sortarray[right][0] == pivotx) &&
+                                  (sortarray[right][1] > pivoty))));
+    if (left < right) {
+      /* Swap the left and right vertices. */
+      temp = sortarray[left];
+      sortarray[left] = sortarray[right];
+      sortarray[right] = temp;
+    }
+  }
+  if (left > 1) {
+    /* Recursively sort the left subset. */
+    vertexsort(sortarray, left);
+  }
+  if (right < arraysize - 2) {
+    /* Recursively sort the right subset. */
+    vertexsort(&sortarray[right + 1], arraysize - right - 1);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  vertexmedian()   An order statistic algorithm, almost.  Shuffles an      */
+/*                   array of vertices so that the first `median' vertices   */
+/*                   occur lexicographically before the remaining vertices.  */
+/*                                                                           */
+/*  Uses the x-coordinate as the primary key if axis == 0; the y-coordinate  */
+/*  if axis == 1.  Very similar to the vertexsort() procedure, but runs in   */
+/*  randomized linear time.                                                  */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void vertexmedian(vertex *sortarray, int arraysize, int median, int axis)
+#else /* not ANSI_DECLARATORS */
+void vertexmedian(sortarray, arraysize, median, axis)
+vertex *sortarray;
+int arraysize;
+int median;
+int axis;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  int left, right;
+  int pivot;
+  REAL pivot1, pivot2;
+  vertex temp;
+
+  if (arraysize == 2) {
+    /* Recursive base case. */
+    if ((sortarray[0][axis] > sortarray[1][axis]) ||
+        ((sortarray[0][axis] == sortarray[1][axis]) &&
+         (sortarray[0][1 - axis] > sortarray[1][1 - axis]))) {
+      temp = sortarray[1];
+      sortarray[1] = sortarray[0];
+      sortarray[0] = temp;
+    }
+    return;
+  }
+  /* Choose a random pivot to split the array. */
+  pivot = (int) randomnation((unsigned int) arraysize);
+  pivot1 = sortarray[pivot][axis];
+  pivot2 = sortarray[pivot][1 - axis];
+  /* Split the array. */
+  left = -1;
+  right = arraysize;
+  while (left < right) {
+    /* Search for a vertex whose x-coordinate is too large for the left. */
+    do {
+      left++;
+    } while ((left <= right) && ((sortarray[left][axis] < pivot1) ||
+                                 ((sortarray[left][axis] == pivot1) &&
+                                  (sortarray[left][1 - axis] < pivot2))));
+    /* Search for a vertex whose x-coordinate is too small for the right. */
+    do {
+      right--;
+    } while ((left <= right) && ((sortarray[right][axis] > pivot1) ||
+                                 ((sortarray[right][axis] == pivot1) &&
+                                  (sortarray[right][1 - axis] > pivot2))));
+    if (left < right) {
+      /* Swap the left and right vertices. */
+      temp = sortarray[left];
+      sortarray[left] = sortarray[right];
+      sortarray[right] = temp;
+    }
+  }
+  /* Unlike in vertexsort(), at most one of the following */
+  /*   conditionals is true.                             */
+  if (left > median) {
+    /* Recursively shuffle the left subset. */
+    vertexmedian(sortarray, left, median, axis);
+  }
+  if (right < median - 1) {
+    /* Recursively shuffle the right subset. */
+    vertexmedian(&sortarray[right + 1], arraysize - right - 1,
+                 median - right - 1, axis);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  alternateaxes()   Sorts the vertices as appropriate for the divide-and-  */
+/*                    conquer algorithm with alternating cuts.               */
+/*                                                                           */
+/*  Partitions by x-coordinate if axis == 0; by y-coordinate if axis == 1.   */
+/*  For the base case, subsets containing only two or three vertices are     */
+/*  always sorted by x-coordinate.                                           */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void alternateaxes(vertex *sortarray, int arraysize, int axis)
+#else /* not ANSI_DECLARATORS */
+void alternateaxes(sortarray, arraysize, axis)
+vertex *sortarray;
+int arraysize;
+int axis;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  int divider;
+
+  divider = arraysize >> 1;
+  if (arraysize <= 3) {
+    /* Recursive base case:  subsets of two or three vertices will be    */
+    /*   handled specially, and should always be sorted by x-coordinate. */
+    axis = 0;
+  }
+  /* Partition with a horizontal or vertical cut. */
+  vertexmedian(sortarray, arraysize, divider, axis);
+  /* Recursively partition the subsets with a cross cut. */
+  if (arraysize - divider >= 2) {
+    if (divider >= 2) {
+      alternateaxes(sortarray, divider, 1 - axis);
+    }
+    alternateaxes(&sortarray[divider], arraysize - divider, 1 - axis);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  mergehulls()   Merge two adjacent Delaunay triangulations into a         */
+/*                 single Delaunay triangulation.                            */
+/*                                                                           */
+/*  This is similar to the algorithm given by Guibas and Stolfi, but uses    */
+/*  a triangle-based, rather than edge-based, data structure.                */
+/*                                                                           */
+/*  The algorithm walks up the gap between the two triangulations, knitting  */
+/*  them together.  As they are merged, some of their bounding triangles     */
+/*  are converted into real triangles of the triangulation.  The procedure   */
+/*  pulls each hull's bounding triangles apart, then knits them together     */
+/*  like the teeth of two gears.  The Delaunay property determines, at each  */
+/*  step, whether the next "tooth" is a bounding triangle of the left hull   */
+/*  or the right.  When a bounding triangle becomes real, its apex is        */
+/*  changed from NULL to a real vertex.                                      */
+/*                                                                           */
+/*  Only two new triangles need to be allocated.  These become new bounding  */
+/*  triangles at the top and bottom of the seam.  They are used to connect   */
+/*  the remaining bounding triangles (those that have not been converted     */
+/*  into real triangles) into a single fan.                                  */
+/*                                                                           */
+/*  On entry, `farleft' and `innerleft' are bounding triangles of the left   */
+/*  triangulation.  The origin of `farleft' is the leftmost vertex, and      */
+/*  the destination of `innerleft' is the rightmost vertex of the            */
+/*  triangulation.  Similarly, `innerright' and `farright' are bounding      */
+/*  triangles of the right triangulation.  The origin of `innerright' and    */
+/*  destination of `farright' are the leftmost and rightmost vertices.       */
+/*                                                                           */
+/*  On completion, the origin of `farleft' is the leftmost vertex of the     */
+/*  merged triangulation, and the destination of `farright' is the rightmost */
+/*  vertex.                                                                  */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void mergehulls(struct mesh *m, struct behavior *b, struct otri *farleft,
+                struct otri *innerleft, struct otri *innerright,
+                struct otri *farright, int axis)
+#else /* not ANSI_DECLARATORS */
+void mergehulls(m, b, farleft, innerleft, innerright, farright, axis)
+struct mesh *m;
+struct behavior *b;
+struct otri *farleft;
+struct otri *innerleft;
+struct otri *innerright;
+struct otri *farright;
+int axis;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri leftcand, rightcand;
+  struct otri baseedge;
+  struct otri nextedge;
+  struct otri sidecasing, topcasing, outercasing;
+  struct otri checkedge;
+  vertex innerleftdest;
+  vertex innerrightorg;
+  vertex innerleftapex, innerrightapex;
+  vertex farleftpt, farrightpt;
+  vertex farleftapex, farrightapex;
+  vertex lowerleft, lowerright;
+  vertex upperleft, upperright;
+  vertex nextapex;
+  vertex checkvertex;
+  int changemade;
+  int badedge;
+  int leftfinished, rightfinished;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+  dest(*innerleft, innerleftdest);
+  apex(*innerleft, innerleftapex);
+  org(*innerright, innerrightorg);
+  apex(*innerright, innerrightapex);
+  /* Special treatment for horizontal cuts. */
+  if (b->dwyer && (axis == 1)) {
+    org(*farleft, farleftpt);
+    apex(*farleft, farleftapex);
+    dest(*farright, farrightpt);
+    apex(*farright, farrightapex);
+    /* The pointers to the extremal vertices are shifted to point to the */
+    /*   topmost and bottommost vertex of each hull, rather than the     */
+    /*   leftmost and rightmost vertices.                                */
+    while (farleftapex[1] < farleftpt[1]) {
+      lnextself(*farleft);
+      symself(*farleft);
+      farleftpt = farleftapex;
+      apex(*farleft, farleftapex);
+    }
+    sym(*innerleft, checkedge);
+    apex(checkedge, checkvertex);
+    while (checkvertex[1] > innerleftdest[1]) {
+      lnext(checkedge, *innerleft);
+      innerleftapex = innerleftdest;
+      innerleftdest = checkvertex;
+      sym(*innerleft, checkedge);
+      apex(checkedge, checkvertex);
+    }
+    while (innerrightapex[1] < innerrightorg[1]) {
+      lnextself(*innerright);
+      symself(*innerright);
+      innerrightorg = innerrightapex;
+      apex(*innerright, innerrightapex);
+    }
+    sym(*farright, checkedge);
+    apex(checkedge, checkvertex);
+    while (checkvertex[1] > farrightpt[1]) {
+      lnext(checkedge, *farright);
+      farrightapex = farrightpt;
+      farrightpt = checkvertex;
+      sym(*farright, checkedge);
+      apex(checkedge, checkvertex);
+    }
+  }
+  /* Find a line tangent to and below both hulls. */
+  do {
+    changemade = 0;
+    /* Make innerleftdest the "bottommost" vertex of the left hull. */
+    if (counterclockwise(m, b, innerleftdest, innerleftapex, innerrightorg) >
+        0.0) {
+      lprevself(*innerleft);
+      symself(*innerleft);
+      innerleftdest = innerleftapex;
+      apex(*innerleft, innerleftapex);
+      changemade = 1;
+    }
+    /* Make innerrightorg the "bottommost" vertex of the right hull. */
+    if (counterclockwise(m, b, innerrightapex, innerrightorg, innerleftdest) >
+        0.0) {
+      lnextself(*innerright);
+      symself(*innerright);
+      innerrightorg = innerrightapex;
+      apex(*innerright, innerrightapex);
+      changemade = 1;
+    }
+  } while (changemade);
+  /* Find the two candidates to be the next "gear tooth." */
+  sym(*innerleft, leftcand);
+  sym(*innerright, rightcand);
+  /* Create the bottom new bounding triangle. */
+  maketriangle(m, b, &baseedge);
+  /* Connect it to the bounding boxes of the left and right triangulations. */
+  bond(baseedge, *innerleft);
+  lnextself(baseedge);
+  bond(baseedge, *innerright);
+  lnextself(baseedge);
+  setorg(baseedge, innerrightorg);
+  setdest(baseedge, innerleftdest);
+  /* Apex is intentionally left NULL. */
+  if (b->verbose > 2) {
+    printf("  Creating base bounding ");
+    printtriangle(m, b, &baseedge);
+  }
+  /* Fix the extreme triangles if necessary. */
+  org(*farleft, farleftpt);
+  if (innerleftdest == farleftpt) {
+    lnext(baseedge, *farleft);
+  }
+  dest(*farright, farrightpt);
+  if (innerrightorg == farrightpt) {
+    lprev(baseedge, *farright);
+  }
+  /* The vertices of the current knitting edge. */
+  lowerleft = innerleftdest;
+  lowerright = innerrightorg;
+  /* The candidate vertices for knitting. */
+  apex(leftcand, upperleft);
+  apex(rightcand, upperright);
+  /* Walk up the gap between the two triangulations, knitting them together. */
+  while (1) {
+    /* Have we reached the top?  (This isn't quite the right question,       */
+    /*   because even though the left triangulation might seem finished now, */
+    /*   moving up on the right triangulation might reveal a new vertex of   */
+    /*   the left triangulation.  And vice-versa.)                           */
+    leftfinished = counterclockwise(m, b, upperleft, lowerleft, lowerright) <=
+                   0.0;
+    rightfinished = counterclockwise(m, b, upperright, lowerleft, lowerright)
+                 <= 0.0;
+    if (leftfinished && rightfinished) {
+      /* Create the top new bounding triangle. */
+      maketriangle(m, b, &nextedge);
+      setorg(nextedge, lowerleft);
+      setdest(nextedge, lowerright);
+      /* Apex is intentionally left NULL. */
+      /* Connect it to the bounding boxes of the two triangulations. */
+      bond(nextedge, baseedge);
+      lnextself(nextedge);
+      bond(nextedge, rightcand);
+      lnextself(nextedge);
+      bond(nextedge, leftcand);
+      if (b->verbose > 2) {
+        printf("  Creating top bounding ");
+        printtriangle(m, b, &nextedge);
+      }
+      /* Special treatment for horizontal cuts. */
+      if (b->dwyer && (axis == 1)) {
+        org(*farleft, farleftpt);
+        apex(*farleft, farleftapex);
+        dest(*farright, farrightpt);
+        apex(*farright, farrightapex);
+        sym(*farleft, checkedge);
+        apex(checkedge, checkvertex);
+        /* The pointers to the extremal vertices are restored to the  */
+        /*   leftmost and rightmost vertices (rather than topmost and */
+        /*   bottommost).                                             */
+        while (checkvertex[0] < farleftpt[0]) {
+          lprev(checkedge, *farleft);
+          farleftapex = farleftpt;
+          farleftpt = checkvertex;
+          sym(*farleft, checkedge);
+          apex(checkedge, checkvertex);
+        }
+        while (farrightapex[0] > farrightpt[0]) {
+          lprevself(*farright);
+          symself(*farright);
+          farrightpt = farrightapex;
+          apex(*farright, farrightapex);
+        }
+      }
+      return;
+    }
+    /* Consider eliminating edges from the left triangulation. */
+    if (!leftfinished) {
+      /* What vertex would be exposed if an edge were deleted? */
+      lprev(leftcand, nextedge);
+      symself(nextedge);
+      apex(nextedge, nextapex);
+      /* If nextapex is NULL, then no vertex would be exposed; the */
+      /*   triangulation would have been eaten right through.      */
+      if (nextapex != (vertex) NULL) {
+        /* Check whether the edge is Delaunay. */
+        badedge = incircle(m, b, lowerleft, lowerright, upperleft, nextapex) >
+                  0.0;
+        while (badedge) {
+          /* Eliminate the edge with an edge flip.  As a result, the    */
+          /*   left triangulation will have one more boundary triangle. */
+          lnextself(nextedge);
+          sym(nextedge, topcasing);
+          lnextself(nextedge);
+          sym(nextedge, sidecasing);
+          bond(nextedge, topcasing);
+          bond(leftcand, sidecasing);
+          lnextself(leftcand);
+          sym(leftcand, outercasing);
+          lprevself(nextedge);
+          bond(nextedge, outercasing);
+          /* Correct the vertices to reflect the edge flip. */
+          setorg(leftcand, lowerleft);
+          setdest(leftcand, NULL);
+          setapex(leftcand, nextapex);
+          setorg(nextedge, NULL);
+          setdest(nextedge, upperleft);
+          setapex(nextedge, nextapex);
+          /* Consider the newly exposed vertex. */
+          upperleft = nextapex;
+          /* What vertex would be exposed if another edge were deleted? */
+          otricopy(sidecasing, nextedge);
+          apex(nextedge, nextapex);
+          if (nextapex != (vertex) NULL) {
+            /* Check whether the edge is Delaunay. */
+            badedge = incircle(m, b, lowerleft, lowerright, upperleft,
+                               nextapex) > 0.0;
+          } else {
+            /* Avoid eating right through the triangulation. */
+            badedge = 0;
+          }
+        }
+      }
+    }
+    /* Consider eliminating edges from the right triangulation. */
+    if (!rightfinished) {
+      /* What vertex would be exposed if an edge were deleted? */
+      lnext(rightcand, nextedge);
+      symself(nextedge);
+      apex(nextedge, nextapex);
+      /* If nextapex is NULL, then no vertex would be exposed; the */
+      /*   triangulation would have been eaten right through.      */
+      if (nextapex != (vertex) NULL) {
+        /* Check whether the edge is Delaunay. */
+        badedge = incircle(m, b, lowerleft, lowerright, upperright, nextapex) >
+                  0.0;
+        while (badedge) {
+          /* Eliminate the edge with an edge flip.  As a result, the     */
+          /*   right triangulation will have one more boundary triangle. */
+          lprevself(nextedge);
+          sym(nextedge, topcasing);
+          lprevself(nextedge);
+          sym(nextedge, sidecasing);
+          bond(nextedge, topcasing);
+          bond(rightcand, sidecasing);
+          lprevself(rightcand);
+          sym(rightcand, outercasing);
+          lnextself(nextedge);
+          bond(nextedge, outercasing);
+          /* Correct the vertices to reflect the edge flip. */
+          setorg(rightcand, NULL);
+          setdest(rightcand, lowerright);
+          setapex(rightcand, nextapex);
+          setorg(nextedge, upperright);
+          setdest(nextedge, NULL);
+          setapex(nextedge, nextapex);
+          /* Consider the newly exposed vertex. */
+          upperright = nextapex;
+          /* What vertex would be exposed if another edge were deleted? */
+          otricopy(sidecasing, nextedge);
+          apex(nextedge, nextapex);
+          if (nextapex != (vertex) NULL) {
+            /* Check whether the edge is Delaunay. */
+            badedge = incircle(m, b, lowerleft, lowerright, upperright,
+                               nextapex) > 0.0;
+          } else {
+            /* Avoid eating right through the triangulation. */
+            badedge = 0;
+          }
+        }
+      }
+    }
+    if (leftfinished || (!rightfinished &&
+           (incircle(m, b, upperleft, lowerleft, lowerright, upperright) >
+            0.0))) {
+      /* Knit the triangulations, adding an edge from `lowerleft' */
+      /*   to `upperright'.                                       */
+      bond(baseedge, rightcand);
+      lprev(rightcand, baseedge);
+      setdest(baseedge, lowerleft);
+      lowerright = upperright;
+      sym(baseedge, rightcand);
+      apex(rightcand, upperright);
+    } else {
+      /* Knit the triangulations, adding an edge from `upperleft' */
+      /*   to `lowerright'.                                       */
+      bond(baseedge, leftcand);
+      lnext(leftcand, baseedge);
+      setorg(baseedge, lowerright);
+      lowerleft = upperleft;
+      sym(baseedge, leftcand);
+      apex(leftcand, upperleft);
+    }
+    if (b->verbose > 2) {
+      printf("  Connecting ");
+      printtriangle(m, b, &baseedge);
+    }
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  divconqrecurse()   Recursively form a Delaunay triangulation by the      */
+/*                     divide-and-conquer method.                            */
+/*                                                                           */
+/*  Recursively breaks down the problem into smaller pieces, which are       */
+/*  knitted together by mergehulls().  The base cases (problems of two or    */
+/*  three vertices) are handled specially here.                              */
+/*                                                                           */
+/*  On completion, `farleft' and `farright' are bounding triangles such that */
+/*  the origin of `farleft' is the leftmost vertex (breaking ties by         */
+/*  choosing the highest leftmost vertex), and the destination of            */
+/*  `farright' is the rightmost vertex (breaking ties by choosing the        */
+/*  lowest rightmost vertex).                                                */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void divconqrecurse(struct mesh *m, struct behavior *b, vertex *sortarray,
+                    int vertices, int axis,
+                    struct otri *farleft, struct otri *farright)
+#else /* not ANSI_DECLARATORS */
+void divconqrecurse(m, b, sortarray, vertices, axis, farleft, farright)
+struct mesh *m;
+struct behavior *b;
+vertex *sortarray;
+int vertices;
+int axis;
+struct otri *farleft;
+struct otri *farright;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri midtri, tri1, tri2, tri3;
+  struct otri innerleft, innerright;
+  REAL area;
+  int divider;
+
+  if (b->verbose > 2) {
+    printf("  Triangulating %d vertices.\n", vertices);
+  }
+  if (vertices == 2) {
+    /* The triangulation of two vertices is an edge.  An edge is */
+    /*   represented by two bounding triangles.                  */
+    maketriangle(m, b, farleft);
+    setorg(*farleft, sortarray[0]);
+    setdest(*farleft, sortarray[1]);
+    /* The apex is intentionally left NULL. */
+    maketriangle(m, b, farright);
+    setorg(*farright, sortarray[1]);
+    setdest(*farright, sortarray[0]);
+    /* The apex is intentionally left NULL. */
+    bond(*farleft, *farright);
+    lprevself(*farleft);
+    lnextself(*farright);
+    bond(*farleft, *farright);
+    lprevself(*farleft);
+    lnextself(*farright);
+    bond(*farleft, *farright);
+    if (b->verbose > 2) {
+      printf("  Creating ");
+      printtriangle(m, b, farleft);
+      printf("  Creating ");
+      printtriangle(m, b, farright);
+    }
+    /* Ensure that the origin of `farleft' is sortarray[0]. */
+    lprev(*farright, *farleft);
+    return;
+  } else if (vertices == 3) {
+    /* The triangulation of three vertices is either a triangle (with */
+    /*   three bounding triangles) or two edges (with four bounding   */
+    /*   triangles).  In either case, four triangles are created.     */
+    maketriangle(m, b, &midtri);
+    maketriangle(m, b, &tri1);
+    maketriangle(m, b, &tri2);
+    maketriangle(m, b, &tri3);
+    area = counterclockwise(m, b, sortarray[0], sortarray[1], sortarray[2]);
+    if (area == 0.0) {
+      /* Three collinear vertices; the triangulation is two edges. */
+      setorg(midtri, sortarray[0]);
+      setdest(midtri, sortarray[1]);
+      setorg(tri1, sortarray[1]);
+      setdest(tri1, sortarray[0]);
+      setorg(tri2, sortarray[2]);
+      setdest(tri2, sortarray[1]);
+      setorg(tri3, sortarray[1]);
+      setdest(tri3, sortarray[2]);
+      /* All apices are intentionally left NULL. */
+      bond(midtri, tri1);
+      bond(tri2, tri3);
+      lnextself(midtri);
+      lprevself(tri1);
+      lnextself(tri2);
+      lprevself(tri3);
+      bond(midtri, tri3);
+      bond(tri1, tri2);
+      lnextself(midtri);
+      lprevself(tri1);
+      lnextself(tri2);
+      lprevself(tri3);
+      bond(midtri, tri1);
+      bond(tri2, tri3);
+      /* Ensure that the origin of `farleft' is sortarray[0]. */
+      otricopy(tri1, *farleft);
+      /* Ensure that the destination of `farright' is sortarray[2]. */
+      otricopy(tri2, *farright);
+    } else {
+      /* The three vertices are not collinear; the triangulation is one */
+      /*   triangle, namely `midtri'.                                   */
+      setorg(midtri, sortarray[0]);
+      setdest(tri1, sortarray[0]);
+      setorg(tri3, sortarray[0]);
+      /* Apices of tri1, tri2, and tri3 are left NULL. */
+      if (area > 0.0) {
+        /* The vertices are in counterclockwise order. */
+        setdest(midtri, sortarray[1]);
+        setorg(tri1, sortarray[1]);
+        setdest(tri2, sortarray[1]);
+        setapex(midtri, sortarray[2]);
+        setorg(tri2, sortarray[2]);
+        setdest(tri3, sortarray[2]);
+      } else {
+        /* The vertices are in clockwise order. */
+        setdest(midtri, sortarray[2]);
+        setorg(tri1, sortarray[2]);
+        setdest(tri2, sortarray[2]);
+        setapex(midtri, sortarray[1]);
+        setorg(tri2, sortarray[1]);
+        setdest(tri3, sortarray[1]);
+      }
+      /* The topology does not depend on how the vertices are ordered. */
+      bond(midtri, tri1);
+      lnextself(midtri);
+      bond(midtri, tri2);
+      lnextself(midtri);
+      bond(midtri, tri3);
+      lprevself(tri1);
+      lnextself(tri2);
+      bond(tri1, tri2);
+      lprevself(tri1);
+      lprevself(tri3);
+      bond(tri1, tri3);
+      lnextself(tri2);
+      lprevself(tri3);
+      bond(tri2, tri3);
+      /* Ensure that the origin of `farleft' is sortarray[0]. */
+      otricopy(tri1, *farleft);
+      /* Ensure that the destination of `farright' is sortarray[2]. */
+      if (area > 0.0) {
+        otricopy(tri2, *farright);
+      } else {
+        lnext(*farleft, *farright);
+      }
+    }
+    if (b->verbose > 2) {
+      printf("  Creating ");
+      printtriangle(m, b, &midtri);
+      printf("  Creating ");
+      printtriangle(m, b, &tri1);
+      printf("  Creating ");
+      printtriangle(m, b, &tri2);
+      printf("  Creating ");
+      printtriangle(m, b, &tri3);
+    }
+    return;
+  } else {
+    /* Split the vertices in half. */
+    divider = vertices >> 1;
+    /* Recursively triangulate each half. */
+    divconqrecurse(m, b, sortarray, divider, 1 - axis, farleft, &innerleft);
+    divconqrecurse(m, b, &sortarray[divider], vertices - divider, 1 - axis,
+                   &innerright, farright);
+    if (b->verbose > 1) {
+      printf("  Joining triangulations with %d and %d vertices.\n", divider,
+             vertices - divider);
+    }
+    /* Merge the two triangulations into one. */
+    mergehulls(m, b, farleft, &innerleft, &innerright, farright, axis);
+  }
+}
+
+#ifdef ANSI_DECLARATORS
+long removeghosts(struct mesh *m, struct behavior *b, struct otri *startghost)
+#else /* not ANSI_DECLARATORS */
+long removeghosts(m, b, startghost)
+struct mesh *m;
+struct behavior *b;
+struct otri *startghost;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri searchedge;
+  struct otri dissolveedge;
+  struct otri deadtriangle;
+  vertex markorg;
+  long hullsize;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+  if (b->verbose) {
+    printf("  Removing ghost triangles.\n");
+  }
+  /* Find an edge on the convex hull to start point location from. */
+  lprev(*startghost, searchedge);
+  symself(searchedge);
+  m->dummytri[0] = encode(searchedge);
+  /* Remove the bounding box and count the convex hull edges. */
+  otricopy(*startghost, dissolveedge);
+  hullsize = 0;
+  do {
+    hullsize++;
+    lnext(dissolveedge, deadtriangle);
+    lprevself(dissolveedge);
+    symself(dissolveedge);
+    /* If no PSLG is involved, set the boundary markers of all the vertices */
+    /*   on the convex hull.  If a PSLG is used, this step is done later.   */
+    if (!b->poly) {
+      /* Watch out for the case where all the input vertices are collinear. */
+      if (dissolveedge.tri != m->dummytri) {
+        org(dissolveedge, markorg);
+        if (vertexmark(markorg) == 0) {
+          setvertexmark(markorg, 1);
+        }
+      }
+    }
+    /* Remove a bounding triangle from a convex hull triangle. */
+    dissolve(dissolveedge);
+    /* Find the next bounding triangle. */
+    sym(deadtriangle, dissolveedge);
+    /* Delete the bounding triangle. */
+    triangledealloc(m, deadtriangle.tri);
+  } while (!otriequal(dissolveedge, *startghost));
+  return hullsize;
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  divconqdelaunay()   Form a Delaunay triangulation by the divide-and-     */
+/*                      conquer method.                                      */
+/*                                                                           */
+/*  Sorts the vertices, calls a recursive procedure to triangulate them, and */
+/*  removes the bounding box, setting boundary markers as appropriate.       */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+long divconqdelaunay(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+long divconqdelaunay(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  vertex *sortarray;
+  struct otri hullleft, hullright;
+  int divider;
+  int i, j;
+
+  if (b->verbose) {
+    printf("  Sorting vertices.\n");
+  }
+
+  /* Allocate an array of pointers to vertices for sorting. */
+  sortarray = (vertex *) trimalloc(m->invertices * (int) sizeof(vertex));
+  traversalinit(&m->vertices);
+  for (i = 0; i < m->invertices; i++) {
+    sortarray[i] = vertextraverse(m);
+  }
+  /* Sort the vertices. */
+  vertexsort(sortarray, m->invertices);
+  /* Discard duplicate vertices, which can really mess up the algorithm. */
+  i = 0;
+  for (j = 1; j < m->invertices; j++) {
+    if ((sortarray[i][0] == sortarray[j][0])
+        && (sortarray[i][1] == sortarray[j][1])) {
+      if (!b->quiet) {
+        printf(
+"Warning:  A duplicate vertex at (%.12g, %.12g) appeared and was ignored.\n",
+               sortarray[j][0], sortarray[j][1]);
+      }
+      setvertextype(sortarray[j], UNDEADVERTEX);
+      m->undeads++;
+    } else {
+      i++;
+      sortarray[i] = sortarray[j];
+    }
+  }
+  i++;
+  if (b->dwyer) {
+    /* Re-sort the array of vertices to accommodate alternating cuts. */
+    divider = i >> 1;
+    if (i - divider >= 2) {
+      if (divider >= 2) {
+        alternateaxes(sortarray, divider, 1);
+      }
+      alternateaxes(&sortarray[divider], i - divider, 1);
+    }
+  }
+
+  if (b->verbose) {
+    printf("  Forming triangulation.\n");
+  }
+
+  /* Form the Delaunay triangulation. */
+  divconqrecurse(m, b, sortarray, i, 0, &hullleft, &hullright);
+  trifree((VOID *) sortarray);
+
+  return removeghosts(m, b, &hullleft);
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Divide-and-conquer Delaunay triangulation ends here       *********/
+
+/********* Incremental Delaunay triangulation begins here            *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  boundingbox()   Form an "infinite" bounding triangle to insert vertices  */
+/*                  into.                                                    */
+/*                                                                           */
+/*  The vertices at "infinity" are assigned finite coordinates, which are    */
+/*  used by the point location routines, but (mostly) ignored by the         */
+/*  Delaunay edge flip routines.                                             */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+void boundingbox(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void boundingbox(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri inftri;          /* Handle for the triangular bounding box. */
+  REAL width;
+
+  if (b->verbose) {
+    printf("  Creating triangular bounding box.\n");
+  }
+  /* Find the width (or height, whichever is larger) of the triangulation. */
+  width = m->xmax - m->xmin;
+  if (m->ymax - m->ymin > width) {
+    width = m->ymax - m->ymin;
+  }
+  if (width == 0.0) {
+    width = 1.0;
+  }
+  /* Create the vertices of the bounding box. */
+  m->infvertex1 = (vertex) trimalloc(m->vertices.itembytes);
+  m->infvertex2 = (vertex) trimalloc(m->vertices.itembytes);
+  m->infvertex3 = (vertex) trimalloc(m->vertices.itembytes);
+  m->infvertex1[0] = m->xmin - 50.0 * width;
+  m->infvertex1[1] = m->ymin - 40.0 * width;
+  m->infvertex2[0] = m->xmax + 50.0 * width;
+  m->infvertex2[1] = m->ymin - 40.0 * width;
+  m->infvertex3[0] = 0.5 * (m->xmin + m->xmax);
+  m->infvertex3[1] = m->ymax + 60.0 * width;
+
+  /* Create the bounding box. */
+  maketriangle(m, b, &inftri);
+  setorg(inftri, m->infvertex1);
+  setdest(inftri, m->infvertex2);
+  setapex(inftri, m->infvertex3);
+  /* Link dummytri to the bounding box so we can always find an */
+  /*   edge to begin searching (point location) from.           */
+  m->dummytri[0] = (triangle) inftri.tri;
+  if (b->verbose > 2) {
+    printf("  Creating ");
+    printtriangle(m, b, &inftri);
+  }
+}
+
+#endif /* not REDUCED */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  removebox()   Remove the "infinite" bounding triangle, setting boundary  */
+/*                markers as appropriate.                                    */
+/*                                                                           */
+/*  The triangular bounding box has three boundary triangles (one for each   */
+/*  side of the bounding box), and a bunch of triangles fanning out from     */
+/*  the three bounding box vertices (one triangle for each edge of the       */
+/*  convex hull of the inner mesh).  This routine removes these triangles.   */
+/*                                                                           */
+/*  Returns the number of edges on the convex hull of the triangulation.     */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+long removebox(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+long removebox(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri deadtriangle;
+  struct otri searchedge;
+  struct otri checkedge;
+  struct otri nextedge, finaledge, dissolveedge;
+  vertex markorg;
+  long hullsize;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+  if (b->verbose) {
+    printf("  Removing triangular bounding box.\n");
+  }
+  /* Find a boundary triangle. */
+  nextedge.tri = m->dummytri;
+  nextedge.orient = 0;
+  symself(nextedge);
+  /* Mark a place to stop. */
+  lprev(nextedge, finaledge);
+  lnextself(nextedge);
+  symself(nextedge);
+  /* Find a triangle (on the boundary of the vertex set) that isn't */
+  /*   a bounding box triangle.                                     */
+  lprev(nextedge, searchedge);
+  symself(searchedge);
+  /* Check whether nextedge is another boundary triangle */
+  /*   adjacent to the first one.                        */
+  lnext(nextedge, checkedge);
+  symself(checkedge);
+  if (checkedge.tri == m->dummytri) {
+    /* Go on to the next triangle.  There are only three boundary   */
+    /*   triangles, and this next triangle cannot be the third one, */
+    /*   so it's safe to stop here.                                 */
+    lprevself(searchedge);
+    symself(searchedge);
+  }
+  /* Find a new boundary edge to search from, as the current search */
+  /*   edge lies on a bounding box triangle and will be deleted.    */
+  m->dummytri[0] = encode(searchedge);
+  hullsize = -2l;
+  while (!otriequal(nextedge, finaledge)) {
+    hullsize++;
+    lprev(nextedge, dissolveedge);
+    symself(dissolveedge);
+    /* If not using a PSLG, the vertices should be marked now. */
+    /*   (If using a PSLG, markhull() will do the job.)        */
+    if (!b->poly) {
+      /* Be careful!  One must check for the case where all the input     */
+      /*   vertices are collinear, and thus all the triangles are part of */
+      /*   the bounding box.  Otherwise, the setvertexmark() call below   */
+      /*   will cause a bad pointer reference.                            */
+      if (dissolveedge.tri != m->dummytri) {
+        org(dissolveedge, markorg);
+        if (vertexmark(markorg) == 0) {
+          setvertexmark(markorg, 1);
+        }
+      }
+    }
+    /* Disconnect the bounding box triangle from the mesh triangle. */
+    dissolve(dissolveedge);
+    lnext(nextedge, deadtriangle);
+    sym(deadtriangle, nextedge);
+    /* Get rid of the bounding box triangle. */
+    triangledealloc(m, deadtriangle.tri);
+    /* Do we need to turn the corner? */
+    if (nextedge.tri == m->dummytri) {
+      /* Turn the corner. */
+      otricopy(dissolveedge, nextedge);
+    }
+  }
+  triangledealloc(m, finaledge.tri);
+
+  trifree((VOID *) m->infvertex1);  /* Deallocate the bounding box vertices. */
+  trifree((VOID *) m->infvertex2);
+  trifree((VOID *) m->infvertex3);
+
+  return hullsize;
+}
+
+#endif /* not REDUCED */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  incrementaldelaunay()   Form a Delaunay triangulation by incrementally   */
+/*                          inserting vertices.                              */
+/*                                                                           */
+/*  Returns the number of edges on the convex hull of the triangulation.     */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+long incrementaldelaunay(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+long incrementaldelaunay(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri starttri;
+  vertex vertexloop;
+
+  /* Create a triangular bounding box. */
+  boundingbox(m, b);
+  if (b->verbose) {
+    printf("  Incrementally inserting vertices.\n");
+  }
+  traversalinit(&m->vertices);
+  vertexloop = vertextraverse(m);
+  while (vertexloop != (vertex) NULL) {
+    starttri.tri = m->dummytri;
+    if (insertvertex(m, b, vertexloop, &starttri, (struct osub *) NULL, 0, 0)
+        == DUPLICATEVERTEX) {
+      if (!b->quiet) {
+        printf(
+"Warning:  A duplicate vertex at (%.12g, %.12g) appeared and was ignored.\n",
+               vertexloop[0], vertexloop[1]);
+      }
+      setvertextype(vertexloop, UNDEADVERTEX);
+      m->undeads++;
+    }
+    vertexloop = vertextraverse(m);
+  }
+  /* Remove the bounding box. */
+  return removebox(m, b);
+}
+
+#endif /* not REDUCED */
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Incremental Delaunay triangulation ends here              *********/
+
+/********* Sweepline Delaunay triangulation begins here              *********/
+/**                                                                         **/
+/**                                                                         **/
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+void eventheapinsert(struct event **heap, int heapsize, struct event *newevent)
+#else /* not ANSI_DECLARATORS */
+void eventheapinsert(heap, heapsize, newevent)
+struct event **heap;
+int heapsize;
+struct event *newevent;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  REAL eventx, eventy;
+  int eventnum;
+  int parent;
+  int notdone;
+
+  eventx = newevent->xkey;
+  eventy = newevent->ykey;
+  eventnum = heapsize;
+  notdone = eventnum > 0;
+  while (notdone) {
+    parent = (eventnum - 1) >> 1;
+    if ((heap[parent]->ykey < eventy) ||
+        ((heap[parent]->ykey == eventy)
+         && (heap[parent]->xkey <= eventx))) {
+      notdone = 0;
+    } else {
+      heap[eventnum] = heap[parent];
+      heap[eventnum]->heapposition = eventnum;
+
+      eventnum = parent;
+      notdone = eventnum > 0;
+    }
+  }
+  heap[eventnum] = newevent;
+  newevent->heapposition = eventnum;
+}
+
+#endif /* not REDUCED */
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+void eventheapify(struct event **heap, int heapsize, int eventnum)
+#else /* not ANSI_DECLARATORS */
+void eventheapify(heap, heapsize, eventnum)
+struct event **heap;
+int heapsize;
+int eventnum;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct event *thisevent;
+  REAL eventx, eventy;
+  int leftchild, rightchild;
+  int smallest;
+  int notdone;
+
+  thisevent = heap[eventnum];
+  eventx = thisevent->xkey;
+  eventy = thisevent->ykey;
+  leftchild = 2 * eventnum + 1;
+  notdone = leftchild < heapsize;
+  while (notdone) {
+    if ((heap[leftchild]->ykey < eventy) ||
+        ((heap[leftchild]->ykey == eventy)
+         && (heap[leftchild]->xkey < eventx))) {
+      smallest = leftchild;
+    } else {
+      smallest = eventnum;
+    }
+    rightchild = leftchild + 1;
+    if (rightchild < heapsize) {
+      if ((heap[rightchild]->ykey < heap[smallest]->ykey) ||
+          ((heap[rightchild]->ykey == heap[smallest]->ykey)
+           && (heap[rightchild]->xkey < heap[smallest]->xkey))) {
+        smallest = rightchild;
+      }
+    }
+    if (smallest == eventnum) {
+      notdone = 0;
+    } else {
+      heap[eventnum] = heap[smallest];
+      heap[eventnum]->heapposition = eventnum;
+      heap[smallest] = thisevent;
+      thisevent->heapposition = smallest;
+
+      eventnum = smallest;
+      leftchild = 2 * eventnum + 1;
+      notdone = leftchild < heapsize;
+    }
+  }
+}
+
+#endif /* not REDUCED */
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+void eventheapdelete(struct event **heap, int heapsize, int eventnum)
+#else /* not ANSI_DECLARATORS */
+void eventheapdelete(heap, heapsize, eventnum)
+struct event **heap;
+int heapsize;
+int eventnum;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct event *moveevent;
+  REAL eventx, eventy;
+  int parent;
+  int notdone;
+
+  moveevent = heap[heapsize - 1];
+  if (eventnum > 0) {
+    eventx = moveevent->xkey;
+    eventy = moveevent->ykey;
+    do {
+      parent = (eventnum - 1) >> 1;
+      if ((heap[parent]->ykey < eventy) ||
+          ((heap[parent]->ykey == eventy)
+           && (heap[parent]->xkey <= eventx))) {
+        notdone = 0;
+      } else {
+        heap[eventnum] = heap[parent];
+        heap[eventnum]->heapposition = eventnum;
+
+        eventnum = parent;
+        notdone = eventnum > 0;
+      }
+    } while (notdone);
+  }
+  heap[eventnum] = moveevent;
+  moveevent->heapposition = eventnum;
+  eventheapify(heap, heapsize - 1, eventnum);
+}
+
+#endif /* not REDUCED */
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+void createeventheap(struct mesh *m, struct event ***eventheap,
+                     struct event **events, struct event **freeevents)
+#else /* not ANSI_DECLARATORS */
+void createeventheap(m, eventheap, events, freeevents)
+struct mesh *m;
+struct event ***eventheap;
+struct event **events;
+struct event **freeevents;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  vertex thisvertex;
+  int maxevents;
+  int i;
+
+  maxevents = (3 * m->invertices) / 2;
+  *eventheap = (struct event **) trimalloc(maxevents *
+                                           (int) sizeof(struct event *));
+  *events = (struct event *) trimalloc(maxevents * (int) sizeof(struct event));
+  traversalinit(&m->vertices);
+  for (i = 0; i < m->invertices; i++) {
+    thisvertex = vertextraverse(m);
+    (*events)[i].eventptr = (VOID *) thisvertex;
+    (*events)[i].xkey = thisvertex[0];
+    (*events)[i].ykey = thisvertex[1];
+    eventheapinsert(*eventheap, i, *events + i);
+  }
+  *freeevents = (struct event *) NULL;
+  for (i = maxevents - 1; i >= m->invertices; i--) {
+    (*events)[i].eventptr = (VOID *) *freeevents;
+    *freeevents = *events + i;
+  }
+}
+
+#endif /* not REDUCED */
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+int rightofhyperbola(struct mesh *m, struct otri *fronttri, vertex newsite)
+#else /* not ANSI_DECLARATORS */
+int rightofhyperbola(m, fronttri, newsite)
+struct mesh *m;
+struct otri *fronttri;
+vertex newsite;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  vertex leftvertex, rightvertex;
+  REAL dxa, dya, dxb, dyb;
+
+  m->hyperbolacount++;
+
+  dest(*fronttri, leftvertex);
+  apex(*fronttri, rightvertex);
+  if ((leftvertex[1] < rightvertex[1]) ||
+      ((leftvertex[1] == rightvertex[1]) &&
+       (leftvertex[0] < rightvertex[0]))) {
+    if (newsite[0] >= rightvertex[0]) {
+      return 1;
+    }
+  } else {
+    if (newsite[0] <= leftvertex[0]) {
+      return 0;
+    }
+  }
+  dxa = leftvertex[0] - newsite[0];
+  dya = leftvertex[1] - newsite[1];
+  dxb = rightvertex[0] - newsite[0];
+  dyb = rightvertex[1] - newsite[1];
+  return dya * (dxb * dxb + dyb * dyb) > dyb * (dxa * dxa + dya * dya);
+}
+
+#endif /* not REDUCED */
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+REAL circletop(struct mesh *m, vertex pa, vertex pb, vertex pc, REAL ccwabc)
+#else /* not ANSI_DECLARATORS */
+REAL circletop(m, pa, pb, pc, ccwabc)
+struct mesh *m;
+vertex pa;
+vertex pb;
+vertex pc;
+REAL ccwabc;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  REAL xac, yac, xbc, ybc, xab, yab;
+  REAL aclen2, bclen2, ablen2;
+
+  m->circletopcount++;
+
+  xac = pa[0] - pc[0];
+  yac = pa[1] - pc[1];
+  xbc = pb[0] - pc[0];
+  ybc = pb[1] - pc[1];
+  xab = pa[0] - pb[0];
+  yab = pa[1] - pb[1];
+  aclen2 = xac * xac + yac * yac;
+  bclen2 = xbc * xbc + ybc * ybc;
+  ablen2 = xab * xab + yab * yab;
+  return pc[1] + (xac * bclen2 - xbc * aclen2 + sqrt(aclen2 * bclen2 * ablen2))
+               / (2.0 * ccwabc);
+}
+
+#endif /* not REDUCED */
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+void check4deadevent(struct otri *checktri, struct event **freeevents,
+                     struct event **eventheap, int *heapsize)
+#else /* not ANSI_DECLARATORS */
+void check4deadevent(checktri, freeevents, eventheap, heapsize)
+struct otri *checktri;
+struct event **freeevents;
+struct event **eventheap;
+int *heapsize;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct event *deadevent;
+  vertex eventvertex;
+  int eventnum;
+
+  org(*checktri, eventvertex);
+  if (eventvertex != (vertex) NULL) {
+    deadevent = (struct event *) eventvertex;
+    eventnum = deadevent->heapposition;
+    deadevent->eventptr = (VOID *) *freeevents;
+    *freeevents = deadevent;
+    eventheapdelete(eventheap, *heapsize, eventnum);
+    (*heapsize)--;
+    setorg(*checktri, NULL);
+  }
+}
+
+#endif /* not REDUCED */
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+struct splaynode *splay(struct mesh *m, struct splaynode *splaytree,
+                        vertex searchpoint, struct otri *searchtri)
+#else /* not ANSI_DECLARATORS */
+struct splaynode *splay(m, splaytree, searchpoint, searchtri)
+struct mesh *m;
+struct splaynode *splaytree;
+vertex searchpoint;
+struct otri *searchtri;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct splaynode *child, *grandchild;
+  struct splaynode *lefttree, *righttree;
+  struct splaynode *leftright;
+  vertex checkvertex;
+  int rightofroot, rightofchild;
+
+  if (splaytree == (struct splaynode *) NULL) {
+    return (struct splaynode *) NULL;
+  }
+  dest(splaytree->keyedge, checkvertex);
+  if (checkvertex == splaytree->keydest) {
+    rightofroot = rightofhyperbola(m, &splaytree->keyedge, searchpoint);
+    if (rightofroot) {
+      otricopy(splaytree->keyedge, *searchtri);
+      child = splaytree->rchild;
+    } else {
+      child = splaytree->lchild;
+    }
+    if (child == (struct splaynode *) NULL) {
+      return splaytree;
+    }
+    dest(child->keyedge, checkvertex);
+    if (checkvertex != child->keydest) {
+      child = splay(m, child, searchpoint, searchtri);
+      if (child == (struct splaynode *) NULL) {
+        if (rightofroot) {
+          splaytree->rchild = (struct splaynode *) NULL;
+        } else {
+          splaytree->lchild = (struct splaynode *) NULL;
+        }
+        return splaytree;
+      }
+    }
+    rightofchild = rightofhyperbola(m, &child->keyedge, searchpoint);
+    if (rightofchild) {
+      otricopy(child->keyedge, *searchtri);
+      grandchild = splay(m, child->rchild, searchpoint, searchtri);
+      child->rchild = grandchild;
+    } else {
+      grandchild = splay(m, child->lchild, searchpoint, searchtri);
+      child->lchild = grandchild;
+    }
+    if (grandchild == (struct splaynode *) NULL) {
+      if (rightofroot) {
+        splaytree->rchild = child->lchild;
+        child->lchild = splaytree;
+      } else {
+        splaytree->lchild = child->rchild;
+        child->rchild = splaytree;
+      }
+      return child;
+    }
+    if (rightofchild) {
+      if (rightofroot) {
+        splaytree->rchild = child->lchild;
+        child->lchild = splaytree;
+      } else {
+        splaytree->lchild = grandchild->rchild;
+        grandchild->rchild = splaytree;
+      }
+      child->rchild = grandchild->lchild;
+      grandchild->lchild = child;
+    } else {
+      if (rightofroot) {
+        splaytree->rchild = grandchild->lchild;
+        grandchild->lchild = splaytree;
+      } else {
+        splaytree->lchild = child->rchild;
+        child->rchild = splaytree;
+      }
+      child->lchild = grandchild->rchild;
+      grandchild->rchild = child;
+    }
+    return grandchild;
+  } else {
+    lefttree = splay(m, splaytree->lchild, searchpoint, searchtri);
+    righttree = splay(m, splaytree->rchild, searchpoint, searchtri);
+
+    pooldealloc(&m->splaynodes, (VOID *) splaytree);
+    if (lefttree == (struct splaynode *) NULL) {
+      return righttree;
+    } else if (righttree == (struct splaynode *) NULL) {
+      return lefttree;
+    } else if (lefttree->rchild == (struct splaynode *) NULL) {
+      lefttree->rchild = righttree->lchild;
+      righttree->lchild = lefttree;
+      return righttree;
+    } else if (righttree->lchild == (struct splaynode *) NULL) {
+      righttree->lchild = lefttree->rchild;
+      lefttree->rchild = righttree;
+      return lefttree;
+    } else {
+/*      printf("Holy Toledo!!!\n"); */
+      leftright = lefttree->rchild;
+      while (leftright->rchild != (struct splaynode *) NULL) {
+        leftright = leftright->rchild;
+      }
+      leftright->rchild = righttree;
+      return lefttree;
+    }
+  }
+}
+
+#endif /* not REDUCED */
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+struct splaynode *splayinsert(struct mesh *m, struct splaynode *splayroot,
+                              struct otri *newkey, vertex searchpoint)
+#else /* not ANSI_DECLARATORS */
+struct splaynode *splayinsert(m, splayroot, newkey, searchpoint)
+struct mesh *m;
+struct splaynode *splayroot;
+struct otri *newkey;
+vertex searchpoint;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct splaynode *newsplaynode;
+
+  newsplaynode = (struct splaynode *) poolalloc(&m->splaynodes);
+  otricopy(*newkey, newsplaynode->keyedge);
+  dest(*newkey, newsplaynode->keydest);
+  if (splayroot == (struct splaynode *) NULL) {
+    newsplaynode->lchild = (struct splaynode *) NULL;
+    newsplaynode->rchild = (struct splaynode *) NULL;
+  } else if (rightofhyperbola(m, &splayroot->keyedge, searchpoint)) {
+    newsplaynode->lchild = splayroot;
+    newsplaynode->rchild = splayroot->rchild;
+    splayroot->rchild = (struct splaynode *) NULL;
+  } else {
+    newsplaynode->lchild = splayroot->lchild;
+    newsplaynode->rchild = splayroot;
+    splayroot->lchild = (struct splaynode *) NULL;
+  }
+  return newsplaynode;
+}
+
+#endif /* not REDUCED */
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+struct splaynode *circletopinsert(struct mesh *m, struct behavior *b,
+                                  struct splaynode *splayroot,
+                                  struct otri *newkey,
+                                  vertex pa, vertex pb, vertex pc, REAL topy)
+#else /* not ANSI_DECLARATORS */
+struct splaynode *circletopinsert(m, b, splayroot, newkey, pa, pb, pc, topy)
+struct mesh *m;
+struct behavior *b;
+struct splaynode *splayroot;
+struct otri *newkey;
+vertex pa;
+vertex pb;
+vertex pc;
+REAL topy;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  REAL ccwabc;
+  REAL xac, yac, xbc, ybc;
+  REAL aclen2, bclen2;
+  REAL searchpoint[2];
+  struct otri dummytri;
+
+  ccwabc = counterclockwise(m, b, pa, pb, pc);
+  xac = pa[0] - pc[0];
+  yac = pa[1] - pc[1];
+  xbc = pb[0] - pc[0];
+  ybc = pb[1] - pc[1];
+  aclen2 = xac * xac + yac * yac;
+  bclen2 = xbc * xbc + ybc * ybc;
+  searchpoint[0] = pc[0] - (yac * bclen2 - ybc * aclen2) / (2.0 * ccwabc);
+  searchpoint[1] = topy;
+  return splayinsert(m, splay(m, splayroot, (vertex) searchpoint, &dummytri),
+                     newkey, (vertex) searchpoint);
+}
+
+#endif /* not REDUCED */
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+struct splaynode *frontlocate(struct mesh *m, struct splaynode *splayroot,
+                              struct otri *bottommost, vertex searchvertex,
+                              struct otri *searchtri, int *farright)
+#else /* not ANSI_DECLARATORS */
+struct splaynode *frontlocate(m, splayroot, bottommost, searchvertex,
+                              searchtri, farright)
+struct mesh *m;
+struct splaynode *splayroot;
+struct otri *bottommost;
+vertex searchvertex;
+struct otri *searchtri;
+int *farright;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  int farrightflag;
+  triangle ptr;                       /* Temporary variable used by onext(). */
+
+  otricopy(*bottommost, *searchtri);
+  splayroot = splay(m, splayroot, searchvertex, searchtri);
+
+  farrightflag = 0;
+  while (!farrightflag && rightofhyperbola(m, searchtri, searchvertex)) {
+    onextself(*searchtri);
+    farrightflag = otriequal(*searchtri, *bottommost);
+  }
+  *farright = farrightflag;
+  return splayroot;
+}
+
+#endif /* not REDUCED */
+
+#ifndef REDUCED
+
+#ifdef ANSI_DECLARATORS
+long sweeplinedelaunay(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+long sweeplinedelaunay(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct event **eventheap;
+  struct event *events;
+  struct event *freeevents;
+  struct event *nextevent;
+  struct event *newevent;
+  struct splaynode *splayroot;
+  struct otri bottommost;
+  struct otri searchtri;
+  struct otri fliptri;
+  struct otri lefttri, righttri, farlefttri, farrighttri;
+  struct otri inserttri;
+  vertex firstvertex, secondvertex;
+  vertex nextvertex, lastvertex;
+  vertex connectvertex;
+  vertex leftvertex, midvertex, rightvertex;
+  REAL lefttest, righttest;
+  int heapsize;
+  int check4events, farrightflag;
+  triangle ptr;   /* Temporary variable used by sym(), onext(), and oprev(). */
+
+  poolinit(&m->splaynodes, sizeof(struct splaynode), SPLAYNODEPERBLOCK,
+           SPLAYNODEPERBLOCK, 0);
+  splayroot = (struct splaynode *) NULL;
+
+  if (b->verbose) {
+    printf("  Placing vertices in event heap.\n");
+  }
+  createeventheap(m, &eventheap, &events, &freeevents);
+  heapsize = m->invertices;
+
+  if (b->verbose) {
+    printf("  Forming triangulation.\n");
+  }
+  maketriangle(m, b, &lefttri);
+  maketriangle(m, b, &righttri);
+  bond(lefttri, righttri);
+  lnextself(lefttri);
+  lprevself(righttri);
+  bond(lefttri, righttri);
+  lnextself(lefttri);
+  lprevself(righttri);
+  bond(lefttri, righttri);
+  firstvertex = (vertex) eventheap[0]->eventptr;
+  eventheap[0]->eventptr = (VOID *) freeevents;
+  freeevents = eventheap[0];
+  eventheapdelete(eventheap, heapsize, 0);
+  heapsize--;
+  do {
+    if (heapsize == 0) {
+      printf("Error:  Input vertices are all identical.\n");
+      triexit(1);
+    }
+    secondvertex = (vertex) eventheap[0]->eventptr;
+    eventheap[0]->eventptr = (VOID *) freeevents;
+    freeevents = eventheap[0];
+    eventheapdelete(eventheap, heapsize, 0);
+    heapsize--;
+    if ((firstvertex[0] == secondvertex[0]) &&
+        (firstvertex[1] == secondvertex[1])) {
+      if (!b->quiet) {
+        printf(
+"Warning:  A duplicate vertex at (%.12g, %.12g) appeared and was ignored.\n",
+               secondvertex[0], secondvertex[1]);
+      }
+      setvertextype(secondvertex, UNDEADVERTEX);
+      m->undeads++;
+    }
+  } while ((firstvertex[0] == secondvertex[0]) &&
+           (firstvertex[1] == secondvertex[1]));
+  setorg(lefttri, firstvertex);
+  setdest(lefttri, secondvertex);
+  setorg(righttri, secondvertex);
+  setdest(righttri, firstvertex);
+  lprev(lefttri, bottommost);
+  lastvertex = secondvertex;
+  while (heapsize > 0) {
+    nextevent = eventheap[0];
+    eventheapdelete(eventheap, heapsize, 0);
+    heapsize--;
+    check4events = 1;
+    if (nextevent->xkey < m->xmin) {
+      decode(nextevent->eventptr, fliptri);
+      oprev(fliptri, farlefttri);
+      check4deadevent(&farlefttri, &freeevents, eventheap, &heapsize);
+      onext(fliptri, farrighttri);
+      check4deadevent(&farrighttri, &freeevents, eventheap, &heapsize);
+
+      if (otriequal(farlefttri, bottommost)) {
+        lprev(fliptri, bottommost);
+      }
+      flip(m, b, &fliptri);
+      setapex(fliptri, NULL);
+      lprev(fliptri, lefttri);
+      lnext(fliptri, righttri);
+      sym(lefttri, farlefttri);
+
+      if (randomnation(SAMPLERATE) == 0) {
+        symself(fliptri);
+        dest(fliptri, leftvertex);
+        apex(fliptri, midvertex);
+        org(fliptri, rightvertex);
+        splayroot = circletopinsert(m, b, splayroot, &lefttri, leftvertex,
+                                    midvertex, rightvertex, nextevent->ykey);
+      }
+    } else {
+      nextvertex = (vertex) nextevent->eventptr;
+      if ((nextvertex[0] == lastvertex[0]) &&
+          (nextvertex[1] == lastvertex[1])) {
+        if (!b->quiet) {
+          printf(
+"Warning:  A duplicate vertex at (%.12g, %.12g) appeared and was ignored.\n",
+                 nextvertex[0], nextvertex[1]);
+        }
+        setvertextype(nextvertex, UNDEADVERTEX);
+        m->undeads++;
+        check4events = 0;
+      } else {
+        lastvertex = nextvertex;
+
+        splayroot = frontlocate(m, splayroot, &bottommost, nextvertex,
+                                &searchtri, &farrightflag);
+/*
+        otricopy(bottommost, searchtri);
+        farrightflag = 0;
+        while (!farrightflag && rightofhyperbola(m, &searchtri, nextvertex)) {
+          onextself(searchtri);
+          farrightflag = otriequal(searchtri, bottommost);
+        }
+*/
+
+        check4deadevent(&searchtri, &freeevents, eventheap, &heapsize);
+
+        otricopy(searchtri, farrighttri);
+        sym(searchtri, farlefttri);
+        maketriangle(m, b, &lefttri);
+        maketriangle(m, b, &righttri);
+        dest(farrighttri, connectvertex);
+        setorg(lefttri, connectvertex);
+        setdest(lefttri, nextvertex);
+        setorg(righttri, nextvertex);
+        setdest(righttri, connectvertex);
+        bond(lefttri, righttri);
+        lnextself(lefttri);
+        lprevself(righttri);
+        bond(lefttri, righttri);
+        lnextself(lefttri);
+        lprevself(righttri);
+        bond(lefttri, farlefttri);
+        bond(righttri, farrighttri);
+        if (!farrightflag && otriequal(farrighttri, bottommost)) {
+          otricopy(lefttri, bottommost);
+        }
+
+        if (randomnation(SAMPLERATE) == 0) {
+          splayroot = splayinsert(m, splayroot, &lefttri, nextvertex);
+        } else if (randomnation(SAMPLERATE) == 0) {
+          lnext(righttri, inserttri);
+          splayroot = splayinsert(m, splayroot, &inserttri, nextvertex);
+        }
+      }
+    }
+    nextevent->eventptr = (VOID *) freeevents;
+    freeevents = nextevent;
+
+    if (check4events) {
+      apex(farlefttri, leftvertex);
+      dest(lefttri, midvertex);
+      apex(lefttri, rightvertex);
+      lefttest = counterclockwise(m, b, leftvertex, midvertex, rightvertex);
+      if (lefttest > 0.0) {
+        newevent = freeevents;
+        freeevents = (struct event *) freeevents->eventptr;
+        newevent->xkey = m->xminextreme;
+        newevent->ykey = circletop(m, leftvertex, midvertex, rightvertex,
+                                   lefttest);
+        newevent->eventptr = (VOID *) encode(lefttri);
+        eventheapinsert(eventheap, heapsize, newevent);
+        heapsize++;
+        setorg(lefttri, newevent);
+      }
+      apex(righttri, leftvertex);
+      org(righttri, midvertex);
+      apex(farrighttri, rightvertex);
+      righttest = counterclockwise(m, b, leftvertex, midvertex, rightvertex);
+      if (righttest > 0.0) {
+        newevent = freeevents;
+        freeevents = (struct event *) freeevents->eventptr;
+        newevent->xkey = m->xminextreme;
+        newevent->ykey = circletop(m, leftvertex, midvertex, rightvertex,
+                                   righttest);
+        newevent->eventptr = (VOID *) encode(farrighttri);
+        eventheapinsert(eventheap, heapsize, newevent);
+        heapsize++;
+        setorg(farrighttri, newevent);
+      }
+    }
+  }
+
+  pooldeinit(&m->splaynodes);
+  lprevself(bottommost);
+  return removeghosts(m, b, &bottommost);
+}
+
+#endif /* not REDUCED */
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Sweepline Delaunay triangulation ends here                *********/
+
+/********* General mesh construction routines begin here             *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  delaunay()   Form a Delaunay triangulation.                              */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+long delaunay(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+long delaunay(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  long hulledges;
+
+  m->eextras = 0;
+  initializetrisubpools(m, b);
+
+#ifdef REDUCED
+  if (!b->quiet) {
+    printf(
+      "Constructing Delaunay triangulation by divide-and-conquer method.\n");
+  }
+  hulledges = divconqdelaunay(m, b);
+#else /* not REDUCED */
+  if (!b->quiet) {
+    printf("Constructing Delaunay triangulation ");
+    if (b->incremental) {
+      printf("by incremental method.\n");
+    } else if (b->sweepline) {
+      printf("by sweepline method.\n");
+    } else {
+      printf("by divide-and-conquer method.\n");
+    }
+  }
+  if (b->incremental) {
+    hulledges = incrementaldelaunay(m, b);
+  } else if (b->sweepline) {
+    hulledges = sweeplinedelaunay(m, b);
+  } else {
+    hulledges = divconqdelaunay(m, b);
+  }
+#endif /* not REDUCED */
+
+  if (m->triangles.items == 0) {
+    /* The input vertices were all collinear, so there are no triangles. */
+    return 0l;
+  } else {
+    return hulledges;
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  reconstruct()   Reconstruct a triangulation from its .ele (and possibly  */
+/*                  .poly) file.  Used when the -r switch is used.           */
+/*                                                                           */
+/*  Reads an .ele file and reconstructs the original mesh.  If the -p switch */
+/*  is used, this procedure will also read a .poly file and reconstruct the  */
+/*  subsegments of the original mesh.  If the -a switch is used, this        */
+/*  procedure will also read an .area file and set a maximum area constraint */
+/*  on each triangle.                                                        */
+/*                                                                           */
+/*  Vertices that are not corners of triangles, such as nodes on edges of    */
+/*  subparametric elements, are discarded.                                   */
+/*                                                                           */
+/*  This routine finds the adjacencies between triangles (and subsegments)   */
+/*  by forming one stack of triangles for each vertex.  Each triangle is on  */
+/*  three different stacks simultaneously.  Each triangle's subsegment       */
+/*  pointers are used to link the items in each stack.  This memory-saving   */
+/*  feature makes the code harder to read.  The most important thing to keep */
+/*  in mind is that each triangle is removed from a stack precisely when     */
+/*  the corresponding pointer is adjusted to refer to a subsegment rather    */
+/*  than the next triangle of the stack.                                     */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef CDT_ONLY
+
+#ifdef TRILIBRARY
+
+#ifdef ANSI_DECLARATORS
+int reconstruct(struct mesh *m, struct behavior *b, int *trianglelist,
+                REAL *triangleattriblist, REAL *trianglearealist,
+                int elements, int corners, int attribs,
+                int *segmentlist,int *segmentmarkerlist, int numberofsegments)
+#else /* not ANSI_DECLARATORS */
+int reconstruct(m, b, trianglelist, triangleattriblist, trianglearealist,
+                elements, corners, attribs, segmentlist, segmentmarkerlist,
+                numberofsegments)
+struct mesh *m;
+struct behavior *b;
+int *trianglelist;
+REAL *triangleattriblist;
+REAL *trianglearealist;
+int elements;
+int corners;
+int attribs;
+int *segmentlist;
+int *segmentmarkerlist;
+int numberofsegments;
+#endif /* not ANSI_DECLARATORS */
+
+#else /* not TRILIBRARY */
+
+#ifdef ANSI_DECLARATORS
+long reconstruct(struct mesh *m, struct behavior *b, char *elefilename,
+                 char *areafilename, char *polyfilename, FILE *polyfile)
+#else /* not ANSI_DECLARATORS */
+long reconstruct(m, b, elefilename, areafilename, polyfilename, polyfile)
+struct mesh *m;
+struct behavior *b;
+char *elefilename;
+char *areafilename;
+char *polyfilename;
+FILE *polyfile;
+#endif /* not ANSI_DECLARATORS */
+
+#endif /* not TRILIBRARY */
+
+{
+#ifdef TRILIBRARY
+  int vertexindex;
+  int attribindex;
+#else /* not TRILIBRARY */
+  FILE *elefile;
+  FILE *areafile;
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  int areaelements;
+#endif /* not TRILIBRARY */
+  struct otri triangleloop;
+  struct otri triangleleft;
+  struct otri checktri;
+  struct otri checkleft;
+  struct otri checkneighbor;
+  struct osub subsegloop;
+  triangle *vertexarray;
+  triangle *prevlink;
+  triangle nexttri;
+  vertex tdest, tapex;
+  vertex checkdest, checkapex;
+  vertex shorg;
+  vertex killvertex;
+  vertex segmentorg, segmentdest;
+  REAL area;
+  int corner[3];
+  int end[2];
+  int killvertexindex;
+  int incorners;
+  int segmentmarkers;
+  int boundmarker;
+  int aroundvertex;
+  long hullsize;
+  int notfound;
+  long elementnumber, segmentnumber;
+  int i, j;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+#ifdef TRILIBRARY
+  m->inelements = elements;
+  incorners = corners;
+  if (incorners < 3) {
+    printf("Error:  Triangles must have at least 3 vertices.\n");
+    triexit(1);
+  }
+  m->eextras = attribs;
+#else /* not TRILIBRARY */
+  /* Read the triangles from an .ele file. */
+  if (!b->quiet) {
+    printf("Opening %s.\n", elefilename);
+  }
+  elefile = fopen(elefilename, "r");
+  if (elefile == (FILE *) NULL) {
+    printf("  Error:  Cannot access file %s.\n", elefilename);
+    triexit(1);
+  }
+  /* Read number of triangles, number of vertices per triangle, and */
+  /*   number of triangle attributes from .ele file.                */
+  stringptr = readline(inputline, elefile, elefilename);
+  m->inelements = (int) strtol(stringptr, &stringptr, 0);
+  stringptr = findfield(stringptr);
+  if (*stringptr == '\0') {
+    incorners = 3;
+  } else {
+    incorners = (int) strtol(stringptr, &stringptr, 0);
+    if (incorners < 3) {
+      printf("Error:  Triangles in %s must have at least 3 vertices.\n",
+             elefilename);
+      triexit(1);
+    }
+  }
+  stringptr = findfield(stringptr);
+  if (*stringptr == '\0') {
+    m->eextras = 0;
+  } else {
+    m->eextras = (int) strtol(stringptr, &stringptr, 0);
+  }
+#endif /* not TRILIBRARY */
+
+  initializetrisubpools(m, b);
+
+  /* Create the triangles. */
+  for (elementnumber = 1; elementnumber <= m->inelements; elementnumber++) {
+    maketriangle(m, b, &triangleloop);
+    /* Mark the triangle as living. */
+    triangleloop.tri[3] = (triangle) triangleloop.tri;
+  }
+
+  segmentmarkers = 0;
+  if (b->poly) {
+#ifdef TRILIBRARY
+    m->insegments = numberofsegments;
+    segmentmarkers = segmentmarkerlist != (int *) NULL;
+#else /* not TRILIBRARY */
+    /* Read number of segments and number of segment */
+    /*   boundary markers from .poly file.           */
+    stringptr = readline(inputline, polyfile, b->inpolyfilename);
+    m->insegments = (int) strtol(stringptr, &stringptr, 0);
+    stringptr = findfield(stringptr);
+    if (*stringptr != '\0') {
+      segmentmarkers = (int) strtol(stringptr, &stringptr, 0);
+    }
+#endif /* not TRILIBRARY */
+
+    /* Create the subsegments. */
+    for (segmentnumber = 1; segmentnumber <= m->insegments; segmentnumber++) {
+      makesubseg(m, &subsegloop);
+      /* Mark the subsegment as living. */
+      subsegloop.ss[2] = (subseg) subsegloop.ss;
+    }
+  }
+
+#ifdef TRILIBRARY
+  vertexindex = 0;
+  attribindex = 0;
+#else /* not TRILIBRARY */
+  if (b->vararea) {
+    /* Open an .area file, check for consistency with the .ele file. */
+    if (!b->quiet) {
+      printf("Opening %s.\n", areafilename);
+    }
+    areafile = fopen(areafilename, "r");
+    if (areafile == (FILE *) NULL) {
+      printf("  Error:  Cannot access file %s.\n", areafilename);
+      triexit(1);
+    }
+    stringptr = readline(inputline, areafile, areafilename);
+    areaelements = (int) strtol(stringptr, &stringptr, 0);
+    if (areaelements != m->inelements) {
+      printf("Error:  %s and %s disagree on number of triangles.\n",
+             elefilename, areafilename);
+      triexit(1);
+    }
+  }
+#endif /* not TRILIBRARY */
+
+  if (!b->quiet) {
+    printf("Reconstructing mesh.\n");
+  }
+  /* Allocate a temporary array that maps each vertex to some adjacent */
+  /*   triangle.  I took care to allocate all the permanent memory for */
+  /*   triangles and subsegments first.                                */
+  vertexarray = (triangle *) trimalloc(m->vertices.items *
+                                       (int) sizeof(triangle));
+  /* Each vertex is initially unrepresented. */
+  for (i = 0; i < m->vertices.items; i++) {
+    vertexarray[i] = (triangle) m->dummytri;
+  }
+
+  if (b->verbose) {
+    printf("  Assembling triangles.\n");
+  }
+  /* Read the triangles from the .ele file, and link */
+  /*   together those that share an edge.            */
+  traversalinit(&m->triangles);
+  triangleloop.tri = triangletraverse(m);
+  elementnumber = b->firstnumber;
+  while (triangleloop.tri != (triangle *) NULL) {
+#ifdef TRILIBRARY
+    /* Copy the triangle's three corners. */
+    for (j = 0; j < 3; j++) {
+      corner[j] = trianglelist[vertexindex++];
+      if ((corner[j] < b->firstnumber) ||
+          (corner[j] >= b->firstnumber + m->invertices)) {
+        printf("Error:  Triangle %ld has an invalid vertex index.\n",
+               elementnumber);
+        triexit(1);
+      }
+    }
+#else /* not TRILIBRARY */
+    /* Read triangle number and the triangle's three corners. */
+    stringptr = readline(inputline, elefile, elefilename);
+    for (j = 0; j < 3; j++) {
+      stringptr = findfield(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  Triangle %ld is missing vertex %d in %s.\n",
+               elementnumber, j + 1, elefilename);
+        triexit(1);
+      } else {
+        corner[j] = (int) strtol(stringptr, &stringptr, 0);
+        if ((corner[j] < b->firstnumber) ||
+            (corner[j] >= b->firstnumber + m->invertices)) {
+          printf("Error:  Triangle %ld has an invalid vertex index.\n",
+                 elementnumber);
+          triexit(1);
+        }
+      }
+    }
+#endif /* not TRILIBRARY */
+
+    /* Find out about (and throw away) extra nodes. */
+    for (j = 3; j < incorners; j++) {
+#ifdef TRILIBRARY
+      killvertexindex = trianglelist[vertexindex++];
+#else /* not TRILIBRARY */
+      stringptr = findfield(stringptr);
+      if (*stringptr != '\0') {
+        killvertexindex = (int) strtol(stringptr, &stringptr, 0);
+#endif /* not TRILIBRARY */
+        if ((killvertexindex >= b->firstnumber) &&
+            (killvertexindex < b->firstnumber + m->invertices)) {
+          /* Delete the non-corner vertex if it's not already deleted. */
+          killvertex = getvertex(m, b, killvertexindex);
+          if (vertextype(killvertex) != DEADVERTEX) {
+            vertexdealloc(m, killvertex);
+          }
+        }
+#ifndef TRILIBRARY
+      }
+#endif /* not TRILIBRARY */
+    }
+
+    /* Read the triangle's attributes. */
+    for (j = 0; j < m->eextras; j++) {
+#ifdef TRILIBRARY
+      setelemattribute(triangleloop, j, triangleattriblist[attribindex++]);
+#else /* not TRILIBRARY */
+      stringptr = findfield(stringptr);
+      if (*stringptr == '\0') {
+        setelemattribute(triangleloop, j, 0);
+      } else {
+        setelemattribute(triangleloop, j,
+                         (REAL) strtod(stringptr, &stringptr));
+      }
+#endif /* not TRILIBRARY */
+    }
+
+    if (b->vararea) {
+#ifdef TRILIBRARY
+      area = trianglearealist[elementnumber - b->firstnumber];
+#else /* not TRILIBRARY */
+      /* Read an area constraint from the .area file. */
+      stringptr = readline(inputline, areafile, areafilename);
+      stringptr = findfield(stringptr);
+      if (*stringptr == '\0') {
+        area = -1.0;                      /* No constraint on this triangle. */
+      } else {
+        area = (REAL) strtod(stringptr, &stringptr);
+      }
+#endif /* not TRILIBRARY */
+      setareabound(triangleloop, area);
+    }
+
+    /* Set the triangle's vertices. */
+    triangleloop.orient = 0;
+    setorg(triangleloop, getvertex(m, b, corner[0]));
+    setdest(triangleloop, getvertex(m, b, corner[1]));
+    setapex(triangleloop, getvertex(m, b, corner[2]));
+    /* Try linking the triangle to others that share these vertices. */
+    for (triangleloop.orient = 0; triangleloop.orient < 3;
+         triangleloop.orient++) {
+      /* Take the number for the origin of triangleloop. */
+      aroundvertex = corner[triangleloop.orient];
+      /* Look for other triangles having this vertex. */
+      nexttri = vertexarray[aroundvertex - b->firstnumber];
+      /* Link the current triangle to the next one in the stack. */
+      triangleloop.tri[6 + triangleloop.orient] = nexttri;
+      /* Push the current triangle onto the stack. */
+      vertexarray[aroundvertex - b->firstnumber] = encode(triangleloop);
+      decode(nexttri, checktri);
+      if (checktri.tri != m->dummytri) {
+        dest(triangleloop, tdest);
+        apex(triangleloop, tapex);
+        /* Look for other triangles that share an edge. */
+        do {
+          dest(checktri, checkdest);
+          apex(checktri, checkapex);
+          if (tapex == checkdest) {
+            /* The two triangles share an edge; bond them together. */
+            lprev(triangleloop, triangleleft);
+            bond(triangleleft, checktri);
+          }
+          if (tdest == checkapex) {
+            /* The two triangles share an edge; bond them together. */
+            lprev(checktri, checkleft);
+            bond(triangleloop, checkleft);
+          }
+          /* Find the next triangle in the stack. */
+          nexttri = checktri.tri[6 + checktri.orient];
+          decode(nexttri, checktri);
+        } while (checktri.tri != m->dummytri);
+      }
+    }
+    triangleloop.tri = triangletraverse(m);
+    elementnumber++;
+  }
+
+#ifdef TRILIBRARY
+  vertexindex = 0;
+#else /* not TRILIBRARY */
+  fclose(elefile);
+  if (b->vararea) {
+    fclose(areafile);
+  }
+#endif /* not TRILIBRARY */
+
+  hullsize = 0;                      /* Prepare to count the boundary edges. */
+  if (b->poly) {
+    if (b->verbose) {
+      printf("  Marking segments in triangulation.\n");
+    }
+    /* Read the segments from the .poly file, and link them */
+    /*   to their neighboring triangles.                    */
+    boundmarker = 0;
+    traversalinit(&m->subsegs);
+    subsegloop.ss = subsegtraverse(m);
+    segmentnumber = b->firstnumber;
+    while (subsegloop.ss != (subseg *) NULL) {
+#ifdef TRILIBRARY
+      end[0] = segmentlist[vertexindex++];
+      end[1] = segmentlist[vertexindex++];
+      if (segmentmarkers) {
+        boundmarker = segmentmarkerlist[segmentnumber - b->firstnumber];
+      }
+#else /* not TRILIBRARY */
+      /* Read the endpoints of each segment, and possibly a boundary marker. */
+      stringptr = readline(inputline, polyfile, b->inpolyfilename);
+      /* Skip the first (segment number) field. */
+      stringptr = findfield(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  Segment %ld has no endpoints in %s.\n", segmentnumber,
+               polyfilename);
+        triexit(1);
+      } else {
+        end[0] = (int) strtol(stringptr, &stringptr, 0);
+      }
+      stringptr = findfield(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  Segment %ld is missing its second endpoint in %s.\n",
+               segmentnumber, polyfilename);
+        triexit(1);
+      } else {
+        end[1] = (int) strtol(stringptr, &stringptr, 0);
+      }
+      if (segmentmarkers) {
+        stringptr = findfield(stringptr);
+        if (*stringptr == '\0') {
+          boundmarker = 0;
+        } else {
+          boundmarker = (int) strtol(stringptr, &stringptr, 0);
+        }
+      }
+#endif /* not TRILIBRARY */
+      for (j = 0; j < 2; j++) {
+        if ((end[j] < b->firstnumber) ||
+            (end[j] >= b->firstnumber + m->invertices)) {
+          printf("Error:  Segment %ld has an invalid vertex index.\n", 
+                 segmentnumber);
+          triexit(1);
+        }
+      }
+
+      /* set the subsegment's vertices. */
+      subsegloop.ssorient = 0;
+      segmentorg = getvertex(m, b, end[0]);
+      segmentdest = getvertex(m, b, end[1]);
+      setsorg(subsegloop, segmentorg);
+      setsdest(subsegloop, segmentdest);
+      setsegorg(subsegloop, segmentorg);
+      setsegdest(subsegloop, segmentdest);
+      setmark(subsegloop, boundmarker);
+      /* Try linking the subsegment to triangles that share these vertices. */
+      for (subsegloop.ssorient = 0; subsegloop.ssorient < 2;
+           subsegloop.ssorient++) {
+        /* Take the number for the destination of subsegloop. */
+        aroundvertex = end[1 - subsegloop.ssorient];
+        /* Look for triangles having this vertex. */
+        prevlink = &vertexarray[aroundvertex - b->firstnumber];
+        nexttri = vertexarray[aroundvertex - b->firstnumber];
+        decode(nexttri, checktri);
+        sorg(subsegloop, shorg);
+        notfound = 1;
+        /* Look for triangles having this edge.  Note that I'm only       */
+        /*   comparing each triangle's destination with the subsegment;   */
+        /*   each triangle's apex is handled through a different vertex.  */
+        /*   Because each triangle appears on three vertices' lists, each */
+        /*   occurrence of a triangle on a list can (and does) represent  */
+        /*   an edge.  In this way, most edges are represented twice, and */
+        /*   every triangle-subsegment bond is represented once.          */
+        while (notfound && (checktri.tri != m->dummytri)) {
+          dest(checktri, checkdest);
+          if (shorg == checkdest) {
+            /* We have a match.  Remove this triangle from the list. */
+            *prevlink = checktri.tri[6 + checktri.orient];
+            /* Bond the subsegment to the triangle. */
+            tsbond(checktri, subsegloop);
+            /* Check if this is a boundary edge. */
+            sym(checktri, checkneighbor);
+            if (checkneighbor.tri == m->dummytri) {
+              /* The next line doesn't insert a subsegment (because there's */
+              /*   already one there), but it sets the boundary markers of  */
+              /*   the existing subsegment and its vertices.                */
+              insertsubseg(m, b, &checktri, 1);
+              hullsize++;
+            }
+            notfound = 0;
+          }
+          /* Find the next triangle in the stack. */
+          prevlink = &checktri.tri[6 + checktri.orient];
+          nexttri = checktri.tri[6 + checktri.orient];
+          decode(nexttri, checktri);
+        }
+      }
+      subsegloop.ss = subsegtraverse(m);
+      segmentnumber++;
+    }
+  }
+
+  /* Mark the remaining edges as not being attached to any subsegment. */
+  /* Also, count the (yet uncounted) boundary edges.                   */
+  for (i = 0; i < m->vertices.items; i++) {
+    /* Search the stack of triangles adjacent to a vertex. */
+    nexttri = vertexarray[i];
+    decode(nexttri, checktri);
+    while (checktri.tri != m->dummytri) {
+      /* Find the next triangle in the stack before this */
+      /*   information gets overwritten.                 */
+      nexttri = checktri.tri[6 + checktri.orient];
+      /* No adjacent subsegment.  (This overwrites the stack info.) */
+      tsdissolve(checktri);
+      sym(checktri, checkneighbor);
+      if (checkneighbor.tri == m->dummytri) {
+        insertsubseg(m, b, &checktri, 1);
+        hullsize++;
+      }
+      decode(nexttri, checktri);
+    }
+  }
+
+  trifree((VOID *) vertexarray);
+  return hullsize;
+}
+
+#endif /* not CDT_ONLY */
+
+/**                                                                         **/
+/**                                                                         **/
+/********* General mesh construction routines end here               *********/
+
+/********* Segment insertion begins here                             *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  finddirection()   Find the first triangle on the path from one point     */
+/*                    to another.                                            */
+/*                                                                           */
+/*  Finds the triangle that intersects a line segment drawn from the         */
+/*  origin of `searchtri' to the point `searchpoint', and returns the result */
+/*  in `searchtri'.  The origin of `searchtri' does not change, even though  */
+/*  the triangle returned may differ from the one passed in.  This routine   */
+/*  is used to find the direction to move in to get from one point to        */
+/*  another.                                                                 */
+/*                                                                           */
+/*  The return value notes whether the destination or apex of the found      */
+/*  triangle is collinear with the two points in question.                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+enum finddirectionresult finddirection(struct mesh *m, struct behavior *b,
+                                       struct otri *searchtri,
+                                       vertex searchpoint)
+#else /* not ANSI_DECLARATORS */
+enum finddirectionresult finddirection(m, b, searchtri, searchpoint)
+struct mesh *m;
+struct behavior *b;
+struct otri *searchtri;
+vertex searchpoint;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri checktri;
+  vertex startvertex;
+  vertex leftvertex, rightvertex;
+  REAL leftccw, rightccw;
+  int leftflag, rightflag;
+  triangle ptr;           /* Temporary variable used by onext() and oprev(). */
+
+  org(*searchtri, startvertex);
+  dest(*searchtri, rightvertex);
+  apex(*searchtri, leftvertex);
+  /* Is `searchpoint' to the left? */
+  leftccw = counterclockwise(m, b, searchpoint, startvertex, leftvertex);
+  leftflag = leftccw > 0.0;
+  /* Is `searchpoint' to the right? */
+  rightccw = counterclockwise(m, b, startvertex, searchpoint, rightvertex);
+  rightflag = rightccw > 0.0;
+  if (leftflag && rightflag) {
+    /* `searchtri' faces directly away from `searchpoint'.  We could go left */
+    /*   or right.  Ask whether it's a triangle or a boundary on the left.   */
+    onext(*searchtri, checktri);
+    if (checktri.tri == m->dummytri) {
+      leftflag = 0;
+    } else {
+      rightflag = 0;
+    }
+  }
+  while (leftflag) {
+    /* Turn left until satisfied. */
+    onextself(*searchtri);
+    if (searchtri->tri == m->dummytri) {
+      printf("Internal error in finddirection():  Unable to find a\n");
+      printf("  triangle leading from (%.12g, %.12g) to", startvertex[0],
+             startvertex[1]);
+      printf("  (%.12g, %.12g).\n", searchpoint[0], searchpoint[1]);
+      internalerror();
+    }
+    apex(*searchtri, leftvertex);
+    rightccw = leftccw;
+    leftccw = counterclockwise(m, b, searchpoint, startvertex, leftvertex);
+    leftflag = leftccw > 0.0;
+  }
+  while (rightflag) {
+    /* Turn right until satisfied. */
+    oprevself(*searchtri);
+    if (searchtri->tri == m->dummytri) {
+      printf("Internal error in finddirection():  Unable to find a\n");
+      printf("  triangle leading from (%.12g, %.12g) to", startvertex[0],
+             startvertex[1]);
+      printf("  (%.12g, %.12g).\n", searchpoint[0], searchpoint[1]);
+      internalerror();
+    }
+    dest(*searchtri, rightvertex);
+    leftccw = rightccw;
+    rightccw = counterclockwise(m, b, startvertex, searchpoint, rightvertex);
+    rightflag = rightccw > 0.0;
+  }
+  if (leftccw == 0.0) {
+    return LEFTCOLLINEAR;
+  } else if (rightccw == 0.0) {
+    return RIGHTCOLLINEAR;
+  } else {
+    return WITHIN;
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  segmentintersection()   Find the intersection of an existing segment     */
+/*                          and a segment that is being inserted.  Insert    */
+/*                          a vertex at the intersection, splitting an       */
+/*                          existing subsegment.                             */
+/*                                                                           */
+/*  The segment being inserted connects the apex of splittri to endpoint2.   */
+/*  splitsubseg is the subsegment being split, and MUST adjoin splittri.     */
+/*  Hence, endpoints of the subsegment being split are the origin and        */
+/*  destination of splittri.                                                 */
+/*                                                                           */
+/*  On completion, splittri is a handle having the newly inserted            */
+/*  intersection point as its origin, and endpoint1 as its destination.      */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void segmentintersection(struct mesh *m, struct behavior *b,
+                         struct otri *splittri, struct osub *splitsubseg,
+                         vertex endpoint2)
+#else /* not ANSI_DECLARATORS */
+void segmentintersection(m, b, splittri, splitsubseg, endpoint2)
+struct mesh *m;
+struct behavior *b;
+struct otri *splittri;
+struct osub *splitsubseg;
+vertex endpoint2;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct osub opposubseg;
+  vertex endpoint1;
+  vertex torg, tdest;
+  vertex leftvertex, rightvertex;
+  vertex newvertex;
+  enum insertvertexresult success;
+  enum finddirectionresult collinear;
+  REAL ex, ey;
+  REAL tx, ty;
+  REAL etx, ety;
+  REAL split, denom;
+  int i;
+  triangle ptr;                       /* Temporary variable used by onext(). */
+  subseg sptr;                        /* Temporary variable used by snext(). */
+
+  /* Find the other three segment endpoints. */
+  apex(*splittri, endpoint1);
+  org(*splittri, torg);
+  dest(*splittri, tdest);
+  /* Segment intersection formulae; see the Antonio reference. */
+  tx = tdest[0] - torg[0];
+  ty = tdest[1] - torg[1];
+  ex = endpoint2[0] - endpoint1[0];
+  ey = endpoint2[1] - endpoint1[1];
+  etx = torg[0] - endpoint2[0];
+  ety = torg[1] - endpoint2[1];
+  denom = ty * ex - tx * ey;
+  if (denom == 0.0) {
+    printf("Internal error in segmentintersection():");
+    printf("  Attempt to find intersection of parallel segments.\n");
+    internalerror();
+  }
+  split = (ey * etx - ex * ety) / denom;
+  /* Create the new vertex. */
+  newvertex = (vertex) poolalloc(&m->vertices);
+  /* Interpolate its coordinate and attributes. */
+  for (i = 0; i < 2 + m->nextras; i++) {
+    newvertex[i] = torg[i] + split * (tdest[i] - torg[i]);
+  }
+  setvertexmark(newvertex, mark(*splitsubseg));
+  setvertextype(newvertex, INPUTVERTEX);
+  if (b->verbose > 1) {
+    printf(
+  "  Splitting subsegment (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n",
+           torg[0], torg[1], tdest[0], tdest[1], newvertex[0], newvertex[1]);
+  }
+  /* Insert the intersection vertex.  This should always succeed. */
+  success = insertvertex(m, b, newvertex, splittri, splitsubseg, 0, 0);
+  if (success != SUCCESSFULVERTEX) {
+    printf("Internal error in segmentintersection():\n");
+    printf("  Failure to split a segment.\n");
+    internalerror();
+  }
+  /* Record a triangle whose origin is the new vertex. */
+  setvertex2tri(newvertex, encode(*splittri));
+  if (m->steinerleft > 0) {
+    m->steinerleft--;
+  }
+
+  /* Divide the segment into two, and correct the segment endpoints. */
+  ssymself(*splitsubseg);
+  spivot(*splitsubseg, opposubseg);
+  sdissolve(*splitsubseg);
+  sdissolve(opposubseg);
+  do {
+    setsegorg(*splitsubseg, newvertex);
+    snextself(*splitsubseg);
+  } while (splitsubseg->ss != m->dummysub);
+  do {
+    setsegorg(opposubseg, newvertex);
+    snextself(opposubseg);
+  } while (opposubseg.ss != m->dummysub);
+
+  /* Inserting the vertex may have caused edge flips.  We wish to rediscover */
+  /*   the edge connecting endpoint1 to the new intersection vertex.         */
+  collinear = finddirection(m, b, splittri, endpoint1);
+  dest(*splittri, rightvertex);
+  apex(*splittri, leftvertex);
+  if ((leftvertex[0] == endpoint1[0]) && (leftvertex[1] == endpoint1[1])) {
+    onextself(*splittri);
+  } else if ((rightvertex[0] != endpoint1[0]) ||
+             (rightvertex[1] != endpoint1[1])) {
+    printf("Internal error in segmentintersection():\n");
+    printf("  Topological inconsistency after splitting a segment.\n");
+    internalerror();
+  }
+  /* `splittri' should have destination endpoint1. */
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  scoutsegment()   Scout the first triangle on the path from one endpoint  */
+/*                   to another, and check for completion (reaching the      */
+/*                   second endpoint), a collinear vertex, or the            */
+/*                   intersection of two segments.                           */
+/*                                                                           */
+/*  Returns one if the entire segment is successfully inserted, and zero if  */
+/*  the job must be finished by conformingedge() or constrainededge().       */
+/*                                                                           */
+/*  If the first triangle on the path has the second endpoint as its         */
+/*  destination or apex, a subsegment is inserted and the job is done.       */
+/*                                                                           */
+/*  If the first triangle on the path has a destination or apex that lies on */
+/*  the segment, a subsegment is inserted connecting the first endpoint to   */
+/*  the collinear vertex, and the search is continued from the collinear     */
+/*  vertex.                                                                  */
+/*                                                                           */
+/*  If the first triangle on the path has a subsegment opposite its origin,  */
+/*  then there is a segment that intersects the segment being inserted.      */
+/*  Their intersection vertex is inserted, splitting the subsegment.         */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+int scoutsegment(struct mesh *m, struct behavior *b, struct otri *searchtri,
+                 vertex endpoint2, int newmark)
+#else /* not ANSI_DECLARATORS */
+int scoutsegment(m, b, searchtri, endpoint2, newmark)
+struct mesh *m;
+struct behavior *b;
+struct otri *searchtri;
+vertex endpoint2;
+int newmark;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri crosstri;
+  struct osub crosssubseg;
+  vertex leftvertex, rightvertex;
+  enum finddirectionresult collinear;
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+
+  collinear = finddirection(m, b, searchtri, endpoint2);
+  dest(*searchtri, rightvertex);
+  apex(*searchtri, leftvertex);
+  if (((leftvertex[0] == endpoint2[0]) && (leftvertex[1] == endpoint2[1])) ||
+      ((rightvertex[0] == endpoint2[0]) && (rightvertex[1] == endpoint2[1]))) {
+    /* The segment is already an edge in the mesh. */
+    if ((leftvertex[0] == endpoint2[0]) && (leftvertex[1] == endpoint2[1])) {
+      lprevself(*searchtri);
+    }
+    /* Insert a subsegment, if there isn't already one there. */
+    insertsubseg(m, b, searchtri, newmark);
+    return 1;
+  } else if (collinear == LEFTCOLLINEAR) {
+    /* We've collided with a vertex between the segment's endpoints. */
+    /* Make the collinear vertex be the triangle's origin. */
+    lprevself(*searchtri);
+    insertsubseg(m, b, searchtri, newmark);
+    /* Insert the remainder of the segment. */
+    return scoutsegment(m, b, searchtri, endpoint2, newmark);
+  } else if (collinear == RIGHTCOLLINEAR) {
+    /* We've collided with a vertex between the segment's endpoints. */
+    insertsubseg(m, b, searchtri, newmark);
+    /* Make the collinear vertex be the triangle's origin. */
+    lnextself(*searchtri);
+    /* Insert the remainder of the segment. */
+    return scoutsegment(m, b, searchtri, endpoint2, newmark);
+  } else {
+    lnext(*searchtri, crosstri);
+    tspivot(crosstri, crosssubseg);
+    /* Check for a crossing segment. */
+    if (crosssubseg.ss == m->dummysub) {
+      return 0;
+    } else {
+      /* Insert a vertex at the intersection. */
+      segmentintersection(m, b, &crosstri, &crosssubseg, endpoint2);
+      otricopy(crosstri, *searchtri);
+      insertsubseg(m, b, searchtri, newmark);
+      /* Insert the remainder of the segment. */
+      return scoutsegment(m, b, searchtri, endpoint2, newmark);
+    }
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  conformingedge()   Force a segment into a conforming Delaunay            */
+/*                     triangulation by inserting a vertex at its midpoint,  */
+/*                     and recursively forcing in the two half-segments if   */
+/*                     necessary.                                            */
+/*                                                                           */
+/*  Generates a sequence of subsegments connecting `endpoint1' to            */
+/*  `endpoint2'.  `newmark' is the boundary marker of the segment, assigned  */
+/*  to each new splitting vertex and subsegment.                             */
+/*                                                                           */
+/*  Note that conformingedge() does not always maintain the conforming       */
+/*  Delaunay property.  Once inserted, segments are locked into place;       */
+/*  vertices inserted later (to force other segments in) may render these    */
+/*  fixed segments non-Delaunay.  The conforming Delaunay property will be   */
+/*  restored by enforcequality() by splitting encroached subsegments.        */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef REDUCED
+#ifndef CDT_ONLY
+
+#ifdef ANSI_DECLARATORS
+void conformingedge(struct mesh *m, struct behavior *b,
+                    vertex endpoint1, vertex endpoint2, int newmark)
+#else /* not ANSI_DECLARATORS */
+void conformingedge(m, b, endpoint1, endpoint2, newmark)
+struct mesh *m;
+struct behavior *b;
+vertex endpoint1;
+vertex endpoint2;
+int newmark;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri searchtri1, searchtri2;
+  struct osub brokensubseg;
+  vertex newvertex;
+  vertex midvertex1, midvertex2;
+  enum insertvertexresult success;
+  int i;
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+
+  if (b->verbose > 2) {
+    printf("Forcing segment into triangulation by recursive splitting:\n");
+    printf("  (%.12g, %.12g) (%.12g, %.12g)\n", endpoint1[0], endpoint1[1],
+           endpoint2[0], endpoint2[1]);
+  }
+  /* Create a new vertex to insert in the middle of the segment. */
+  newvertex = (vertex) poolalloc(&m->vertices);
+  /* Interpolate coordinates and attributes. */
+  for (i = 0; i < 2 + m->nextras; i++) {
+    newvertex[i] = 0.5 * (endpoint1[i] + endpoint2[i]);
+  }
+  setvertexmark(newvertex, newmark);
+  setvertextype(newvertex, SEGMENTVERTEX);
+  /* No known triangle to search from. */
+  searchtri1.tri = m->dummytri;
+  /* Attempt to insert the new vertex. */
+  success = insertvertex(m, b, newvertex, &searchtri1, (struct osub *) NULL,
+                         0, 0);
+  if (success == DUPLICATEVERTEX) {
+    if (b->verbose > 2) {
+      printf("  Segment intersects existing vertex (%.12g, %.12g).\n",
+             newvertex[0], newvertex[1]);
+    }
+    /* Use the vertex that's already there. */
+    vertexdealloc(m, newvertex);
+    org(searchtri1, newvertex);
+  } else {
+    if (success == VIOLATINGVERTEX) {
+      if (b->verbose > 2) {
+        printf("  Two segments intersect at (%.12g, %.12g).\n",
+               newvertex[0], newvertex[1]);
+      }
+      /* By fluke, we've landed right on another segment.  Split it. */
+      tspivot(searchtri1, brokensubseg);
+      success = insertvertex(m, b, newvertex, &searchtri1, &brokensubseg,
+                             0, 0);
+      if (success != SUCCESSFULVERTEX) {
+        printf("Internal error in conformingedge():\n");
+        printf("  Failure to split a segment.\n");
+        internalerror();
+      }
+    }
+    /* The vertex has been inserted successfully. */
+    if (m->steinerleft > 0) {
+      m->steinerleft--;
+    }
+  }
+  otricopy(searchtri1, searchtri2);
+  /* `searchtri1' and `searchtri2' are fastened at their origins to         */
+  /*   `newvertex', and will be directed toward `endpoint1' and `endpoint2' */
+  /*   respectively.  First, we must get `searchtri2' out of the way so it  */
+  /*   won't be invalidated during the insertion of the first half of the   */
+  /*   segment.                                                             */
+  finddirection(m, b, &searchtri2, endpoint2);
+  if (!scoutsegment(m, b, &searchtri1, endpoint1, newmark)) {
+    /* The origin of searchtri1 may have changed if a collision with an */
+    /*   intervening vertex on the segment occurred.                    */
+    org(searchtri1, midvertex1);
+    conformingedge(m, b, midvertex1, endpoint1, newmark);
+  }
+  if (!scoutsegment(m, b, &searchtri2, endpoint2, newmark)) {
+    /* The origin of searchtri2 may have changed if a collision with an */
+    /*   intervening vertex on the segment occurred.                    */
+    org(searchtri2, midvertex2);
+    conformingedge(m, b, midvertex2, endpoint2, newmark);
+  }
+}
+
+#endif /* not CDT_ONLY */
+#endif /* not REDUCED */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  delaunayfixup()   Enforce the Delaunay condition at an edge, fanning out */
+/*                    recursively from an existing vertex.  Pay special      */
+/*                    attention to stacking inverted triangles.              */
+/*                                                                           */
+/*  This is a support routine for inserting segments into a constrained      */
+/*  Delaunay triangulation.                                                  */
+/*                                                                           */
+/*  The origin of fixuptri is treated as if it has just been inserted, and   */
+/*  the local Delaunay condition needs to be enforced.  It is only enforced  */
+/*  in one sector, however, that being the angular range defined by          */
+/*  fixuptri.                                                                */
+/*                                                                           */
+/*  This routine also needs to make decisions regarding the "stacking" of    */
+/*  triangles.  (Read the description of constrainededge() below before      */
+/*  reading on here, so you understand the algorithm.)  If the position of   */
+/*  the new vertex (the origin of fixuptri) indicates that the vertex before */
+/*  it on the polygon is a reflex vertex, then "stack" the triangle by       */
+/*  doing nothing.  (fixuptri is an inverted triangle, which is how stacked  */
+/*  triangles are identified.)                                               */
+/*                                                                           */
+/*  Otherwise, check whether the vertex before that was a reflex vertex.     */
+/*  If so, perform an edge flip, thereby eliminating an inverted triangle    */
+/*  (popping it off the stack).  The edge flip may result in the creation    */
+/*  of a new inverted triangle, depending on whether or not the new vertex   */
+/*  is visible to the vertex three edges behind on the polygon.              */
+/*                                                                           */
+/*  If neither of the two vertices behind the new vertex are reflex          */
+/*  vertices, fixuptri and fartri, the triangle opposite it, are not         */
+/*  inverted; hence, ensure that the edge between them is locally Delaunay.  */
+/*                                                                           */
+/*  `leftside' indicates whether or not fixuptri is to the left of the       */
+/*  segment being inserted.  (Imagine that the segment is pointing up from   */
+/*  endpoint1 to endpoint2.)                                                 */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void delaunayfixup(struct mesh *m, struct behavior *b,
+                   struct otri *fixuptri, int leftside)
+#else /* not ANSI_DECLARATORS */
+void delaunayfixup(m, b, fixuptri, leftside)
+struct mesh *m;
+struct behavior *b;
+struct otri *fixuptri;
+int leftside;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri neartri;
+  struct otri fartri;
+  struct osub faredge;
+  vertex nearvertex, leftvertex, rightvertex, farvertex;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+
+  lnext(*fixuptri, neartri);
+  sym(neartri, fartri);
+  /* Check if the edge opposite the origin of fixuptri can be flipped. */
+  if (fartri.tri == m->dummytri) {
+    return;
+  }
+  tspivot(neartri, faredge);
+  if (faredge.ss != m->dummysub) {
+    return;
+  }
+  /* Find all the relevant vertices. */
+  apex(neartri, nearvertex);
+  org(neartri, leftvertex);
+  dest(neartri, rightvertex);
+  apex(fartri, farvertex);
+  /* Check whether the previous polygon vertex is a reflex vertex. */
+  if (leftside) {
+    if (counterclockwise(m, b, nearvertex, leftvertex, farvertex) <= 0.0) {
+      /* leftvertex is a reflex vertex too.  Nothing can */
+      /*   be done until a convex section is found.      */
+      return;
+    }
+  } else {
+    if (counterclockwise(m, b, farvertex, rightvertex, nearvertex) <= 0.0) {
+      /* rightvertex is a reflex vertex too.  Nothing can */
+      /*   be done until a convex section is found.       */
+      return;
+    }
+  }
+  if (counterclockwise(m, b, rightvertex, leftvertex, farvertex) > 0.0) {
+    /* fartri is not an inverted triangle, and farvertex is not a reflex */
+    /*   vertex.  As there are no reflex vertices, fixuptri isn't an     */
+    /*   inverted triangle, either.  Hence, test the edge between the    */
+    /*   triangles to ensure it is locally Delaunay.                     */
+    if (incircle(m, b, leftvertex, farvertex, rightvertex, nearvertex) <=
+        0.0) {
+      return;
+    }
+    /* Not locally Delaunay; go on to an edge flip. */
+  }        /* else fartri is inverted; remove it from the stack by flipping. */
+  flip(m, b, &neartri);
+  lprevself(*fixuptri);    /* Restore the origin of fixuptri after the flip. */
+  /* Recursively process the two triangles that result from the flip. */
+  delaunayfixup(m, b, fixuptri, leftside);
+  delaunayfixup(m, b, &fartri, leftside);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  constrainededge()   Force a segment into a constrained Delaunay          */
+/*                      triangulation by deleting the triangles it           */
+/*                      intersects, and triangulating the polygons that      */
+/*                      form on each side of it.                             */
+/*                                                                           */
+/*  Generates a single subsegment connecting `endpoint1' to `endpoint2'.     */
+/*  The triangle `starttri' has `endpoint1' as its origin.  `newmark' is the */
+/*  boundary marker of the segment.                                          */
+/*                                                                           */
+/*  To insert a segment, every triangle whose interior intersects the        */
+/*  segment is deleted.  The union of these deleted triangles is a polygon   */
+/*  (which is not necessarily monotone, but is close enough), which is       */
+/*  divided into two polygons by the new segment.  This routine's task is    */
+/*  to generate the Delaunay triangulation of these two polygons.            */
+/*                                                                           */
+/*  You might think of this routine's behavior as a two-step process.  The   */
+/*  first step is to walk from endpoint1 to endpoint2, flipping each edge    */
+/*  encountered.  This step creates a fan of edges connected to endpoint1,   */
+/*  including the desired edge to endpoint2.  The second step enforces the   */
+/*  Delaunay condition on each side of the segment in an incremental manner: */
+/*  proceeding along the polygon from endpoint1 to endpoint2 (this is done   */
+/*  independently on each side of the segment), each vertex is "enforced"    */
+/*  as if it had just been inserted, but affecting only the previous         */
+/*  vertices.  The result is the same as if the vertices had been inserted   */
+/*  in the order they appear on the polygon, so the result is Delaunay.      */
+/*                                                                           */
+/*  In truth, constrainededge() interleaves these two steps.  The procedure  */
+/*  walks from endpoint1 to endpoint2, and each time an edge is encountered  */
+/*  and flipped, the newly exposed vertex (at the far end of the flipped     */
+/*  edge) is "enforced" upon the previously flipped edges, usually affecting */
+/*  only one side of the polygon (depending upon which side of the segment   */
+/*  the vertex falls on).                                                    */
+/*                                                                           */
+/*  The algorithm is complicated by the need to handle polygons that are not */
+/*  convex.  Although the polygon is not necessarily monotone, it can be     */
+/*  triangulated in a manner similar to the stack-based algorithms for       */
+/*  monotone polygons.  For each reflex vertex (local concavity) of the      */
+/*  polygon, there will be an inverted triangle formed by one of the edge    */
+/*  flips.  (An inverted triangle is one with negative area - that is, its   */
+/*  vertices are arranged in clockwise order - and is best thought of as a   */
+/*  wrinkle in the fabric of the mesh.)  Each inverted triangle can be       */
+/*  thought of as a reflex vertex pushed on the stack, waiting to be fixed   */
+/*  later.                                                                   */
+/*                                                                           */
+/*  A reflex vertex is popped from the stack when a vertex is inserted that  */
+/*  is visible to the reflex vertex.  (However, if the vertex behind the     */
+/*  reflex vertex is not visible to the reflex vertex, a new inverted        */
+/*  triangle will take its place on the stack.)  These details are handled   */
+/*  by the delaunayfixup() routine above.                                    */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void constrainededge(struct mesh *m, struct behavior *b,
+                     struct otri *starttri, vertex endpoint2, int newmark)
+#else /* not ANSI_DECLARATORS */
+void constrainededge(m, b, starttri, endpoint2, newmark)
+struct mesh *m;
+struct behavior *b;
+struct otri *starttri;
+vertex endpoint2;
+int newmark;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri fixuptri, fixuptri2;
+  struct osub crosssubseg;
+  vertex endpoint1;
+  vertex farvertex;
+  REAL area;
+  int collision;
+  int done;
+  triangle ptr;             /* Temporary variable used by sym() and oprev(). */
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+
+  org(*starttri, endpoint1);
+  lnext(*starttri, fixuptri);
+  flip(m, b, &fixuptri);
+  /* `collision' indicates whether we have found a vertex directly */
+  /*   between endpoint1 and endpoint2.                            */
+  collision = 0;
+  done = 0;
+  do {
+    org(fixuptri, farvertex);
+    /* `farvertex' is the extreme point of the polygon we are "digging" */
+    /*   to get from endpoint1 to endpoint2.                           */
+    if ((farvertex[0] == endpoint2[0]) && (farvertex[1] == endpoint2[1])) {
+      oprev(fixuptri, fixuptri2);
+      /* Enforce the Delaunay condition around endpoint2. */
+      delaunayfixup(m, b, &fixuptri, 0);
+      delaunayfixup(m, b, &fixuptri2, 1);
+      done = 1;
+    } else {
+      /* Check whether farvertex is to the left or right of the segment */
+      /*   being inserted, to decide which edge of fixuptri to dig      */
+      /*   through next.                                                */
+      area = counterclockwise(m, b, endpoint1, endpoint2, farvertex);
+      if (area == 0.0) {
+        /* We've collided with a vertex between endpoint1 and endpoint2. */
+        collision = 1;
+        oprev(fixuptri, fixuptri2);
+        /* Enforce the Delaunay condition around farvertex. */
+        delaunayfixup(m, b, &fixuptri, 0);
+        delaunayfixup(m, b, &fixuptri2, 1);
+        done = 1;
+      } else {
+        if (area > 0.0) {        /* farvertex is to the left of the segment. */
+          oprev(fixuptri, fixuptri2);
+          /* Enforce the Delaunay condition around farvertex, on the */
+          /*   left side of the segment only.                        */
+          delaunayfixup(m, b, &fixuptri2, 1);
+          /* Flip the edge that crosses the segment.  After the edge is */
+          /*   flipped, one of its endpoints is the fan vertex, and the */
+          /*   destination of fixuptri is the fan vertex.               */
+          lprevself(fixuptri);
+        } else {                /* farvertex is to the right of the segment. */
+          delaunayfixup(m, b, &fixuptri, 0);
+          /* Flip the edge that crosses the segment.  After the edge is */
+          /*   flipped, one of its endpoints is the fan vertex, and the */
+          /*   destination of fixuptri is the fan vertex.               */
+          oprevself(fixuptri);
+        }
+        /* Check for two intersecting segments. */
+        tspivot(fixuptri, crosssubseg);
+        if (crosssubseg.ss == m->dummysub) {
+          flip(m, b, &fixuptri);    /* May create inverted triangle at left. */
+        } else {
+          /* We've collided with a segment between endpoint1 and endpoint2. */
+          collision = 1;
+          /* Insert a vertex at the intersection. */
+          segmentintersection(m, b, &fixuptri, &crosssubseg, endpoint2);
+          done = 1;
+        }
+      }
+    }
+  } while (!done);
+  /* Insert a subsegment to make the segment permanent. */
+  insertsubseg(m, b, &fixuptri, newmark);
+  /* If there was a collision with an interceding vertex, install another */
+  /*   segment connecting that vertex with endpoint2.                     */
+  if (collision) {
+    /* Insert the remainder of the segment. */
+    if (!scoutsegment(m, b, &fixuptri, endpoint2, newmark)) {
+      constrainededge(m, b, &fixuptri, endpoint2, newmark);
+    }
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  insertsegment()   Insert a PSLG segment into a triangulation.            */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void insertsegment(struct mesh *m, struct behavior *b,
+                   vertex endpoint1, vertex endpoint2, int newmark)
+#else /* not ANSI_DECLARATORS */
+void insertsegment(m, b, endpoint1, endpoint2, newmark)
+struct mesh *m;
+struct behavior *b;
+vertex endpoint1;
+vertex endpoint2;
+int newmark;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri searchtri1, searchtri2;
+  triangle encodedtri;
+  vertex checkvertex;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+  if (b->verbose > 1) {
+    printf("  Connecting (%.12g, %.12g) to (%.12g, %.12g).\n",
+           endpoint1[0], endpoint1[1], endpoint2[0], endpoint2[1]);
+  }
+
+  /* Find a triangle whose origin is the segment's first endpoint. */
+  checkvertex = (vertex) NULL;
+  encodedtri = vertex2tri(endpoint1);
+  if (encodedtri != (triangle) NULL) {
+    decode(encodedtri, searchtri1);
+    org(searchtri1, checkvertex);
+  }
+  if (checkvertex != endpoint1) {
+    /* Find a boundary triangle to search from. */
+    searchtri1.tri = m->dummytri;
+    searchtri1.orient = 0;
+    symself(searchtri1);
+    /* Search for the segment's first endpoint by point location. */
+    if (locate(m, b, endpoint1, &searchtri1) != ONVERTEX) {
+      printf(
+        "Internal error in insertsegment():  Unable to locate PSLG vertex\n");
+      printf("  (%.12g, %.12g) in triangulation.\n",
+             endpoint1[0], endpoint1[1]);
+      internalerror();
+    }
+  }
+  /* Remember this triangle to improve subsequent point location. */
+  otricopy(searchtri1, m->recenttri);
+  /* Scout the beginnings of a path from the first endpoint */
+  /*   toward the second.                                   */
+  if (scoutsegment(m, b, &searchtri1, endpoint2, newmark)) {
+    /* The segment was easily inserted. */
+    return;
+  }
+  /* The first endpoint may have changed if a collision with an intervening */
+  /*   vertex on the segment occurred.                                      */
+  org(searchtri1, endpoint1);
+
+  /* Find a triangle whose origin is the segment's second endpoint. */
+  checkvertex = (vertex) NULL;
+  encodedtri = vertex2tri(endpoint2);
+  if (encodedtri != (triangle) NULL) {
+    decode(encodedtri, searchtri2);
+    org(searchtri2, checkvertex);
+  }
+  if (checkvertex != endpoint2) {
+    /* Find a boundary triangle to search from. */
+    searchtri2.tri = m->dummytri;
+    searchtri2.orient = 0;
+    symself(searchtri2);
+    /* Search for the segment's second endpoint by point location. */
+    if (locate(m, b, endpoint2, &searchtri2) != ONVERTEX) {
+      printf(
+        "Internal error in insertsegment():  Unable to locate PSLG vertex\n");
+      printf("  (%.12g, %.12g) in triangulation.\n",
+             endpoint2[0], endpoint2[1]);
+      internalerror();
+    }
+  }
+  /* Remember this triangle to improve subsequent point location. */
+  otricopy(searchtri2, m->recenttri);
+  /* Scout the beginnings of a path from the second endpoint */
+  /*   toward the first.                                     */
+  if (scoutsegment(m, b, &searchtri2, endpoint1, newmark)) {
+    /* The segment was easily inserted. */
+    return;
+  }
+  /* The second endpoint may have changed if a collision with an intervening */
+  /*   vertex on the segment occurred.                                       */
+  org(searchtri2, endpoint2);
+
+#ifndef REDUCED
+#ifndef CDT_ONLY
+  if (b->splitseg) {
+    /* Insert vertices to force the segment into the triangulation. */
+    conformingedge(m, b, endpoint1, endpoint2, newmark);
+  } else {
+#endif /* not CDT_ONLY */
+#endif /* not REDUCED */
+    /* Insert the segment directly into the triangulation. */
+    constrainededge(m, b, &searchtri1, endpoint2, newmark);
+#ifndef REDUCED
+#ifndef CDT_ONLY
+  }
+#endif /* not CDT_ONLY */
+#endif /* not REDUCED */
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  markhull()   Cover the convex hull of a triangulation with subsegments.  */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void markhull(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void markhull(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri hulltri;
+  struct otri nexttri;
+  struct otri starttri;
+  triangle ptr;             /* Temporary variable used by sym() and oprev(). */
+
+  /* Find a triangle handle on the hull. */
+  hulltri.tri = m->dummytri;
+  hulltri.orient = 0;
+  symself(hulltri);
+  /* Remember where we started so we know when to stop. */
+  otricopy(hulltri, starttri);
+  /* Go once counterclockwise around the convex hull. */
+  do {
+    /* Create a subsegment if there isn't already one here. */
+    insertsubseg(m, b, &hulltri, 1);
+    /* To find the next hull edge, go clockwise around the next vertex. */
+    lnextself(hulltri);
+    oprev(hulltri, nexttri);
+    while (nexttri.tri != m->dummytri) {
+      otricopy(nexttri, hulltri);
+      oprev(hulltri, nexttri);
+    }
+  } while (!otriequal(hulltri, starttri));
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  formskeleton()   Create the segments of a triangulation, including PSLG  */
+/*                   segments and edges on the convex hull.                  */
+/*                                                                           */
+/*  The PSLG segments are read from a .poly file.  The return value is the   */
+/*  number of segments in the file.                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef TRILIBRARY
+
+#ifdef ANSI_DECLARATORS
+void formskeleton(struct mesh *m, struct behavior *b, int *segmentlist,
+                  int *segmentmarkerlist, int numberofsegments)
+#else /* not ANSI_DECLARATORS */
+void formskeleton(m, b, segmentlist, segmentmarkerlist, numberofsegments)
+struct mesh *m;
+struct behavior *b;
+int *segmentlist;
+int *segmentmarkerlist;
+int numberofsegments;
+#endif /* not ANSI_DECLARATORS */
+
+#else /* not TRILIBRARY */
+
+#ifdef ANSI_DECLARATORS
+void formskeleton(struct mesh *m, struct behavior *b,
+                  FILE *polyfile, char *polyfilename)
+#else /* not ANSI_DECLARATORS */
+void formskeleton(m, b, polyfile, polyfilename)
+struct mesh *m;
+struct behavior *b;
+FILE *polyfile;
+char *polyfilename;
+#endif /* not ANSI_DECLARATORS */
+
+#endif /* not TRILIBRARY */
+
+{
+#ifdef TRILIBRARY
+  char polyfilename[6];
+  int index;
+#else /* not TRILIBRARY */
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+#endif /* not TRILIBRARY */
+  vertex endpoint1, endpoint2;
+  int segmentmarkers;
+  int end1, end2;
+  int boundmarker;
+  int i;
+
+  if (b->poly) {
+    if (!b->quiet) {
+      printf("Recovering segments in Delaunay triangulation.\n");
+    }
+#ifdef TRILIBRARY
+    strcpy(polyfilename, "input");
+    m->insegments = numberofsegments;
+    segmentmarkers = segmentmarkerlist != (int *) NULL;
+    index = 0;
+#else /* not TRILIBRARY */
+    /* Read the segments from a .poly file. */
+    /* Read number of segments and number of boundary markers. */
+    stringptr = readline(inputline, polyfile, polyfilename);
+    m->insegments = (int) strtol(stringptr, &stringptr, 0);
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      segmentmarkers = 0;
+    } else {
+      segmentmarkers = (int) strtol(stringptr, &stringptr, 0);
+    }
+#endif /* not TRILIBRARY */
+    /* If the input vertices are collinear, there is no triangulation, */
+    /*   so don't try to insert segments.                              */
+    if (m->triangles.items == 0) {
+      return;
+    }
+
+    /* If segments are to be inserted, compute a mapping */
+    /*   from vertices to triangles.                     */
+    if (m->insegments > 0) {
+      makevertexmap(m, b);
+      if (b->verbose) {
+        printf("  Recovering PSLG segments.\n");
+      }
+    }
+
+    boundmarker = 0;
+    /* Read and insert the segments. */
+    for (i = 0; i < m->insegments; i++) {
+#ifdef TRILIBRARY
+      end1 = segmentlist[index++];
+      end2 = segmentlist[index++];
+      if (segmentmarkers) {
+        boundmarker = segmentmarkerlist[i];
+      }
+#else /* not TRILIBRARY */
+      stringptr = readline(inputline, polyfile, b->inpolyfilename);
+      stringptr = findfield(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  Segment %d has no endpoints in %s.\n",
+               b->firstnumber + i, polyfilename);
+        triexit(1);
+      } else {
+        end1 = (int) strtol(stringptr, &stringptr, 0);
+      }
+      stringptr = findfield(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  Segment %d is missing its second endpoint in %s.\n",
+               b->firstnumber + i, polyfilename);
+        triexit(1);
+      } else {
+        end2 = (int) strtol(stringptr, &stringptr, 0);
+      }
+      if (segmentmarkers) {
+        stringptr = findfield(stringptr);
+        if (*stringptr == '\0') {
+          boundmarker = 0;
+        } else {
+          boundmarker = (int) strtol(stringptr, &stringptr, 0);
+        }
+      }
+#endif /* not TRILIBRARY */
+      if ((end1 < b->firstnumber) ||
+          (end1 >= b->firstnumber + m->invertices)) {
+        if (!b->quiet) {
+          printf("Warning:  Invalid first endpoint of segment %d in %s.\n",
+                 b->firstnumber + i, polyfilename);
+        }
+      } else if ((end2 < b->firstnumber) ||
+                 (end2 >= b->firstnumber + m->invertices)) {
+        if (!b->quiet) {
+          printf("Warning:  Invalid second endpoint of segment %d in %s.\n",
+                 b->firstnumber + i, polyfilename);
+        }
+      } else {
+        /* Find the vertices numbered `end1' and `end2'. */
+        endpoint1 = getvertex(m, b, end1);
+        endpoint2 = getvertex(m, b, end2);
+        if ((endpoint1[0] == endpoint2[0]) && (endpoint1[1] == endpoint2[1])) {
+          if (!b->quiet) {
+            printf("Warning:  Endpoints of segment %d are coincident in %s.\n",
+                   b->firstnumber + i, polyfilename);
+          }
+        } else {
+          insertsegment(m, b, endpoint1, endpoint2, boundmarker);
+        }
+      }
+    }
+  } else {
+    m->insegments = 0;
+  }
+  if (b->convex || !b->poly) {
+    /* Enclose the convex hull with subsegments. */
+    if (b->verbose) {
+      printf("  Enclosing convex hull with segments.\n");
+    }
+    markhull(m, b);
+  }
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Segment insertion ends here                               *********/
+
+/********* Carving out holes and concavities begins here             *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  infecthull()   Virally infect all of the triangles of the convex hull    */
+/*                 that are not protected by subsegments.  Where there are   */
+/*                 subsegments, set boundary markers as appropriate.         */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void infecthull(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void infecthull(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri hulltri;
+  struct otri nexttri;
+  struct otri starttri;
+  struct osub hullsubseg;
+  triangle **deadtriangle;
+  vertex horg, hdest;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+
+  if (b->verbose) {
+    printf("  Marking concavities (external triangles) for elimination.\n");
+  }
+  /* Find a triangle handle on the hull. */
+  hulltri.tri = m->dummytri;
+  hulltri.orient = 0;
+  symself(hulltri);
+  /* Remember where we started so we know when to stop. */
+  otricopy(hulltri, starttri);
+  /* Go once counterclockwise around the convex hull. */
+  do {
+    /* Ignore triangles that are already infected. */
+    if (!infected(hulltri)) {
+      /* Is the triangle protected by a subsegment? */
+      tspivot(hulltri, hullsubseg);
+      if (hullsubseg.ss == m->dummysub) {
+        /* The triangle is not protected; infect it. */
+        if (!infected(hulltri)) {
+          infect(hulltri);
+          deadtriangle = (triangle **) poolalloc(&m->viri);
+          *deadtriangle = hulltri.tri;
+        }
+      } else {
+        /* The triangle is protected; set boundary markers if appropriate. */
+        if (mark(hullsubseg) == 0) {
+          setmark(hullsubseg, 1);
+          org(hulltri, horg);
+          dest(hulltri, hdest);
+          if (vertexmark(horg) == 0) {
+            setvertexmark(horg, 1);
+          }
+          if (vertexmark(hdest) == 0) {
+            setvertexmark(hdest, 1);
+          }
+        }
+      }
+    }
+    /* To find the next hull edge, go clockwise around the next vertex. */
+    lnextself(hulltri);
+    oprev(hulltri, nexttri);
+    while (nexttri.tri != m->dummytri) {
+      otricopy(nexttri, hulltri);
+      oprev(hulltri, nexttri);
+    }
+  } while (!otriequal(hulltri, starttri));
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  plague()   Spread the virus from all infected triangles to any neighbors */
+/*             not protected by subsegments.  Delete all infected triangles. */
+/*                                                                           */
+/*  This is the procedure that actually creates holes and concavities.       */
+/*                                                                           */
+/*  This procedure operates in two phases.  The first phase identifies all   */
+/*  the triangles that will die, and marks them as infected.  They are       */
+/*  marked to ensure that each triangle is added to the virus pool only      */
+/*  once, so the procedure will terminate.                                   */
+/*                                                                           */
+/*  The second phase actually eliminates the infected triangles.  It also    */
+/*  eliminates orphaned vertices.                                            */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void plague(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void plague(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri testtri;
+  struct otri neighbor;
+  triangle **virusloop;
+  triangle **deadtriangle;
+  struct osub neighborsubseg;
+  vertex testvertex;
+  vertex norg, ndest;
+  vertex deadorg, deaddest, deadapex;
+  int killorg;
+  triangle ptr;             /* Temporary variable used by sym() and onext(). */
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+
+  if (b->verbose) {
+    printf("  Marking neighbors of marked triangles.\n");
+  }
+  /* Loop through all the infected triangles, spreading the virus to */
+  /*   their neighbors, then to their neighbors' neighbors.          */
+  traversalinit(&m->viri);
+  virusloop = (triangle **) traverse(&m->viri);
+  while (virusloop != (triangle **) NULL) {
+    testtri.tri = *virusloop;
+    /* A triangle is marked as infected by messing with one of its pointers */
+    /*   to subsegments, setting it to an illegal value.  Hence, we have to */
+    /*   temporarily uninfect this triangle so that we can examine its      */
+    /*   adjacent subsegments.                                              */
+    uninfect(testtri);
+    if (b->verbose > 2) {
+      /* Assign the triangle an orientation for convenience in */
+      /*   checking its vertices.                              */
+      testtri.orient = 0;
+      org(testtri, deadorg);
+      dest(testtri, deaddest);
+      apex(testtri, deadapex);
+      printf("    Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
+             deadorg[0], deadorg[1], deaddest[0], deaddest[1],
+             deadapex[0], deadapex[1]);
+    }
+    /* Check each of the triangle's three neighbors. */
+    for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
+      /* Find the neighbor. */
+      sym(testtri, neighbor);
+      /* Check for a subsegment between the triangle and its neighbor. */
+      tspivot(testtri, neighborsubseg);
+      /* Check if the neighbor is nonexistent or already infected. */
+      if ((neighbor.tri == m->dummytri) || infected(neighbor)) {
+        if (neighborsubseg.ss != m->dummysub) {
+          /* There is a subsegment separating the triangle from its      */
+          /*   neighbor, but both triangles are dying, so the subsegment */
+          /*   dies too.                                                 */
+          subsegdealloc(m, neighborsubseg.ss);
+          if (neighbor.tri != m->dummytri) {
+            /* Make sure the subsegment doesn't get deallocated again */
+            /*   later when the infected neighbor is visited.         */
+            uninfect(neighbor);
+            tsdissolve(neighbor);
+            infect(neighbor);
+          }
+        }
+      } else {                   /* The neighbor exists and is not infected. */
+        if (neighborsubseg.ss == m->dummysub) {
+          /* There is no subsegment protecting the neighbor, so */
+          /*   the neighbor becomes infected.                   */
+          if (b->verbose > 2) {
+            org(neighbor, deadorg);
+            dest(neighbor, deaddest);
+            apex(neighbor, deadapex);
+            printf(
+              "    Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
+                   deadorg[0], deadorg[1], deaddest[0], deaddest[1],
+                   deadapex[0], deadapex[1]);
+          }
+          infect(neighbor);
+          /* Ensure that the neighbor's neighbors will be infected. */
+          deadtriangle = (triangle **) poolalloc(&m->viri);
+          *deadtriangle = neighbor.tri;
+        } else {               /* The neighbor is protected by a subsegment. */
+          /* Remove this triangle from the subsegment. */
+          stdissolve(neighborsubseg);
+          /* The subsegment becomes a boundary.  Set markers accordingly. */
+          if (mark(neighborsubseg) == 0) {
+            setmark(neighborsubseg, 1);
+          }
+          org(neighbor, norg);
+          dest(neighbor, ndest);
+          if (vertexmark(norg) == 0) {
+            setvertexmark(norg, 1);
+          }
+          if (vertexmark(ndest) == 0) {
+            setvertexmark(ndest, 1);
+          }
+        }
+      }
+    }
+    /* Remark the triangle as infected, so it doesn't get added to the */
+    /*   virus pool again.                                             */
+    infect(testtri);
+    virusloop = (triangle **) traverse(&m->viri);
+  }
+
+  if (b->verbose) {
+    printf("  Deleting marked triangles.\n");
+  }
+
+  traversalinit(&m->viri);
+  virusloop = (triangle **) traverse(&m->viri);
+  while (virusloop != (triangle **) NULL) {
+    testtri.tri = *virusloop;
+
+    /* Check each of the three corners of the triangle for elimination. */
+    /*   This is done by walking around each vertex, checking if it is  */
+    /*   still connected to at least one live triangle.                 */
+    for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
+      org(testtri, testvertex);
+      /* Check if the vertex has already been tested. */
+      if (testvertex != (vertex) NULL) {
+        killorg = 1;
+        /* Mark the corner of the triangle as having been tested. */
+        setorg(testtri, NULL);
+        /* Walk counterclockwise about the vertex. */
+        onext(testtri, neighbor);
+        /* Stop upon reaching a boundary or the starting triangle. */
+        while ((neighbor.tri != m->dummytri) &&
+               (!otriequal(neighbor, testtri))) {
+          if (infected(neighbor)) {
+            /* Mark the corner of this triangle as having been tested. */
+            setorg(neighbor, NULL);
+          } else {
+            /* A live triangle.  The vertex survives. */
+            killorg = 0;
+          }
+          /* Walk counterclockwise about the vertex. */
+          onextself(neighbor);
+        }
+        /* If we reached a boundary, we must walk clockwise as well. */
+        if (neighbor.tri == m->dummytri) {
+          /* Walk clockwise about the vertex. */
+          oprev(testtri, neighbor);
+          /* Stop upon reaching a boundary. */
+          while (neighbor.tri != m->dummytri) {
+            if (infected(neighbor)) {
+            /* Mark the corner of this triangle as having been tested. */
+              setorg(neighbor, NULL);
+            } else {
+              /* A live triangle.  The vertex survives. */
+              killorg = 0;
+            }
+            /* Walk clockwise about the vertex. */
+            oprevself(neighbor);
+          }
+        }
+        if (killorg) {
+          if (b->verbose > 1) {
+            printf("    Deleting vertex (%.12g, %.12g)\n",
+                   testvertex[0], testvertex[1]);
+          }
+          setvertextype(testvertex, UNDEADVERTEX);
+          m->undeads++;
+        }
+      }
+    }
+
+    /* Record changes in the number of boundary edges, and disconnect */
+    /*   dead triangles from their neighbors.                         */
+    for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
+      sym(testtri, neighbor);
+      if (neighbor.tri == m->dummytri) {
+        /* There is no neighboring triangle on this edge, so this edge    */
+        /*   is a boundary edge.  This triangle is being deleted, so this */
+        /*   boundary edge is deleted.                                    */
+        m->hullsize--;
+      } else {
+        /* Disconnect the triangle from its neighbor. */
+        dissolve(neighbor);
+        /* There is a neighboring triangle on this edge, so this edge */
+        /*   becomes a boundary edge when this triangle is deleted.   */
+        m->hullsize++;
+      }
+    }
+    /* Return the dead triangle to the pool of triangles. */
+    triangledealloc(m, testtri.tri);
+    virusloop = (triangle **) traverse(&m->viri);
+  }
+  /* Empty the virus pool. */
+  poolrestart(&m->viri);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  regionplague()   Spread regional attributes and/or area constraints      */
+/*                   (from a .poly file) throughout the mesh.                */
+/*                                                                           */
+/*  This procedure operates in two phases.  The first phase spreads an       */
+/*  attribute and/or an area constraint through a (segment-bounded) region.  */
+/*  The triangles are marked to ensure that each triangle is added to the    */
+/*  virus pool only once, so the procedure will terminate.                   */
+/*                                                                           */
+/*  The second phase uninfects all infected triangles, returning them to     */
+/*  normal.                                                                  */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void regionplague(struct mesh *m, struct behavior *b,
+                  REAL attribute, REAL area)
+#else /* not ANSI_DECLARATORS */
+void regionplague(m, b, attribute, area)
+struct mesh *m;
+struct behavior *b;
+REAL attribute;
+REAL area;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri testtri;
+  struct otri neighbor;
+  triangle **virusloop;
+  triangle **regiontri;
+  struct osub neighborsubseg;
+  vertex regionorg, regiondest, regionapex;
+  triangle ptr;             /* Temporary variable used by sym() and onext(). */
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+
+  if (b->verbose > 1) {
+    printf("  Marking neighbors of marked triangles.\n");
+  }
+  /* Loop through all the infected triangles, spreading the attribute      */
+  /*   and/or area constraint to their neighbors, then to their neighbors' */
+  /*   neighbors.                                                          */
+  traversalinit(&m->viri);
+  virusloop = (triangle **) traverse(&m->viri);
+  while (virusloop != (triangle **) NULL) {
+    testtri.tri = *virusloop;
+    /* A triangle is marked as infected by messing with one of its pointers */
+    /*   to subsegments, setting it to an illegal value.  Hence, we have to */
+    /*   temporarily uninfect this triangle so that we can examine its      */
+    /*   adjacent subsegments.                                              */
+    uninfect(testtri);
+    if (b->regionattrib) {
+      /* Set an attribute. */
+      setelemattribute(testtri, m->eextras, attribute);
+    }
+    if (b->vararea) {
+      /* Set an area constraint. */
+      setareabound(testtri, area);
+    }
+    if (b->verbose > 2) {
+      /* Assign the triangle an orientation for convenience in */
+      /*   checking its vertices.                              */
+      testtri.orient = 0;
+      org(testtri, regionorg);
+      dest(testtri, regiondest);
+      apex(testtri, regionapex);
+      printf("    Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
+             regionorg[0], regionorg[1], regiondest[0], regiondest[1],
+             regionapex[0], regionapex[1]);
+    }
+    /* Check each of the triangle's three neighbors. */
+    for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
+      /* Find the neighbor. */
+      sym(testtri, neighbor);
+      /* Check for a subsegment between the triangle and its neighbor. */
+      tspivot(testtri, neighborsubseg);
+      /* Make sure the neighbor exists, is not already infected, and */
+      /*   isn't protected by a subsegment.                          */
+      if ((neighbor.tri != m->dummytri) && !infected(neighbor)
+          && (neighborsubseg.ss == m->dummysub)) {
+        if (b->verbose > 2) {
+          org(neighbor, regionorg);
+          dest(neighbor, regiondest);
+          apex(neighbor, regionapex);
+          printf("    Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
+                 regionorg[0], regionorg[1], regiondest[0], regiondest[1],
+                 regionapex[0], regionapex[1]);
+        }
+        /* Infect the neighbor. */
+        infect(neighbor);
+        /* Ensure that the neighbor's neighbors will be infected. */
+        regiontri = (triangle **) poolalloc(&m->viri);
+        *regiontri = neighbor.tri;
+      }
+    }
+    /* Remark the triangle as infected, so it doesn't get added to the */
+    /*   virus pool again.                                             */
+    infect(testtri);
+    virusloop = (triangle **) traverse(&m->viri);
+  }
+
+  /* Uninfect all triangles. */
+  if (b->verbose > 1) {
+    printf("  Unmarking marked triangles.\n");
+  }
+  traversalinit(&m->viri);
+  virusloop = (triangle **) traverse(&m->viri);
+  while (virusloop != (triangle **) NULL) {
+    testtri.tri = *virusloop;
+    uninfect(testtri);
+    virusloop = (triangle **) traverse(&m->viri);
+  }
+  /* Empty the virus pool. */
+  poolrestart(&m->viri);
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  carveholes()   Find the holes and infect them.  Find the area            */
+/*                 constraints and infect them.  Infect the convex hull.     */
+/*                 Spread the infection and kill triangles.  Spread the      */
+/*                 area constraints.                                         */
+/*                                                                           */
+/*  This routine mainly calls other routines to carry out all these          */
+/*  functions.                                                               */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void carveholes(struct mesh *m, struct behavior *b, REAL *holelist, int holes,
+                REAL *regionlist, int regions)
+#else /* not ANSI_DECLARATORS */
+void carveholes(m, b, holelist, holes, regionlist, regions)
+struct mesh *m;
+struct behavior *b;
+REAL *holelist;
+int holes;
+REAL *regionlist;
+int regions;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri searchtri;
+  struct otri triangleloop;
+  struct otri *regiontris;
+  triangle **holetri;
+  triangle **regiontri;
+  vertex searchorg, searchdest;
+  enum locateresult intersect;
+  int i;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+  if (!(b->quiet || (b->noholes && b->convex))) {
+    printf("Removing unwanted triangles.\n");
+    if (b->verbose && (holes > 0)) {
+      printf("  Marking holes for elimination.\n");
+    }
+  }
+
+  if (regions > 0) {
+    /* Allocate storage for the triangles in which region points fall. */
+    regiontris = (struct otri *) trimalloc(regions *
+                                           (int) sizeof(struct otri));
+  } else {
+    regiontris = (struct otri *) NULL;
+  }
+
+  if (((holes > 0) && !b->noholes) || !b->convex || (regions > 0)) {
+    /* Initialize a pool of viri to be used for holes, concavities, */
+    /*   regional attributes, and/or regional area constraints.     */
+    poolinit(&m->viri, sizeof(triangle *), VIRUSPERBLOCK, VIRUSPERBLOCK, 0);
+  }
+
+  if (!b->convex) {
+    /* Mark as infected any unprotected triangles on the boundary. */
+    /*   This is one way by which concavities are created.         */
+    infecthull(m, b);
+  }
+
+  if ((holes > 0) && !b->noholes) {
+    /* Infect each triangle in which a hole lies. */
+    for (i = 0; i < 2 * holes; i += 2) {
+      /* Ignore holes that aren't within the bounds of the mesh. */
+      if ((holelist[i] >= m->xmin) && (holelist[i] <= m->xmax)
+          && (holelist[i + 1] >= m->ymin) && (holelist[i + 1] <= m->ymax)) {
+        /* Start searching from some triangle on the outer boundary. */
+        searchtri.tri = m->dummytri;
+        searchtri.orient = 0;
+        symself(searchtri);
+        /* Ensure that the hole is to the left of this boundary edge; */
+        /*   otherwise, locate() will falsely report that the hole    */
+        /*   falls within the starting triangle.                      */
+        org(searchtri, searchorg);
+        dest(searchtri, searchdest);
+        if (counterclockwise(m, b, searchorg, searchdest, &holelist[i]) >
+            0.0) {
+          /* Find a triangle that contains the hole. */
+          intersect = locate(m, b, &holelist[i], &searchtri);
+          if ((intersect != OUTSIDE) && (!infected(searchtri))) {
+            /* Infect the triangle.  This is done by marking the triangle  */
+            /*   as infected and including the triangle in the virus pool. */
+            infect(searchtri);
+            holetri = (triangle **) poolalloc(&m->viri);
+            *holetri = searchtri.tri;
+          }
+        }
+      }
+    }
+  }
+
+  /* Now, we have to find all the regions BEFORE we carve the holes, because */
+  /*   locate() won't work when the triangulation is no longer convex.       */
+  /*   (Incidentally, this is the reason why regional attributes and area    */
+  /*   constraints can't be used when refining a preexisting mesh, which     */
+  /*   might not be convex; they can only be used with a freshly             */
+  /*   triangulated PSLG.)                                                   */
+  if (regions > 0) {
+    /* Find the starting triangle for each region. */
+    for (i = 0; i < regions; i++) {
+      regiontris[i].tri = m->dummytri;
+      /* Ignore region points that aren't within the bounds of the mesh. */
+      if ((regionlist[4 * i] >= m->xmin) && (regionlist[4 * i] <= m->xmax) &&
+          (regionlist[4 * i + 1] >= m->ymin) &&
+          (regionlist[4 * i + 1] <= m->ymax)) {
+        /* Start searching from some triangle on the outer boundary. */
+        searchtri.tri = m->dummytri;
+        searchtri.orient = 0;
+        symself(searchtri);
+        /* Ensure that the region point is to the left of this boundary */
+        /*   edge; otherwise, locate() will falsely report that the     */
+        /*   region point falls within the starting triangle.           */
+        org(searchtri, searchorg);
+        dest(searchtri, searchdest);
+        if (counterclockwise(m, b, searchorg, searchdest, &regionlist[4 * i]) >
+            0.0) {
+          /* Find a triangle that contains the region point. */
+          intersect = locate(m, b, &regionlist[4 * i], &searchtri);
+          if ((intersect != OUTSIDE) && (!infected(searchtri))) {
+            /* Record the triangle for processing after the */
+            /*   holes have been carved.                    */
+            otricopy(searchtri, regiontris[i]);
+          }
+        }
+      }
+    }
+  }
+
+  if (m->viri.items > 0) {
+    /* Carve the holes and concavities. */
+    plague(m, b);
+  }
+  /* The virus pool should be empty now. */
+
+  if (regions > 0) {
+    if (!b->quiet) {
+      if (b->regionattrib) {
+        if (b->vararea) {
+          printf("Spreading regional attributes and area constraints.\n");
+        } else {
+          printf("Spreading regional attributes.\n");
+        }
+      } else { 
+        printf("Spreading regional area constraints.\n");
+      }
+    }
+    if (b->regionattrib && !b->refine) {
+      /* Assign every triangle a regional attribute of zero. */
+      traversalinit(&m->triangles);
+      triangleloop.orient = 0;
+      triangleloop.tri = triangletraverse(m);
+      while (triangleloop.tri != (triangle *) NULL) {
+        setelemattribute(triangleloop, m->eextras, 0.0);
+        triangleloop.tri = triangletraverse(m);
+      }
+    }
+    for (i = 0; i < regions; i++) {
+      if (regiontris[i].tri != m->dummytri) {
+        /* Make sure the triangle under consideration still exists. */
+        /*   It may have been eaten by the virus.                   */
+        if (!deadtri(regiontris[i].tri)) {
+          /* Put one triangle in the virus pool. */
+          infect(regiontris[i]);
+          regiontri = (triangle **) poolalloc(&m->viri);
+          *regiontri = regiontris[i].tri;
+          /* Apply one region's attribute and/or area constraint. */
+          regionplague(m, b, regionlist[4 * i + 2], regionlist[4 * i + 3]);
+          /* The virus pool should be empty now. */
+        }
+      }
+    }
+    if (b->regionattrib && !b->refine) {
+      /* Note the fact that each triangle has an additional attribute. */
+      m->eextras++;
+    }
+  }
+
+  /* Free up memory. */
+  if (((holes > 0) && !b->noholes) || !b->convex || (regions > 0)) {
+    pooldeinit(&m->viri);
+  }
+  if (regions > 0) {
+    trifree((VOID *) regiontris);
+  }
+}
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Carving out holes and concavities ends here               *********/
+
+/********* Mesh quality maintenance begins here                      *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  tallyencs()   Traverse the entire list of subsegments, and check each    */
+/*                to see if it is encroached.  If so, add it to the list.    */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef CDT_ONLY
+
+#ifdef ANSI_DECLARATORS
+void tallyencs(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void tallyencs(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct osub subsegloop;
+  int dummy;
+
+  traversalinit(&m->subsegs);
+  subsegloop.ssorient = 0;
+  subsegloop.ss = subsegtraverse(m);
+  while (subsegloop.ss != (subseg *) NULL) {
+    /* If the segment is encroached, add it to the list. */
+    dummy = checkseg4encroach(m, b, &subsegloop);
+    subsegloop.ss = subsegtraverse(m);
+  }
+}
+
+#endif /* not CDT_ONLY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  precisionerror()  Print an error message for precision problems.         */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef CDT_ONLY
+
+void precisionerror(void)
+{
+  printf("Try increasing the area criterion and/or reducing the minimum\n");
+  printf("  allowable angle so that tiny triangles are not created.\n");
+#ifdef SINGLE
+  printf("Alternatively, try recompiling me with double precision\n");
+  printf("  arithmetic (by removing \"#define SINGLE\" from the\n");
+  printf("  source file or \"-DSINGLE\" from the makefile).\n");
+#endif /* SINGLE */
+}
+
+#endif /* not CDT_ONLY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  splitencsegs()   Split all the encroached subsegments.                   */
+/*                                                                           */
+/*  Each encroached subsegment is repaired by splitting it - inserting a     */
+/*  vertex at or near its midpoint.  Newly inserted vertices may encroach    */
+/*  upon other subsegments; these are also repaired.                         */
+/*                                                                           */
+/*  `triflaws' is a flag that specifies whether one should take note of new  */
+/*  bad triangles that result from inserting vertices to repair encroached   */
+/*  subsegments.                                                             */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef CDT_ONLY
+
+#ifdef ANSI_DECLARATORS
+void splitencsegs(struct mesh *m, struct behavior *b, int triflaws)
+#else /* not ANSI_DECLARATORS */
+void splitencsegs(m, b, triflaws)
+struct mesh *m;
+struct behavior *b;
+int triflaws;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri enctri;
+  struct otri testtri;
+  struct osub testsh;
+  struct osub currentenc;
+  struct badsubseg *encloop;
+  vertex eorg, edest, eapex;
+  vertex newvertex;
+  enum insertvertexresult success;
+  REAL segmentlength, nearestpoweroftwo;
+  REAL split;
+  REAL multiplier, divisor;
+  int acuteorg, acuteorg2, acutedest, acutedest2;
+  int dummy;
+  int i;
+  triangle ptr;                     /* Temporary variable used by stpivot(). */
+  subseg sptr;                        /* Temporary variable used by snext(). */
+
+  /* Note that steinerleft == -1 if an unlimited number */
+  /*   of Steiner points is allowed.                    */
+  while ((m->badsubsegs.items > 0) && (m->steinerleft != 0)) {
+    traversalinit(&m->badsubsegs);
+    encloop = badsubsegtraverse(m);
+    while ((encloop != (struct badsubseg *) NULL) && (m->steinerleft != 0)) {
+      sdecode(encloop->encsubseg, currentenc);
+      sorg(currentenc, eorg);
+      sdest(currentenc, edest);
+      /* Make sure that this segment is still the same segment it was   */
+      /*   when it was determined to be encroached.  If the segment was */
+      /*   enqueued multiple times (because several newly inserted      */
+      /*   vertices encroached it), it may have already been split.     */
+      if (!deadsubseg(currentenc.ss) &&
+          (eorg == encloop->subsegorg) && (edest == encloop->subsegdest)) {
+        /* To decide where to split a segment, we need to know if the   */
+        /*   segment shares an endpoint with an adjacent segment.       */
+        /*   The concern is that, if we simply split every encroached   */
+        /*   segment in its center, two adjacent segments with a small  */
+        /*   angle between them might lead to an infinite loop; each    */
+        /*   vertex added to split one segment will encroach upon the   */
+        /*   other segment, which must then be split with a vertex that */
+        /*   will encroach upon the first segment, and so on forever.   */
+        /* To avoid this, imagine a set of concentric circles, whose    */
+        /*   radii are powers of two, about each segment endpoint.      */
+        /*   These concentric circles determine where the segment is    */
+        /*   split.  (If both endpoints are shared with adjacent        */
+        /*   segments, split the segment in the middle, and apply the   */
+        /*   concentric circles for later splittings.)                  */
+
+        /* Is the origin shared with another segment? */
+        stpivot(currentenc, enctri);
+        lnext(enctri, testtri);
+        tspivot(testtri, testsh);
+        acuteorg = testsh.ss != m->dummysub;
+        /* Is the destination shared with another segment? */
+        lnextself(testtri);
+        tspivot(testtri, testsh);
+        acutedest = testsh.ss != m->dummysub;
+
+        /* If we're using Chew's algorithm (rather than Ruppert's) */
+        /*   to define encroachment, delete free vertices from the */
+        /*   subsegment's diametral circle.                        */
+        if (!b->conformdel && !acuteorg && !acutedest) {
+          apex(enctri, eapex);
+          while ((vertextype(eapex) == FREEVERTEX) &&
+                 ((eorg[0] - eapex[0]) * (edest[0] - eapex[0]) +
+                  (eorg[1] - eapex[1]) * (edest[1] - eapex[1]) < 0.0)) {
+            deletevertex(m, b, &testtri);
+            stpivot(currentenc, enctri);
+            apex(enctri, eapex);
+            lprev(enctri, testtri);
+          }
+        }
+
+        /* Now, check the other side of the segment, if there's a triangle */
+        /*   there.                                                        */
+        sym(enctri, testtri);
+        if (testtri.tri != m->dummytri) {
+          /* Is the destination shared with another segment? */
+          lnextself(testtri);
+          tspivot(testtri, testsh);
+          acutedest2 = testsh.ss != m->dummysub;
+          acutedest = acutedest || acutedest2;
+          /* Is the origin shared with another segment? */
+          lnextself(testtri);
+          tspivot(testtri, testsh);
+          acuteorg2 = testsh.ss != m->dummysub;
+          acuteorg = acuteorg || acuteorg2;
+
+          /* Delete free vertices from the subsegment's diametral circle. */
+          if (!b->conformdel && !acuteorg2 && !acutedest2) {
+            org(testtri, eapex);
+            while ((vertextype(eapex) == FREEVERTEX) &&
+                   ((eorg[0] - eapex[0]) * (edest[0] - eapex[0]) +
+                    (eorg[1] - eapex[1]) * (edest[1] - eapex[1]) < 0.0)) {
+              deletevertex(m, b, &testtri);
+              sym(enctri, testtri);
+              apex(testtri, eapex);
+              lprevself(testtri);
+            }
+          }
+        }
+
+        /* Use the concentric circles if exactly one endpoint is shared */
+        /*   with another adjacent segment.                             */
+        if (acuteorg || acutedest) {
+          segmentlength = sqrt((edest[0] - eorg[0]) * (edest[0] - eorg[0]) +
+                               (edest[1] - eorg[1]) * (edest[1] - eorg[1]));
+          /* Find the power of two that most evenly splits the segment.  */
+          /*   The worst case is a 2:1 ratio between subsegment lengths. */
+          nearestpoweroftwo = 1.0;
+          while (segmentlength > 3.0 * nearestpoweroftwo) {
+            nearestpoweroftwo *= 2.0;
+          }
+          while (segmentlength < 1.5 * nearestpoweroftwo) {
+            nearestpoweroftwo *= 0.5;
+          }
+          /* Where do we split the segment? */
+          split = nearestpoweroftwo / segmentlength;
+          if (acutedest) {
+            split = 1.0 - split;
+          }
+        } else {
+          /* If we're not worried about adjacent segments, split */
+          /*   this segment in the middle.                       */
+          split = 0.5;
+        }
+
+        /* Create the new vertex. */
+        newvertex = (vertex) poolalloc(&m->vertices);
+        /* Interpolate its coordinate and attributes. */
+        for (i = 0; i < 2 + m->nextras; i++) {
+          newvertex[i] = eorg[i] + split * (edest[i] - eorg[i]);
+        }
+
+        if (!b->noexact) {
+          /* Roundoff in the above calculation may yield a `newvertex'   */
+          /*   that is not precisely collinear with `eorg' and `edest'.  */
+          /*   Improve collinearity by one step of iterative refinement. */
+          multiplier = counterclockwise(m, b, eorg, edest, newvertex);
+          divisor = ((eorg[0] - edest[0]) * (eorg[0] - edest[0]) +
+                     (eorg[1] - edest[1]) * (eorg[1] - edest[1]));
+          if ((multiplier != 0.0) && (divisor != 0.0)) {
+            multiplier = multiplier / divisor;
+            /* Watch out for NANs. */
+            if (multiplier == multiplier) {
+              newvertex[0] += multiplier * (edest[1] - eorg[1]);
+              newvertex[1] += multiplier * (eorg[0] - edest[0]);
+            }
+          }
+        }
+
+        setvertexmark(newvertex, mark(currentenc));
+        setvertextype(newvertex, SEGMENTVERTEX);
+        if (b->verbose > 1) {
+          printf(
+  "  Splitting subsegment (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n",
+                 eorg[0], eorg[1], edest[0], edest[1],
+                 newvertex[0], newvertex[1]);
+        }
+        /* Check whether the new vertex lies on an endpoint. */
+        if (((newvertex[0] == eorg[0]) && (newvertex[1] == eorg[1])) ||
+            ((newvertex[0] == edest[0]) && (newvertex[1] == edest[1]))) {
+          printf("Error:  Ran out of precision at (%.12g, %.12g).\n",
+                 newvertex[0], newvertex[1]);
+          printf("I attempted to split a segment to a smaller size than\n");
+          printf("  can be accommodated by the finite precision of\n");
+          printf("  floating point arithmetic.\n");
+          precisionerror();
+          triexit(1);
+        }
+        /* Insert the splitting vertex.  This should always succeed. */
+        success = insertvertex(m, b, newvertex, &enctri, &currentenc,
+                               1, triflaws);
+        if ((success != SUCCESSFULVERTEX) && (success != ENCROACHINGVERTEX)) {
+          printf("Internal error in splitencsegs():\n");
+          printf("  Failure to split a segment.\n");
+          internalerror();
+        }
+        if (m->steinerleft > 0) {
+          m->steinerleft--;
+        }
+        /* Check the two new subsegments to see if they're encroached. */
+        dummy = checkseg4encroach(m, b, &currentenc);
+        snextself(currentenc);
+        dummy = checkseg4encroach(m, b, &currentenc);
+      }
+
+      badsubsegdealloc(m, encloop);
+      encloop = badsubsegtraverse(m);
+    }
+  }
+}
+
+#endif /* not CDT_ONLY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  tallyfaces()   Test every triangle in the mesh for quality measures.     */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef CDT_ONLY
+
+#ifdef ANSI_DECLARATORS
+void tallyfaces(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void tallyfaces(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri triangleloop;
+
+  if (b->verbose) {
+    printf("  Making a list of bad triangles.\n");
+  }
+  traversalinit(&m->triangles);
+  triangleloop.orient = 0;
+  triangleloop.tri = triangletraverse(m);
+  while (triangleloop.tri != (triangle *) NULL) {
+    /* If the triangle is bad, enqueue it. */
+    testtriangle(m, b, &triangleloop);
+    triangleloop.tri = triangletraverse(m);
+  }
+}
+
+#endif /* not CDT_ONLY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  splittriangle()   Inserts a vertex at the circumcenter of a triangle.    */
+/*                    Deletes the newly inserted vertex if it encroaches     */
+/*                    upon a segment.                                        */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef CDT_ONLY
+
+#ifdef ANSI_DECLARATORS
+void splittriangle(struct mesh *m, struct behavior *b,
+                   struct badtriang *badtri)
+#else /* not ANSI_DECLARATORS */
+void splittriangle(m, b, badtri)
+struct mesh *m;
+struct behavior *b;
+struct badtriang *badtri;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri badotri;
+  vertex borg, bdest, bapex;
+  vertex newvertex;
+  REAL xi, eta;
+  enum insertvertexresult success;
+  int errorflag;
+  int i;
+
+  decode(badtri->poortri, badotri);
+  org(badotri, borg);
+  dest(badotri, bdest);
+  apex(badotri, bapex);
+  /* Make sure that this triangle is still the same triangle it was      */
+  /*   when it was tested and determined to be of bad quality.           */
+  /*   Subsequent transformations may have made it a different triangle. */
+  if (!deadtri(badotri.tri) && (borg == badtri->triangorg) &&
+      (bdest == badtri->triangdest) && (bapex == badtri->triangapex)) {
+    if (b->verbose > 1) {
+      printf("  Splitting this triangle at its circumcenter:\n");
+      printf("    (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", borg[0],
+             borg[1], bdest[0], bdest[1], bapex[0], bapex[1]);
+    }
+
+    errorflag = 0;
+    /* Create a new vertex at the triangle's circumcenter. */
+    newvertex = (vertex) poolalloc(&m->vertices);
+    findcircumcenter(m, b, borg, bdest, bapex, newvertex, &xi, &eta, 1);
+
+    /* Check whether the new vertex lies on a triangle vertex. */
+    if (((newvertex[0] == borg[0]) && (newvertex[1] == borg[1])) ||
+        ((newvertex[0] == bdest[0]) && (newvertex[1] == bdest[1])) ||
+        ((newvertex[0] == bapex[0]) && (newvertex[1] == bapex[1]))) {
+      if (!b->quiet) {
+        printf(
+             "Warning:  New vertex (%.12g, %.12g) falls on existing vertex.\n",
+               newvertex[0], newvertex[1]);
+        errorflag = 1;
+      }
+      vertexdealloc(m, newvertex);
+    } else {
+      for (i = 2; i < 2 + m->nextras; i++) {
+        /* Interpolate the vertex attributes at the circumcenter. */
+        newvertex[i] = borg[i] + xi * (bdest[i] - borg[i])
+                              + eta * (bapex[i] - borg[i]);
+      }
+      /* The new vertex must be in the interior, and therefore is a */
+      /*   free vertex with a marker of zero.                       */
+      setvertexmark(newvertex, 0);
+      setvertextype(newvertex, FREEVERTEX);
+
+      /* Ensure that the handle `badotri' does not represent the longest  */
+      /*   edge of the triangle.  This ensures that the circumcenter must */
+      /*   fall to the left of this edge, so point location will work.    */
+      /*   (If the angle org-apex-dest exceeds 90 degrees, then the       */
+      /*   circumcenter lies outside the org-dest edge, and eta is        */
+      /*   negative.  Roundoff error might prevent eta from being         */
+      /*   negative when it should be, so I test eta against xi.)         */
+      if (eta < xi) {
+        lprevself(badotri);
+      }
+
+      /* Insert the circumcenter, searching from the edge of the triangle, */
+      /*   and maintain the Delaunay property of the triangulation.        */
+      success = insertvertex(m, b, newvertex, &badotri, (struct osub *) NULL,
+                             1, 1);
+      if (success == SUCCESSFULVERTEX) {
+        if (m->steinerleft > 0) {
+          m->steinerleft--;
+        }
+      } else if (success == ENCROACHINGVERTEX) {
+        /* If the newly inserted vertex encroaches upon a subsegment, */
+        /*   delete the new vertex.                                   */
+        undovertex(m, b);
+        if (b->verbose > 1) {
+          printf("  Rejecting (%.12g, %.12g).\n", newvertex[0], newvertex[1]);
+        }
+        vertexdealloc(m, newvertex);
+      } else if (success == VIOLATINGVERTEX) {
+        /* Failed to insert the new vertex, but some subsegment was */
+        /*   marked as being encroached.                            */
+        vertexdealloc(m, newvertex);
+      } else {                                 /* success == DUPLICATEVERTEX */
+        /* Couldn't insert the new vertex because a vertex is already there. */
+        if (!b->quiet) {
+          printf(
+            "Warning:  New vertex (%.12g, %.12g) falls on existing vertex.\n",
+                 newvertex[0], newvertex[1]);
+          errorflag = 1;
+        }
+        vertexdealloc(m, newvertex);
+      }
+    }
+    if (errorflag) {
+      if (b->verbose) {
+        printf("  The new vertex is at the circumcenter of triangle\n");
+        printf("    (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
+               borg[0], borg[1], bdest[0], bdest[1], bapex[0], bapex[1]);
+      }
+      printf("This probably means that I am trying to refine triangles\n");
+      printf("  to a smaller size than can be accommodated by the finite\n");
+      printf("  precision of floating point arithmetic.  (You can be\n");
+      printf("  sure of this if I fail to terminate.)\n");
+      precisionerror();
+    }
+  }
+}
+
+#endif /* not CDT_ONLY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  enforcequality()   Remove all the encroached subsegments and bad         */
+/*                     triangles from the triangulation.                     */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef CDT_ONLY
+
+#ifdef ANSI_DECLARATORS
+void enforcequality(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void enforcequality(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct badtriang *badtri;
+  int i;
+
+  if (!b->quiet) {
+    printf("Adding Steiner points to enforce quality.\n");
+  }
+  /* Initialize the pool of encroached subsegments. */
+  poolinit(&m->badsubsegs, sizeof(struct badsubseg), BADSUBSEGPERBLOCK,
+           BADSUBSEGPERBLOCK, 0);
+  if (b->verbose) {
+    printf("  Looking for encroached subsegments.\n");
+  }
+  /* Test all segments to see if they're encroached. */
+  tallyencs(m, b);
+  if (b->verbose && (m->badsubsegs.items > 0)) {
+    printf("  Splitting encroached subsegments.\n");
+  }
+  /* Fix encroached subsegments without noting bad triangles. */
+  splitencsegs(m, b, 0);
+  /* At this point, if we haven't run out of Steiner points, the */
+  /*   triangulation should be (conforming) Delaunay.            */
+
+  /* Next, we worry about enforcing triangle quality. */
+  if ((b->minangle > 0.0) || b->vararea || b->fixedarea || b->usertest) {
+    /* Initialize the pool of bad triangles. */
+    poolinit(&m->badtriangles, sizeof(struct badtriang), BADTRIPERBLOCK,
+             BADTRIPERBLOCK, 0);
+    /* Initialize the queues of bad triangles. */
+    for (i = 0; i < 4096; i++) {
+      m->queuefront[i] = (struct badtriang *) NULL;
+    }
+    m->firstnonemptyq = -1;
+    /* Test all triangles to see if they're bad. */
+    tallyfaces(m, b);
+    /* Initialize the pool of recently flipped triangles. */
+    poolinit(&m->flipstackers, sizeof(struct flipstacker), FLIPSTACKERPERBLOCK,
+             FLIPSTACKERPERBLOCK, 0);
+    m->checkquality = 1;
+    if (b->verbose) {
+      printf("  Splitting bad triangles.\n");
+    }
+    while ((m->badtriangles.items > 0) && (m->steinerleft != 0)) {
+      /* Fix one bad triangle by inserting a vertex at its circumcenter. */
+      badtri = dequeuebadtriang(m);
+      splittriangle(m, b, badtri);
+      if (m->badsubsegs.items > 0) {
+        /* Put bad triangle back in queue for another try later. */
+        enqueuebadtriang(m, b, badtri);
+        /* Fix any encroached subsegments that resulted. */
+        /*   Record any new bad triangles that result.   */
+        splitencsegs(m, b, 1);
+      } else {
+        /* Return the bad triangle to the pool. */
+        pooldealloc(&m->badtriangles, (VOID *) badtri);
+      }
+    }
+  }
+  /* At this point, if the "-D" switch was selected and we haven't run out  */
+  /*   of Steiner points, the triangulation should be (conforming) Delaunay */
+  /*   and have no low-quality triangles.                                   */
+
+  /* Might we have run out of Steiner points too soon? */
+  if (!b->quiet && b->conformdel && (m->badsubsegs.items > 0) &&
+      (m->steinerleft == 0)) {
+    printf("\nWarning:  I ran out of Steiner points, but the mesh has\n");
+    if (m->badsubsegs.items == 1) {
+      printf("  one encroached subsegment, and therefore might not be truly\n"
+             );
+    } else {
+      printf("  %ld encroached subsegments, and therefore might not be truly\n"
+             , m->badsubsegs.items);
+    }
+    printf("  Delaunay.  If the Delaunay property is important to you,\n");
+    printf("  try increasing the number of Steiner points (controlled by\n");
+    printf("  the -S switch) slightly and try again.\n\n");
+  }
+}
+
+#endif /* not CDT_ONLY */
+
+/**                                                                         **/
+/**                                                                         **/
+/********* Mesh quality maintenance ends here                        *********/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  highorder()   Create extra nodes for quadratic subparametric elements.   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void highorder(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void highorder(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri triangleloop, trisym;
+  struct osub checkmark;
+  vertex newvertex;
+  vertex torg, tdest;
+  int i;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+
+  if (!b->quiet) {
+    printf("Adding vertices for second-order triangles.\n");
+  }
+  /* The following line ensures that dead items in the pool of nodes    */
+  /*   cannot be allocated for the extra nodes associated with high     */
+  /*   order elements.  This ensures that the primary nodes (at the     */
+  /*   corners of elements) will occur earlier in the output files, and */
+  /*   have lower indices, than the extra nodes.                        */
+  m->vertices.deaditemstack = (VOID *) NULL;
+
+  traversalinit(&m->triangles);
+  triangleloop.tri = triangletraverse(m);
+  /* To loop over the set of edges, loop over all triangles, and look at   */
+  /*   the three edges of each triangle.  If there isn't another triangle  */
+  /*   adjacent to the edge, operate on the edge.  If there is another     */
+  /*   adjacent triangle, operate on the edge only if the current triangle */
+  /*   has a smaller pointer than its neighbor.  This way, each edge is    */
+  /*   considered only once.                                               */
+  while (triangleloop.tri != (triangle *) NULL) {
+    for (triangleloop.orient = 0; triangleloop.orient < 3;
+         triangleloop.orient++) {
+      sym(triangleloop, trisym);
+      if ((triangleloop.tri < trisym.tri) || (trisym.tri == m->dummytri)) {
+        org(triangleloop, torg);
+        dest(triangleloop, tdest);
+        /* Create a new node in the middle of the edge.  Interpolate */
+        /*   its attributes.                                         */
+        newvertex = (vertex) poolalloc(&m->vertices);
+        for (i = 0; i < 2 + m->nextras; i++) {
+          newvertex[i] = 0.5 * (torg[i] + tdest[i]);
+        }
+        /* Set the new node's marker to zero or one, depending on */
+        /*   whether it lies on a boundary.                       */
+        setvertexmark(newvertex, trisym.tri == m->dummytri);
+        setvertextype(newvertex,
+                      trisym.tri == m->dummytri ? FREEVERTEX : SEGMENTVERTEX);
+        if (b->usesegments) {
+          tspivot(triangleloop, checkmark);
+          /* If this edge is a segment, transfer the marker to the new node. */
+          if (checkmark.ss != m->dummysub) {
+            setvertexmark(newvertex, mark(checkmark));
+            setvertextype(newvertex, SEGMENTVERTEX);
+          }
+        }
+        if (b->verbose > 1) {
+          printf("  Creating (%.12g, %.12g).\n", newvertex[0], newvertex[1]);
+        }
+        /* Record the new node in the (one or two) adjacent elements. */
+        triangleloop.tri[m->highorderindex + triangleloop.orient] =
+                (triangle) newvertex;
+        if (trisym.tri != m->dummytri) {
+          trisym.tri[m->highorderindex + trisym.orient] = (triangle) newvertex;
+        }
+      }
+    }
+    triangleloop.tri = triangletraverse(m);
+  }
+}
+
+/********* File I/O routines begin here                              *********/
+/**                                                                         **/
+/**                                                                         **/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  readline()   Read a nonempty line from a file.                           */
+/*                                                                           */
+/*  A line is considered "nonempty" if it contains something that looks like */
+/*  a number.  Comments (prefaced by `#') are ignored.                       */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef TRILIBRARY
+
+#ifdef ANSI_DECLARATORS
+char *readline(char *string, FILE *infile, char *infilename)
+#else /* not ANSI_DECLARATORS */
+char *readline(string, infile, infilename)
+char *string;
+FILE *infile;
+char *infilename;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  char *result;
+
+  /* Search for something that looks like a number. */
+  do {
+    result = fgets(string, INPUTLINESIZE, infile);
+    if (result == (char *) NULL) {
+      printf("  Error:  Unexpected end of file in %s.\n", infilename);
+      triexit(1);
+    }
+    /* Skip anything that doesn't look like a number, a comment, */
+    /*   or the end of a line.                                   */
+    while ((*result != '\0') && (*result != '#')
+           && (*result != '.') && (*result != '+') && (*result != '-')
+           && ((*result < '0') || (*result > '9'))) {
+      result++;
+    }
+  /* If it's a comment or end of line, read another line and try again. */
+  } while ((*result == '#') || (*result == '\0'));
+  return result;
+}
+
+#endif /* not TRILIBRARY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  findfield()   Find the next field of a string.                           */
+/*                                                                           */
+/*  Jumps past the current field by searching for whitespace, then jumps     */
+/*  past the whitespace to find the next field.                              */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef TRILIBRARY
+
+#ifdef ANSI_DECLARATORS
+char *findfield(char *string)
+#else /* not ANSI_DECLARATORS */
+char *findfield(string)
+char *string;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  char *result;
+
+  result = string;
+  /* Skip the current field.  Stop upon reaching whitespace. */
+  while ((*result != '\0') && (*result != '#')
+         && (*result != ' ') && (*result != '\t')) {
+    result++;
+  }
+  /* Now skip the whitespace and anything else that doesn't look like a */
+  /*   number, a comment, or the end of a line.                         */
+  while ((*result != '\0') && (*result != '#')
+         && (*result != '.') && (*result != '+') && (*result != '-')
+         && ((*result < '0') || (*result > '9'))) {
+    result++;
+  }
+  /* Check for a comment (prefixed with `#'). */
+  if (*result == '#') {
+    *result = '\0';
+  }
+  return result;
+}
+
+#endif /* not TRILIBRARY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  readnodes()   Read the vertices from a file, which may be a .node or     */
+/*                .poly file.                                                */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef TRILIBRARY
+
+#ifdef ANSI_DECLARATORS
+void readnodes(struct mesh *m, struct behavior *b, char *nodefilename,
+               char *polyfilename, FILE **polyfile)
+#else /* not ANSI_DECLARATORS */
+void readnodes(m, b, nodefilename, polyfilename, polyfile)
+struct mesh *m;
+struct behavior *b;
+char *nodefilename;
+char *polyfilename;
+FILE **polyfile;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  FILE *infile;
+  vertex vertexloop;
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  char *infilename;
+  REAL x, y;
+  int firstnode;
+  int nodemarkers;
+  int currentmarker;
+  int i, j;
+
+  if (b->poly) {
+    /* Read the vertices from a .poly file. */
+    if (!b->quiet) {
+      printf("Opening %s.\n", polyfilename);
+    }
+    *polyfile = fopen(polyfilename, "r");
+    if (*polyfile == (FILE *) NULL) {
+      printf("  Error:  Cannot access file %s.\n", polyfilename);
+      triexit(1);
+    }
+    /* Read number of vertices, number of dimensions, number of vertex */
+    /*   attributes, and number of boundary markers.                   */
+    stringptr = readline(inputline, *polyfile, polyfilename);
+    m->invertices = (int) strtol(stringptr, &stringptr, 0);
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      m->mesh_dim = 2;
+    } else {
+      m->mesh_dim = (int) strtol(stringptr, &stringptr, 0);
+    }
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      m->nextras = 0;
+    } else {
+      m->nextras = (int) strtol(stringptr, &stringptr, 0);
+    }
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      nodemarkers = 0;
+    } else {
+      nodemarkers = (int) strtol(stringptr, &stringptr, 0);
+    }
+    if (m->invertices > 0) {
+      infile = *polyfile;
+      infilename = polyfilename;
+      m->readnodefile = 0;
+    } else {
+      /* If the .poly file claims there are zero vertices, that means that */
+      /*   the vertices should be read from a separate .node file.         */
+      m->readnodefile = 1;
+      infilename = nodefilename;
+    }
+  } else {
+    m->readnodefile = 1;
+    infilename = nodefilename;
+    *polyfile = (FILE *) NULL;
+  }
+
+  if (m->readnodefile) {
+    /* Read the vertices from a .node file. */
+    if (!b->quiet) {
+      printf("Opening %s.\n", nodefilename);
+    }
+    infile = fopen(nodefilename, "r");
+    if (infile == (FILE *) NULL) {
+      printf("  Error:  Cannot access file %s.\n", nodefilename);
+      triexit(1);
+    }
+    /* Read number of vertices, number of dimensions, number of vertex */
+    /*   attributes, and number of boundary markers.                   */
+    stringptr = readline(inputline, infile, nodefilename);
+    m->invertices = (int) strtol(stringptr, &stringptr, 0);
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      m->mesh_dim = 2;
+    } else {
+      m->mesh_dim = (int) strtol(stringptr, &stringptr, 0);
+    }
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      m->nextras = 0;
+    } else {
+      m->nextras = (int) strtol(stringptr, &stringptr, 0);
+    }
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      nodemarkers = 0;
+    } else {
+      nodemarkers = (int) strtol(stringptr, &stringptr, 0);
+    }
+  }
+
+  if (m->invertices < 3) {
+    printf("Error:  Input must have at least three input vertices.\n");
+    triexit(1);
+  }
+  if (m->mesh_dim != 2) {
+    printf("Error:  Triangle only works with two-dimensional meshes.\n");
+    triexit(1);
+  }
+  if (m->nextras == 0) {
+    b->weighted = 0;
+  }
+
+  initializevertexpool(m, b);
+
+  /* Read the vertices. */
+  for (i = 0; i < m->invertices; i++) {
+    vertexloop = (vertex) poolalloc(&m->vertices);
+    stringptr = readline(inputline, infile, infilename);
+    if (i == 0) {
+      firstnode = (int) strtol(stringptr, &stringptr, 0);
+      if ((firstnode == 0) || (firstnode == 1)) {
+        b->firstnumber = firstnode;
+      }
+    }
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      printf("Error:  Vertex %d has no x coordinate.\n", b->firstnumber + i);
+      triexit(1);
+    }
+    x = (REAL) strtod(stringptr, &stringptr);
+    stringptr = findfield(stringptr);
+    if (*stringptr == '\0') {
+      printf("Error:  Vertex %d has no y coordinate.\n", b->firstnumber + i);
+      triexit(1);
+    }
+    y = (REAL) strtod(stringptr, &stringptr);
+    vertexloop[0] = x;
+    vertexloop[1] = y;
+    /* Read the vertex attributes. */
+    for (j = 2; j < 2 + m->nextras; j++) {
+      stringptr = findfield(stringptr);
+      if (*stringptr == '\0') {
+        vertexloop[j] = 0.0;
+      } else {
+        vertexloop[j] = (REAL) strtod(stringptr, &stringptr);
+      }
+    }
+    if (nodemarkers) {
+      /* Read a vertex marker. */
+      stringptr = findfield(stringptr);
+      if (*stringptr == '\0') {
+        setvertexmark(vertexloop, 0);
+      } else {
+        currentmarker = (int) strtol(stringptr, &stringptr, 0);
+        setvertexmark(vertexloop, currentmarker);
+      }
+    } else {
+      /* If no markers are specified in the file, they default to zero. */
+      setvertexmark(vertexloop, 0);
+    }
+    setvertextype(vertexloop, INPUTVERTEX);
+    /* Determine the smallest and largest x and y coordinates. */
+    if (i == 0) {
+      m->xmin = m->xmax = x;
+      m->ymin = m->ymax = y;
+    } else {
+      m->xmin = (x < m->xmin) ? x : m->xmin;
+      m->xmax = (x > m->xmax) ? x : m->xmax;
+      m->ymin = (y < m->ymin) ? y : m->ymin;
+      m->ymax = (y > m->ymax) ? y : m->ymax;
+    }
+  }
+  if (m->readnodefile) {
+    fclose(infile);
+  }
+
+  /* Nonexistent x value used as a flag to mark circle events in sweepline */
+  /*   Delaunay algorithm.                                                 */
+  m->xminextreme = 10 * m->xmin - 9 * m->xmax;
+}
+
+#endif /* not TRILIBRARY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  transfernodes()   Read the vertices from memory.                         */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef TRILIBRARY
+
+#ifdef ANSI_DECLARATORS
+void transfernodes(struct mesh *m, struct behavior *b, REAL *pointlist,
+                   REAL *pointattriblist, int *pointmarkerlist,
+                   int numberofpoints, int numberofpointattribs)
+#else /* not ANSI_DECLARATORS */
+void transfernodes(m, b, pointlist, pointattriblist, pointmarkerlist,
+                   numberofpoints, numberofpointattribs)
+struct mesh *m;
+struct behavior *b;
+REAL *pointlist;
+REAL *pointattriblist;
+int *pointmarkerlist;
+int numberofpoints;
+int numberofpointattribs;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  vertex vertexloop;
+  REAL x, y;
+  int i, j;
+  int coordindex;
+  int attribindex;
+
+  m->invertices = numberofpoints;
+  m->mesh_dim = 2;
+  m->nextras = numberofpointattribs;
+  m->readnodefile = 0;
+  if (m->invertices < 3) {
+    printf("Error:  Input must have at least three input vertices.\n");
+    triexit(1);
+  }
+  if (m->nextras == 0) {
+    b->weighted = 0;
+  }
+
+  initializevertexpool(m, b);
+
+  /* Read the vertices. */
+  coordindex = 0;
+  attribindex = 0;
+  for (i = 0; i < m->invertices; i++) {
+    vertexloop = (vertex) poolalloc(&m->vertices);
+    /* Read the vertex coordinates. */
+    x = vertexloop[0] = pointlist[coordindex++];
+    y = vertexloop[1] = pointlist[coordindex++];
+    /* Read the vertex attributes. */
+    for (j = 0; j < numberofpointattribs; j++) {
+      vertexloop[2 + j] = pointattriblist[attribindex++];
+    }
+    if (pointmarkerlist != (int *) NULL) {
+      /* Read a vertex marker. */
+      setvertexmark(vertexloop, pointmarkerlist[i]);
+    } else {
+      /* If no markers are specified, they default to zero. */
+      setvertexmark(vertexloop, 0);
+    }
+    setvertextype(vertexloop, INPUTVERTEX);
+    /* Determine the smallest and largest x and y coordinates. */
+    if (i == 0) {
+      m->xmin = m->xmax = x;
+      m->ymin = m->ymax = y;
+    } else {
+      m->xmin = (x < m->xmin) ? x : m->xmin;
+      m->xmax = (x > m->xmax) ? x : m->xmax;
+      m->ymin = (y < m->ymin) ? y : m->ymin;
+      m->ymax = (y > m->ymax) ? y : m->ymax;
+    }
+  }
+
+  /* Nonexistent x value used as a flag to mark circle events in sweepline */
+  /*   Delaunay algorithm.                                                 */
+  m->xminextreme = 10 * m->xmin - 9 * m->xmax;
+}
+
+#endif /* TRILIBRARY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  readholes()   Read the holes, and possibly regional attributes and area  */
+/*                constraints, from a .poly file.                            */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef TRILIBRARY
+
+#ifdef ANSI_DECLARATORS
+void readholes(struct mesh *m, struct behavior *b,
+               FILE *polyfile, char *polyfilename, REAL **hlist, int *holes,
+               REAL **rlist, int *regions)
+#else /* not ANSI_DECLARATORS */
+void readholes(m, b, polyfile, polyfilename, hlist, holes, rlist, regions)
+struct mesh *m;
+struct behavior *b;
+FILE *polyfile;
+char *polyfilename;
+REAL **hlist;
+int *holes;
+REAL **rlist;
+int *regions;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  REAL *holelist;
+  REAL *regionlist;
+  char inputline[INPUTLINESIZE];
+  char *stringptr;
+  int index;
+  int i;
+
+  /* Read the holes. */
+  stringptr = readline(inputline, polyfile, polyfilename);
+  *holes = (int) strtol(stringptr, &stringptr, 0);
+  if (*holes > 0) {
+    holelist = (REAL *) trimalloc(2 * *holes * (int) sizeof(REAL));
+    *hlist = holelist;
+    for (i = 0; i < 2 * *holes; i += 2) {
+      stringptr = readline(inputline, polyfile, polyfilename);
+      stringptr = findfield(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  Hole %d has no x coordinate.\n",
+               b->firstnumber + (i >> 1));
+        triexit(1);
+      } else {
+        holelist[i] = (REAL) strtod(stringptr, &stringptr);
+      }
+      stringptr = findfield(stringptr);
+      if (*stringptr == '\0') {
+        printf("Error:  Hole %d has no y coordinate.\n",
+               b->firstnumber + (i >> 1));
+        triexit(1);
+      } else {
+        holelist[i + 1] = (REAL) strtod(stringptr, &stringptr);
+      }
+    }
+  } else {
+    *hlist = (REAL *) NULL;
+  }
+
+#ifndef CDT_ONLY
+  if ((b->regionattrib || b->vararea) && !b->refine) {
+    /* Read the area constraints. */
+    stringptr = readline(inputline, polyfile, polyfilename);
+    *regions = (int) strtol(stringptr, &stringptr, 0);
+    if (*regions > 0) {
+      regionlist = (REAL *) trimalloc(4 * *regions * (int) sizeof(REAL));
+      *rlist = regionlist;
+      index = 0;
+      for (i = 0; i < *regions; i++) {
+        stringptr = readline(inputline, polyfile, polyfilename);
+        stringptr = findfield(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Region %d has no x coordinate.\n",
+                 b->firstnumber + i);
+          triexit(1);
+        } else {
+          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findfield(stringptr);
+        if (*stringptr == '\0') {
+          printf("Error:  Region %d has no y coordinate.\n",
+                 b->firstnumber + i);
+          triexit(1);
+        } else {
+          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findfield(stringptr);
+        if (*stringptr == '\0') {
+          printf(
+            "Error:  Region %d has no region attribute or area constraint.\n",
+                 b->firstnumber + i);
+          triexit(1);
+        } else {
+          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
+        }
+        stringptr = findfield(stringptr);
+        if (*stringptr == '\0') {
+          regionlist[index] = regionlist[index - 1];
+        } else {
+          regionlist[index] = (REAL) strtod(stringptr, &stringptr);
+        }
+        index++;
+      }
+    }
+  } else {
+    /* Set `*regions' to zero to avoid an accidental free() later. */
+    *regions = 0;
+    *rlist = (REAL *) NULL;
+  }
+#endif /* not CDT_ONLY */
+
+  fclose(polyfile);
+}
+
+#endif /* not TRILIBRARY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  finishfile()   Write the command line to the output file so the user     */
+/*                 can remember how the file was generated.  Close the file. */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef TRILIBRARY
+
+#ifdef ANSI_DECLARATORS
+void finishfile(FILE *outfile, int argc, char **argv)
+#else /* not ANSI_DECLARATORS */
+void finishfile(outfile, argc, argv)
+FILE *outfile;
+int argc;
+char **argv;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  int i;
+
+  fprintf(outfile, "# Generated by");
+  for (i = 0; i < argc; i++) {
+    fprintf(outfile, " ");
+    fputs(argv[i], outfile);
+  }
+  fprintf(outfile, "\n");
+  fclose(outfile);
+}
+
+#endif /* not TRILIBRARY */
+
+/*****************************************************************************/
+/*                                                                           */
+/*  writenodes()   Number the vertices and write them to a .node file.       */
+/*                                                                           */
+/*  To save memory, the vertex numbers are written over the boundary markers */
+/*  after the vertices are written to a file.                                */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef TRILIBRARY
+
+#ifdef ANSI_DECLARATORS
+void writenodes(struct mesh *m, struct behavior *b, REAL **pointlist,
+                REAL **pointattriblist, int **pointmarkerlist)
+#else /* not ANSI_DECLARATORS */
+void writenodes(m, b, pointlist, pointattriblist, pointmarkerlist)
+struct mesh *m;
+struct behavior *b;
+REAL **pointlist;
+REAL **pointattriblist;
+int **pointmarkerlist;
+#endif /* not ANSI_DECLARATORS */
+
+#else /* not TRILIBRARY */
+
+#ifdef ANSI_DECLARATORS
+void writenodes(struct mesh *m, struct behavior *b, char *nodefilename,
+                int argc, char **argv)
+#else /* not ANSI_DECLARATORS */
+void writenodes(m, b, nodefilename, argc, argv)
+struct mesh *m;
+struct behavior *b;
+char *nodefilename;
+int argc;
+char **argv;
+#endif /* not ANSI_DECLARATORS */
+
+#endif /* not TRILIBRARY */
+
+{
+#ifdef TRILIBRARY
+  REAL *plist;
+  REAL *palist;
+  int *pmlist;
+  int coordindex;
+  int attribindex;
+#else /* not TRILIBRARY */
+  FILE *outfile;
+#endif /* not TRILIBRARY */
+  vertex vertexloop;
+  long outvertices;
+  int vertexnumber;
+  int i;
+
+  if (b->jettison) {
+    outvertices = m->vertices.items - m->undeads;
+  } else {
+    outvertices = m->vertices.items;
+  }
+
+#ifdef TRILIBRARY
+  if (!b->quiet) {
+    printf("Writing vertices.\n");
+  }
+  /* Allocate memory for output vertices if necessary. */
+  if (*pointlist == (REAL *) NULL) {
+    *pointlist = (REAL *) trimalloc((int) (outvertices * 2 * sizeof(REAL)));
+  }
+  /* Allocate memory for output vertex attributes if necessary. */
+  if ((m->nextras > 0) && (*pointattriblist == (REAL *) NULL)) {
+    *pointattriblist = (REAL *) trimalloc((int) (outvertices * m->nextras *
+                                                 sizeof(REAL)));
+  }
+  /* Allocate memory for output vertex markers if necessary. */
+  if (!b->nobound && (*pointmarkerlist == (int *) NULL)) {
+    *pointmarkerlist = (int *) trimalloc((int) (outvertices * sizeof(int)));
+  }
+  plist = *pointlist;
+  palist = *pointattriblist;
+  pmlist = *pointmarkerlist;
+  coordindex = 0;
+  attribindex = 0;
+#else /* not TRILIBRARY */
+  if (!b->quiet) {
+    printf("Writing %s.\n", nodefilename);
+  }
+  outfile = fopen(nodefilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("  Error:  Cannot create file %s.\n", nodefilename);
+    triexit(1);
+  }
+  /* Number of vertices, number of dimensions, number of vertex attributes, */
+  /*   and number of boundary markers (zero or one).                        */
+  fprintf(outfile, "%ld  %d  %d  %d\n", outvertices, m->mesh_dim,
+          m->nextras, 1 - b->nobound);
+#endif /* not TRILIBRARY */
+
+  traversalinit(&m->vertices);
+  vertexnumber = b->firstnumber;
+  vertexloop = vertextraverse(m);
+  while (vertexloop != (vertex) NULL) {
+    if (!b->jettison || (vertextype(vertexloop) != UNDEADVERTEX)) {
+#ifdef TRILIBRARY
+      /* X and y coordinates. */
+      plist[coordindex++] = vertexloop[0];
+      plist[coordindex++] = vertexloop[1];
+      /* Vertex attributes. */
+      for (i = 0; i < m->nextras; i++) {
+        palist[attribindex++] = vertexloop[2 + i];
+      }
+      if (!b->nobound) {
+        /* Copy the boundary marker. */
+        pmlist[vertexnumber - b->firstnumber] = vertexmark(vertexloop);
+      }
+#else /* not TRILIBRARY */
+      /* Vertex number, x and y coordinates. */
+      fprintf(outfile, "%4d    %.17g  %.17g", vertexnumber, vertexloop[0],
+              vertexloop[1]);
+      for (i = 0; i < m->nextras; i++) {
+        /* Write an attribute. */
+        fprintf(outfile, "  %.17g", vertexloop[i + 2]);
+      }
+      if (b->nobound) {
+        fprintf(outfile, "\n");
+      } else {
+        /* Write the boundary marker. */
+        fprintf(outfile, "    %d\n", vertexmark(vertexloop));
+      }
+#endif /* not TRILIBRARY */
+
+      setvertexmark(vertexloop, vertexnumber);
+      vertexnumber++;
+    }
+    vertexloop = vertextraverse(m);
+  }
+
+#ifndef TRILIBRARY
+  finishfile(outfile, argc, argv);
+#endif /* not TRILIBRARY */
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  numbernodes()   Number the vertices.                                     */
+/*                                                                           */
+/*  Each vertex is assigned a marker equal to its number.                    */
+/*                                                                           */
+/*  Used when writenodes() is not called because no .node file is written.   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void numbernodes(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void numbernodes(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  vertex vertexloop;
+  int vertexnumber;
+
+  traversalinit(&m->vertices);
+  vertexnumber = b->firstnumber;
+  vertexloop = vertextraverse(m);
+  while (vertexloop != (vertex) NULL) {
+    setvertexmark(vertexloop, vertexnumber);
+    if (!b->jettison || (vertextype(vertexloop) != UNDEADVERTEX)) {
+      vertexnumber++;
+    }
+    vertexloop = vertextraverse(m);
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  writeelements()   Write the triangles to an .ele file.                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef TRILIBRARY
+
+#ifdef ANSI_DECLARATORS
+void writeelements(struct mesh *m, struct behavior *b,
+                   int **trianglelist, REAL **triangleattriblist)
+#else /* not ANSI_DECLARATORS */
+void writeelements(m, b, trianglelist, triangleattriblist)
+struct mesh *m;
+struct behavior *b;
+int **trianglelist;
+REAL **triangleattriblist;
+#endif /* not ANSI_DECLARATORS */
+
+#else /* not TRILIBRARY */
+
+#ifdef ANSI_DECLARATORS
+void writeelements(struct mesh *m, struct behavior *b, char *elefilename,
+                   int argc, char **argv)
+#else /* not ANSI_DECLARATORS */
+void writeelements(m, b, elefilename, argc, argv)
+struct mesh *m;
+struct behavior *b;
+char *elefilename;
+int argc;
+char **argv;
+#endif /* not ANSI_DECLARATORS */
+
+#endif /* not TRILIBRARY */
+
+{
+#ifdef TRILIBRARY
+  int *tlist;
+  REAL *talist;
+  int vertexindex;
+  int attribindex;
+#else /* not TRILIBRARY */
+  FILE *outfile;
+#endif /* not TRILIBRARY */
+  struct otri triangleloop;
+  vertex p1, p2, p3;
+  vertex mid1, mid2, mid3;
+  long elementnumber;
+  int i;
+
+#ifdef TRILIBRARY
+  if (!b->quiet) {
+    printf("Writing triangles.\n");
+  }
+  /* Allocate memory for output triangles if necessary. */
+  if (*trianglelist == (int *) NULL) {
+    *trianglelist = (int *) trimalloc((int) (m->triangles.items *
+                                             ((b->order + 1) * (b->order + 2) /
+                                              2) * sizeof(int)));
+  }
+  /* Allocate memory for output triangle attributes if necessary. */
+  if ((m->eextras > 0) && (*triangleattriblist == (REAL *) NULL)) {
+    *triangleattriblist = (REAL *) trimalloc((int) (m->triangles.items *
+                                                    m->eextras *
+                                                    sizeof(REAL)));
+  }
+  tlist = *trianglelist;
+  talist = *triangleattriblist;
+  vertexindex = 0;
+  attribindex = 0;
+#else /* not TRILIBRARY */
+  if (!b->quiet) {
+    printf("Writing %s.\n", elefilename);
+  }
+  outfile = fopen(elefilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("  Error:  Cannot create file %s.\n", elefilename);
+    triexit(1);
+  }
+  /* Number of triangles, vertices per triangle, attributes per triangle. */
+  fprintf(outfile, "%ld  %d  %d\n", m->triangles.items,
+          (b->order + 1) * (b->order + 2) / 2, m->eextras);
+#endif /* not TRILIBRARY */
+
+  traversalinit(&m->triangles);
+  triangleloop.tri = triangletraverse(m);
+  triangleloop.orient = 0;
+  elementnumber = b->firstnumber;
+  while (triangleloop.tri != (triangle *) NULL) {
+    org(triangleloop, p1);
+    dest(triangleloop, p2);
+    apex(triangleloop, p3);
+    if (b->order == 1) {
+#ifdef TRILIBRARY
+      tlist[vertexindex++] = vertexmark(p1);
+      tlist[vertexindex++] = vertexmark(p2);
+      tlist[vertexindex++] = vertexmark(p3);
+#else /* not TRILIBRARY */
+      /* Triangle number, indices for three vertices. */
+      fprintf(outfile, "%4ld    %4d  %4d  %4d", elementnumber,
+              vertexmark(p1), vertexmark(p2), vertexmark(p3));
+#endif /* not TRILIBRARY */
+    } else {
+      mid1 = (vertex) triangleloop.tri[m->highorderindex + 1];
+      mid2 = (vertex) triangleloop.tri[m->highorderindex + 2];
+      mid3 = (vertex) triangleloop.tri[m->highorderindex];
+#ifdef TRILIBRARY
+      tlist[vertexindex++] = vertexmark(p1);
+      tlist[vertexindex++] = vertexmark(p2);
+      tlist[vertexindex++] = vertexmark(p3);
+      tlist[vertexindex++] = vertexmark(mid1);
+      tlist[vertexindex++] = vertexmark(mid2);
+      tlist[vertexindex++] = vertexmark(mid3);
+#else /* not TRILIBRARY */
+      /* Triangle number, indices for six vertices. */
+      fprintf(outfile, "%4ld    %4d  %4d  %4d  %4d  %4d  %4d", elementnumber,
+              vertexmark(p1), vertexmark(p2), vertexmark(p3), vertexmark(mid1),
+              vertexmark(mid2), vertexmark(mid3));
+#endif /* not TRILIBRARY */
+    }
+
+#ifdef TRILIBRARY
+    for (i = 0; i < m->eextras; i++) {
+      talist[attribindex++] = elemattribute(triangleloop, i);
+    }
+#else /* not TRILIBRARY */
+    for (i = 0; i < m->eextras; i++) {
+      fprintf(outfile, "  %.17g", elemattribute(triangleloop, i));
+    }
+    fprintf(outfile, "\n");
+#endif /* not TRILIBRARY */
+
+    triangleloop.tri = triangletraverse(m);
+    elementnumber++;
+  }
+
+#ifndef TRILIBRARY
+  finishfile(outfile, argc, argv);
+#endif /* not TRILIBRARY */
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  writepoly()   Write the segments and holes to a .poly file.              */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef TRILIBRARY
+
+#ifdef ANSI_DECLARATORS
+void writepoly(struct mesh *m, struct behavior *b,
+               int **segmentlist, int **segmentmarkerlist)
+#else /* not ANSI_DECLARATORS */
+void writepoly(m, b, segmentlist, segmentmarkerlist)
+struct mesh *m;
+struct behavior *b;
+int **segmentlist;
+int **segmentmarkerlist;
+#endif /* not ANSI_DECLARATORS */
+
+#else /* not TRILIBRARY */
+
+#ifdef ANSI_DECLARATORS
+void writepoly(struct mesh *m, struct behavior *b, char *polyfilename,
+               REAL *holelist, int holes, REAL *regionlist, int regions,
+               int argc, char **argv)
+#else /* not ANSI_DECLARATORS */
+void writepoly(m, b, polyfilename, holelist, holes, regionlist, regions,
+               argc, argv)
+struct mesh *m;
+struct behavior *b;
+char *polyfilename;
+REAL *holelist;
+int holes;
+REAL *regionlist;
+int regions;
+int argc;
+char **argv;
+#endif /* not ANSI_DECLARATORS */
+
+#endif /* not TRILIBRARY */
+
+{
+#ifdef TRILIBRARY
+  int *slist;
+  int *smlist;
+  int index;
+#else /* not TRILIBRARY */
+  FILE *outfile;
+  long holenumber, regionnumber;
+#endif /* not TRILIBRARY */
+  struct osub subsegloop;
+  vertex endpoint1, endpoint2;
+  long subsegnumber;
+
+#ifdef TRILIBRARY
+  if (!b->quiet) {
+    printf("Writing segments.\n");
+  }
+  /* Allocate memory for output segments if necessary. */
+  if (*segmentlist == (int *) NULL) {
+    *segmentlist = (int *) trimalloc((int) (m->subsegs.items * 2 *
+                                            sizeof(int)));
+  }
+  /* Allocate memory for output segment markers if necessary. */
+  if (!b->nobound && (*segmentmarkerlist == (int *) NULL)) {
+    *segmentmarkerlist = (int *) trimalloc((int) (m->subsegs.items *
+                                                  sizeof(int)));
+  }
+  slist = *segmentlist;
+  smlist = *segmentmarkerlist;
+  index = 0;
+#else /* not TRILIBRARY */
+  if (!b->quiet) {
+    printf("Writing %s.\n", polyfilename);
+  }
+  outfile = fopen(polyfilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("  Error:  Cannot create file %s.\n", polyfilename);
+    triexit(1);
+  }
+  /* 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(outfile, "%d  %d  %d  %d\n", 0, m->mesh_dim, m->nextras,
+          1 - b->nobound);
+  /* Number of segments, number of boundary markers (zero or one). */
+  fprintf(outfile, "%ld  %d\n", m->subsegs.items, 1 - b->nobound);
+#endif /* not TRILIBRARY */
+
+  traversalinit(&m->subsegs);
+  subsegloop.ss = subsegtraverse(m);
+  subsegloop.ssorient = 0;
+  subsegnumber = b->firstnumber;
+  while (subsegloop.ss != (subseg *) NULL) {
+    sorg(subsegloop, endpoint1);
+    sdest(subsegloop, endpoint2);
+#ifdef TRILIBRARY
+    /* Copy indices of the segment's two endpoints. */
+    slist[index++] = vertexmark(endpoint1);
+    slist[index++] = vertexmark(endpoint2);
+    if (!b->nobound) {
+      /* Copy the boundary marker. */
+      smlist[subsegnumber - b->firstnumber] = mark(subsegloop);
+    }
+#else /* not TRILIBRARY */
+    /* Segment number, indices of its two endpoints, and possibly a marker. */
+    if (b->nobound) {
+      fprintf(outfile, "%4ld    %4d  %4d\n", subsegnumber,
+              vertexmark(endpoint1), vertexmark(endpoint2));
+    } else {
+      fprintf(outfile, "%4ld    %4d  %4d    %4d\n", subsegnumber,
+              vertexmark(endpoint1), vertexmark(endpoint2), mark(subsegloop));
+    }
+#endif /* not TRILIBRARY */
+
+    subsegloop.ss = subsegtraverse(m);
+    subsegnumber++;
+  }
+
+#ifndef TRILIBRARY
+#ifndef CDT_ONLY
+  fprintf(outfile, "%d\n", holes);
+  if (holes > 0) {
+    for (holenumber = 0; holenumber < holes; holenumber++) {
+      /* Hole number, x and y coordinates. */
+      fprintf(outfile, "%4ld   %.17g  %.17g\n", b->firstnumber + holenumber,
+              holelist[2 * holenumber], holelist[2 * holenumber + 1]);
+    }
+  }
+  if (regions > 0) {
+    fprintf(outfile, "%d\n", regions);
+    for (regionnumber = 0; regionnumber < regions; regionnumber++) {
+      /* Region number, x and y coordinates, attribute, maximum area. */
+      fprintf(outfile, "%4ld   %.17g  %.17g  %.17g  %.17g\n",
+              b->firstnumber + regionnumber,
+              regionlist[4 * regionnumber], regionlist[4 * regionnumber + 1],
+              regionlist[4 * regionnumber + 2],
+              regionlist[4 * regionnumber + 3]);
+    }
+  }
+#endif /* not CDT_ONLY */
+
+  finishfile(outfile, argc, argv);
+#endif /* not TRILIBRARY */
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  writeedges()   Write the edges to an .edge file.                         */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef TRILIBRARY
+
+#ifdef ANSI_DECLARATORS
+void writeedges(struct mesh *m, struct behavior *b,
+                int **edgelist, int **edgemarkerlist)
+#else /* not ANSI_DECLARATORS */
+void writeedges(m, b, edgelist, edgemarkerlist)
+struct mesh *m;
+struct behavior *b;
+int **edgelist;
+int **edgemarkerlist;
+#endif /* not ANSI_DECLARATORS */
+
+#else /* not TRILIBRARY */
+
+#ifdef ANSI_DECLARATORS
+void writeedges(struct mesh *m, struct behavior *b, char *edgefilename,
+                int argc, char **argv)
+#else /* not ANSI_DECLARATORS */
+void writeedges(m, b, edgefilename, argc, argv)
+struct mesh *m;
+struct behavior *b;
+char *edgefilename;
+int argc;
+char **argv;
+#endif /* not ANSI_DECLARATORS */
+
+#endif /* not TRILIBRARY */
+
+{
+#ifdef TRILIBRARY
+  int *elist;
+  int *emlist;
+  int index;
+#else /* not TRILIBRARY */
+  FILE *outfile;
+#endif /* not TRILIBRARY */
+  struct otri triangleloop, trisym;
+  struct osub checkmark;
+  vertex p1, p2;
+  long edgenumber;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+  subseg sptr;                      /* Temporary variable used by tspivot(). */
+
+#ifdef TRILIBRARY
+  if (!b->quiet) {
+    printf("Writing edges.\n");
+  }
+  /* Allocate memory for edges if necessary. */
+  if (*edgelist == (int *) NULL) {
+    *edgelist = (int *) trimalloc((int) (m->edges * 2 * sizeof(int)));
+  }
+  /* Allocate memory for edge markers if necessary. */
+  if (!b->nobound && (*edgemarkerlist == (int *) NULL)) {
+    *edgemarkerlist = (int *) trimalloc((int) (m->edges * sizeof(int)));
+  }
+  elist = *edgelist;
+  emlist = *edgemarkerlist;
+  index = 0;
+#else /* not TRILIBRARY */
+  if (!b->quiet) {
+    printf("Writing %s.\n", edgefilename);
+  }
+  outfile = fopen(edgefilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("  Error:  Cannot create file %s.\n", edgefilename);
+    triexit(1);
+  }
+  /* Number of edges, number of boundary markers (zero or one). */
+  fprintf(outfile, "%ld  %d\n", m->edges, 1 - b->nobound);
+#endif /* not TRILIBRARY */
+
+  traversalinit(&m->triangles);
+  triangleloop.tri = triangletraverse(m);
+  edgenumber = b->firstnumber;
+  /* To loop over the set of edges, loop over all triangles, and look at   */
+  /*   the three edges of each triangle.  If there isn't another triangle  */
+  /*   adjacent to the edge, operate on the edge.  If there is another     */
+  /*   adjacent triangle, operate on the edge only if the current triangle */
+  /*   has a smaller pointer than its neighbor.  This way, each edge is    */
+  /*   considered only once.                                               */
+  while (triangleloop.tri != (triangle *) NULL) {
+    for (triangleloop.orient = 0; triangleloop.orient < 3;
+         triangleloop.orient++) {
+      sym(triangleloop, trisym);
+      if ((triangleloop.tri < trisym.tri) || (trisym.tri == m->dummytri)) {
+        org(triangleloop, p1);
+        dest(triangleloop, p2);
+#ifdef TRILIBRARY
+        elist[index++] = vertexmark(p1);
+        elist[index++] = vertexmark(p2);
+#endif /* TRILIBRARY */
+        if (b->nobound) {
+#ifndef TRILIBRARY
+          /* Edge number, indices of two endpoints. */
+          fprintf(outfile, "%4ld   %d  %d\n", edgenumber,
+                  vertexmark(p1), vertexmark(p2));
+#endif /* not TRILIBRARY */
+        } else {
+          /* Edge number, indices of two endpoints, and a boundary marker. */
+          /*   If there's no subsegment, the boundary marker is zero.      */
+          if (b->usesegments) {
+            tspivot(triangleloop, checkmark);
+            if (checkmark.ss == m->dummysub) {
+#ifdef TRILIBRARY
+              emlist[edgenumber - b->firstnumber] = 0;
+#else /* not TRILIBRARY */
+              fprintf(outfile, "%4ld   %d  %d  %d\n", edgenumber,
+                      vertexmark(p1), vertexmark(p2), 0);
+#endif /* not TRILIBRARY */
+            } else {
+#ifdef TRILIBRARY
+              emlist[edgenumber - b->firstnumber] = mark(checkmark);
+#else /* not TRILIBRARY */
+              fprintf(outfile, "%4ld   %d  %d  %d\n", edgenumber,
+                      vertexmark(p1), vertexmark(p2), mark(checkmark));
+#endif /* not TRILIBRARY */
+            }
+          } else {
+#ifdef TRILIBRARY
+            emlist[edgenumber - b->firstnumber] = trisym.tri == m->dummytri;
+#else /* not TRILIBRARY */
+            fprintf(outfile, "%4ld   %d  %d  %d\n", edgenumber,
+                    vertexmark(p1), vertexmark(p2), trisym.tri == m->dummytri);
+#endif /* not TRILIBRARY */
+          }
+        }
+        edgenumber++;
+      }
+    }
+    triangleloop.tri = triangletraverse(m);
+  }
+
+#ifndef TRILIBRARY
+  finishfile(outfile, argc, argv);
+#endif /* not TRILIBRARY */
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  writevoronoi()   Write the Voronoi diagram to a .v.node and .v.edge      */
+/*                   file.                                                   */
+/*                                                                           */
+/*  The Voronoi diagram is the geometric dual of the Delaunay triangulation. */
+/*  Hence, the Voronoi vertices are listed by traversing the Delaunay        */
+/*  triangles, and the Voronoi edges are listed by traversing the Delaunay   */
+/*  edges.                                                                   */
+/*                                                                           */
+/*  WARNING:  In order to assign numbers to the Voronoi vertices, this       */
+/*  procedure messes up the subsegments or the extra nodes of every          */
+/*  element.  Hence, you should call this procedure last.                    */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef TRILIBRARY
+
+#ifdef ANSI_DECLARATORS
+void writevoronoi(struct mesh *m, struct behavior *b, REAL **vpointlist,
+                  REAL **vpointattriblist, int **vpointmarkerlist,
+                  int **vedgelist, int **vedgemarkerlist, REAL **vnormlist)
+#else /* not ANSI_DECLARATORS */
+void writevoronoi(m, b, vpointlist, vpointattriblist, vpointmarkerlist,
+                  vedgelist, vedgemarkerlist, vnormlist)
+struct mesh *m;
+struct behavior *b;
+REAL **vpointlist;
+REAL **vpointattriblist;
+int **vpointmarkerlist;
+int **vedgelist;
+int **vedgemarkerlist;
+REAL **vnormlist;
+#endif /* not ANSI_DECLARATORS */
+
+#else /* not TRILIBRARY */
+
+#ifdef ANSI_DECLARATORS
+void writevoronoi(struct mesh *m, struct behavior *b, char *vnodefilename,
+                  char *vedgefilename, int argc, char **argv)
+#else /* not ANSI_DECLARATORS */
+void writevoronoi(m, b, vnodefilename, vedgefilename, argc, argv)
+struct mesh *m;
+struct behavior *b;
+char *vnodefilename;
+char *vedgefilename;
+int argc;
+char **argv;
+#endif /* not ANSI_DECLARATORS */
+
+#endif /* not TRILIBRARY */
+
+{
+#ifdef TRILIBRARY
+  REAL *plist;
+  REAL *palist;
+  int *elist;
+  REAL *normlist;
+  int coordindex;
+  int attribindex;
+#else /* not TRILIBRARY */
+  FILE *outfile;
+#endif /* not TRILIBRARY */
+  struct otri triangleloop, trisym;
+  vertex torg, tdest, tapex;
+  REAL circumcenter[2];
+  REAL xi, eta;
+  long vnodenumber, vedgenumber;
+  int p1, p2;
+  int i;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+#ifdef TRILIBRARY
+  if (!b->quiet) {
+    printf("Writing Voronoi vertices.\n");
+  }
+  /* Allocate memory for Voronoi vertices if necessary. */
+  if (*vpointlist == (REAL *) NULL) {
+    *vpointlist = (REAL *) trimalloc((int) (m->triangles.items * 2 *
+                                            sizeof(REAL)));
+  }
+  /* Allocate memory for Voronoi vertex attributes if necessary. */
+  if (*vpointattriblist == (REAL *) NULL) {
+    *vpointattriblist = (REAL *) trimalloc((int) (m->triangles.items *
+                                                  m->nextras * sizeof(REAL)));
+  }
+  *vpointmarkerlist = (int *) NULL;
+  plist = *vpointlist;
+  palist = *vpointattriblist;
+  coordindex = 0;
+  attribindex = 0;
+#else /* not TRILIBRARY */
+  if (!b->quiet) {
+    printf("Writing %s.\n", vnodefilename);
+  }
+  outfile = fopen(vnodefilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("  Error:  Cannot create file %s.\n", vnodefilename);
+    triexit(1);
+  }
+  /* Number of triangles, two dimensions, number of vertex attributes, */
+  /*   no markers.                                                     */
+  fprintf(outfile, "%ld  %d  %d  %d\n", m->triangles.items, 2, m->nextras, 0);
+#endif /* not TRILIBRARY */
+
+  traversalinit(&m->triangles);
+  triangleloop.tri = triangletraverse(m);
+  triangleloop.orient = 0;
+  vnodenumber = b->firstnumber;
+  while (triangleloop.tri != (triangle *) NULL) {
+    org(triangleloop, torg);
+    dest(triangleloop, tdest);
+    apex(triangleloop, tapex);
+    findcircumcenter(m, b, torg, tdest, tapex, circumcenter, &xi, &eta, 0);
+#ifdef TRILIBRARY
+    /* X and y coordinates. */
+    plist[coordindex++] = circumcenter[0];
+    plist[coordindex++] = circumcenter[1];
+    for (i = 2; i < 2 + m->nextras; i++) {
+      /* Interpolate the vertex attributes at the circumcenter. */
+      palist[attribindex++] = torg[i] + xi * (tdest[i] - torg[i])
+                                     + eta * (tapex[i] - torg[i]);
+    }
+#else /* not TRILIBRARY */
+    /* Voronoi vertex number, x and y coordinates. */
+    fprintf(outfile, "%4ld    %.17g  %.17g", vnodenumber, circumcenter[0],
+            circumcenter[1]);
+    for (i = 2; i < 2 + m->nextras; i++) {
+      /* Interpolate the vertex attributes at the circumcenter. */
+      fprintf(outfile, "  %.17g", torg[i] + xi * (tdest[i] - torg[i])
+                                         + eta * (tapex[i] - torg[i]));
+    }
+    fprintf(outfile, "\n");
+#endif /* not TRILIBRARY */
+
+    * (int *) (triangleloop.tri + 6) = (int) vnodenumber;
+    triangleloop.tri = triangletraverse(m);
+    vnodenumber++;
+  }
+
+#ifndef TRILIBRARY
+  finishfile(outfile, argc, argv);
+#endif /* not TRILIBRARY */
+
+#ifdef TRILIBRARY
+  if (!b->quiet) {
+    printf("Writing Voronoi edges.\n");
+  }
+  /* Allocate memory for output Voronoi edges if necessary. */
+  if (*vedgelist == (int *) NULL) {
+    *vedgelist = (int *) trimalloc((int) (m->edges * 2 * sizeof(int)));
+  }
+  *vedgemarkerlist = (int *) NULL;
+  /* Allocate memory for output Voronoi norms if necessary. */
+  if (*vnormlist == (REAL *) NULL) {
+    *vnormlist = (REAL *) trimalloc((int) (m->edges * 2 * sizeof(REAL)));
+  }
+  elist = *vedgelist;
+  normlist = *vnormlist;
+  coordindex = 0;
+#else /* not TRILIBRARY */
+  if (!b->quiet) {
+    printf("Writing %s.\n", vedgefilename);
+  }
+  outfile = fopen(vedgefilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("  Error:  Cannot create file %s.\n", vedgefilename);
+    triexit(1);
+  }
+  /* Number of edges, zero boundary markers. */
+  fprintf(outfile, "%ld  %d\n", m->edges, 0);
+#endif /* not TRILIBRARY */
+
+  traversalinit(&m->triangles);
+  triangleloop.tri = triangletraverse(m);
+  vedgenumber = b->firstnumber;
+  /* To loop over the set of edges, loop over all triangles, and look at   */
+  /*   the three edges of each triangle.  If there isn't another triangle  */
+  /*   adjacent to the edge, operate on the edge.  If there is another     */
+  /*   adjacent triangle, operate on the edge only if the current triangle */
+  /*   has a smaller pointer than its neighbor.  This way, each edge is    */
+  /*   considered only once.                                               */
+  while (triangleloop.tri != (triangle *) NULL) {
+    for (triangleloop.orient = 0; triangleloop.orient < 3;
+         triangleloop.orient++) {
+      sym(triangleloop, trisym);
+      if ((triangleloop.tri < trisym.tri) || (trisym.tri == m->dummytri)) {
+        /* Find the number of this triangle (and Voronoi vertex). */
+        p1 = * (int *) (triangleloop.tri + 6);
+        if (trisym.tri == m->dummytri) {
+          org(triangleloop, torg);
+          dest(triangleloop, tdest);
+#ifdef TRILIBRARY
+          /* Copy an infinite ray.  Index of one endpoint, and -1. */
+          elist[coordindex] = p1;
+          normlist[coordindex++] = tdest[1] - torg[1];
+          elist[coordindex] = -1;
+          normlist[coordindex++] = torg[0] - tdest[0];
+#else /* not TRILIBRARY */
+          /* Write an infinite ray.  Edge number, index of one endpoint, -1, */
+          /*   and x and y coordinates of a vector representing the          */
+          /*   direction of the ray.                                         */
+          fprintf(outfile, "%4ld   %d  %d   %.17g  %.17g\n", vedgenumber,
+                  p1, -1, tdest[1] - torg[1], torg[0] - tdest[0]);
+#endif /* not TRILIBRARY */
+        } else {
+          /* Find the number of the adjacent triangle (and Voronoi vertex). */
+          p2 = * (int *) (trisym.tri + 6);
+          /* Finite edge.  Write indices of two endpoints. */
+#ifdef TRILIBRARY
+          elist[coordindex] = p1;
+          normlist[coordindex++] = 0.0;
+          elist[coordindex] = p2;
+          normlist[coordindex++] = 0.0;
+#else /* not TRILIBRARY */
+          fprintf(outfile, "%4ld   %d  %d\n", vedgenumber, p1, p2);
+#endif /* not TRILIBRARY */
+        }
+        vedgenumber++;
+      }
+    }
+    triangleloop.tri = triangletraverse(m);
+  }
+
+#ifndef TRILIBRARY
+  finishfile(outfile, argc, argv);
+#endif /* not TRILIBRARY */
+}
+
+#ifdef TRILIBRARY
+
+#ifdef ANSI_DECLARATORS
+void writeneighbors(struct mesh *m, struct behavior *b, int **neighborlist)
+#else /* not ANSI_DECLARATORS */
+void writeneighbors(m, b, neighborlist)
+struct mesh *m;
+struct behavior *b;
+int **neighborlist;
+#endif /* not ANSI_DECLARATORS */
+
+#else /* not TRILIBRARY */
+
+#ifdef ANSI_DECLARATORS
+void writeneighbors(struct mesh *m, struct behavior *b, char *neighborfilename,
+                    int argc, char **argv)
+#else /* not ANSI_DECLARATORS */
+void writeneighbors(m, b, neighborfilename, argc, argv)
+struct mesh *m;
+struct behavior *b;
+char *neighborfilename;
+int argc;
+char **argv;
+#endif /* not ANSI_DECLARATORS */
+
+#endif /* not TRILIBRARY */
+
+{
+#ifdef TRILIBRARY
+  int *nlist;
+  int index;
+#else /* not TRILIBRARY */
+  FILE *outfile;
+#endif /* not TRILIBRARY */
+  struct otri triangleloop, trisym;
+  long elementnumber;
+  int neighbor1, neighbor2, neighbor3;
+  triangle ptr;                         /* Temporary variable used by sym(). */
+
+#ifdef TRILIBRARY
+  if (!b->quiet) {
+    printf("Writing neighbors.\n");
+  }
+  /* Allocate memory for neighbors if necessary. */
+  if (*neighborlist == (int *) NULL) {
+    *neighborlist = (int *) trimalloc((int) (m->triangles.items * 3 *
+                                             sizeof(int)));
+  }
+  nlist = *neighborlist;
+  index = 0;
+#else /* not TRILIBRARY */
+  if (!b->quiet) {
+    printf("Writing %s.\n", neighborfilename);
+  }
+  outfile = fopen(neighborfilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("  Error:  Cannot create file %s.\n", neighborfilename);
+    triexit(1);
+  }
+  /* Number of triangles, three neighbors per triangle. */
+  fprintf(outfile, "%ld  %d\n", m->triangles.items, 3);
+#endif /* not TRILIBRARY */
+
+  traversalinit(&m->triangles);
+  triangleloop.tri = triangletraverse(m);
+  triangleloop.orient = 0;
+  elementnumber = b->firstnumber;
+  while (triangleloop.tri != (triangle *) NULL) {
+    * (int *) (triangleloop.tri + 6) = (int) elementnumber;
+    triangleloop.tri = triangletraverse(m);
+    elementnumber++;
+  }
+  * (int *) (m->dummytri + 6) = -1;
+
+  traversalinit(&m->triangles);
+  triangleloop.tri = triangletraverse(m);
+  elementnumber = b->firstnumber;
+  while (triangleloop.tri != (triangle *) NULL) {
+    triangleloop.orient = 1;
+    sym(triangleloop, trisym);
+    neighbor1 = * (int *) (trisym.tri + 6);
+    triangleloop.orient = 2;
+    sym(triangleloop, trisym);
+    neighbor2 = * (int *) (trisym.tri + 6);
+    triangleloop.orient = 0;
+    sym(triangleloop, trisym);
+    neighbor3 = * (int *) (trisym.tri + 6);
+#ifdef TRILIBRARY
+    nlist[index++] = neighbor1;
+    nlist[index++] = neighbor2;
+    nlist[index++] = neighbor3;
+#else /* not TRILIBRARY */
+    /* Triangle number, neighboring triangle numbers. */
+    fprintf(outfile, "%4ld    %d  %d  %d\n", elementnumber,
+            neighbor1, neighbor2, neighbor3);
+#endif /* not TRILIBRARY */
+
+    triangleloop.tri = triangletraverse(m);
+    elementnumber++;
+  }
+
+#ifndef TRILIBRARY
+  finishfile(outfile, argc, argv);
+#endif /* not TRILIBRARY */
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  writeoff()   Write the triangulation to an .off file.                    */
+/*                                                                           */
+/*  OFF stands for the Object File Format, a format used by the Geometry     */
+/*  Center's Geomview package.                                               */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef TRILIBRARY
+
+#ifdef ANSI_DECLARATORS
+void writeoff(struct mesh *m, struct behavior *b, char *offfilename,
+              int argc, char **argv)
+#else /* not ANSI_DECLARATORS */
+void writeoff(m, b, offfilename, argc, argv)
+struct mesh *m;
+struct behavior *b;
+char *offfilename;
+int argc;
+char **argv;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  FILE *outfile;
+  struct otri triangleloop;
+  vertex vertexloop;
+  vertex p1, p2, p3;
+  long outvertices;
+
+  if (!b->quiet) {
+    printf("Writing %s.\n", offfilename);
+  }
+
+  if (b->jettison) {
+    outvertices = m->vertices.items - m->undeads;
+  } else {
+    outvertices = m->vertices.items;
+  }
+
+  outfile = fopen(offfilename, "w");
+  if (outfile == (FILE *) NULL) {
+    printf("  Error:  Cannot create file %s.\n", offfilename);
+    triexit(1);
+  }
+  /* Number of vertices, triangles, and edges. */
+  fprintf(outfile, "OFF\n%ld  %ld  %ld\n", outvertices, m->triangles.items,
+          m->edges);
+
+  /* Write the vertices. */
+  traversalinit(&m->vertices);
+  vertexloop = vertextraverse(m);
+  while (vertexloop != (vertex) NULL) {
+    if (!b->jettison || (vertextype(vertexloop) != UNDEADVERTEX)) {
+      /* The "0.0" is here because the OFF format uses 3D coordinates. */
+      fprintf(outfile, " %.17g  %.17g  %.17g\n", vertexloop[0], vertexloop[1],
+              0.0);
+    }
+    vertexloop = vertextraverse(m);
+  }
+
+  /* Write the triangles. */
+  traversalinit(&m->triangles);
+  triangleloop.tri = triangletraverse(m);
+  triangleloop.orient = 0;
+  while (triangleloop.tri != (triangle *) NULL) {
+    org(triangleloop, p1);
+    dest(triangleloop, p2);
+    apex(triangleloop, p3);
+    /* The "3" means a three-vertex polygon. */
+    fprintf(outfile, " 3   %4d  %4d  %4d\n", vertexmark(p1) - b->firstnumber,
+            vertexmark(p2) - b->firstnumber, vertexmark(p3) - b->firstnumber);
+    triangleloop.tri = triangletraverse(m);
+  }
+  finishfile(outfile, argc, argv);
+}
+
+#endif /* not TRILIBRARY */
+
+/**                                                                         **/
+/**                                                                         **/
+/********* File I/O routines end here                                *********/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  quality_statistics()   Print statistics about the quality of the mesh.   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void quality_statistics(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void quality_statistics(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  struct otri triangleloop;
+  vertex p[3];
+  REAL cossquaretable[8];
+  REAL ratiotable[16];
+  REAL dx[3], dy[3];
+  REAL edgelength[3];
+  REAL dotproduct;
+  REAL cossquare;
+  REAL triarea;
+  REAL shortest, longest;
+  REAL trilongest2;
+  REAL smallestarea, biggestarea;
+  REAL triminaltitude2;
+  REAL minaltitude;
+  REAL triaspect2;
+  REAL worstaspect;
+  REAL smallestangle, biggestangle;
+  REAL radconst, degconst;
+  int angletable[18];
+  int aspecttable[16];
+  int aspectindex;
+  int tendegree;
+  int acutebiggest;
+  int i, ii, j, k;
+
+  printf("Mesh quality statistics:\n\n");
+  radconst = PI / 18.0;
+  degconst = 180.0 / PI;
+  for (i = 0; i < 8; i++) {
+    cossquaretable[i] = cos(radconst * (REAL) (i + 1));
+    cossquaretable[i] = cossquaretable[i] * cossquaretable[i];
+  }
+  for (i = 0; i < 18; i++) {
+    angletable[i] = 0;
+  }
+
+  ratiotable[0]  =      1.5;      ratiotable[1]  =     2.0;
+  ratiotable[2]  =      2.5;      ratiotable[3]  =     3.0;
+  ratiotable[4]  =      4.0;      ratiotable[5]  =     6.0;
+  ratiotable[6]  =     10.0;      ratiotable[7]  =    15.0;
+  ratiotable[8]  =     25.0;      ratiotable[9]  =    50.0;
+  ratiotable[10] =    100.0;      ratiotable[11] =   300.0;
+  ratiotable[12] =   1000.0;      ratiotable[13] = 10000.0;
+  ratiotable[14] = 100000.0;      ratiotable[15] =     0.0;
+  for (i = 0; i < 16; i++) {
+    aspecttable[i] = 0;
+  }
+
+  worstaspect = 0.0;
+  minaltitude = m->xmax - m->xmin + m->ymax - m->ymin;
+  minaltitude = minaltitude * minaltitude;
+  shortest = minaltitude;
+  longest = 0.0;
+  smallestarea = minaltitude;
+  biggestarea = 0.0;
+  worstaspect = 0.0;
+  smallestangle = 0.0;
+  biggestangle = 2.0;
+  acutebiggest = 1;
+
+  traversalinit(&m->triangles);
+  triangleloop.tri = triangletraverse(m);
+  triangleloop.orient = 0;
+  while (triangleloop.tri != (triangle *) NULL) {
+    org(triangleloop, p[0]);
+    dest(triangleloop, p[1]);
+    apex(triangleloop, p[2]);
+    trilongest2 = 0.0;
+
+    for (i = 0; i < 3; i++) {
+      j = plus1mod3[i];
+      k = minus1mod3[i];
+      dx[i] = p[j][0] - p[k][0];
+      dy[i] = p[j][1] - p[k][1];
+      edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i];
+      if (edgelength[i] > trilongest2) {
+        trilongest2 = edgelength[i];
+      }
+      if (edgelength[i] > longest) {
+        longest = edgelength[i];
+      }
+      if (edgelength[i] < shortest) {
+        shortest = edgelength[i];
+      }
+    }
+
+    triarea = counterclockwise(m, b, p[0], p[1], p[2]);
+    if (triarea < smallestarea) {
+      smallestarea = triarea;
+    }
+    if (triarea > biggestarea) {
+      biggestarea = triarea;
+    }
+    triminaltitude2 = triarea * triarea / trilongest2;
+    if (triminaltitude2 < minaltitude) {
+      minaltitude = triminaltitude2;
+    }
+    triaspect2 = trilongest2 / triminaltitude2;
+    if (triaspect2 > worstaspect) {
+      worstaspect = triaspect2;
+    }
+    aspectindex = 0;
+    while ((triaspect2 > ratiotable[aspectindex] * ratiotable[aspectindex])
+           && (aspectindex < 15)) {
+      aspectindex++;
+    }
+    aspecttable[aspectindex]++;
+
+    for (i = 0; i < 3; i++) {
+      j = plus1mod3[i];
+      k = minus1mod3[i];
+      dotproduct = dx[j] * dx[k] + dy[j] * dy[k];
+      cossquare = dotproduct * dotproduct / (edgelength[j] * edgelength[k]);
+      tendegree = 8;
+      for (ii = 7; ii >= 0; ii--) {
+        if (cossquare > cossquaretable[ii]) {
+          tendegree = ii;
+        }
+      }
+      if (dotproduct <= 0.0) {
+        angletable[tendegree]++;
+        if (cossquare > smallestangle) {
+          smallestangle = cossquare;
+        }
+        if (acutebiggest && (cossquare < biggestangle)) {
+          biggestangle = cossquare;
+        }
+      } else {
+        angletable[17 - tendegree]++;
+        if (acutebiggest || (cossquare > biggestangle)) {
+          biggestangle = cossquare;
+          acutebiggest = 0;
+        }
+      }
+    }
+    triangleloop.tri = triangletraverse(m);
+  }
+
+  shortest = sqrt(shortest);
+  longest = sqrt(longest);
+  minaltitude = sqrt(minaltitude);
+  worstaspect = sqrt(worstaspect);
+  smallestarea *= 0.5;
+  biggestarea *= 0.5;
+  if (smallestangle >= 1.0) {
+    smallestangle = 0.0;
+  } else {
+    smallestangle = degconst * acos(sqrt(smallestangle));
+  }
+  if (biggestangle >= 1.0) {
+    biggestangle = 180.0;
+  } else {
+    if (acutebiggest) {
+      biggestangle = degconst * acos(sqrt(biggestangle));
+    } else {
+      biggestangle = 180.0 - degconst * acos(sqrt(biggestangle));
+    }
+  }
+
+  printf("  Smallest area: %16.5g   |  Largest area: %16.5g\n",
+         smallestarea, biggestarea);
+  printf("  Shortest edge: %16.5g   |  Longest edge: %16.5g\n",
+         shortest, longest);
+  printf("  Shortest altitude: %12.5g   |  Largest aspect ratio: %8.5g\n\n",
+         minaltitude, worstaspect);
+
+  printf("  Triangle aspect ratio histogram:\n");
+  printf("  1.1547 - %-6.6g    :  %8d    | %6.6g - %-6.6g     :  %8d\n",
+         ratiotable[0], aspecttable[0], ratiotable[7], ratiotable[8],
+         aspecttable[8]);
+  for (i = 1; i < 7; i++) {
+    printf("  %6.6g - %-6.6g    :  %8d    | %6.6g - %-6.6g     :  %8d\n",
+           ratiotable[i - 1], ratiotable[i], aspecttable[i],
+           ratiotable[i + 7], ratiotable[i + 8], aspecttable[i + 8]);
+  }
+  printf("  %6.6g - %-6.6g    :  %8d    | %6.6g -            :  %8d\n",
+         ratiotable[6], ratiotable[7], aspecttable[7], ratiotable[14],
+         aspecttable[15]);
+  printf("  (Aspect ratio is longest edge divided by shortest altitude)\n\n");
+
+  printf("  Smallest angle: %15.5g   |  Largest angle: %15.5g\n\n",
+         smallestangle, biggestangle);
+
+  printf("  Angle histogram:\n");
+  for (i = 0; i < 9; i++) {
+    printf("    %3d - %3d degrees:  %8d    |    %3d - %3d degrees:  %8d\n",
+           i * 10, i * 10 + 10, angletable[i],
+           i * 10 + 90, i * 10 + 100, angletable[i + 9]);
+  }
+  printf("\n");
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  statistics()   Print all sorts of cool facts.                            */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef ANSI_DECLARATORS
+void statistics(struct mesh *m, struct behavior *b)
+#else /* not ANSI_DECLARATORS */
+void statistics(m, b)
+struct mesh *m;
+struct behavior *b;
+#endif /* not ANSI_DECLARATORS */
+
+{
+  printf("\nStatistics:\n\n");
+  printf("  Input vertices: %d\n", m->invertices);
+  if (b->refine) {
+    printf("  Input triangles: %d\n", m->inelements);
+  }
+  if (b->poly) {
+    printf("  Input segments: %d\n", m->insegments);
+    if (!b->refine) {
+      printf("  Input holes: %d\n", m->holes);
+    }
+  }
+
+  printf("\n  Mesh vertices: %ld\n", m->vertices.items - m->undeads);
+  printf("  Mesh triangles: %ld\n", m->triangles.items);
+  printf("  Mesh edges: %ld\n", m->edges);
+  printf("  Mesh exterior boundary edges: %ld\n", m->hullsize);
+  if (b->poly || b->refine) {
+    printf("  Mesh interior boundary edges: %ld\n",
+           m->subsegs.items - m->hullsize);
+    printf("  Mesh subsegments (constrained edges): %ld\n",
+           m->subsegs.items);
+  }
+  printf("\n");
+
+  if (b->verbose) {
+    quality_statistics(m, b);
+    printf("Memory allocation statistics:\n\n");
+    printf("  Maximum number of vertices: %ld\n", m->vertices.maxitems);
+    printf("  Maximum number of triangles: %ld\n", m->triangles.maxitems);
+    if (m->subsegs.maxitems > 0) {
+      printf("  Maximum number of subsegments: %ld\n", m->subsegs.maxitems);
+    }
+    if (m->viri.maxitems > 0) {
+      printf("  Maximum number of viri: %ld\n", m->viri.maxitems);
+    }
+    if (m->badsubsegs.maxitems > 0) {
+      printf("  Maximum number of encroached subsegments: %ld\n",
+             m->badsubsegs.maxitems);
+    }
+    if (m->badtriangles.maxitems > 0) {
+      printf("  Maximum number of bad triangles: %ld\n",
+             m->badtriangles.maxitems);
+    }
+    if (m->flipstackers.maxitems > 0) {
+      printf("  Maximum number of stacked triangle flips: %ld\n",
+             m->flipstackers.maxitems);
+    }
+    if (m->splaynodes.maxitems > 0) {
+      printf("  Maximum number of splay tree nodes: %ld\n",
+             m->splaynodes.maxitems);
+    }
+    printf("  Approximate heap memory use (bytes): %ld\n\n",
+           m->vertices.maxitems * m->vertices.itembytes +
+           m->triangles.maxitems * m->triangles.itembytes +
+           m->subsegs.maxitems * m->subsegs.itembytes +
+           m->viri.maxitems * m->viri.itembytes +
+           m->badsubsegs.maxitems * m->badsubsegs.itembytes +
+           m->badtriangles.maxitems * m->badtriangles.itembytes +
+           m->flipstackers.maxitems * m->flipstackers.itembytes +
+           m->splaynodes.maxitems * m->splaynodes.itembytes);
+
+    printf("Algorithmic statistics:\n\n");
+    if (!b->weighted) {
+      printf("  Number of incircle tests: %ld\n", m->incirclecount);
+    } else {
+      printf("  Number of 3D orientation tests: %ld\n", m->orient3dcount);
+    }
+    printf("  Number of 2D orientation tests: %ld\n", m->counterclockcount);
+    if (m->hyperbolacount > 0) {
+      printf("  Number of right-of-hyperbola tests: %ld\n",
+             m->hyperbolacount);
+    }
+    if (m->circletopcount > 0) {
+      printf("  Number of circle top computations: %ld\n",
+             m->circletopcount);
+    }
+    if (m->circumcentercount > 0) {
+      printf("  Number of triangle circumcenter computations: %ld\n",
+             m->circumcentercount);
+    }
+    printf("\n");
+  }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*  main() or triangulate()   Gosh, do everything.                           */
+/*                                                                           */
+/*  The sequence is roughly as follows.  Many of these steps can be skipped, */
+/*  depending on the command line switches.                                  */
+/*                                                                           */
+/*  - Initialize constants and parse the command line.                       */
+/*  - Read the vertices from a file and either                               */
+/*    - triangulate them (no -r), or                                         */
+/*    - read an old mesh from files and reconstruct it (-r).                 */
+/*  - Insert the PSLG segments (-p), and possibly segments on the convex     */
+/*      hull (-c).                                                           */
+/*  - Read the holes (-p), regional attributes (-pA), and regional area      */
+/*      constraints (-pa).  Carve the holes and concavities, and spread the  */
+/*      regional attributes and area constraints.                            */
+/*  - Enforce the constraints on minimum angle (-q) and maximum area (-a).   */
+/*      Also enforce the conforming Delaunay property (-q and -a).           */
+/*  - Compute the number of edges in the resulting mesh.                     */
+/*  - Promote the mesh's linear triangles to higher order elements (-o).     */
+/*  - Write the output files and print the statistics.                       */
+/*  - Check the consistency and Delaunay property of the mesh (-C).          */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef TRILIBRARY
+
+#ifdef ANSI_DECLARATORS
+void triangulate(char *triswitches, struct triangulateio *in,
+                 struct triangulateio *out, struct triangulateio *vorout)
+#else /* not ANSI_DECLARATORS */
+void triangulate(triswitches, in, out, vorout)
+char *triswitches;
+struct triangulateio *in;
+struct triangulateio *out;
+struct triangulateio *vorout;
+#endif /* not ANSI_DECLARATORS */
+
+#else /* not TRILIBRARY */
+
+#ifdef ANSI_DECLARATORS
+int main(int argc, char **argv)
+#else /* not ANSI_DECLARATORS */
+int main(argc, argv)
+int argc;
+char **argv;
+#endif /* not ANSI_DECLARATORS */
+
+#endif /* not TRILIBRARY */
+
+{
+  struct mesh m;
+  struct behavior b;
+  REAL *holearray;                                        /* Array of holes. */
+  REAL *regionarray;   /* Array of regional attributes and area constraints. */
+#ifndef TRILIBRARY
+  FILE *polyfile;
+#endif /* not TRILIBRARY */
+#ifndef NO_TIMER
+  /* Variables for timing the performance of Triangle.  The types are */
+  /*   defined in sys/time.h.                                         */
+  struct timeval tv0, tv1, tv2, tv3, tv4, tv5, tv6;
+  struct timezone tz;
+#endif /* not NO_TIMER */
+
+#ifndef NO_TIMER
+  gettimeofday(&tv0, &tz);
+#endif /* not NO_TIMER */
+
+  triangleinit(&m);
+#ifdef TRILIBRARY
+  parsecommandline(1, &triswitches, &b);
+#else /* not TRILIBRARY */
+  parsecommandline(argc, argv, &b);
+#endif /* not TRILIBRARY */
+  m.steinerleft = b.steiner;
+
+#ifdef TRILIBRARY
+  transfernodes(&m, &b, in->pointlist, in->pointattributelist,
+                in->pointmarkerlist, in->numberofpoints,
+                in->numberofpointattributes);
+#else /* not TRILIBRARY */
+  readnodes(&m, &b, b.innodefilename, b.inpolyfilename, &polyfile);
+#endif /* not TRILIBRARY */
+
+#ifndef NO_TIMER
+  if (!b.quiet) {
+    gettimeofday(&tv1, &tz);
+  }
+#endif /* not NO_TIMER */
+
+#ifdef CDT_ONLY
+  m.hullsize = delaunay(&m, &b);                /* Triangulate the vertices. */
+#else /* not CDT_ONLY */
+  if (b.refine) {
+    /* Read and reconstruct a mesh. */
+#ifdef TRILIBRARY
+    m.hullsize = reconstruct(&m, &b, in->trianglelist,
+                             in->triangleattributelist, in->trianglearealist,
+                             in->numberoftriangles, in->numberofcorners,
+                             in->numberoftriangleattributes,
+                             in->segmentlist, in->segmentmarkerlist,
+                             in->numberofsegments);
+#else /* not TRILIBRARY */
+    m.hullsize = reconstruct(&m, &b, b.inelefilename, b.areafilename,
+                             b.inpolyfilename, polyfile);
+#endif /* not TRILIBRARY */
+  } else {
+    m.hullsize = delaunay(&m, &b);              /* Triangulate the vertices. */
+  }
+#endif /* not CDT_ONLY */
+
+#ifndef NO_TIMER
+  if (!b.quiet) {
+    gettimeofday(&tv2, &tz);
+    if (b.refine) {
+      printf("Mesh reconstruction");
+    } else {
+      printf("Delaunay");
+    }
+    printf(" milliseconds:  %ld\n", 1000l * (tv2.tv_sec - tv1.tv_sec) +
+           (tv2.tv_usec - tv1.tv_usec) / 1000l);
+  }
+#endif /* not NO_TIMER */
+
+  /* Ensure that no vertex can be mistaken for a triangular bounding */
+  /*   box vertex in insertvertex().                                 */
+  m.infvertex1 = (vertex) NULL;
+  m.infvertex2 = (vertex) NULL;
+  m.infvertex3 = (vertex) NULL;
+
+  if (b.usesegments) {
+    m.checksegments = 1;                /* Segments will be introduced next. */
+    if (!b.refine) {
+      /* Insert PSLG segments and/or convex hull segments. */
+#ifdef TRILIBRARY
+      formskeleton(&m, &b, in->segmentlist,
+                   in->segmentmarkerlist, in->numberofsegments);
+#else /* not TRILIBRARY */
+      formskeleton(&m, &b, polyfile, b.inpolyfilename);
+#endif /* not TRILIBRARY */
+    }
+  }
+
+#ifndef NO_TIMER
+  if (!b.quiet) {
+    gettimeofday(&tv3, &tz);
+    if (b.usesegments && !b.refine) {
+      printf("Segment milliseconds:  %ld\n",
+             1000l * (tv3.tv_sec - tv2.tv_sec) +
+             (tv3.tv_usec - tv2.tv_usec) / 1000l);
+    }
+  }
+#endif /* not NO_TIMER */
+
+  if (b.poly && (m.triangles.items > 0)) {
+#ifdef TRILIBRARY
+    holearray = in->holelist;
+    m.holes = in->numberofholes;
+    regionarray = in->regionlist;
+    m.regions = in->numberofregions;
+#else /* not TRILIBRARY */
+    readholes(&m, &b, polyfile, b.inpolyfilename, &holearray, &m.holes,
+              &regionarray, &m.regions);
+#endif /* not TRILIBRARY */
+    if (!b.refine) {
+      /* Carve out holes and concavities. */
+      carveholes(&m, &b, holearray, m.holes, regionarray, m.regions);
+    }
+  } else {
+    /* Without a PSLG, there can be no holes or regional attributes   */
+    /*   or area constraints.  The following are set to zero to avoid */
+    /*   an accidental free() later.                                  */
+    m.holes = 0;
+    m.regions = 0;
+  }
+
+#ifndef NO_TIMER
+  if (!b.quiet) {
+    gettimeofday(&tv4, &tz);
+    if (b.poly && !b.refine) {
+      printf("Hole milliseconds:  %ld\n", 1000l * (tv4.tv_sec - tv3.tv_sec) +
+             (tv4.tv_usec - tv3.tv_usec) / 1000l);
+    }
+  }
+#endif /* not NO_TIMER */
+
+#ifndef CDT_ONLY
+  if (b.quality && (m.triangles.items > 0)) {
+    enforcequality(&m, &b);           /* Enforce angle and area constraints. */
+  }
+#endif /* not CDT_ONLY */
+
+#ifndef NO_TIMER
+  if (!b.quiet) {
+    gettimeofday(&tv5, &tz);
+#ifndef CDT_ONLY
+    if (b.quality) {
+      printf("Quality milliseconds:  %ld\n",
+             1000l * (tv5.tv_sec - tv4.tv_sec) +
+             (tv5.tv_usec - tv4.tv_usec) / 1000l);
+    }
+#endif /* not CDT_ONLY */
+  }
+#endif /* not NO_TIMER */
+
+  /* Calculate the number of edges. */
+  m.edges = (3l * m.triangles.items + m.hullsize) / 2l;
+
+  if (b.order > 1) {
+    highorder(&m, &b);       /* Promote elements to higher polynomial order. */
+  }
+  if (!b.quiet) {
+    printf("\n");
+  }
+
+#ifdef TRILIBRARY
+  if (b.jettison) {
+    out->numberofpoints = m.vertices.items - m.undeads;
+  } else {
+    out->numberofpoints = m.vertices.items;
+  }
+  out->numberofpointattributes = m.nextras;
+  out->numberoftriangles = m.triangles.items;
+  out->numberofcorners = (b.order + 1) * (b.order + 2) / 2;
+  out->numberoftriangleattributes = m.eextras;
+  out->numberofedges = m.edges;
+  if (b.usesegments) {
+    out->numberofsegments = m.subsegs.items;
+  } else {
+    out->numberofsegments = m.hullsize;
+  }
+  if (vorout != (struct triangulateio *) NULL) {
+    vorout->numberofpoints = m.triangles.items;
+    vorout->numberofpointattributes = m.nextras;
+    vorout->numberofedges = m.edges;
+  }
+#endif /* TRILIBRARY */
+  /* If not using iteration numbers, don't write a .node file if one was */
+  /*   read, because the original one would be overwritten!              */
+  if (b.nonodewritten || (b.noiterationnum && m.readnodefile)) {
+    if (!b.quiet) {
+#ifdef TRILIBRARY
+      printf("NOT writing vertices.\n");
+#else /* not TRILIBRARY */
+      printf("NOT writing a .node file.\n");
+#endif /* not TRILIBRARY */
+    }
+    numbernodes(&m, &b);         /* We must remember to number the vertices. */
+  } else {
+    /* writenodes() numbers the vertices too. */
+#ifdef TRILIBRARY
+    writenodes(&m, &b, &out->pointlist, &out->pointattributelist,
+               &out->pointmarkerlist);
+#else /* not TRILIBRARY */
+    writenodes(&m, &b, b.outnodefilename, argc, argv);
+#endif /* TRILIBRARY */
+  }
+  if (b.noelewritten) {
+    if (!b.quiet) {
+#ifdef TRILIBRARY
+      printf("NOT writing triangles.\n");
+#else /* not TRILIBRARY */
+      printf("NOT writing an .ele file.\n");
+#endif /* not TRILIBRARY */
+    }
+  } else {
+#ifdef TRILIBRARY
+    writeelements(&m, &b, &out->trianglelist, &out->triangleattributelist);
+#else /* not TRILIBRARY */
+    writeelements(&m, &b, b.outelefilename, argc, argv);
+#endif /* not TRILIBRARY */
+  }
+  /* The -c switch (convex switch) causes a PSLG to be written */
+  /*   even if none was read.                                  */
+  if (b.poly || b.convex) {
+    /* If not using iteration numbers, don't overwrite the .poly file. */
+    if (b.nopolywritten || b.noiterationnum) {
+      if (!b.quiet) {
+#ifdef TRILIBRARY
+        printf("NOT writing segments.\n");
+#else /* not TRILIBRARY */
+        printf("NOT writing a .poly file.\n");
+#endif /* not TRILIBRARY */
+      }
+    } else {
+#ifdef TRILIBRARY
+      writepoly(&m, &b, &out->segmentlist, &out->segmentmarkerlist);
+      out->numberofholes = m.holes;
+      out->numberofregions = m.regions;
+      if (b.poly) {
+        out->holelist = in->holelist;
+        out->regionlist = in->regionlist;
+      } else {
+        out->holelist = (REAL *) NULL;
+        out->regionlist = (REAL *) NULL;
+      }
+#else /* not TRILIBRARY */
+      writepoly(&m, &b, b.outpolyfilename, holearray, m.holes, regionarray,
+                m.regions, argc, argv);
+#endif /* not TRILIBRARY */
+    }
+  }
+#ifndef TRILIBRARY
+#ifndef CDT_ONLY
+  if (m.regions > 0) {
+    trifree((VOID *) regionarray);
+  }
+#endif /* not CDT_ONLY */
+  if (m.holes > 0) {
+    trifree((VOID *) holearray);
+  }
+  if (b.geomview) {
+    writeoff(&m, &b, b.offfilename, argc, argv);
+  }
+#endif /* not TRILIBRARY */
+  if (b.edgesout) {
+#ifdef TRILIBRARY
+    writeedges(&m, &b, &out->edgelist, &out->edgemarkerlist);
+#else /* not TRILIBRARY */
+    writeedges(&m, &b, b.edgefilename, argc, argv);
+#endif /* not TRILIBRARY */
+  }
+  if (b.voronoi) {
+#ifdef TRILIBRARY
+    writevoronoi(&m, &b, &vorout->pointlist, &vorout->pointattributelist,
+                 &vorout->pointmarkerlist, &vorout->edgelist,
+                 &vorout->edgemarkerlist, &vorout->normlist);
+#else /* not TRILIBRARY */
+    writevoronoi(&m, &b, b.vnodefilename, b.vedgefilename, argc, argv);
+#endif /* not TRILIBRARY */
+  }
+  if (b.neighbors) {
+#ifdef TRILIBRARY
+    writeneighbors(&m, &b, &out->neighborlist);
+#else /* not TRILIBRARY */
+    writeneighbors(&m, &b, b.neighborfilename, argc, argv);
+#endif /* not TRILIBRARY */
+  }
+
+  if (!b.quiet) {
+#ifndef NO_TIMER
+    gettimeofday(&tv6, &tz);
+    printf("\nOutput milliseconds:  %ld\n",
+           1000l * (tv6.tv_sec - tv5.tv_sec) +
+           (tv6.tv_usec - tv5.tv_usec) / 1000l);
+    printf("Total running milliseconds:  %ld\n",
+           1000l * (tv6.tv_sec - tv0.tv_sec) +
+           (tv6.tv_usec - tv0.tv_usec) / 1000l);
+#endif /* not NO_TIMER */
+
+    statistics(&m, &b);
+  }
+
+#ifndef REDUCED
+  if (b.docheck) {
+    checkmesh(&m, &b);
+    checkdelaunay(&m, &b);
+  }
+#endif /* not REDUCED */
+
+  triangledeinit(&m, &b);
+#ifndef TRILIBRARY
+  return 0;
+#endif /* not TRILIBRARY */
+}
diff --git a/meshpy/src/cpp/triangle.h b/meshpy/src/cpp/triangle.h
new file mode 100644
index 0000000000000000000000000000000000000000..3f08ddec29cec9f45a545b278cdb99928cff3714
--- /dev/null
+++ b/meshpy/src/cpp/triangle.h
@@ -0,0 +1,324 @@
+#ifndef _HEADER_SEEN_TRIANGLE_H
+#define _HEADER_SEEN_TRIANGLE_H
+
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/*****************************************************************************/
+/*                                                                           */
+/*  (triangle.h)                                                             */
+/*                                                                           */
+/*  Include file for programs that call Triangle.                            */
+/*                                                                           */
+/*  Accompanies Triangle Version 1.6                                         */
+/*  July 28, 2005                                                            */
+/*                                                                           */
+/*  Copyright 1996, 2005                                                     */
+/*  Jonathan Richard Shewchuk                                                */
+/*  2360 Woolsey #H                                                          */
+/*  Berkeley, California  94705-1927                                         */
+/*  jrs@cs.berkeley.edu                                                      */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  How to call Triangle from another program                                */
+/*                                                                           */
+/*                                                                           */
+/*  If you haven't read Triangle's instructions (run "triangle -h" to read   */
+/*  them), you won't understand what follows.                                */
+/*                                                                           */
+/*  Triangle must be compiled into an object file (triangle.o) with the      */
+/*  TRILIBRARY symbol defined (generally by using the -DTRILIBRARY compiler  */
+/*  switch).  The makefile included with Triangle will do this for you if    */
+/*  you run "make trilibrary".  The resulting object file can be called via  */
+/*  the procedure triangulate().                                             */
+/*                                                                           */
+/*  If the size of the object file is important to you, you may wish to      */
+/*  generate a reduced version of triangle.o.  The REDUCED symbol gets rid   */
+/*  of all features that are primarily of research interest.  Specifically,  */
+/*  the -DREDUCED switch eliminates Triangle's -i, -F, -s, and -C switches.  */
+/*  The CDT_ONLY symbol gets rid of all meshing algorithms above and beyond  */
+/*  constrained Delaunay triangulation.  Specifically, the -DCDT_ONLY switch */
+/*  eliminates Triangle's -r, -q, -a, -u, -D, -Y, -S, and -s switches.       */
+/*                                                                           */
+/*  IMPORTANT:  These definitions (TRILIBRARY, REDUCED, CDT_ONLY) must be    */
+/*  made in the makefile or in triangle.c itself.  Putting these definitions */
+/*  in this file (triangle.h) will not create the desired effect.            */
+/*                                                                           */
+/*                                                                           */
+/*  The calling convention for triangulate() follows.                        */
+/*                                                                           */
+/*      void triangulate(triswitches, in, out, vorout)                       */
+/*      char *triswitches;                                                   */
+/*      struct triangulateio *in;                                            */
+/*      struct triangulateio *out;                                           */
+/*      struct triangulateio *vorout;                                        */
+/*                                                                           */
+/*  `triswitches' is a string containing the command line switches you wish  */
+/*  to invoke.  No initial dash is required.  Some suggestions:              */
+/*                                                                           */
+/*  - You'll probably find it convenient to use the `z' switch so that       */
+/*    points (and other items) are numbered from zero.  This simplifies      */
+/*    indexing, because the first item of any type always starts at index    */
+/*    [0] of the corresponding array, whether that item's number is zero or  */
+/*    one.                                                                   */
+/*  - You'll probably want to use the `Q' (quiet) switch in your final code, */
+/*    but you can take advantage of Triangle's printed output (including the */
+/*    `V' switch) while debugging.                                           */
+/*  - If you are not using the `q', `a', `u', `D', `j', or `s' switches,     */
+/*    then the output points will be identical to the input points, except   */
+/*    possibly for the boundary markers.  If you don't need the boundary     */
+/*    markers, you should use the `N' (no nodes output) switch to save       */
+/*    memory.  (If you do need boundary markers, but need to save memory, a  */
+/*    good nasty trick is to set out->pointlist equal to in->pointlist       */
+/*    before calling triangulate(), so that Triangle overwrites the input    */
+/*    points with identical copies.)                                         */
+/*  - The `I' (no iteration numbers) and `g' (.off file output) switches     */
+/*    have no effect when Triangle is compiled with TRILIBRARY defined.      */
+/*                                                                           */
+/*  `in', `out', and `vorout' are descriptions of the input, the output,     */
+/*  and the Voronoi output.  If the `v' (Voronoi output) switch is not used, */
+/*  `vorout' may be NULL.  `in' and `out' may never be NULL.                 */
+/*                                                                           */
+/*  Certain fields of the input and output structures must be initialized,   */
+/*  as described below.                                                      */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/*                                                                           */
+/*  The `triangulateio' structure.                                           */
+/*                                                                           */
+/*  Used to pass data into and out of the triangulate() procedure.           */
+/*                                                                           */
+/*                                                                           */
+/*  Arrays are used to store points, triangles, markers, and so forth.  In   */
+/*  all cases, the first item in any array is stored starting at index [0].  */
+/*  However, that item is item number `1' unless the `z' switch is used, in  */
+/*  which case it is item number `0'.  Hence, you may find it easier to      */
+/*  index points (and triangles in the neighbor list) if you use the `z'     */
+/*  switch.  Unless, of course, you're calling Triangle from a Fortran       */
+/*  program.                                                                 */
+/*                                                                           */
+/*  Description of fields (except the `numberof' fields, which are obvious): */
+/*                                                                           */
+/*  `pointlist':  An array of point coordinates.  The first point's x        */
+/*    coordinate is at index [0] and its y coordinate at index [1], followed */
+/*    by the coordinates of the remaining points.  Each point occupies two   */
+/*    REALs.                                                                 */
+/*  `pointattributelist':  An array of point attributes.  Each point's       */
+/*    attributes occupy `numberofpointattributes' REALs.                     */
+/*  `pointmarkerlist':  An array of point markers; one int per point.        */
+/*                                                                           */
+/*  `trianglelist':  An array of triangle corners.  The first triangle's     */
+/*    first corner is at index [0], followed by its other two corners in     */
+/*    counterclockwise order, followed by any other nodes if the triangle    */
+/*    represents a nonlinear element.  Each triangle occupies                */
+/*    `numberofcorners' ints.                                                */
+/*  `triangleattributelist':  An array of triangle attributes.  Each         */
+/*    triangle's attributes occupy `numberoftriangleattributes' REALs.       */
+/*  `trianglearealist':  An array of triangle area constraints; one REAL per */
+/*    triangle.  Input only.                                                 */
+/*  `neighborlist':  An array of triangle neighbors; three ints per          */
+/*    triangle.  Output only.                                                */
+/*                                                                           */
+/*  `segmentlist':  An array of segment endpoints.  The first segment's      */
+/*    endpoints are at indices [0] and [1], followed by the remaining        */
+/*    segments.  Two ints per segment.                                       */
+/*  `segmentmarkerlist':  An array of segment markers; one int per segment.  */
+/*                                                                           */
+/*  `holelist':  An array of holes.  The first hole's x and y coordinates    */
+/*    are at indices [0] and [1], followed by the remaining holes.  Two      */
+/*    REALs per hole.  Input only, although the pointer is copied to the     */
+/*    output structure for your convenience.                                 */
+/*                                                                           */
+/*  `regionlist':  An array of regional attributes and area constraints.     */
+/*    The first constraint's x and y coordinates are at indices [0] and [1], */
+/*    followed by the regional attribute at index [2], followed by the       */
+/*    maximum area at index [3], followed by the remaining area constraints. */
+/*    Four REALs per area constraint.  Note that each regional attribute is  */
+/*    used only if you select the `A' switch, and each area constraint is    */
+/*    used only if you select the `a' switch (with no number following), but */
+/*    omitting one of these switches does not change the memory layout.      */
+/*    Input only, although the pointer is copied to the output structure for */
+/*    your convenience.                                                      */
+/*                                                                           */
+/*  `edgelist':  An array of edge endpoints.  The first edge's endpoints are */
+/*    at indices [0] and [1], followed by the remaining edges.  Two ints per */
+/*    edge.  Output only.                                                    */
+/*  `edgemarkerlist':  An array of edge markers; one int per edge.  Output   */
+/*    only.                                                                  */
+/*  `normlist':  An array of normal vectors, used for infinite rays in       */
+/*    Voronoi diagrams.  The first normal vector's x and y magnitudes are    */
+/*    at indices [0] and [1], followed by the remaining vectors.  For each   */
+/*    finite edge in a Voronoi diagram, the normal vector written is the     */
+/*    zero vector.  Two REALs per edge.  Output only.                        */
+/*                                                                           */
+/*                                                                           */
+/*  Any input fields that Triangle will examine must be initialized.         */
+/*  Furthermore, for each output array that Triangle will write to, you      */
+/*  must either provide space by setting the appropriate pointer to point    */
+/*  to the space you want the data written to, or you must initialize the    */
+/*  pointer to NULL, which tells Triangle to allocate space for the results. */
+/*  The latter option is preferable, because Triangle always knows exactly   */
+/*  how much space to allocate.  The former option is provided mainly for    */
+/*  people who need to call Triangle from Fortran code, though it also makes */
+/*  possible some nasty space-saving tricks, like writing the output to the  */
+/*  same arrays as the input.                                                */
+/*                                                                           */
+/*  Triangle will not free() any input or output arrays, including those it  */
+/*  allocates itself; that's up to you.  You should free arrays allocated by */
+/*  Triangle by calling the trifree() procedure defined below.  (By default, */
+/*  trifree() just calls the standard free() library procedure, but          */
+/*  applications that call triangulate() may replace trimalloc() and         */
+/*  trifree() in triangle.c to use specialized memory allocators.)           */
+/*                                                                           */
+/*  Here's a guide to help you decide which fields you must initialize       */
+/*  before you call triangulate().                                           */
+/*                                                                           */
+/*  `in':                                                                    */
+/*                                                                           */
+/*    - `pointlist' must always point to a list of points; `numberofpoints'  */
+/*      and `numberofpointattributes' must be properly set.                  */
+/*      `pointmarkerlist' must either be set to NULL (in which case all      */
+/*      markers default to zero), or must point to a list of markers.  If    */
+/*      `numberofpointattributes' is not zero, `pointattributelist' must     */
+/*      point to a list of point attributes.                                 */
+/*    - If the `r' switch is used, `trianglelist' must point to a list of    */
+/*      triangles, and `numberoftriangles', `numberofcorners', and           */
+/*      `numberoftriangleattributes' must be properly set.  If               */
+/*      `numberoftriangleattributes' is not zero, `triangleattributelist'    */
+/*      must point to a list of triangle attributes.  If the `a' switch is   */
+/*      used (with no number following), `trianglearealist' must point to a  */
+/*      list of triangle area constraints.  `neighborlist' may be ignored.   */
+/*    - If the `p' switch is used, `segmentlist' must point to a list of     */
+/*      segments, `numberofsegments' must be properly set, and               */
+/*      `segmentmarkerlist' must either be set to NULL (in which case all    */
+/*      markers default to zero), or must point to a list of markers.        */
+/*    - If the `p' switch is used without the `r' switch, then               */
+/*      `numberofholes' and `numberofregions' must be properly set.  If      */
+/*      `numberofholes' is not zero, `holelist' must point to a list of      */
+/*      holes.  If `numberofregions' is not zero, `regionlist' must point to */
+/*      a list of region constraints.                                        */
+/*    - If the `p' switch is used, `holelist', `numberofholes',              */
+/*      `regionlist', and `numberofregions' is copied to `out'.  (You can    */
+/*      nonetheless get away with not initializing them if the `r' switch is */
+/*      used.)                                                               */
+/*    - `edgelist', `edgemarkerlist', `normlist', and `numberofedges' may be */
+/*      ignored.                                                             */
+/*                                                                           */
+/*  `out':                                                                   */
+/*                                                                           */
+/*    - `pointlist' must be initialized (NULL or pointing to memory) unless  */
+/*      the `N' switch is used.  `pointmarkerlist' must be initialized       */
+/*      unless the `N' or `B' switch is used.  If `N' is not used and        */
+/*      `in->numberofpointattributes' is not zero, `pointattributelist' must */
+/*      be initialized.                                                      */
+/*    - `trianglelist' must be initialized unless the `E' switch is used.    */
+/*      `neighborlist' must be initialized if the `n' switch is used.  If    */
+/*      the `E' switch is not used and (`in->numberofelementattributes' is   */
+/*      not zero or the `A' switch is used), `elementattributelist' must be  */
+/*      initialized.  `trianglearealist' may be ignored.                     */
+/*    - `segmentlist' must be initialized if the `p' or `c' switch is used,  */
+/*      and the `P' switch is not used.  `segmentmarkerlist' must also be    */
+/*      initialized under these circumstances unless the `B' switch is used. */
+/*    - `edgelist' must be initialized if the `e' switch is used.            */
+/*      `edgemarkerlist' must be initialized if the `e' switch is used and   */
+/*      the `B' switch is not.                                               */
+/*    - `holelist', `regionlist', `normlist', and all scalars may be ignored.*/
+/*                                                                           */
+/*  `vorout' (only needed if `v' switch is used):                            */
+/*                                                                           */
+/*    - `pointlist' must be initialized.  If `in->numberofpointattributes'   */
+/*      is not zero, `pointattributelist' must be initialized.               */
+/*      `pointmarkerlist' may be ignored.                                    */
+/*    - `edgelist' and `normlist' must both be initialized.                  */
+/*      `edgemarkerlist' may be ignored.                                     */
+/*    - Everything else may be ignored.                                      */
+/*                                                                           */
+/*  After a call to triangulate(), the valid fields of `out' and `vorout'    */
+/*  will depend, in an obvious way, on the choice of switches used.  Note    */
+/*  that when the `p' switch is used, the pointers `holelist' and            */
+/*  `regionlist' are copied from `in' to `out', but no new space is          */
+/*  allocated; be careful that you don't free() the same array twice.  On    */
+/*  the other hand, Triangle will never copy the `pointlist' pointer (or any */
+/*  others); new space is allocated for `out->pointlist', or if the `N'      */
+/*  switch is used, `out->pointlist' remains uninitialized.                  */
+/*                                                                           */
+/*  All of the meaningful `numberof' fields will be properly set; for        */
+/*  instance, `numberofedges' will represent the number of edges in the      */
+/*  triangulation whether or not the edges were written.  If segments are    */
+/*  not used, `numberofsegments' will indicate the number of boundary edges. */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifdef SINGLE
+#define REAL float
+#else /* not SINGLE */
+#define REAL double
+#endif /* not SINGLE */
+
+#define VOID void
+
+/* The vertex data structure.  Each vertex is actually an array of REALs.    */
+/*   The number of REALs is unknown until runtime.  An integer boundary      */
+/*   marker, and sometimes a pointer to a triangle, is appended after the    */
+/*   REALs.                                                                  */
+
+typedef REAL *vertex;
+
+int triunsuitable(vertex triorg, vertex tridest, vertex triapex, REAL area);
+
+struct triangulateio {
+  REAL *pointlist;                                               /* In / out */
+  REAL *pointattributelist;                                      /* In / out */
+  int *pointmarkerlist;                                          /* In / out */
+  int numberofpoints;                                            /* In / out */
+  int numberofpointattributes;                                   /* In / out */
+
+  int *trianglelist;                                             /* In / out */
+  REAL *triangleattributelist;                                   /* In / out */
+  REAL *trianglearealist;                                         /* In only */
+  int *neighborlist;                                             /* Out only */
+  int numberoftriangles;                                         /* In / out */
+  int numberofcorners;                                           /* In / out */
+  int numberoftriangleattributes;                                /* In / out */
+
+  int *segmentlist;                                              /* In / out */
+  int *segmentmarkerlist;                                        /* In / out */
+  int numberofsegments;                                          /* In / out */
+
+  REAL *holelist;                        /* In / pointer to array copied out */
+  int numberofholes;                                      /* In / copied out */
+
+  REAL *regionlist;                      /* In / pointer to array copied out */
+  int numberofregions;                                    /* In / copied out */
+
+  int *edgelist;                                                 /* Out only */
+  int *edgemarkerlist;            /* Not used with Voronoi diagram; out only */
+  REAL *normlist;                /* Used only with Voronoi diagram; out only */
+  int numberofedges;                                             /* Out only */
+};
+
+#ifdef ANSI_DECLARATORS
+void triangulate(char *, struct triangulateio *, struct triangulateio *,
+                 struct triangulateio *);
+void trifree(VOID *memptr);
+#else /* not ANSI_DECLARATORS */
+void triangulate();
+void trifree();
+#endif /* not ANSI_DECLARATORS */
+#ifdef __cplusplus
+}
+#endif
+
+
+
+
+#endif
diff --git a/meshpy/src/cpp/wrap_tetgen.cpp b/meshpy/src/cpp/wrap_tetgen.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2c715b30f351f9db3c1dbb4f02df151cf9f5a1a8
--- /dev/null
+++ b/meshpy/src/cpp/wrap_tetgen.cpp
@@ -0,0 +1,442 @@
+#include "tetgen.h"
+#include <pybind11/pybind11.h>
+#include <vector>
+#include <stdexcept>
+#include <iostream>
+#include "foreign_array_wrap.hpp"
+
+
+
+
+namespace py = pybind11;
+using namespace std;
+
+
+namespace
+{
+  struct tMeshInfo : public tetgenio, public noncopyable
+  {
+    private:
+      typedef tetgenio super;
+
+    public:
+      tForeignArray<REAL>                       Points; // in/out
+      tForeignArray<REAL>                       PointAttributes; // in/out
+      tForeignArray<REAL>                       PointMetricTensors; // in/out
+      tForeignArray<int>                        PointMarkers; // in/out
+
+      tForeignArray<int>                        Elements; // in/out
+      tForeignArray<REAL>                       ElementAttributes; // in/out
+      tForeignArray<REAL>                       ElementVolumes; // out
+      tForeignArray<int>                        Neighbors; // out
+
+      tForeignArray<tetgenio::facet>      Facets;
+      tForeignArray<int>                  FacetMarkers;
+
+      tForeignArray<REAL>                 Holes;
+      tForeignArray<REAL>                 Regions;
+
+      tForeignArray<REAL>                 FacetConstraints;
+      tForeignArray<REAL>                 SegmentConstraints;
+
+      tForeignArray<int>                  Faces;
+      tForeignArray<int>                  AdjacentElements;
+      tForeignArray<int>                  FaceMarkers;
+
+      tForeignArray<int>                  Edges;
+      tForeignArray<int>                  EdgeMarkers;
+      tForeignArray<int>                  EdgeAdjTetList;
+
+    public:
+      tMeshInfo()
+        : Points(pointlist, numberofpoints, 3),
+          PointAttributes(pointattributelist, numberofpoints, 0, &Points),
+          PointMetricTensors(pointmtrlist, numberofpoints, 0, &Points),
+          PointMarkers(pointmarkerlist, numberofpoints, 1, &Points),
+
+          Elements(tetrahedronlist, numberoftetrahedra, 0),
+          ElementAttributes(tetrahedronattributelist,
+              numberoftetrahedra, 0, &Elements),
+          ElementVolumes(tetrahedronvolumelist, numberoftetrahedra, 1, &Elements),
+          Neighbors(neighborlist, numberoftetrahedra, 4, &Elements),
+
+          Facets(facetlist, numberoffacets),
+          FacetMarkers(facetmarkerlist, numberoffacets, 1, &Facets),
+
+          Holes(holelist, numberofholes, 3),
+
+          Regions(regionlist, numberofregions, 5),
+
+          FacetConstraints(facetconstraintlist, numberoffacetconstraints, 2),
+          SegmentConstraints(segmentconstraintlist, numberofsegmentconstraints, 3),
+
+          Faces(trifacelist, numberoftrifaces, 3),
+          AdjacentElements(adjtetlist, numberoftrifaces, 2, &Faces),
+          FaceMarkers(trifacemarkerlist, numberoftrifaces, 1, &Faces),
+
+          Edges(edgelist, numberofedges, 2),
+          EdgeMarkers(edgemarkerlist, numberofedges, 1, &Edges),
+          EdgeAdjTetList(edgeadjtetlist, numberofedges, 1, &Edges)
+      {
+        Elements.fixUnit(numberofcorners);
+      }
+
+      unsigned numberOfPointAttributes() const
+      {
+        return numberofpointattributes;
+      }
+
+      unsigned numberOfPointMetricTensors() const
+      {
+        return numberofpointmtrs;
+      }
+
+      unsigned numberOfElementVertices() const
+      {
+        return numberofcorners;
+      }
+
+      unsigned numberOfElementAttributes() const
+      {
+        return numberoftetrahedronattributes;
+      }
+
+      void setNumberOfPointAttributes(unsigned attrs)
+      {
+        PointAttributes.setUnit(attrs);
+        numberofpointattributes = attrs;
+      }
+
+      void setNumberOfPointMetricTensors(unsigned mtrs)
+      {
+        PointMetricTensors.setUnit(mtrs);
+        numberofpointmtrs = mtrs;
+      }
+
+      void setNumberOfElementVertices(unsigned verts)
+      {
+        Elements.setUnit(verts);
+        numberofcorners = verts;
+      }
+
+      void setNumberOfElementAttributes(unsigned attrs)
+      {
+        ElementAttributes.setUnit(attrs);
+        numberoftetrahedronattributes = attrs;
+      }
+
+#define OVERRIDE_LOAD_WITH_ERROR_CHECK(WHAT, POSTPROC) \
+      void load_##WHAT(char* filename) \
+      { \
+        if (!super::load_##WHAT(filename)) \
+          throw std::runtime_error("load_" #WHAT " failed"); \
+        POSTPROC; \
+      }
+
+      OVERRIDE_LOAD_WITH_ERROR_CHECK(node,);
+      OVERRIDE_LOAD_WITH_ERROR_CHECK(var,);
+      OVERRIDE_LOAD_WITH_ERROR_CHECK(mtr,);
+      OVERRIDE_LOAD_WITH_ERROR_CHECK(poly,);
+      OVERRIDE_LOAD_WITH_ERROR_CHECK(off,);
+      OVERRIDE_LOAD_WITH_ERROR_CHECK(ply,);
+      OVERRIDE_LOAD_WITH_ERROR_CHECK(stl,);
+      OVERRIDE_LOAD_WITH_ERROR_CHECK(vtk,);
+
+      void load_plc(char* filename, int object)
+      {
+        if (!super::load_plc(filename, object))
+          throw std::runtime_error("load_plc failed");
+      }
+
+      void load_medit(char* filename, int object)
+      {
+        if (!super::load_medit(filename, object))
+          throw std::runtime_error("load_tetmesh failed");
+      }
+
+      void load_tetmesh(char* filename, int object)
+      {
+        if (!super::load_tetmesh(filename, object))
+          throw std::runtime_error("load_tetmesh failed");
+        Elements.fixUnit(numberofcorners);
+      }
+
+      /*
+      tTriangulationParameters &operator=(const tTriangulationParameters &src)
+      {
+        numberofpointattributes = src.numberofpointattributes ;
+        numberofcorners = src.numberofcorners;
+        numberoftriangleattributes = src.numberoftriangleattributes;
+
+        Points = src.Points;
+        PointAttributes = src.PointAttributes;
+        PointMarkers = src.PointMarkers;
+
+        Triangles = src.Triangles;
+        TriangleAttributes = src.TriangleAttributes;
+        TriangleAreas = src.TriangleAreas;
+        Neighbors = src.Neighbors;
+
+        Segments = src.Segments;
+        SegmentMarkers = src.SegmentMarkers;
+
+        Holes = src.Holes;
+
+        Regions = src.Regions;
+
+        Edges = src.Edges;
+        EdgeMarkers = src.EdgeMarkers;
+        Normals = src.Normals;
+
+        return *this;
+      }
+      */
+  };
+
+
+
+
+  /*
+  tTriangulationParameters *copyTriangulationParameters(const tTriangulationParameters &src)
+  {
+    auto_ptr<tTriangulationParameters> copy(new tTriangulationParameters);
+    *copy = src;
+    return copy.release();
+  }
+  */
+
+
+
+
+  void tetrahedralizeWrapper(tetgenbehavior &bhv, tMeshInfo &in, tMeshInfo &out,
+      tMeshInfo *addin)
+  {
+    try
+    {
+      tetrahedralize(&bhv, &in, &out, addin);
+    }
+    catch (int &i)
+    {
+      throw runtime_error("TetGen runtime error code "+std::to_string(i));
+    }
+
+    out.Elements.fixUnit(out.numberofcorners);
+    out.PointAttributes.fixUnit(out.numberofpointattributes);
+    out.PointMetricTensors.fixUnit(out.numberofpointmtrs);
+    out.ElementAttributes.fixUnit(out.numberoftetrahedronattributes);
+  }
+
+
+
+
+  tForeignArray<tetgenio::polygon> *facet_get_polygons(tetgenio::facet &self)
+  {
+    return new tForeignArray<tetgenio::polygon>(
+        self.polygonlist, self.numberofpolygons);
+  }
+
+
+
+
+  tForeignArray<REAL> *facet_get_holes(tetgenio::facet &self)
+  {
+    return new tForeignArray<REAL>(self.holelist, self.numberofholes, 3);
+  }
+
+
+
+
+
+  tForeignArray<int> *polygon_get_vertices(tetgenio::polygon &self)
+  {
+    return new tForeignArray<int>(self.vertexlist, self.numberofvertices);
+  }
+}
+
+
+
+
+
+#define DEF_RW_MEMBER(NAME) \
+    def_readwrite(#NAME, &cl::NAME)
+#define DEF_METHOD(NAME) \
+    def(#NAME, &cl::NAME)
+
+PYBIND11_MODULE(_tetgen, m)
+{
+  m.def("tetrahedralize", tetrahedralizeWrapper,
+      py::arg("behavior"), py::arg("in"), py::arg("out"),
+      py::arg("addin").none(true)=py::none());
+
+  {
+    typedef tMeshInfo cl;
+    py::class_<cl>(m, "MeshInfo")
+      .def(py::init<>())
+      .def_readonly("points", &cl::Points)
+      .def_readonly("point_attributes", &cl::PointAttributes)
+      .def_readonly("point_metric_tensors", &cl::PointMetricTensors)
+      .def_readonly("point_markers", &cl::PointMarkers)
+
+      .def_readonly("elements", &cl::Elements)
+      .def_readonly("element_attributes", &cl::ElementAttributes)
+      .def_readonly("element_volumes", &cl::ElementVolumes)
+      .def_readonly("neighbors", &cl::Neighbors)
+
+
+      .def_readonly("facets", &cl::Facets)
+      .def_readonly("facet_markers", &cl::FacetMarkers)
+
+      .def_readonly("holes", &cl::Holes)
+
+      .def_readonly("regions", &cl::Regions)
+
+      .def_readonly("facet_constraints", &cl::FacetConstraints)
+      .def_readonly("segment_constraints", &cl::SegmentConstraints)
+
+      .def_readonly("faces", &cl::Faces)
+      .def_readonly("adjacent_elements", &cl::AdjacentElements)
+      .def_readonly("face_markers", &cl::FaceMarkers)
+
+      .def_readonly("edges", &cl::Edges)
+      .def_readonly("edge_markers", &cl::EdgeMarkers)
+      .def_readonly("edge_adjacent_elements", &cl::EdgeAdjTetList)
+
+      .def_property("number_of_point_attributes",
+          &cl::numberOfPointAttributes,
+          &cl::setNumberOfPointAttributes)
+      .def_property("number_of_element_vertices",
+          &cl::numberOfElementVertices,
+          &cl::setNumberOfElementVertices)
+      .def_property("number_of_element_attributes",
+          &cl::numberOfElementAttributes,
+          &cl::setNumberOfElementAttributes)
+
+      .DEF_METHOD(save_nodes)
+      .DEF_METHOD(save_elements)
+      .DEF_METHOD(save_faces)
+      .DEF_METHOD(save_edges)
+      .DEF_METHOD(save_neighbors)
+      .DEF_METHOD(save_poly)
+
+      .DEF_METHOD(load_node)
+      .DEF_METHOD(load_var)
+      .DEF_METHOD(load_mtr)
+      .DEF_METHOD(load_poly)
+      .DEF_METHOD(load_off)
+      .DEF_METHOD(load_ply)
+      .DEF_METHOD(load_stl)
+      .DEF_METHOD(load_medit)
+      .DEF_METHOD(load_plc)
+      .DEF_METHOD(load_tetmesh)
+
+      /*
+         .def("copy", &copyTriangulationParameters,
+         return_value_policy<manage_new_object>())
+         */
+      //.enable_pickling()
+      ;
+  }
+
+  {
+    typedef tetgenio::facet cl;
+    py::class_<cl>(m, "Facet")
+      .def_property_readonly("polygons",
+          facet_get_polygons, py::return_value_policy::reference_internal)
+      .def_property_readonly("holes",
+          facet_get_holes, py::return_value_policy::reference_internal)
+      ;
+  }
+
+  {
+    typedef tetgenio::polygon cl;
+    py::class_<cl>(m, "Polygon")
+      .def_property_readonly("vertices",
+          polygon_get_vertices, py::return_value_policy::reference_internal)
+      ;
+  }
+
+  {
+    typedef tetgenbehavior cl;
+    py::class_<cl>(m, "Options")
+      .def(py::init<>())
+      .DEF_RW_MEMBER(plc)
+      .DEF_RW_MEMBER(psc)
+      .DEF_RW_MEMBER(refine)
+      .DEF_RW_MEMBER(quality)
+      .DEF_RW_MEMBER(nobisect)
+      .DEF_RW_MEMBER(coarsen)
+      .DEF_RW_MEMBER(weighted)
+      .DEF_RW_MEMBER(brio_hilbert)
+      .DEF_RW_MEMBER(incrflip)
+      .DEF_RW_MEMBER(flipinsert)
+      .DEF_RW_MEMBER(metric)
+      .DEF_RW_MEMBER(varvolume)
+      .DEF_RW_MEMBER(fixedvolume)
+      .DEF_RW_MEMBER(regionattrib)
+      .DEF_RW_MEMBER(conforming)
+      .DEF_RW_MEMBER(insertaddpoints)
+      .DEF_RW_MEMBER(diagnose)
+      .DEF_RW_MEMBER(convex)
+      .DEF_RW_MEMBER(nomergefacet)
+      .DEF_RW_MEMBER(nomergevertex)
+      .DEF_RW_MEMBER(noexact)
+      .DEF_RW_MEMBER(nostaticfilter)
+      .DEF_RW_MEMBER(zeroindex)
+      .DEF_RW_MEMBER(facesout)
+      .DEF_RW_MEMBER(edgesout)
+      .DEF_RW_MEMBER(neighout)
+      .DEF_RW_MEMBER(voroout)
+      .DEF_RW_MEMBER(meditview)
+      .DEF_RW_MEMBER(vtkview)
+      .DEF_RW_MEMBER(nobound)
+      .DEF_RW_MEMBER(nonodewritten)
+      .DEF_RW_MEMBER(noelewritten)
+      .DEF_RW_MEMBER(nofacewritten)
+      .DEF_RW_MEMBER(noiterationnum)
+      .DEF_RW_MEMBER(nojettison)
+      .DEF_RW_MEMBER(reversetetori)
+      .DEF_RW_MEMBER(docheck)
+      .DEF_RW_MEMBER(quiet)
+      .DEF_RW_MEMBER(verbose)
+
+      .DEF_RW_MEMBER(vertexperblock)
+      .DEF_RW_MEMBER(tetrahedraperblock)
+      .DEF_RW_MEMBER(shellfaceperblock)
+      .DEF_RW_MEMBER(nobisect_param)
+      .DEF_RW_MEMBER(addsteiner_algo)
+      .DEF_RW_MEMBER(coarsen_param)
+      .DEF_RW_MEMBER(weighted_param)
+      .DEF_RW_MEMBER(fliplinklevel)
+      .DEF_RW_MEMBER(flipstarsize)
+      .DEF_RW_MEMBER(fliplinklevelinc)
+      .DEF_RW_MEMBER(reflevel)
+      .DEF_RW_MEMBER(optlevel)
+      .DEF_RW_MEMBER(optscheme)
+      .DEF_RW_MEMBER(delmaxfliplevel)
+      .DEF_RW_MEMBER(order)
+      .DEF_RW_MEMBER(steinerleft)
+      .DEF_RW_MEMBER(no_sort)
+      .DEF_RW_MEMBER(hilbert_order)
+      .DEF_RW_MEMBER(hilbert_limit)
+      .DEF_RW_MEMBER(brio_threshold)
+      .DEF_RW_MEMBER(brio_ratio)
+      .DEF_RW_MEMBER(facet_ang_tol)
+      .DEF_RW_MEMBER(maxvolume)
+      .DEF_RW_MEMBER(minratio)
+      .DEF_RW_MEMBER(mindihedral)
+      .DEF_RW_MEMBER(optmaxdihedral)
+      .DEF_RW_MEMBER(optminsmtdihed)
+      .DEF_RW_MEMBER(optminslidihed)
+      .DEF_RW_MEMBER(epsilon)
+      .DEF_RW_MEMBER(minedgelength)
+      .DEF_RW_MEMBER(coarsen_percent)
+
+      .def("parse_switches", (bool (tetgenbehavior::*)(char *)) &cl::parse_commandline)
+      ;
+  }
+
+  exposePODForeignArray<REAL>(m, "RealArray");
+  exposePODForeignArray<int>(m, "IntArray");
+  exposeStructureForeignArray<tetgenio::facet>(m, "FacetArray");
+  exposeStructureForeignArray<tetgenio::polygon>(m, "PolygonArray");
+}
diff --git a/meshpy/src/cpp/wrap_triangle.cpp b/meshpy/src/cpp/wrap_triangle.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4857345ff410d82e3e55bbd8b022b85c68e9ba25
--- /dev/null
+++ b/meshpy/src/cpp/wrap_triangle.cpp
@@ -0,0 +1,295 @@
+#include "triangle.h"
+#include <pybind11/pybind11.h>
+#include <stdexcept>
+#include <iostream>
+#include <memory>
+#include "foreign_array_wrap.hpp"
+
+namespace py = pybind11;
+
+using namespace std;
+
+
+/*
+namespace boost {
+template <>
+inline tForeignArray<int> const volatile * get_pointer(class tForeignArray<int> const volatile *tF) {
+  return tF;
+}
+
+template <>
+inline tForeignArray<double> const volatile * get_pointer(class tForeignArray<double> const volatile *tF) {
+  return tF;
+}
+}
+*/
+
+
+
+struct tMeshInfo : public triangulateio, public noncopyable
+{
+  public:
+    tForeignArray<REAL>         Points; // in/out
+    tForeignArray<REAL>         PointAttributes; // in/out
+    tForeignArray<int>          PointMarkers; // in/out
+
+    tForeignArray<int>          Elements; // in/out
+    tForeignArray<REAL>         ElementAttributes; // in/out
+    tForeignArray<REAL>         ElementVolumes; // in only
+    tForeignArray<int>          Neighbors; // out only
+
+    tForeignArray<int>          Facets; // in/out
+    tForeignArray<int>          FacetMarkers; // in/out
+
+    tForeignArray<REAL>         Holes; // in only
+
+    tForeignArray<REAL>         Regions; // in only
+
+    tForeignArray<int>          Faces; // out only
+    tForeignArray<int>          FaceMarkers; // out only
+    tForeignArray<REAL>         Normals; // out only
+
+  public:
+    tMeshInfo()
+      : Points(pointlist, numberofpoints, 2, NULL, true),
+        PointAttributes(pointattributelist, numberofpoints, 0, &Points, true),
+        PointMarkers(pointmarkerlist, numberofpoints, 1, &Points, true),
+
+        Elements(trianglelist, numberoftriangles, 3, NULL, true),
+        ElementAttributes(triangleattributelist,
+            numberoftriangles, 0, &Elements, true),
+        ElementVolumes(trianglearealist,
+            numberoftriangles, 1, &Elements, true),
+        Neighbors(neighborlist,
+            numberoftriangles, 3, &Elements, true),
+
+        Facets(segmentlist, numberofsegments, 2, NULL, true),
+        FacetMarkers(segmentmarkerlist, numberofsegments, 1, &Facets, true),
+
+        Holes(holelist, numberofholes, 2, NULL, true),
+
+        Regions(regionlist, numberofregions, 4, NULL, true),
+
+        Faces(edgelist, numberofedges, 2, NULL, true),
+        FaceMarkers(edgemarkerlist, numberofedges, 1, &Faces, true),
+        Normals(normlist, numberofedges, 2, &Faces, true)
+    {
+      numberofpointattributes = 0;
+      numberofcorners = 3;
+      numberoftriangleattributes = 0;
+    }
+
+    unsigned numberOfPointAttributes() const
+    {
+      return numberofpointattributes;
+    }
+
+    unsigned numberOfElementAttributes() const
+    {
+      return numberoftriangleattributes;
+    }
+
+    void setNumberOfPointAttributes(unsigned attrs)
+    {
+      PointAttributes.setUnit(attrs);
+      numberofpointattributes = attrs;
+    }
+
+    void setNumberOfElementAttributes(unsigned attrs)
+    {
+      ElementAttributes.setUnit(attrs);
+      numberoftriangleattributes = attrs;
+    }
+
+    tMeshInfo &operator=(const tMeshInfo &src)
+    {
+      numberofpointattributes = src.numberofpointattributes ;
+      numberofcorners = src.numberofcorners;
+      numberoftriangleattributes = src.numberoftriangleattributes;
+
+      Points = src.Points;
+      PointAttributes = src.PointAttributes;
+      PointMarkers = src.PointMarkers;
+
+      Elements = src.Elements;
+      ElementAttributes = src.ElementAttributes;
+      ElementVolumes = src.ElementVolumes;
+      Neighbors = src.Neighbors;
+
+      Facets = src.Facets;
+      FacetMarkers = src.FacetMarkers;
+
+      Holes = src.Holes;
+
+      Regions = src.Regions;
+
+      Faces = src.Faces;
+      FaceMarkers = src.FaceMarkers;
+      Normals = src.Normals;
+
+      return *this;
+    }
+};
+
+
+
+
+tMeshInfo *copyMesh(const tMeshInfo &src)
+{
+  std::unique_ptr<tMeshInfo> copy(new tMeshInfo);
+  *copy = src;
+  return copy.release();
+}
+
+
+
+
+PyObject *RefinementFunction;
+
+
+
+
+class tVertex : public noncopyable
+{
+  public:
+    REAL        *Data;
+
+  public:
+    tVertex(REAL *data)
+    : Data(data)
+    {
+    }
+
+    REAL operator[](unsigned i)
+    {
+      if (i >= 2)
+        PYTHON_ERROR(IndexError, "vertex index out of bounds");
+      return Data[i];
+    }
+
+    unsigned size()
+    {
+      return 2;
+    }
+
+    REAL x() { return Data[0]; }
+    REAL y() { return Data[1]; }
+};
+
+
+
+
+int triunsuitable(vertex triorg, vertex tridest, vertex triapex, REAL area)
+{
+  // return 1 if triangle is too large, 0 otherwise
+  tVertex org(triorg);
+  tVertex dest(tridest);
+  tVertex apex(triapex);
+
+  py::handle refine_func = py::reinterpret_borrow<py::object>(RefinementFunction);
+
+  try
+  {
+    return py::cast<bool>(refine_func(
+        py::make_tuple(
+          py::cast(org, py::return_value_policy::reference),
+          py::cast(dest, py::return_value_policy::reference),
+          py::cast(apex, py::return_value_policy::reference)), area));
+  }
+  catch (py::error_already_set &)
+  {
+    std::cout << "[MeshPy warning] A Python exception occurred in "
+      "a Python refinement query:" << std::endl;
+    PyErr_Print();
+    std::cout << "[MeshPy] Aborting now." << std::endl;
+    abort();
+  }
+  catch (std::exception &e)
+  {
+    std::cout << "[MeshPy warning] An exception occurred in "
+      "a Python refinement query:" << std::endl
+      << e.what() << std::endl;
+    std::cout << "[MeshPy] Aborting now." << std::endl;
+    abort();
+  }
+}
+
+
+
+
+void triangulateWrapper(char *options, tMeshInfo &in,
+    tMeshInfo &out,
+    tMeshInfo &voronoi,
+    py::object refinement_func)
+{
+  RefinementFunction = refinement_func.ptr();
+  triangulate(options, &in, &out, &voronoi);
+
+  out.holelist = NULL;
+  out.numberofholes = 0;
+
+  out.regionlist = NULL;
+  out.numberofregions = 0;
+
+  out.Elements.fixUnit(out.numberofcorners);
+  out.PointAttributes.fixUnit(out.numberofpointattributes);
+  out.ElementAttributes.fixUnit(out.numberoftriangleattributes);
+}
+
+
+
+
+PYBIND11_MODULE(_triangle, m)
+{
+  m.def("triangulate", triangulateWrapper);
+
+  {
+    typedef tMeshInfo cl;
+    py::class_<cl>(m, "MeshInfo")
+      .def(py::init<>())
+      .def_readonly("points", &cl::Points)
+      .def_readonly("point_attributes", &cl::PointAttributes)
+      .def_readonly("point_markers", &cl::PointMarkers)
+
+      .def_readonly("elements", &cl::Elements)
+      .def_readonly("element_attributes", &cl::ElementAttributes)
+      .def_readonly("element_volumes", &cl::ElementVolumes)
+      .def_readonly("neighbors", &cl::Neighbors)
+
+      .def_readonly("facets", &cl::Facets)
+      .def_readonly("facet_markers", &cl::FacetMarkers)
+
+      .def_readonly("holes", &cl::Holes)
+
+      .def_readonly("regions", &cl::Regions)
+
+      .def_readonly("faces", &cl::Faces)
+      .def_readonly("face_markers", &cl::FaceMarkers)
+
+      .def_readonly("normals", &cl::Normals)
+
+      .def_property("number_of_point_attributes",
+          &cl::numberOfPointAttributes,
+          &cl::setNumberOfPointAttributes)
+      .def_property("number_of_element_attributes",
+          &cl::numberOfElementAttributes,
+          &cl::setNumberOfElementAttributes)
+
+      .def("copy", &copyMesh)
+      // .enable_pickling()
+      ;
+  }
+
+  exposePODForeignArray<REAL>(m, "RealArray");
+  exposePODForeignArray<int>(m, "IntArray");
+
+  {
+    typedef tVertex cl;
+    py::class_<cl>(m, "Vertex")
+      .def_property_readonly("x", &cl::x)
+      .def_property_readonly("y", &cl::y)
+      .def("__len__", &cl::size)
+      .def("__getitem__", &cl::operator[])
+      ;
+  }
+}
diff --git a/meshpy/test/test_meshpy.py b/meshpy/test/test_meshpy.py
new file mode 100644
index 0000000000000000000000000000000000000000..6ac566ffed132b73290b3b292cd7b13ba5cee587
--- /dev/null
+++ b/meshpy/test/test_meshpy.py
@@ -0,0 +1,164 @@
+from __future__ import division, absolute_import, print_function
+
+__copyright__ = "Copyright (C) 2013 Andreas Kloeckner"
+
+__license__ = """
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+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.
+"""
+
+from six.moves import range
+
+
+# {{{ triangle
+
+def test_triangle_refine():
+    import meshpy.triangle as triangle
+    import math
+
+    segments = 50
+
+    points = [(1, 0), (1, 1), (-1, 1), (-1, -1), (1, -1)]
+    n_outer_points = len(points)
+
+    for i in range(0, segments):
+        angle = i * 2 * math.pi / segments
+        points.append((0.5 * math.cos(angle), 0.5 * math.sin(angle)))
+
+    def round_trip_connect(start, end):
+        result = []
+        for i in range(start, end):
+            result.append((i, i+1))
+        result.append((end, start))
+        return result
+
+    def needs_refinement(vertices, area):
+        vert_origin, vert_destination, vert_apex = vertices
+        bary_x = (vert_origin.x + vert_destination.x + vert_apex.x) / 3
+        bary_y = (vert_origin.y + vert_destination.y + vert_apex.y) / 3
+
+        dist_center = math.sqrt(bary_x**2 + bary_y**2)
+        max_area = 100*(math.fabs(0.002 * (dist_center-0.3)) + 0.0001)
+        return area > max_area
+
+    info = triangle.MeshInfo()
+    info.set_points(points)
+    info.set_holes([(0, 0)])
+    info.set_facets(
+        round_trip_connect(0, n_outer_points-1)
+        +
+        round_trip_connect(n_outer_points, len(points)-1))
+
+    mesh = triangle.build(info, refinement_func=needs_refinement)
+
+    triangle.write_gnuplot_mesh("triangles-unrefined.dat", mesh)
+
+    mesh.element_volumes.setup()
+
+    for i in range(len(mesh.elements)):
+        mesh.element_volumes[i] = -1
+    for i in range(0, len(mesh.elements), 10):
+        mesh.element_volumes[i] = 1e-8
+
+    mesh = triangle.refine(mesh)
+
+# }}}
+
+
+# {{{ tetgen
+
+def test_tetgen():
+    from meshpy.tet import MeshInfo, build
+    mesh_info = MeshInfo()
+
+    mesh_info.set_points([
+        (0, 0, 0),
+        (2, 0, 0),
+        (2, 2, 0),
+        (0, 2, 0),
+        (0, 0, 12),
+        (2, 0, 12),
+        (2, 2, 12),
+        (0, 2, 12),
+        ])
+
+    mesh_info.set_facets([
+        [0, 1, 2, 3],
+        [4, 5, 6, 7],
+        [0, 4, 5, 1],
+        [1, 5, 6, 2],
+        [2, 6, 7, 3],
+        [3, 7, 4, 0],
+        ])
+
+    build(mesh_info)
+
+
+def test_torus():
+    from math import pi, cos, sin
+    from meshpy.tet import MeshInfo, build
+    from meshpy.geometry import generate_surface_of_revolution, \
+            EXT_CLOSED_IN_RZ, GeometryBuilder
+
+    big_r = 3
+    little_r = 2.9
+
+    points = 50
+    dphi = 2*pi/points
+
+    rz = [(big_r+little_r*cos(i*dphi), little_r*sin(i*dphi))
+            for i in range(points)]
+
+    geob = GeometryBuilder()
+    geob.add_geometry(*generate_surface_of_revolution(rz,
+            closure=EXT_CLOSED_IN_RZ, radial_subdiv=20))
+
+    mesh_info = MeshInfo()
+    geob.set(mesh_info)
+
+    build(mesh_info)
+
+
+def test_tetgen_points():
+    from meshpy.tet import MeshInfo, build, Options
+
+    import numpy as np
+    points = np.random.randn(10000, 3)
+
+    mesh_info = MeshInfo()
+    mesh_info.set_points(points)
+    options = Options("")
+    mesh = build(mesh_info, options=options)
+
+    print(len(mesh.points))
+    print(len(mesh.elements))
+
+    #mesh.write_vtk("test.vtk")
+
+# }}}
+
+
+if __name__ == "__main__":
+    import sys
+    if len(sys.argv) > 1:
+        exec(sys.argv[1])
+    else:
+        from pytest import main
+        main([__file__])
+
+# vim: foldmethod=marker
diff --git a/meshpy/tmp/tmp653i24s9.o b/meshpy/tmp/tmp653i24s9.o
new file mode 100644
index 0000000000000000000000000000000000000000..1f570c7748de44df732928d14bf53f2c836f3d72
Binary files /dev/null and b/meshpy/tmp/tmp653i24s9.o differ
diff --git a/meshpy/tmp/tmpaess8rcr.o b/meshpy/tmp/tmpaess8rcr.o
new file mode 100644
index 0000000000000000000000000000000000000000..d887ccb6872b8e78195b0f0deb537054bdeb2713
Binary files /dev/null and b/meshpy/tmp/tmpaess8rcr.o differ
diff --git a/meshpy/tmp/tmpbddib1zs.o b/meshpy/tmp/tmpbddib1zs.o
new file mode 100644
index 0000000000000000000000000000000000000000..4ce107c1b602917510f854a435a15718a1bd5ca9
Binary files /dev/null and b/meshpy/tmp/tmpbddib1zs.o differ
diff --git a/meshpy/tmp/tmpgzh6jz53.o b/meshpy/tmp/tmpgzh6jz53.o
new file mode 100644
index 0000000000000000000000000000000000000000..31675f2eb282a8f62f9939b16190a9ee0042b250
Binary files /dev/null and b/meshpy/tmp/tmpgzh6jz53.o differ
diff --git a/meshpy/tmp/tmphn9d34h2.o b/meshpy/tmp/tmphn9d34h2.o
new file mode 100644
index 0000000000000000000000000000000000000000..2f6d19034fd6ad4f929073a7006bfd31f326f8d0
Binary files /dev/null and b/meshpy/tmp/tmphn9d34h2.o differ
diff --git a/meshpy/tmp/tmpivj51evt.o b/meshpy/tmp/tmpivj51evt.o
new file mode 100644
index 0000000000000000000000000000000000000000..f4a2ee000b32895f2723289888a762550b3fc23d
Binary files /dev/null and b/meshpy/tmp/tmpivj51evt.o differ
diff --git a/meshpy/tmp/tmpj82kgq3q.o b/meshpy/tmp/tmpj82kgq3q.o
new file mode 100644
index 0000000000000000000000000000000000000000..34dfb07e2a9ebb5d1e0183e30524d222d648d0af
Binary files /dev/null and b/meshpy/tmp/tmpj82kgq3q.o differ
diff --git a/meshpy/tmp/tmpjb_vnaxl.o b/meshpy/tmp/tmpjb_vnaxl.o
new file mode 100644
index 0000000000000000000000000000000000000000..a70170ec5a32843c2cb3ba31d0e2407b6bfaea83
Binary files /dev/null and b/meshpy/tmp/tmpjb_vnaxl.o differ
diff --git a/meshpy/tmp/tmpjf9ugm2d.o b/meshpy/tmp/tmpjf9ugm2d.o
new file mode 100644
index 0000000000000000000000000000000000000000..6b76e0c3a69de1fca31d2642695f66c448e29dcf
Binary files /dev/null and b/meshpy/tmp/tmpjf9ugm2d.o differ
diff --git a/meshpy/tmp/tmple8msne0.o b/meshpy/tmp/tmple8msne0.o
new file mode 100644
index 0000000000000000000000000000000000000000..be53fd14ad688d3a8ec50f74b2aaee178a1a12df
Binary files /dev/null and b/meshpy/tmp/tmple8msne0.o differ
diff --git a/meshpy/tmp/tmpltvop8dr.o b/meshpy/tmp/tmpltvop8dr.o
new file mode 100644
index 0000000000000000000000000000000000000000..509e349a0e15904da8e46fbecc66b8a6c8244125
Binary files /dev/null and b/meshpy/tmp/tmpltvop8dr.o differ
diff --git a/meshpy/tmp/tmpmcpouu1z.o b/meshpy/tmp/tmpmcpouu1z.o
new file mode 100644
index 0000000000000000000000000000000000000000..ea7a9f4339eaee21debce9b155c35b0df25a85ad
Binary files /dev/null and b/meshpy/tmp/tmpmcpouu1z.o differ
diff --git a/meshpy/tmp/tmpmpjyzequ.o b/meshpy/tmp/tmpmpjyzequ.o
new file mode 100644
index 0000000000000000000000000000000000000000..2def1fa81c5612fbb8cd89c8554a2cc745331792
Binary files /dev/null and b/meshpy/tmp/tmpmpjyzequ.o differ
diff --git a/meshpy/tmp/tmpn6aeuj1i.o b/meshpy/tmp/tmpn6aeuj1i.o
new file mode 100644
index 0000000000000000000000000000000000000000..1d60b68dcee4bb1e3c85bf74b2c21f9545d9b3a1
Binary files /dev/null and b/meshpy/tmp/tmpn6aeuj1i.o differ
diff --git a/meshpy/tmp/tmpoq1boa0h.o b/meshpy/tmp/tmpoq1boa0h.o
new file mode 100644
index 0000000000000000000000000000000000000000..d15d2fe8817d2d165c56ee362e36d490107ba31f
Binary files /dev/null and b/meshpy/tmp/tmpoq1boa0h.o differ
diff --git a/meshpy/tmp/tmptd08gv0x.o b/meshpy/tmp/tmptd08gv0x.o
new file mode 100644
index 0000000000000000000000000000000000000000..427cbf287a34107cc6667f0d516f29e794daf47f
Binary files /dev/null and b/meshpy/tmp/tmptd08gv0x.o differ
diff --git a/meshpy/tmp/tmpxe8dct_f.o b/meshpy/tmp/tmpxe8dct_f.o
new file mode 100644
index 0000000000000000000000000000000000000000..09efde3bd8d264b46c59b935b3d9380e7f1fd6e2
Binary files /dev/null and b/meshpy/tmp/tmpxe8dct_f.o differ
diff --git a/meshpy/tmp/tmpydz4y0k5.o b/meshpy/tmp/tmpydz4y0k5.o
new file mode 100644
index 0000000000000000000000000000000000000000..06127a8811c3167546752029c778e8d33c61847d
Binary files /dev/null and b/meshpy/tmp/tmpydz4y0k5.o differ
diff --git a/meshpy/var/folders/7c/2blc1zln7gd0fhs5nllk3s2m0000gn/T/tmp4pw54c6v.o b/meshpy/var/folders/7c/2blc1zln7gd0fhs5nllk3s2m0000gn/T/tmp4pw54c6v.o
new file mode 100644
index 0000000000000000000000000000000000000000..431515b5c4a79a0d87c0714985573439ea0233c7
Binary files /dev/null and b/meshpy/var/folders/7c/2blc1zln7gd0fhs5nllk3s2m0000gn/T/tmp4pw54c6v.o differ
diff --git a/meshpy/var/folders/7c/2blc1zln7gd0fhs5nllk3s2m0000gn/T/tmpgz2qbhwh.o b/meshpy/var/folders/7c/2blc1zln7gd0fhs5nllk3s2m0000gn/T/tmpgz2qbhwh.o
new file mode 100644
index 0000000000000000000000000000000000000000..431515b5c4a79a0d87c0714985573439ea0233c7
Binary files /dev/null and b/meshpy/var/folders/7c/2blc1zln7gd0fhs5nllk3s2m0000gn/T/tmpgz2qbhwh.o differ
diff --git a/meshpy/var/folders/7c/2blc1zln7gd0fhs5nllk3s2m0000gn/T/tmpou2abthp.o b/meshpy/var/folders/7c/2blc1zln7gd0fhs5nllk3s2m0000gn/T/tmpou2abthp.o
new file mode 100644
index 0000000000000000000000000000000000000000..431515b5c4a79a0d87c0714985573439ea0233c7
Binary files /dev/null and b/meshpy/var/folders/7c/2blc1zln7gd0fhs5nllk3s2m0000gn/T/tmpou2abthp.o differ
diff --git a/meshpy/var/folders/7c/2blc1zln7gd0fhs5nllk3s2m0000gn/T/tmpswvj1ivk.o b/meshpy/var/folders/7c/2blc1zln7gd0fhs5nllk3s2m0000gn/T/tmpswvj1ivk.o
new file mode 100644
index 0000000000000000000000000000000000000000..431515b5c4a79a0d87c0714985573439ea0233c7
Binary files /dev/null and b/meshpy/var/folders/7c/2blc1zln7gd0fhs5nllk3s2m0000gn/T/tmpswvj1ivk.o differ
diff --git a/tests.py b/tests.py
index 62f90bf0d8528cdf7f7e59a5881c1529aa89d9ba..9dd4bc1a295d4f069109ba4dddbee11b07dd8746 100755
--- a/tests.py
+++ b/tests.py
@@ -71,7 +71,7 @@ for element_id in range(STRUCT.get_number_elements()):
         print('{:>5}'.format(int(dof)), end='')
     print('')
 '''
-'''
+
 # TEST 5 - Full model execution with small tetraeder model
 # Gets the structure object from the models modcule.
 STRUCT = small_tetraeder()
@@ -99,11 +99,13 @@ VIZ.draw_displaced_forces()
 VIZ.draw_normal_forces()
 # Runs the visualizer.
 VIEWER.run()
-'''
 
+'''
 # TEST 6 - Importing model from csv files
 STRUCT = load_model('small_bridge')
 STRUCT.print_details()
+#STRUCT.solve()
+#STRUCT.select_displacements()
 
 # Instantiates a viewer object
 VIEWER = Viewer()
@@ -113,6 +115,8 @@ VIZ = Visualizer(STRUCT, VIEWER)
 VIZ.draw_elements()
 VIZ.draw_constraints()
 VIZ.draw_element_forces()
+VIZ.draw_displaced_elements()
+VIZ.draw_displaced_forces()
 # Runs the visualizer.
 VIEWER.run()
-
+'''