diff --git a/src/geometric-tools/GTEngineDEF.h b/src/geometric-tools/GTEngineDEF.h
new file mode 100644
index 0000000000000000000000000000000000000000..88d1869e2b65ba82d5c055109d72f7cdca221b62
--- /dev/null
+++ b/src/geometric-tools/GTEngineDEF.h
@@ -0,0 +1,80 @@
+// David Eberly, Geometric Tools, Redmond WA 98052
+// Copyright (c) 1998-2018
+// Distributed under the Boost Software License, Version 1.0.
+// http://www.boost.org/LICENSE_1_0.txt
+// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
+// File Version: 3.0.0 (2016/06/19)
+
+#pragma once
+
+//----------------------------------------------------------------------------
+// The platform specification.
+//
+// __MSWINDOWS__            :  Microsoft Windows (WIN32 or WIN64)
+// __APPLE__                :  Macintosh OS X
+// __LINUX__                :  Linux or Cygwin
+//----------------------------------------------------------------------------
+
+#if !defined(__LINUX__) && (defined(WIN32) || defined(_WIN64))
+#define __MSWINDOWS__
+
+#if !defined(_MSC_VER)
+#error Microsoft Visual Studio 2013 or later is required.
+#endif
+
+//  MSVC  6   is version 12.0
+//  MSVC  7.0 is version 13.0 (MSVS 2002)
+//  MSVC  7.1 is version 13.1 (MSVS 2003)
+//  MSVC  8.0 is version 14.0 (MSVS 2005)
+//  MSVC  9.0 is version 15.0 (MSVS 2008)
+//  MSVC 10.0 is version 16.0 (MSVS 2010)
+//  MSVC 11.0 is version 17.0 (MSVS 2012)
+//  MSVC 12.0 is version 18.0 (MSVS 2013)
+//  MSVC 14.0 is version 19.0 (MSVS 2015)
+//  Currently, projects are provided only for MSVC 12.0 and 14.0.
+#if _MSC_VER < 1800
+#error Microsoft Visual Studio 2013 or later is required.
+#endif
+
+// Debug build values (choose_your_value is 0, 1, or 2)
+// 0:  Disables checked iterators and disables iterator debugging.
+// 1:  Enables checked iterators and disables iterator debugging.
+// 2:  (default) Enables iterator debugging; checked iterators are not relevant.
+//
+// Release build values (choose_your_value is 0 or 1)
+// 0:  (default) Disables checked iterators.
+// 1:  Enables checked iterators; iterator debugging is not relevant.
+//
+// #define _ITERATOR_DEBUG_LEVEL choose_your_value
+
+#endif  // WIN32 or _WIN64
+
+// TODO: Windows DLL configurations have not yet been added to the project,
+// but these defines are required to support them (when we do add them).
+//
+// Add GTE_EXPORT to project preprocessor options for dynamic library
+// configurations to export their symbols.
+#if defined(GTE_EXPORT)
+    // For the dynamic library configurations.
+    #define GTE_IMPEXP __declspec(dllexport)
+#else
+    // For a client of the dynamic library or for the static library
+    // configurations.
+    #define GTE_IMPEXP
+#endif
+
+// Expose exactly one of these.
+#define GTE_USE_ROW_MAJOR
+//#define GTE_USE_COL_MAJOR
+
+// Expose exactly one of these.
+#define GTE_USE_MAT_VEC
+//#define GTE_USE_VEC_MAT
+
+#if (defined(GTE_USE_ROW_MAJOR) && defined(GTE_USE_COL_MAJOR)) || (!defined(GTE_USE_ROW_MAJOR) && !defined(GTE_USE_COL_MAJOR))
+#error Exactly one storage order must be specified.
+#endif
+
+#if (defined(GTE_USE_MAT_VEC) && defined(GTE_USE_VEC_MAT)) || (!defined(GTE_USE_MAT_VEC) && !defined(GTE_USE_VEC_MAT))
+#error Exactly one multiplication convention must be specified.
+#endif
diff --git a/src/geometric-tools/Mathematics/GteDCPQuery.h b/src/geometric-tools/Mathematics/GteDCPQuery.h
new file mode 100644
index 0000000000000000000000000000000000000000..3bf5c6b97b40d4eaf369911382bda2fe3c8def10
--- /dev/null
+++ b/src/geometric-tools/Mathematics/GteDCPQuery.h
@@ -0,0 +1,35 @@
+// David Eberly, Geometric Tools, Redmond WA 98052
+// Copyright (c) 1998-2018
+// Distributed under the Boost Software License, Version 1.0.
+// http://www.boost.org/LICENSE_1_0.txt
+// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
+// File Version: 3.0.1 (2018/10/05)
+
+#pragma once
+#ifndef GTE_DCPQUERY_H
+#define GTE_DCPQUERY_H
+
+#include <Mathematics/GteMath.h>
+
+namespace gte
+{
+
+// Distance and closest-point queries.
+template <typename Real, typename Type0, typename Type1>
+class DCPQuery
+{
+public:
+    struct Result
+    {
+        // A DCPQuery-base class B must define a B::Result struct with member
+        // 'Real distance'.  A DCPQuery-derived class D must also derive a
+        // D::Result from B:Result but may have no members.  The idea is to
+        // allow Result to store closest-point information in addition to the
+        // distance.  The operator() is non-const to allow DCPQuery to store
+        // and modify private state that supports the query.
+    };
+    Result operator()(Type0 const& primitive0, Type1 const& primitive1);
+};
+
+}
+#endif
diff --git a/src/geometric-tools/Mathematics/GteDistLine3Triangle3.h b/src/geometric-tools/Mathematics/GteDistLine3Triangle3.h
new file mode 100644
index 0000000000000000000000000000000000000000..993bb4736afb1e13293c13be5ab25e3c4cfce5f7
--- /dev/null
+++ b/src/geometric-tools/Mathematics/GteDistLine3Triangle3.h
@@ -0,0 +1,130 @@
+// David Eberly, Geometric Tools, Redmond WA 98052
+// Copyright (c) 1998-2018
+// Distributed under the Boost Software License, Version 1.0.
+// http://www.boost.org/LICENSE_1_0.txt
+// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
+// File Version: 3.0.0 (2016/06/19)
+
+#pragma once
+#ifndef GTE_DIST_LINE3_TRIANGLE3_H
+#define GTE_DIST_LINE3_TRIANGLE3_H
+
+#include <Mathematics/GteVector3.h>
+#include <Mathematics/GteDistLineSegment.h>
+#include <Mathematics/GteTriangle.h>
+#include <limits>
+
+namespace gte
+{
+
+template <typename Real>
+class DCPQuery<Real, Line3<Real>, Triangle3<Real>>
+{
+public:
+    struct Result
+    {
+        Real distance, sqrDistance;
+        Real lineParameter, triangleParameter[3];
+        Vector3<Real> closestPoint[2];
+    };
+
+    Result operator()(Line3<Real> const& line,
+        Triangle3<Real> const& triangle);
+};
+
+
+template <typename Real>
+typename DCPQuery<Real, Line3<Real>, Triangle3<Real>>::Result
+DCPQuery<Real, Line3<Real>, Triangle3<Real>>::operator()(
+    Line3<Real> const& line, Triangle3<Real> const& triangle)
+{
+    Result result;
+
+    // Test if line intersects triangle.  If so, the squared distance is zero.
+    Vector3<Real> edge0 = triangle.v[1] - triangle.v[0];
+    Vector3<Real> edge1 = triangle.v[2] - triangle.v[0];
+    Vector3<Real> normal = UnitCross(edge0, edge1);
+    Real NdD = Dot(normal, line.direction);
+    if (std::abs(NdD) > (Real)0)
+    {
+        // The line and triangle are not parallel, so the line intersects
+        // the plane of the triangle.
+        Vector3<Real> diff = line.origin - triangle.v[0];
+        Vector3<Real> basis[3];  // {D, U, V}
+        basis[0] = line.direction;
+        ComputeOrthogonalComplement<Real>(1, basis);
+        Real UdE0 = Dot(basis[1], edge0);
+        Real UdE1 = Dot(basis[1], edge1);
+        Real UdDiff = Dot(basis[1], diff);
+        Real VdE0 = Dot(basis[2], edge0);
+        Real VdE1 = Dot(basis[2], edge1);
+        Real VdDiff = Dot(basis[2], diff);
+        Real invDet = ((Real)1) / (UdE0*VdE1 - UdE1*VdE0);
+
+        // Barycentric coordinates for the point of intersection.
+        Real b1 = (VdE1*UdDiff - UdE1*VdDiff)*invDet;
+        Real b2 = (UdE0*VdDiff - VdE0*UdDiff)*invDet;
+        Real b0 = (Real)1 - b1 - b2;
+
+        if (b0 >= (Real)0 && b1 >= (Real)0 && b2 >= (Real)0)
+        {
+            // Line parameter for the point of intersection.
+            Real DdE0 = Dot(line.direction, edge0);
+            Real DdE1 = Dot(line.direction, edge1);
+            Real DdDiff = Dot(line.direction, diff);
+            result.lineParameter = b1*DdE0 + b2*DdE1 - DdDiff;
+
+            // Barycentric coordinates for the point of intersection.
+            result.triangleParameter[0] = b0;
+            result.triangleParameter[1] = b1;
+            result.triangleParameter[2] = b2;
+
+            // The intersection point is inside or on the triangle.
+            result.closestPoint[0] = line.origin +
+                result.lineParameter*line.direction;
+            result.closestPoint[1] = triangle.v[0] + b1*edge0 + b2*edge1;
+
+            result.distance = (Real)0;
+            result.sqrDistance = (Real)0;
+            return result;
+        }
+    }
+
+    // Either (1) the line is not parallel to the triangle and the point of
+    // intersection of the line and the plane of the triangle is outside the
+    // triangle or (2) the line and triangle are parallel.  Regardless, the
+    // closest point on the triangle is on an edge of the triangle.  Compare
+    // the line to all three edges of the triangle.
+    result.distance = std::numeric_limits<Real>::max();
+    result.sqrDistance = std::numeric_limits<Real>::max();
+    for (int i0 = 2, i1 = 0; i1 < 3; i0 = i1++)
+    {
+        Vector3<Real> segCenter = ((Real)0.5)*(triangle.v[i0] +
+            triangle.v[i1]);
+        Vector3<Real> segDirection = triangle.v[i1] - triangle.v[i0];
+        Real segExtent = ((Real)0.5)*Normalize(segDirection);
+        Segment3<Real> segment(segCenter, segDirection, segExtent);
+
+        DCPQuery<Real, Line3<Real>, Segment3<Real>> query;
+        auto lsResult = query(line, segment);
+        if (lsResult.sqrDistance < result.sqrDistance)
+        {
+            result.sqrDistance = lsResult.sqrDistance;
+            result.distance = lsResult.distance;
+            result.lineParameter = lsResult.parameter[0];
+            result.triangleParameter[i0] = ((Real)0.5)*((Real)1 -
+                lsResult.parameter[0] / segExtent);
+            result.triangleParameter[i1] = (Real)1 -
+                result.triangleParameter[i0];
+            result.triangleParameter[3 - i0 - i1] = (Real)0;
+            result.closestPoint[0] = lsResult.closestPoint[0];
+            result.closestPoint[1] = lsResult.closestPoint[1];
+        }
+    }
+
+    return result;
+}
+
+
+}
+#endif
diff --git a/src/geometric-tools/Mathematics/GteDistLineSegment.h b/src/geometric-tools/Mathematics/GteDistLineSegment.h
new file mode 100644
index 0000000000000000000000000000000000000000..f002dfabb1c3145149d6a68de01fafb4a7fe4048
--- /dev/null
+++ b/src/geometric-tools/Mathematics/GteDistLineSegment.h
@@ -0,0 +1,116 @@
+// David Eberly, Geometric Tools, Redmond WA 98052
+// Copyright (c) 1998-2018
+// Distributed under the Boost Software License, Version 1.0.
+// http://www.boost.org/LICENSE_1_0.txt
+// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
+// File Version: 3.0.1 (2018/10/05)
+
+#pragma once
+#ifndef GTE_DIST_LINE_SEGMENT_H
+#define GTE_DIST_LINE_SEGMENT_H
+
+#include <Mathematics/GteDCPQuery.h>
+#include <Mathematics/GteLine.h>
+#include <Mathematics/GteSegment.h>
+
+namespace gte
+{
+
+template <int N, typename Real>
+class DCPQuery<Real, Line<N, Real>, Segment<N, Real>>
+{
+public:
+    struct Result
+    {
+        Real distance, sqrDistance;
+        Real parameter[2];
+        Vector<N, Real> closestPoint[2];
+    };
+
+    // The centered form of the 'segment' is used.  Thus, parameter[1] of
+    // the result is in [-e,e], where e = |segment.p[1] - segment.p[0]|/2.
+    Result operator()(Line<N, Real> const& line,
+        Segment<N, Real> const& segment);
+};
+
+// Template aliases for convenience.
+template <int N, typename Real>
+using DCPLineSegment = DCPQuery<Real, Line<N, Real>, Segment<N, Real>>;
+
+template <typename Real>
+using DCPLine2Segment2 = DCPLineSegment<2, Real>;
+
+template <typename Real>
+using DCPLine3Segment3 = DCPLineSegment<3, Real>;
+
+
+template <int N, typename Real>
+typename DCPQuery<Real, Line<N, Real>, Segment<N, Real>>::Result
+DCPQuery<Real, Line<N, Real>, Segment<N, Real>>::operator()(
+    Line<N, Real> const& line, Segment<N, Real> const& segment)
+{
+    Result result;
+
+    Vector<N, Real> segCenter, segDirection;
+    Real segExtent;
+    segment.GetCenteredForm(segCenter, segDirection, segExtent);
+
+    Vector<N, Real> diff = line.origin - segCenter;
+    Real a01 = -Dot(line.direction, segDirection);
+    Real b0 = Dot(diff, line.direction);
+    Real s0, s1;
+
+    if (std::abs(a01) < (Real)1)
+    {
+        // The line and segment are not parallel.
+        Real det = (Real)1 - a01 * a01;
+        Real extDet = segExtent * det;
+        Real b1 = -Dot(diff, segDirection);
+        s1 = a01 * b0 - b1;
+
+        if (s1 >= -extDet)
+        {
+            if (s1 <= extDet)
+            {
+                // Two interior points are closest, one on the line and one
+                // on the segment.
+                s0 = (a01 * b1 - b0) / det;
+                s1 /= det;
+            }
+            else
+            {
+                // The endpoint e1 of the segment and an interior point of
+                // the line are closest.
+                s1 = segExtent;
+                s0 = -(a01 * s1 + b0);
+            }
+        }
+        else
+        {
+            // The endpoint e0 of the segment and an interior point of the
+            // line are closest.
+            s1 = -segExtent;
+            s0 = -(a01 * s1 + b0);
+        }
+    }
+    else
+    {
+        // The line and segment are parallel.  Choose the closest pair so that
+        // one point is at segment origin.
+        s1 = (Real)0;
+        s0 = -b0;
+    }
+
+    result.parameter[0] = s0;
+    result.parameter[1] = s1;
+    result.closestPoint[0] = line.origin + s0 * line.direction;
+    result.closestPoint[1] = segCenter + s1 * segDirection;
+    diff = result.closestPoint[0] - result.closestPoint[1];
+    result.sqrDistance = Dot(diff, diff);
+    result.distance = std::sqrt(result.sqrDistance);
+    return result;
+}
+
+
+}
+#endif
diff --git a/src/geometric-tools/Mathematics/GteDistPointTriangle.h b/src/geometric-tools/Mathematics/GteDistPointTriangle.h
new file mode 100644
index 0000000000000000000000000000000000000000..9ab7942bd2f8c49c446071178bd854eb8cd08cc5
--- /dev/null
+++ b/src/geometric-tools/Mathematics/GteDistPointTriangle.h
@@ -0,0 +1,269 @@
+// David Eberly, Geometric Tools, Redmond WA 98052
+// Copyright (c) 1998-2018
+// Distributed under the Boost Software License, Version 1.0.
+// http://www.boost.org/LICENSE_1_0.txt
+// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
+// File Version: 3.0.1 (2018/10/05)
+
+#pragma once
+#ifndef GTE_DIST_POINT_TRIANGLE_H
+#define GTE_DIST_POINT_TRIANGLE_H
+
+#include <Mathematics/GteVector.h>
+#include <Mathematics/GteDCPQuery.h>
+#include <Mathematics/GteTriangle.h>
+
+namespace gte
+{
+
+template <int N, typename Real>
+class DCPQuery<Real, Vector<N, Real>, Triangle<N, Real>>
+{
+public:
+    struct Result
+    {
+        Real distance, sqrDistance;
+        Real parameter[3];  // barycentric coordinates for triangle.v[3]
+        Vector<N, Real> closest;
+    };
+
+    Result operator()(Vector<N, Real> const& point,
+        Triangle<N, Real> const& triangle);
+
+private:
+    inline void GetMinEdge02(Real const& a11, Real const& b1,
+        Vector<2, Real>& p) const;
+
+    inline void GetMinEdge12(Real const& a01, Real const& a11, Real const& b1,
+        Real const& f10, Real const& f01, Vector<2, Real>& p) const;
+
+    inline void GetMinInterior(Vector<2, Real> const& p0, Real const& h0,
+        Vector<2, Real> const& p1, Real const& h1, Vector<2, Real>& p) const;
+};
+
+// Template aliases for convenience.
+template <int N, typename Real>
+using DCPPointTriangle =
+DCPQuery<Real, Vector<N, Real>, Triangle<N, Real>>;
+
+template <typename Real>
+using DCPPoint2Triangle2 = DCPPointTriangle<2, Real>;
+
+template <typename Real>
+using DCPPoint3Triangle3 = DCPPointTriangle<3, Real>;
+
+
+template <int N, typename Real> inline
+void DCPQuery<Real, Vector<N, Real>, Triangle<N, Real>>::GetMinEdge02(
+    Real const& a11, Real const& b1, Vector<2, Real>& p) const
+{
+    p[0] = (Real)0;
+    if (b1 >= (Real)0)
+    {
+        p[1] = (Real)0;
+    }
+    else if (a11 + b1 <= (Real)0)
+    {
+        p[1] = (Real)1;
+    }
+    else
+    {
+        p[1] = -b1 / a11;
+    }
+}
+
+template <int N, typename Real> inline
+void DCPQuery<Real, Vector<N, Real>, Triangle<N, Real>>::GetMinEdge12(
+    Real const& a01, Real const& a11, Real const& b1, Real const& f10,
+    Real const& f01, Vector<2, Real>& p) const
+{
+    Real h0 = a01 + b1 - f10;
+    if (h0 >= (Real)0)
+    {
+        p[1] = (Real)0;
+    }
+    else
+    {
+        Real h1 = a11 + b1 - f01;
+        if (h1 <= (Real)0)
+        {
+            p[1] = (Real)1;
+        }
+        else
+        {
+            p[1] = h0 / (h0 - h1);
+        }
+    }
+    p[0] = (Real)1 - p[1];
+}
+
+template <int N, typename Real> inline
+void DCPQuery<Real, Vector<N, Real>, Triangle<N, Real>>::GetMinInterior(
+    Vector<2, Real> const& p0, Real const& h0, Vector<2, Real> const& p1,
+    Real const& h1, Vector<2, Real>& p) const
+{
+    Real z = h0 / (h0 - h1);
+    p = ((Real)1 - z) * p0 + z * p1;
+}
+
+template <int N,typename Real>
+typename DCPQuery<Real, Vector<N, Real>, Triangle<N, Real>>::Result
+DCPQuery<Real, Vector<N, Real>, Triangle<N, Real>>::operator()(
+    Vector<N, Real> const& point, Triangle<N, Real> const& triangle)
+{
+    Vector<N, Real> diff = point - triangle.v[0];
+    Vector<N, Real> edge0 = triangle.v[1] - triangle.v[0];
+    Vector<N, Real> edge1 = triangle.v[2] - triangle.v[0];
+    Real a00 = Dot(edge0, edge0);
+    Real a01 = Dot(edge0, edge1);
+    Real a11 = Dot(edge1, edge1);
+    Real b0 = -Dot(diff, edge0);
+    Real b1 = -Dot(diff, edge1);
+
+    Real f00 = b0;
+    Real f10 = b0 + a00;
+    Real f01 = b0 + a01;
+
+    Vector<2, Real> p0, p1, p;
+    Real dt1, h0, h1;
+
+    // Compute the endpoints p0 and p1 of the segment.  The segment is
+    // parameterized by L(z) = (1-z)*p0 + z*p1 for z in [0,1] and the
+    // directional derivative of half the quadratic on the segment is
+    // H(z) = Dot(p1-p0,gradient[Q](L(z))/2), where gradient[Q]/2 = (F,G).
+    // By design, F(L(z)) = 0 for cases (2), (4), (5), and (6).  Cases (1) and
+    // (3) can correspond to no-intersection or intersection of F = 0 with the
+    // triangle.
+    if (f00 >= (Real)0)
+    {
+        if (f01 >= (Real)0)
+        {
+            // (1) p0 = (0,0), p1 = (0,1), H(z) = G(L(z))
+            GetMinEdge02(a11, b1, p);
+        }
+        else
+        {
+            // (2) p0 = (0,t10), p1 = (t01,1-t01), H(z) = (t11 - t10)*G(L(z))
+            p0[0] = (Real)0;
+            p0[1] = f00 / (f00 - f01);
+            p1[0] = f01 / (f01 - f10);
+            p1[1] = (Real)1 - p1[0];
+            dt1 = p1[1] - p0[1];
+            h0 = dt1 * (a11 * p0[1] + b1);
+            if (h0 >= (Real)0)
+            {
+                GetMinEdge02(a11, b1, p);
+            }
+            else
+            {
+                h1 = dt1 * (a01 * p1[0] + a11 * p1[1] + b1);
+                if (h1 <= (Real)0)
+                {
+                    GetMinEdge12(a01, a11, b1, f10, f01, p);
+                }
+                else
+                {
+                    GetMinInterior(p0, h0, p1, h1, p);
+                }
+            }
+        }
+    }
+    else if (f01 <= (Real)0)
+    {
+        if (f10 <= (Real)0)
+        {
+            // (3) p0 = (1,0), p1 = (0,1), H(z) = G(L(z)) - F(L(z))
+            GetMinEdge12(a01, a11, b1, f10, f01, p);
+        }
+        else
+        {
+            // (4) p0 = (t00,0), p1 = (t01,1-t01), H(z) = t11*G(L(z))
+            p0[0] = f00 / (f00 - f10);
+            p0[1] = (Real)0;
+            p1[0] = f01 / (f01 - f10);
+            p1[1] = (Real)1 - p1[0];
+            h0 = p1[1] * (a01 * p0[0] + b1);
+            if (h0 >= (Real)0)
+            {
+                p = p0;  // GetMinEdge01
+            }
+            else
+            {
+                h1 = p1[1] * (a01 * p1[0] + a11 * p1[1] + b1);
+                if (h1 <= (Real)0)
+                {
+                    GetMinEdge12(a01, a11, b1, f10, f01, p);
+                }
+                else
+                {
+                    GetMinInterior(p0, h0, p1, h1, p);
+                }
+            }
+        }
+    }
+    else if (f10 <= (Real)0)
+    {
+        // (5) p0 = (0,t10), p1 = (t01,1-t01), H(z) = (t11 - t10)*G(L(z))
+        p0[0] = (Real)0;
+        p0[1] = f00 / (f00 - f01);
+        p1[0] = f01 / (f01 - f10);
+        p1[1] = (Real)1 - p1[0];
+        dt1 = p1[1] - p0[1];
+        h0 = dt1 * (a11 * p0[1] + b1);
+        if (h0 >= (Real)0)
+        {
+            GetMinEdge02(a11, b1, p);
+        }
+        else
+        {
+            h1 = dt1 * (a01 * p1[0] + a11 * p1[1] + b1);
+            if (h1 <= (Real)0)
+            {
+                GetMinEdge12(a01, a11, b1, f10, f01, p);
+            }
+            else
+            {
+                GetMinInterior(p0, h0, p1, h1, p);
+            }
+        }
+    }
+    else
+    {
+        // (6) p0 = (t00,0), p1 = (0,t11), H(z) = t11*G(L(z))
+        p0[0] = f00 / (f00 - f10);
+        p0[1] = (Real)0;
+        p1[0] = (Real)0;
+        p1[1] = f00 / (f00 - f01);
+        h0 = p1[1] * (a01 * p0[0] + b1);
+        if (h0 >= (Real)0)
+        {
+            p = p0;  // GetMinEdge01
+        }
+        else
+        {
+            h1 = p1[1] * (a11 * p1[1] + b1);
+            if (h1 <= (Real)0)
+            {
+                GetMinEdge02(a11, b1, p);
+            }
+            else
+            {
+                GetMinInterior(p0, h0, p1, h1, p);
+            }
+        }
+    }
+
+    Result result;
+    result.parameter[0] = (Real)1 - p[0] - p[1];
+    result.parameter[1] = p[0];
+    result.parameter[2] = p[1];
+    result.closest = triangle.v[0] + p[0] * edge0 + p[1] * edge1;
+    diff = point - result.closest;
+    result.sqrDistance = Dot(diff, diff);
+    result.distance = std::sqrt(result.sqrDistance);
+    return result;
+}
+
+
+}
+#endif
diff --git a/src/geometric-tools/Mathematics/GteDistSegment3Triangle3.h b/src/geometric-tools/Mathematics/GteDistSegment3Triangle3.h
new file mode 100644
index 0000000000000000000000000000000000000000..39c71f56383926ba70b3d2d0b9c1574fdb2e4b4a
--- /dev/null
+++ b/src/geometric-tools/Mathematics/GteDistSegment3Triangle3.h
@@ -0,0 +1,91 @@
+// David Eberly, Geometric Tools, Redmond WA 98052
+// Copyright (c) 1998-2018
+// Distributed under the Boost Software License, Version 1.0.
+// http://www.boost.org/LICENSE_1_0.txt
+// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
+// File Version: 3.0.0 (2016/06/19)
+
+#pragma once
+#ifndef GTE_DIST_SEGMENT3_TRIANGLE3_H
+#define GTE_DIST_SEGMENT3_TRIANGLE3_H
+
+#include <Mathematics/GteDistLine3Triangle3.h>
+#include <Mathematics/GteDistPointTriangle.h>
+#include <Mathematics/GteSegment.h>
+
+namespace gte
+{
+
+template <typename Real>
+class DCPQuery<Real, Segment3<Real>, Triangle3<Real>>
+{
+public:
+    struct Result
+    {
+        Real distance, sqrDistance;
+        Real segmentParameter, triangleParameter[3];
+        Vector3<Real> closestPoint[2];
+    };
+
+    Result operator()(Segment3<Real> const& segment,
+        Triangle3<Real> const& triangle);
+};
+
+
+template <typename Real>
+typename DCPQuery<Real, Segment3<Real>, Triangle3<Real>>::Result
+DCPQuery<Real, Segment3<Real>, Triangle3<Real>>::operator()(
+    Segment3<Real> const& segment, Triangle3<Real> const& triangle)
+{
+    Result result;
+
+    Vector3<Real> segCenter, segDirection;
+    Real segExtent;
+    segment.GetCenteredForm(segCenter, segDirection, segExtent);
+
+    Line3<Real> line(segCenter, segDirection);
+    DCPQuery<Real, Line3<Real>, Triangle3<Real>> ltQuery;
+    auto ltResult = ltQuery(line, triangle);
+
+    if (ltResult.lineParameter >= -segExtent)
+    {
+        if (ltResult.lineParameter <= segExtent)
+        {
+            result.distance = ltResult.distance;
+            result.sqrDistance = ltResult.sqrDistance;
+            result.segmentParameter = ltResult.lineParameter;
+            result.triangleParameter[0] = ltResult.triangleParameter[0];
+            result.triangleParameter[1] = ltResult.triangleParameter[1];
+            result.triangleParameter[2] = ltResult.triangleParameter[2];
+            result.closestPoint[0] = ltResult.closestPoint[0];
+            result.closestPoint[1] = ltResult.closestPoint[1];
+        }
+        else
+        {
+            DCPQuery<Real, Vector3<Real>, Triangle3<Real>> ptQuery;
+            Vector3<Real> point = segCenter + segExtent*segDirection;
+            auto ptResult = ptQuery(point, triangle);
+            result.sqrDistance = ptResult.sqrDistance;
+            result.distance = ptResult.distance;
+            result.segmentParameter = segExtent;
+            result.closestPoint[0] = point;
+            result.closestPoint[1] = ptResult.closest;
+        }
+    }
+    else
+    {
+        DCPQuery<Real, Vector3<Real>, Triangle3<Real>> ptQuery;
+        Vector3<Real> point = segCenter - segExtent*segDirection;
+        auto ptResult = ptQuery(point, triangle);
+        result.sqrDistance = ptResult.sqrDistance;
+        result.distance = ptResult.distance;
+        result.segmentParameter = segExtent;
+        result.closestPoint[0] = point;
+        result.closestPoint[1] = ptResult.closest;
+    }
+    return result;
+}
+
+
+}
+#endif
diff --git a/src/geometric-tools/Mathematics/GteDistTriangle3Triangle3.h b/src/geometric-tools/Mathematics/GteDistTriangle3Triangle3.h
new file mode 100644
index 0000000000000000000000000000000000000000..503c08f002c65c4b76895524ee5df6f81353d48e
--- /dev/null
+++ b/src/geometric-tools/Mathematics/GteDistTriangle3Triangle3.h
@@ -0,0 +1,103 @@
+// David Eberly, Geometric Tools, Redmond WA 98052
+// Copyright (c) 1998-2018
+// Distributed under the Boost Software License, Version 1.0.
+// http://www.boost.org/LICENSE_1_0.txt
+// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
+// File Version: 3.0.0 (2016/06/19)
+
+#pragma once
+#ifndef GTE_DIST_TRIANGLE3_TRIANGLE3_H
+#define GTE_DIST_TRIANGLE3_TRIANGLE3_H
+
+#include <Mathematics/GteDistSegment3Triangle3.h>
+
+namespace gte
+{
+
+template <typename Real>
+class DCPQuery<Real, Triangle3<Real>, Triangle3<Real>>
+{
+public:
+    struct Result
+    {
+        Real distance, sqrDistance;
+        Real triangle0Parameter[3], triangle1Parameter[3];
+        Vector3<Real> closestPoint[2];
+    };
+
+    Result operator()(Triangle3<Real> const& triangle0,
+        Triangle3<Real> const& triangle1);
+};
+
+
+template <typename Real>
+typename DCPQuery<Real, Triangle3<Real>, Triangle3<Real>>::Result
+DCPQuery<Real, Triangle3<Real>, Triangle3<Real>>::operator()(
+    Triangle3<Real> const& triangle0, Triangle3<Real> const& triangle1)
+{
+    Result result;
+
+    DCPQuery<Real, Segment3<Real>, Triangle3<Real>> stQuery;
+    typename DCPQuery<Real, Segment3<Real>, Triangle3<Real>>::Result
+        stResult;
+    result.sqrDistance = std::numeric_limits<Real>::max();
+
+    // Compare edges of triangle0 to the interior of triangle1.
+    for (int i0 = 2, i1 = 0; i1 < 3; i0 = i1++)
+    {
+        Vector3<Real> segCenter = ((Real)0.5)*(triangle0.v[i0] +
+            triangle0.v[i1]);
+        Vector3<Real> segDirection = triangle0.v[i1] - triangle0.v[i0];
+        Real segExtent = ((Real)0.5)*Normalize(segDirection);
+        Segment3<Real> edge(segCenter, segDirection, segExtent);
+
+        stResult = stQuery(edge, triangle1);
+        if (stResult.sqrDistance < result.sqrDistance)
+        {
+            result.distance = stResult.distance;
+            result.sqrDistance = stResult.sqrDistance;
+            Real ratio = stResult.segmentParameter / segExtent;  // in [-1,1]
+            result.triangle0Parameter[i0] = ((Real)0.5)*((Real)1 - ratio);
+            result.triangle0Parameter[i1] =
+                (Real)1 - result.triangle0Parameter[i0];
+            result.triangle0Parameter[3 - i0 - i1] = (Real)0;
+            result.triangle1Parameter[0] = stResult.triangleParameter[0];
+            result.triangle1Parameter[1] = stResult.triangleParameter[1];
+            result.triangle1Parameter[2] = stResult.triangleParameter[2];
+            result.closestPoint[0] = stResult.closestPoint[0];
+            result.closestPoint[1] = stResult.closestPoint[1];
+        }
+    }
+
+    // Compare edges of triangle1 to the interior of triangle0.
+    for (int i0 = 2, i1 = 0; i1 < 3; i0 = i1++)
+    {
+        Vector3<Real> segCenter = ((Real)0.5)*(triangle1.v[i0] +
+            triangle1.v[i1]);
+        Vector3<Real> segDirection = triangle1.v[i1] - triangle1.v[i0];
+        Real segExtent = ((Real)0.5)*Normalize(segDirection);
+        Segment3<Real> edge(segCenter, segDirection, segExtent);
+
+        stResult = stQuery(edge, triangle0);
+        if (stResult.sqrDistance < result.sqrDistance)
+        {
+            result.distance = stResult.distance;
+            result.sqrDistance = stResult.sqrDistance;
+            Real ratio = stResult.segmentParameter / segExtent;  // in [-1,1]
+            result.triangle0Parameter[0] = stResult.triangleParameter[0];
+            result.triangle0Parameter[1] = stResult.triangleParameter[1];
+            result.triangle0Parameter[2] = stResult.triangleParameter[2];
+            result.triangle1Parameter[i0] = ((Real)0.5)*((Real)1 - ratio);
+            result.triangle1Parameter[i1] =
+                (Real)1 - result.triangle0Parameter[i0];
+            result.triangle1Parameter[3 - i0 - i1] = (Real)0;
+            result.closestPoint[0] = stResult.closestPoint[0];
+            result.closestPoint[1] = stResult.closestPoint[1];
+        }
+    }
+    return result;
+}
+
+
+}
+#endif
diff --git a/src/geometric-tools/Mathematics/GteLine.h b/src/geometric-tools/Mathematics/GteLine.h
new file mode 100644
index 0000000000000000000000000000000000000000..106631f93120d6f4f8c1711fbda621590e456636
--- /dev/null
+++ b/src/geometric-tools/Mathematics/GteLine.h
@@ -0,0 +1,115 @@
+// David Eberly, Geometric Tools, Redmond WA 98052
+// Copyright (c) 1998-2018
+// Distributed under the Boost Software License, Version 1.0.
+// http://www.boost.org/LICENSE_1_0.txt
+// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
+// File Version: 3.0.0 (2016/06/19)
+
+#pragma once
+#ifndef GTE_LINE_H
+#define GTE_LINE_H
+
+#include <Mathematics/GteVector.h>
+
+// The line is represented by P+t*D, where P is an origin point, D is a
+// unit-length direction vector, and t is any real number.  The user must
+// ensure that D is unit length.
+
+namespace gte
+{
+
+template <int N, typename Real>
+class Line
+{
+public:
+    // Construction and destruction.  The default constructor sets the origin
+    // to (0,...,0) and the line direction to (1,0,...,0).
+    Line();
+    Line(Vector<N, Real> const& inOrigin, Vector<N, Real> const& inDirection);
+
+    // Public member access.  The direction must be unit length.
+    Vector<N, Real> origin, direction;
+
+public:
+    // Comparisons to support sorted containers.
+    bool operator==(Line const& line) const;
+    bool operator!=(Line const& line) const;
+    bool operator< (Line const& line) const;
+    bool operator<=(Line const& line) const;
+    bool operator> (Line const& line) const;
+    bool operator>=(Line const& line) const;
+};
+
+// Template aliases for convenience.
+template <typename Real>
+using Line2 = Line<2, Real>;
+
+template <typename Real>
+using Line3 = Line<3, Real>;
+
+
+template <int N, typename Real>
+Line<N, Real>::Line()
+{
+    origin.MakeZero();
+    direction.MakeUnit(0);
+}
+
+template <int N, typename Real>
+Line<N, Real>::Line(Vector<N, Real> const& inOrigin,
+    Vector<N, Real> const& inDirection)
+    :
+    origin(inOrigin),
+    direction(inDirection)
+{
+}
+
+template <int N, typename Real>
+bool Line<N, Real>::operator==(Line const& line) const
+{
+    return origin == line.origin && direction == line.direction;
+}
+
+template <int N, typename Real>
+bool Line<N, Real>::operator!=(Line const& line) const
+{
+    return !operator==(line);
+}
+
+template <int N, typename Real>
+bool Line<N, Real>::operator<(Line const& line) const
+{
+    if (origin < line.origin)
+    {
+        return true;
+    }
+
+    if (origin > line.origin)
+    {
+        return false;
+    }
+
+    return direction < line.direction;
+}
+
+template <int N, typename Real>
+bool Line<N, Real>::operator<=(Line const& line) const
+{
+    return operator<(line) || operator==(line);
+}
+
+template <int N, typename Real>
+bool Line<N, Real>::operator>(Line const& line) const
+{
+    return !operator<=(line);
+}
+
+template <int N, typename Real>
+bool Line<N, Real>::operator>=(Line const& line) const
+{
+    return !operator<(line);
+}
+
+
+}
+#endif
diff --git a/src/geometric-tools/Mathematics/GteMath.h b/src/geometric-tools/Mathematics/GteMath.h
new file mode 100644
index 0000000000000000000000000000000000000000..7a1a40a730ae14f695bb834fd3ebac75a5cebe78
--- /dev/null
+++ b/src/geometric-tools/Mathematics/GteMath.h
@@ -0,0 +1,616 @@
+// David Eberly, Geometric Tools, Redmond WA 98052
+// Copyright (c) 1998-2018
+// Distributed under the Boost Software License, Version 1.0.
+// http://www.boost.org/LICENSE_1_0.txt
+// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
+// File Version: 3.17.0 (2018/10/05)
+
+#pragma once
+#ifndef GTE_MATH_H
+#define GTE_MATH_H
+
+// This file extends the <cmath> support to include convenient constants and
+// functions.  The shared constants for CPU, Intel SSE and GPU lead to
+// correctly rounded approximations of the constants when using 'float' or
+// 'double'.
+
+#include <GTEngineDEF.h>
+#include <cmath>
+#include <limits>
+
+// Maximum number of iterations for bisection before a subinterval
+// degenerates to a single point. TODO: Verify these.  I used the formula:
+// 3 + std::numeric_limits<T>::digits - std::numeric_limits<T>::min_exponent.
+//   IEEEBinary16:  digits = 11, min_exponent = -13
+//   float:         digits = 27, min_exponent = -125
+//   double:        digits = 53, min_exponent = -1021
+// BSNumber and BSRational use std::numeric_limits<unsigned int>::max(),
+// but maybe these should be set to a large number or be user configurable.
+// The MAX_BISECTIONS_GENERIC is an arbitrary choice for now and is used
+// in template code where Real is the template parameter.
+#define GTE_C_MAX_BISECTIONS_FLOAT16    27u
+#define GTE_C_MAX_BISECTIONS_FLOAT32    155u
+#define GTE_C_MAX_BISECTIONS_FLOAT64    1077u
+#define GTE_C_MAX_BISECTIONS_BSNUMBER   0xFFFFFFFFu
+#define GTE_C_MAX_BISECTIONS_BSRATIONAL 0xFFFFFFFFu
+#define GTE_C_MAX_BISECTIONS_GENERIC    2048u
+
+// Constants involving pi.
+#define GTE_C_PI 3.1415926535897931
+#define GTE_C_HALF_PI 1.5707963267948966
+#define GTE_C_QUARTER_PI 0.7853981633974483
+#define GTE_C_TWO_PI 6.2831853071795862
+#define GTE_C_INV_PI 0.3183098861837907
+#define GTE_C_INV_TWO_PI 0.1591549430918953
+#define GTE_C_INV_HALF_PI 0.6366197723675813
+
+// Conversions between degrees and radians.
+#define GTE_C_DEG_TO_RAD 0.0174532925199433
+#define GTE_C_RAD_TO_DEG 57.295779513082321
+
+// Common constants.
+#define GTE_C_SQRT_2 1.4142135623730951
+#define GTE_C_INV_SQRT_2 0.7071067811865475
+#define GTE_C_LN_2 0.6931471805599453
+#define GTE_C_INV_LN_2 1.4426950408889634
+#define GTE_C_LN_10 2.3025850929940459
+#define GTE_C_INV_LN_10 0.43429448190325176
+
+// Constants for minimax polynomial approximations to sqrt(x).
+// The algorithm minimizes the maximum absolute error on [1,2].
+#define GTE_C_SQRT_DEG1_C0 +1.0
+#define GTE_C_SQRT_DEG1_C1 +4.1421356237309505e-01
+#define GTE_C_SQRT_DEG1_MAX_ERROR 1.7766952966368793e-2
+
+#define GTE_C_SQRT_DEG2_C0 +1.0
+#define GTE_C_SQRT_DEG2_C1 +4.8563183076125260e-01
+#define GTE_C_SQRT_DEG2_C2 -7.1418268388157458e-02
+#define GTE_C_SQRT_DEG2_MAX_ERROR 1.1795695163108744e-3
+
+#define GTE_C_SQRT_DEG3_C0 +1.0
+#define GTE_C_SQRT_DEG3_C1 +4.9750045320242231e-01
+#define GTE_C_SQRT_DEG3_C2 -1.0787308044477850e-01
+#define GTE_C_SQRT_DEG3_C3 +2.4586189615451115e-02
+#define GTE_C_SQRT_DEG3_MAX_ERROR 1.1309620116468910e-4
+
+#define GTE_C_SQRT_DEG4_C0 +1.0
+#define GTE_C_SQRT_DEG4_C1 +4.9955939832918816e-01
+#define GTE_C_SQRT_DEG4_C2 -1.2024066151943025e-01
+#define GTE_C_SQRT_DEG4_C3 +4.5461507257698486e-02
+#define GTE_C_SQRT_DEG4_C4 -1.0566681694362146e-02
+#define GTE_C_SQRT_DEG4_MAX_ERROR 1.2741170151556180e-5
+
+#define GTE_C_SQRT_DEG5_C0 +1.0
+#define GTE_C_SQRT_DEG5_C1 +4.9992197660031912e-01
+#define GTE_C_SQRT_DEG5_C2 -1.2378506719245053e-01
+#define GTE_C_SQRT_DEG5_C3 +5.6122776972699739e-02
+#define GTE_C_SQRT_DEG5_C4 -2.3128836281145482e-02
+#define GTE_C_SQRT_DEG5_C5 +5.0827122737047148e-03
+#define GTE_C_SQRT_DEG5_MAX_ERROR 1.5725568940708201e-6
+
+#define GTE_C_SQRT_DEG6_C0 +1.0
+#define GTE_C_SQRT_DEG6_C1 +4.9998616695784914e-01
+#define GTE_C_SQRT_DEG6_C2 -1.2470733323278438e-01
+#define GTE_C_SQRT_DEG6_C3 +6.0388587356982271e-02
+#define GTE_C_SQRT_DEG6_C4 -3.1692053551807930e-02
+#define GTE_C_SQRT_DEG6_C5 +1.2856590305148075e-02
+#define GTE_C_SQRT_DEG6_C6 -2.6183954624343642e-03
+#define GTE_C_SQRT_DEG6_MAX_ERROR 2.0584155535630089e-7
+
+#define GTE_C_SQRT_DEG7_C0 +1.0
+#define GTE_C_SQRT_DEG7_C1 +4.9999754817809228e-01
+#define GTE_C_SQRT_DEG7_C2 -1.2493243476353655e-01
+#define GTE_C_SQRT_DEG7_C3 +6.1859954146370910e-02
+#define GTE_C_SQRT_DEG7_C4 -3.6091595023208356e-02
+#define GTE_C_SQRT_DEG7_C5 +1.9483946523450868e-02
+#define GTE_C_SQRT_DEG7_C6 -7.5166134568007692e-03
+#define GTE_C_SQRT_DEG7_C7 +1.4127567687864939e-03
+#define GTE_C_SQRT_DEG7_MAX_ERROR 2.8072302919734948e-8
+
+#define GTE_C_SQRT_DEG8_C0 +1.0
+#define GTE_C_SQRT_DEG8_C1 +4.9999956583056759e-01
+#define GTE_C_SQRT_DEG8_C2 -1.2498490369914350e-01
+#define GTE_C_SQRT_DEG8_C3 +6.2318494667579216e-02
+#define GTE_C_SQRT_DEG8_C4 -3.7982961896432244e-02
+#define GTE_C_SQRT_DEG8_C5 +2.3642612312869460e-02
+#define GTE_C_SQRT_DEG8_C6 -1.2529377587270574e-02
+#define GTE_C_SQRT_DEG8_C7 +4.5382426960713929e-03
+#define GTE_C_SQRT_DEG8_C8 -7.8810995273670414e-04
+#define GTE_C_SQRT_DEG8_MAX_ERROR 3.9460605685825989e-9
+
+// Constants for minimax polynomial approximations to 1/sqrt(x).
+// The algorithm minimizes the maximum absolute error on [1,2].
+#define GTE_C_INVSQRT_DEG1_C0 +1.0
+#define GTE_C_INVSQRT_DEG1_C1 -2.9289321881345254e-01
+#define GTE_C_INVSQRT_DEG1_MAX_ERROR 3.7814314552701983e-2
+
+#define GTE_C_INVSQRT_DEG2_C0 +1.0
+#define GTE_C_INVSQRT_DEG2_C1 -4.4539812104566801e-01
+#define GTE_C_INVSQRT_DEG2_C2 +1.5250490223221547e-01
+#define GTE_C_INVSQRT_DEG2_MAX_ERROR 4.1953446330581234e-3
+
+#define GTE_C_INVSQRT_DEG3_C0 +1.0
+#define GTE_C_INVSQRT_DEG3_C1 -4.8703230993068791e-01
+#define GTE_C_INVSQRT_DEG3_C2 +2.8163710486669835e-01
+#define GTE_C_INVSQRT_DEG3_C3 -8.7498013749463421e-02
+#define GTE_C_INVSQRT_DEG3_MAX_ERROR 5.6307702007266786e-4
+
+#define GTE_C_INVSQRT_DEG4_C0 +1.0
+#define GTE_C_INVSQRT_DEG4_C1 -4.9710061558048779e-01
+#define GTE_C_INVSQRT_DEG4_C2 +3.4266247597676802e-01
+#define GTE_C_INVSQRT_DEG4_C3 -1.9106356536293490e-01
+#define GTE_C_INVSQRT_DEG4_C4 +5.2608486153198797e-02
+#define GTE_C_INVSQRT_DEG4_MAX_ERROR 8.1513919987605266e-5
+
+#define GTE_C_INVSQRT_DEG5_C0 +1.0
+#define GTE_C_INVSQRT_DEG5_C1 -4.9937760586004143e-01
+#define GTE_C_INVSQRT_DEG5_C2 +3.6508741295133973e-01
+#define GTE_C_INVSQRT_DEG5_C3 -2.5884890281853501e-01
+#define GTE_C_INVSQRT_DEG5_C4 +1.3275782221320753e-01
+#define GTE_C_INVSQRT_DEG5_C5 -3.2511945299404488e-02
+#define GTE_C_INVSQRT_DEG5_MAX_ERROR 1.2289367475583346e-5
+
+#define GTE_C_INVSQRT_DEG6_C0 +1.0
+#define GTE_C_INVSQRT_DEG6_C1 -4.9987029229547453e-01
+#define GTE_C_INVSQRT_DEG6_C2 +3.7220923604495226e-01
+#define GTE_C_INVSQRT_DEG6_C3 -2.9193067713256937e-01
+#define GTE_C_INVSQRT_DEG6_C4 +1.9937605991094642e-01
+#define GTE_C_INVSQRT_DEG6_C5 -9.3135712130901993e-02
+#define GTE_C_INVSQRT_DEG6_C6 +2.0458166789566690e-02
+#define GTE_C_INVSQRT_DEG6_MAX_ERROR 1.9001451223750465e-6
+
+#define GTE_C_INVSQRT_DEG7_C0 +1.0
+#define GTE_C_INVSQRT_DEG7_C1 -4.9997357250704977e-01
+#define GTE_C_INVSQRT_DEG7_C2 +3.7426216884998809e-01
+#define GTE_C_INVSQRT_DEG7_C3 -3.0539882498248971e-01
+#define GTE_C_INVSQRT_DEG7_C4 +2.3976005607005391e-01
+#define GTE_C_INVSQRT_DEG7_C5 -1.5410326351684489e-01
+#define GTE_C_INVSQRT_DEG7_C6 +6.5598809723041995e-02
+#define GTE_C_INVSQRT_DEG7_C7 -1.3038592450470787e-02
+#define GTE_C_INVSQRT_DEG7_MAX_ERROR 2.9887724993168940e-7
+
+#define GTE_C_INVSQRT_DEG8_C0 +1.0
+#define GTE_C_INVSQRT_DEG8_C1 -4.9999471066120371e-01
+#define GTE_C_INVSQRT_DEG8_C2 +3.7481415745794067e-01
+#define GTE_C_INVSQRT_DEG8_C3 -3.1023804387422160e-01
+#define GTE_C_INVSQRT_DEG8_C4 +2.5977002682930106e-01
+#define GTE_C_INVSQRT_DEG8_C5 -1.9818790717727097e-01
+#define GTE_C_INVSQRT_DEG8_C6 +1.1882414252613671e-01
+#define GTE_C_INVSQRT_DEG8_C7 -4.6270038088550791e-02
+#define GTE_C_INVSQRT_DEG8_C8 +8.3891541755747312e-03
+#define GTE_C_INVSQRT_DEG8_MAX_ERROR 4.7596926146947771e-8
+
+// Constants for minimax polynomial approximations to sin(x).
+// The algorithm minimizes the maximum absolute error on [-pi/2,pi/2].
+#define GTE_C_SIN_DEG3_C0 +1.0
+#define GTE_C_SIN_DEG3_C1 -1.4727245910375519e-01
+#define GTE_C_SIN_DEG3_MAX_ERROR 1.3481903639145865e-2
+
+#define GTE_C_SIN_DEG5_C0 +1.0
+#define GTE_C_SIN_DEG5_C1 -1.6600599923812209e-01
+#define GTE_C_SIN_DEG5_C2 +7.5924178409012000e-03
+#define GTE_C_SIN_DEG5_MAX_ERROR 1.4001209384639779e-4
+
+#define GTE_C_SIN_DEG7_C0 +1.0
+#define GTE_C_SIN_DEG7_C1 -1.6665578084732124e-01
+#define GTE_C_SIN_DEG7_C2 +8.3109378830028557e-03
+#define GTE_C_SIN_DEG7_C3 -1.8447486103462252e-04
+#define GTE_C_SIN_DEG7_MAX_ERROR 1.0205878936686563e-6
+
+#define GTE_C_SIN_DEG9_C0 +1.0
+#define GTE_C_SIN_DEG9_C1 -1.6666656235308897e-01
+#define GTE_C_SIN_DEG9_C2 +8.3329962509886002e-03
+#define GTE_C_SIN_DEG9_C3 -1.9805100675274190e-04
+#define GTE_C_SIN_DEG9_C4 +2.5967200279475300e-06
+#define GTE_C_SIN_DEG9_MAX_ERROR 5.2010746265374053e-9
+
+#define GTE_C_SIN_DEG11_C0 +1.0
+#define GTE_C_SIN_DEG11_C1 -1.6666666601721269e-01
+#define GTE_C_SIN_DEG11_C2 +8.3333303183525942e-03
+#define GTE_C_SIN_DEG11_C3 -1.9840782426250314e-04
+#define GTE_C_SIN_DEG11_C4 +2.7521557770526783e-06
+#define GTE_C_SIN_DEG11_C5 -2.3828544692960918e-08
+#define GTE_C_SIN_DEG11_MAX_ERROR 1.9295870457014530e-11
+
+// Constants for minimax polynomial approximations to cos(x).
+// The algorithm minimizes the maximum absolute error on [-pi/2,pi/2].
+#define GTE_C_COS_DEG2_C0 +1.0
+#define GTE_C_COS_DEG2_C1 -4.0528473456935105e-01
+#define GTE_C_COS_DEG2_MAX_ERROR 5.4870946878404048e-2
+
+#define GTE_C_COS_DEG4_C0 +1.0
+#define GTE_C_COS_DEG4_C1 -4.9607181958647262e-01
+#define GTE_C_COS_DEG4_C2 +3.6794619653489236e-02
+#define GTE_C_COS_DEG4_MAX_ERROR 9.1879932449712154e-4
+
+#define GTE_C_COS_DEG6_C0 +1.0
+#define GTE_C_COS_DEG6_C1 -4.9992746217057404e-01
+#define GTE_C_COS_DEG6_C2 +4.1493920348353308e-02
+#define GTE_C_COS_DEG6_C3 -1.2712435011987822e-03
+#define GTE_C_COS_DEG6_MAX_ERROR 9.2028470133065365e-6
+
+#define GTE_C_COS_DEG8_C0 +1.0
+#define GTE_C_COS_DEG8_C1 -4.9999925121358291e-01
+#define GTE_C_COS_DEG8_C2 +4.1663780117805693e-02
+#define GTE_C_COS_DEG8_C3 -1.3854239405310942e-03
+#define GTE_C_COS_DEG8_C4 +2.3154171575501259e-05
+#define GTE_C_COS_DEG8_MAX_ERROR 5.9804533020235695e-8
+
+#define GTE_C_COS_DEG10_C0 +1.0
+#define GTE_C_COS_DEG10_C1 -4.9999999508695869e-01
+#define GTE_C_COS_DEG10_C2 +4.1666638865338612e-02
+#define GTE_C_COS_DEG10_C3 -1.3888377661039897e-03
+#define GTE_C_COS_DEG10_C4 +2.4760495088926859e-05
+#define GTE_C_COS_DEG10_C5 -2.6051615464872668e-07
+#define GTE_C_COS_DEG10_MAX_ERROR 2.7006769043325107e-10
+
+// Constants for minimax polynomial approximations to tan(x).
+// The algorithm minimizes the maximum absolute error on [-pi/4,pi/4].
+#define GTE_C_TAN_DEG3_C0 1.0
+#define GTE_C_TAN_DEG3_C1 4.4295926544736286e-01
+#define GTE_C_TAN_DEG3_MAX_ERROR 1.1661892256204731e-2
+
+#define GTE_C_TAN_DEG5_C0 1.0
+#define GTE_C_TAN_DEG5_C1 3.1401320403542421e-01
+#define GTE_C_TAN_DEG5_C2 2.0903948109240345e-01
+#define GTE_C_TAN_DEG5_MAX_ERROR 5.8431854390143118e-4
+
+#define GTE_C_TAN_DEG7_C0 1.0
+#define GTE_C_TAN_DEG7_C1 3.3607213284422555e-01
+#define GTE_C_TAN_DEG7_C2 1.1261037305184907e-01
+#define GTE_C_TAN_DEG7_C3 9.8352099470524479e-02
+#define GTE_C_TAN_DEG7_MAX_ERROR 3.5418688397723108e-5
+
+#define GTE_C_TAN_DEG9_C0 1.0
+#define GTE_C_TAN_DEG9_C1 3.3299232843941784e-01
+#define GTE_C_TAN_DEG9_C2 1.3747843432474838e-01
+#define GTE_C_TAN_DEG9_C3 3.7696344813028304e-02
+#define GTE_C_TAN_DEG9_C4 4.6097377279281204e-02
+#define GTE_C_TAN_DEG9_MAX_ERROR 2.2988173242199927e-6
+
+#define GTE_C_TAN_DEG11_C0 1.0
+#define GTE_C_TAN_DEG11_C1 3.3337224456224224e-01
+#define GTE_C_TAN_DEG11_C2 1.3264516053824593e-01
+#define GTE_C_TAN_DEG11_C3 5.8145237645931047e-02
+#define GTE_C_TAN_DEG11_C4 1.0732193237572574e-02
+#define GTE_C_TAN_DEG11_C5 2.1558456793513869e-02
+#define GTE_C_TAN_DEG11_MAX_ERROR 1.5426257940140409e-7
+
+#define GTE_C_TAN_DEG13_C0 1.0
+#define GTE_C_TAN_DEG13_C1 3.3332916426394554e-01
+#define GTE_C_TAN_DEG13_C2 1.3343404625112498e-01
+#define GTE_C_TAN_DEG13_C3 5.3104565343119248e-02
+#define GTE_C_TAN_DEG13_C4 2.5355038312682154e-02
+#define GTE_C_TAN_DEG13_C5 1.8253255966556026e-03
+#define GTE_C_TAN_DEG13_C6 1.0069407176615641e-02
+#define GTE_C_TAN_DEG13_MAX_ERROR 1.0550264249037378e-8
+
+// Constants for minimax polynomial approximations to acos(x), where the
+// approximation is of the form acos(x) = sqrt(1 - x)*p(x) with p(x) a
+// polynomial.  The algorithm minimizes the maximum error
+// |acos(x)/sqrt(1-x) - p(x)| on [0,1].  At the same time we get an
+// approximation for asin(x) = pi/2 - acos(x).
+#define GTE_C_ACOS_DEG1_C0 +1.5707963267948966
+#define GTE_C_ACOS_DEG1_C1 -1.5658276442180141e-01
+#define GTE_C_ACOS_DEG1_MAX_ERROR 1.1659002803738105e-2
+
+#define GTE_C_ACOS_DEG2_C0 +1.5707963267948966
+#define GTE_C_ACOS_DEG2_C1 -2.0347053865798365e-01
+#define GTE_C_ACOS_DEG2_C2 +4.6887774236182234e-02
+#define GTE_C_ACOS_DEG2_MAX_ERROR 9.0311602490029258e-4
+
+#define GTE_C_ACOS_DEG3_C0 +1.5707963267948966
+#define GTE_C_ACOS_DEG3_C1 -2.1253291899190285e-01
+#define GTE_C_ACOS_DEG3_C2 +7.4773789639484223e-02
+#define GTE_C_ACOS_DEG3_C3 -1.8823635069382449e-02
+#define GTE_C_ACOS_DEG3_MAX_ERROR 9.3066396954288172e-5
+
+#define GTE_C_ACOS_DEG4_C0 +1.5707963267948966
+#define GTE_C_ACOS_DEG4_C1 -2.1422258835275865e-01
+#define GTE_C_ACOS_DEG4_C2 +8.4936675142844198e-02
+#define GTE_C_ACOS_DEG4_C3 -3.5991475120957794e-02
+#define GTE_C_ACOS_DEG4_C4 +8.6946239090712751e-03
+#define GTE_C_ACOS_DEG4_MAX_ERROR 1.0930595804481413e-5
+
+#define GTE_C_ACOS_DEG5_C0 +1.5707963267948966
+#define GTE_C_ACOS_DEG5_C1 -2.1453292139805524e-01
+#define GTE_C_ACOS_DEG5_C2 +8.7973089282889383e-02
+#define GTE_C_ACOS_DEG5_C3 -4.5130266382166440e-02
+#define GTE_C_ACOS_DEG5_C4 +1.9467466687281387e-02
+#define GTE_C_ACOS_DEG5_C5 -4.3601326117634898e-03
+#define GTE_C_ACOS_DEG5_MAX_ERROR 1.3861070257241426-6
+
+#define GTE_C_ACOS_DEG6_C0 +1.5707963267948966
+#define GTE_C_ACOS_DEG6_C1 -2.1458939285677325e-01
+#define GTE_C_ACOS_DEG6_C2 +8.8784960563641491e-02
+#define GTE_C_ACOS_DEG6_C3 -4.8887131453156485e-02
+#define GTE_C_ACOS_DEG6_C4 +2.7011519960012720e-02
+#define GTE_C_ACOS_DEG6_C5 -1.1210537323478320e-02
+#define GTE_C_ACOS_DEG6_C6 +2.3078166879102469e-03
+#define GTE_C_ACOS_DEG6_MAX_ERROR 1.8491291330427484e-7
+
+#define GTE_C_ACOS_DEG7_C0 +1.5707963267948966
+#define GTE_C_ACOS_DEG7_C1 -2.1459960076929829e-01
+#define GTE_C_ACOS_DEG7_C2 +8.8986946573346160e-02
+#define GTE_C_ACOS_DEG7_C3 -5.0207843052845647e-02
+#define GTE_C_ACOS_DEG7_C4 +3.0961594977611639e-02
+#define GTE_C_ACOS_DEG7_C5 -1.7162031184398074e-02
+#define GTE_C_ACOS_DEG7_C6 +6.7072304676685235e-03
+#define GTE_C_ACOS_DEG7_C7 -1.2690614339589956e-03
+#define GTE_C_ACOS_DEG7_MAX_ERROR 2.5574620927948377e-8
+
+#define GTE_C_ACOS_DEG8_C0 +1.5707963267948966
+#define GTE_C_ACOS_DEG8_C1 -2.1460143648688035e-01
+#define GTE_C_ACOS_DEG8_C2 +8.9034700107934128e-02
+#define GTE_C_ACOS_DEG8_C3 -5.0625279962389413e-02
+#define GTE_C_ACOS_DEG8_C4 +3.2683762943179318e-02
+#define GTE_C_ACOS_DEG8_C5 -2.0949278766238422e-02
+#define GTE_C_ACOS_DEG8_C6 +1.1272900916992512e-02
+#define GTE_C_ACOS_DEG8_C7 -4.1160981058965262e-03
+#define GTE_C_ACOS_DEG8_C8 +7.1796493341480527e-04
+#define GTE_C_ACOS_DEG8_MAX_ERROR 3.6340015129032732e-9
+
+// Constants for minimax polynomial approximations to atan(x).
+// The algorithm minimizes the maximum absolute error on [-1,1].
+#define GTE_C_ATAN_DEG3_C0 +1.0
+#define GTE_C_ATAN_DEG3_C1 -2.1460183660255172e-01
+#define GTE_C_ATAN_DEG3_MAX_ERROR 1.5970326392614240e-2
+
+#define GTE_C_ATAN_DEG5_C0 +1.0
+#define GTE_C_ATAN_DEG5_C1 -3.0189478312144946e-01
+#define GTE_C_ATAN_DEG5_C2 +8.7292946518897740e-02
+#define GTE_C_ATAN_DEG5_MAX_ERROR 1.3509832247372636e-3
+
+#define GTE_C_ATAN_DEG7_C0 +1.0
+#define GTE_C_ATAN_DEG7_C1 -3.2570157599356531e-01
+#define GTE_C_ATAN_DEG7_C2 +1.5342994884206673e-01
+#define GTE_C_ATAN_DEG7_C3 -4.2330209451053591e-02
+#define GTE_C_ATAN_DEG7_MAX_ERROR 1.5051227215514412e-4
+
+#define GTE_C_ATAN_DEG9_C0 +1.0
+#define GTE_C_ATAN_DEG9_C1 -3.3157878236439586e-01
+#define GTE_C_ATAN_DEG9_C2 +1.8383034738018011e-01
+#define GTE_C_ATAN_DEG9_C3 -8.9253037587244677e-02
+#define GTE_C_ATAN_DEG9_C4 +2.2399635968909593e-02
+#define GTE_C_ATAN_DEG9_MAX_ERROR 1.8921598624582064e-5
+
+#define GTE_C_ATAN_DEG11_C0 +1.0
+#define GTE_C_ATAN_DEG11_C1 -3.3294527685374087e-01
+#define GTE_C_ATAN_DEG11_C2 +1.9498657165383548e-01
+#define GTE_C_ATAN_DEG11_C3 -1.1921576270475498e-01
+#define GTE_C_ATAN_DEG11_C4 +5.5063351366968050e-02
+#define GTE_C_ATAN_DEG11_C5 -1.2490720064867844e-02
+#define GTE_C_ATAN_DEG11_MAX_ERROR 2.5477724974187765e-6
+
+#define GTE_C_ATAN_DEG13_C0 +1.0
+#define GTE_C_ATAN_DEG13_C1 -3.3324998579202170e-01
+#define GTE_C_ATAN_DEG13_C2 +1.9856563505717162e-01
+#define GTE_C_ATAN_DEG13_C3 -1.3374657325451267e-01
+#define GTE_C_ATAN_DEG13_C4 +8.1675882859940430e-02
+#define GTE_C_ATAN_DEG13_C5 -3.5059680836411644e-02
+#define GTE_C_ATAN_DEG13_C6 +7.2128853633444123e-03
+#define GTE_C_ATAN_DEG13_MAX_ERROR 3.5859104691865484e-7
+
+// Constants for minimax polynomial approximations to exp2(x) = 2^x.
+// The algorithm minimizes the maximum absolute error on [0,1].
+#define GTE_C_EXP2_DEG1_C0 1.0
+#define GTE_C_EXP2_DEG1_C1 1.0
+#define GTE_C_EXP2_DEG1_MAX_ERROR 8.6071332055934313e-2
+
+#define GTE_C_EXP2_DEG2_C0 1.0
+#define GTE_C_EXP2_DEG2_C1 6.5571332605741528e-01
+#define GTE_C_EXP2_DEG2_C2 3.4428667394258472e-01
+#define GTE_C_EXP2_DEG2_MAX_ERROR 3.8132476831060358e-3
+
+#define GTE_C_EXP2_DEG3_C0 1.0
+#define GTE_C_EXP2_DEG3_C1 6.9589012084456225e-01
+#define GTE_C_EXP2_DEG3_C2 2.2486494900110188e-01
+#define GTE_C_EXP2_DEG3_C3 7.9244930154334980e-02
+#define GTE_C_EXP2_DEG3_MAX_ERROR 1.4694877755186408e-4
+
+#define GTE_C_EXP2_DEG4_C0 1.0
+#define GTE_C_EXP2_DEG4_C1 6.9300392358459195e-01
+#define GTE_C_EXP2_DEG4_C2 2.4154981722455560e-01
+#define GTE_C_EXP2_DEG4_C3 5.1744260331489045e-02
+#define GTE_C_EXP2_DEG4_C4 1.3701998859367848e-02
+#define GTE_C_EXP2_DEG4_MAX_ERROR 4.7617792624521371e-6
+
+#define GTE_C_EXP2_DEG5_C0 1.0
+#define GTE_C_EXP2_DEG5_C1 6.9315298010274962e-01
+#define GTE_C_EXP2_DEG5_C2 2.4014712313022102e-01
+#define GTE_C_EXP2_DEG5_C3 5.5855296413199085e-02
+#define GTE_C_EXP2_DEG5_C4 8.9477503096873079e-03
+#define GTE_C_EXP2_DEG5_C5 1.8968500441332026e-03
+#define GTE_C_EXP2_DEG5_MAX_ERROR 1.3162098333463490e-7
+
+#define GTE_C_EXP2_DEG6_C0 1.0
+#define GTE_C_EXP2_DEG6_C1 6.9314698914837525e-01
+#define GTE_C_EXP2_DEG6_C2 2.4023013440952923e-01
+#define GTE_C_EXP2_DEG6_C3 5.5481276898206033e-02
+#define GTE_C_EXP2_DEG6_C4 9.6838443037086108e-03
+#define GTE_C_EXP2_DEG6_C5 1.2388324048515642e-03
+#define GTE_C_EXP2_DEG6_C6 2.1892283501756538e-04
+#define GTE_C_EXP2_DEG6_MAX_ERROR 3.1589168225654163e-9
+
+#define GTE_C_EXP2_DEG7_C0 1.0
+#define GTE_C_EXP2_DEG7_C1 6.9314718588750690e-01
+#define GTE_C_EXP2_DEG7_C2 2.4022637363165700e-01
+#define GTE_C_EXP2_DEG7_C3 5.5505235570535660e-02
+#define GTE_C_EXP2_DEG7_C4 9.6136265387940512e-03
+#define GTE_C_EXP2_DEG7_C5 1.3429234504656051e-03
+#define GTE_C_EXP2_DEG7_C6 1.4299202757683815e-04
+#define GTE_C_EXP2_DEG7_C7 2.1662892777385423e-05
+#define GTE_C_EXP2_DEG7_MAX_ERROR 6.6864513925679603e-11
+
+// Constants for minimax polynomial approximations to log2(x).
+// The algorithm minimizes the maximum absolute error on [1,2].
+// The polynomials all have constant term zero.
+#define GTE_C_LOG2_DEG1_C1 +1.0
+#define GTE_C_LOG2_DEG1_MAX_ERROR 8.6071332055934202e-2
+
+#define GTE_C_LOG2_DEG2_C1 +1.3465553856377803 
+#define GTE_C_LOG2_DEG2_C2 -3.4655538563778032e-01
+#define GTE_C_LOG2_DEG2_MAX_ERROR 7.6362868906658110e-3
+
+#define GTE_C_LOG2_DEG3_C1 +1.4228653756681227
+#define GTE_C_LOG2_DEG3_C2 -5.8208556916449616e-01
+#define GTE_C_LOG2_DEG3_C3 +1.5922019349637218e-01
+#define GTE_C_LOG2_DEG3_MAX_ERROR 8.7902902652883808e-4
+
+#define GTE_C_LOG2_DEG4_C1 +1.4387257478171547
+#define GTE_C_LOG2_DEG4_C2 -6.7778401359918661e-01
+#define GTE_C_LOG2_DEG4_C3 +3.2118898377713379e-01
+#define GTE_C_LOG2_DEG4_C4 -8.2130717995088531e-02
+#define GTE_C_LOG2_DEG4_MAX_ERROR 1.1318551355360418e-4
+
+#define GTE_C_LOG2_DEG5_C1 +1.4419170408633741
+#define GTE_C_LOG2_DEG5_C2 -7.0909645927612530e-01
+#define GTE_C_LOG2_DEG5_C3 +4.1560609399164150e-01
+#define GTE_C_LOG2_DEG5_C4 -1.9357573729558908e-01
+#define GTE_C_LOG2_DEG5_C5 +4.5149061716699634e-02
+#define GTE_C_LOG2_DEG5_MAX_ERROR 1.5521274478735858e-5
+
+#define GTE_C_LOG2_DEG6_C1 +1.4425449435950917
+#define GTE_C_LOG2_DEG6_C2 -7.1814525675038965e-01
+#define GTE_C_LOG2_DEG6_C3 +4.5754919692564044e-01
+#define GTE_C_LOG2_DEG6_C4 -2.7790534462849337e-01
+#define GTE_C_LOG2_DEG6_C5 +1.2179791068763279e-01
+#define GTE_C_LOG2_DEG6_C6 -2.5841449829670182e-02
+#define GTE_C_LOG2_DEG6_MAX_ERROR 2.2162051216689793e-6
+
+#define GTE_C_LOG2_DEG7_C1 +1.4426664401536078
+#define GTE_C_LOG2_DEG7_C2 -7.2055423726162360e-01
+#define GTE_C_LOG2_DEG7_C3 +4.7332419162501083e-01
+#define GTE_C_LOG2_DEG7_C4 -3.2514018752954144e-01
+#define GTE_C_LOG2_DEG7_C5 +1.9302965529095673e-01
+#define GTE_C_LOG2_DEG7_C6 -7.8534970641157997e-02
+#define GTE_C_LOG2_DEG7_C7 +1.5209108363023915e-02
+#define GTE_C_LOG2_DEG7_MAX_ERROR 3.2546531700261561e-7
+
+#define GTE_C_LOG2_DEG8_C1 +1.4426896453621882
+#define GTE_C_LOG2_DEG8_C2 -7.2115893912535967e-01
+#define GTE_C_LOG2_DEG8_C3 +4.7861716616785088e-01
+#define GTE_C_LOG2_DEG8_C4 -3.4699935395019565e-01
+#define GTE_C_LOG2_DEG8_C5 +2.4114048765477492e-01
+#define GTE_C_LOG2_DEG8_C6 -1.3657398692885181e-01
+#define GTE_C_LOG2_DEG8_C7 +5.1421382871922106e-02
+#define GTE_C_LOG2_DEG8_C8 -9.1364020499895560e-03
+#define GTE_C_LOG2_DEG8_MAX_ERROR 4.8796219218050219e-8
+
+// These functions are convenient for some applications.  The classes
+// BSNumber, BSRational and IEEEBinary16 have implementations that
+// (for now) use typecasting to call the 'float' or 'double' versions.
+namespace gte
+{
+    inline float atandivpi(float x)
+    {
+        return std::atan(x) * (float)GTE_C_INV_PI;
+    }
+
+    inline float atan2divpi(float y, float x)
+    {
+        return std::atan2(y, x) * (float)GTE_C_INV_PI;
+    }
+
+    inline float clamp(float x, float xmin, float xmax)
+    {
+        return (x <= xmin ? xmin : (x >= xmax ? xmax : x));
+    }
+
+    inline float cospi(float x)
+    {
+        return std::cos(x * (float)GTE_C_PI);
+    }
+
+    inline float exp10(float x)
+    {
+        return std::exp(x * (float)GTE_C_LN_10);
+    }
+
+    inline float invsqrt(float x)
+    {
+        return 1.0f / std::sqrt(x);
+    }
+
+    inline int isign(float x)
+    {
+        return (x > 0.0f ? 1 : (x < 0.0f ? -1 : 0));
+    }
+
+    inline float saturate(float x)
+    {
+        return (x <= 0.0f ? 0.0f : (x >= 1.0f ? 1.0f : x));
+    }
+
+    inline float sign(float x)
+    {
+        return (x > 0.0f ? 1.0f : (x < 0.0f ? -1.0f : 0.0f));
+    }
+
+    inline float sinpi(float x)
+    {
+        return std::sin(x * (float)GTE_C_PI);
+    }
+
+    inline float sqr(float x)
+    {
+        return x * x;
+    }
+
+
+    inline double atandivpi(double x)
+    {
+        return std::atan(x) * GTE_C_INV_PI;
+    }
+
+    inline double atan2divpi(double y, double x)
+    {
+        return std::atan2(y, x) * GTE_C_INV_PI;
+    }
+
+    inline double clamp(double x, double xmin, double xmax)
+    {
+        return (x <= xmin ? xmin : (x >= xmax ? xmax : x));
+    }
+
+    inline double cospi(double x)
+    {
+        return std::cos(x * GTE_C_PI);
+    }
+
+    inline double exp10(double x)
+    {
+        return std::exp(x * GTE_C_LN_10);
+    }
+
+    inline double invsqrt(double x)
+    {
+        return 1.0 / std::sqrt(x);
+    }
+
+    inline double sign(double x)
+    {
+        return (x > 0.0 ? 1.0 : (x < 0.0 ? -1.0 : 0.0f));
+    }
+
+    inline int isign(double x)
+    {
+        return (x > 0.0 ? 1 : (x < 0.0 ? -1 : 0));
+    }
+
+    inline double saturate(double x)
+    {
+        return (x <= 0.0 ? 0.0 : (x >= 1.0 ? 1.0 : x));
+    }
+
+    inline double sinpi(double x)
+    {
+        return std::sin(x * GTE_C_PI);
+    }
+
+    inline double sqr(double x)
+    {
+        return x * x;
+    }
+}
+#endif
diff --git a/src/geometric-tools/Mathematics/GteSegment.h b/src/geometric-tools/Mathematics/GteSegment.h
new file mode 100644
index 0000000000000000000000000000000000000000..15f31e95a8ea2c1ea398a697b8c2d47b44d634e5
--- /dev/null
+++ b/src/geometric-tools/Mathematics/GteSegment.h
@@ -0,0 +1,151 @@
+// David Eberly, Geometric Tools, Redmond WA 98052
+// Copyright (c) 1998-2018
+// Distributed under the Boost Software License, Version 1.0.
+// http://www.boost.org/LICENSE_1_0.txt
+// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
+// File Version: 3.0.0 (2016/06/19)
+
+#pragma once
+#ifndef GTE_SEGMENT_H
+#define GTE_SEGMENT_H
+
+#include <Mathematics/GteVector.h>
+
+// The segment is represented by (1-t)*P0 + t*P1, where P0 and P1 are the
+// endpoints of the segment and 0 <= t <= 1.  Some algorithms prefer a
+// centered representation that is similar to how oriented bounding boxes are
+// defined.  This representation is C + s*D, where C = (P0 + P1)/2 is the
+// center of the segment, D = (P1 - P0)/|P1 - P0| is a unit-length direction
+// vector for the segment, and |t| <= e.  The value e = |P1 - P0|/2 is the
+// extent (or radius or half-length) of the segment.
+
+namespace gte
+{
+
+template <int N, typename Real>
+class Segment
+{
+public:
+    // Construction and destruction.  The default constructor sets p0 to
+    // (-1,0,...,0) and p1 to (1,0,...,0).  NOTE:  If you set p0 and p1;
+    // compute C, D, and e; and then recompute q0 = C-e*D and q1 = C+e*D,
+    // numerical round-off errors can lead to q0 not exactly equal to p0
+    // and q1 not exactly equal to p1.
+    Segment();
+    Segment(Vector<N, Real> const& p0, Vector<N, Real> const& p1);
+    Segment(std::array<Vector<N, Real>, 2> const& inP);
+    Segment(Vector<N, Real> const& center, Vector<N, Real> const& direction,
+        Real extent);
+
+    // Manipulation via the centered form.
+    void SetCenteredForm(Vector<N, Real> const& center,
+        Vector<N, Real> const& direction, Real extent);
+
+    void GetCenteredForm(Vector<N, Real>& center, Vector<N, Real>& direction,
+        Real& extent) const;
+
+    // Public member access.
+    std::array<Vector<N, Real>, 2> p;
+
+public:
+    // Comparisons to support sorted containers.
+    bool operator==(Segment const& segment) const;
+    bool operator!=(Segment const& segment) const;
+    bool operator< (Segment const& segment) const;
+    bool operator<=(Segment const& segment) const;
+    bool operator> (Segment const& segment) const;
+    bool operator>=(Segment const& segment) const;
+};
+
+// Template aliases for convenience.
+template <typename Real>
+using Segment2 = Segment<2, Real>;
+
+template <typename Real>
+using Segment3 = Segment<3, Real>;
+
+
+template <int N, typename Real>
+Segment<N, Real>::Segment()
+{
+    p[1].MakeUnit(0);
+    p[0] = -p[1];
+}
+
+template <int N, typename Real>
+Segment<N, Real>::Segment(Vector<N, Real> const& p0,
+    Vector<N, Real> const& p1)
+{
+    p[0] = p0;
+    p[1] = p1;
+}
+
+template <int N, typename Real>
+Segment<N, Real>::Segment(std::array<Vector<N, Real>, 2> const& inP)
+{
+    p = inP;
+}
+
+template <int N, typename Real>
+Segment<N, Real>::Segment(Vector<N, Real> const& center,
+    Vector<N, Real> const& direction, Real extent)
+{
+    SetCenteredForm(center, direction, extent);
+}
+
+template <int N, typename Real>
+void Segment<N, Real>::SetCenteredForm(Vector<N, Real> const& center,
+    Vector<N, Real> const& direction, Real extent)
+{
+    p[0] = center - extent * direction;
+    p[1] = center + extent * direction;
+}
+
+template <int N, typename Real>
+void Segment<N, Real>::GetCenteredForm(Vector<N, Real>& center,
+    Vector<N, Real>& direction, Real& extent) const
+{
+    center = ((Real)0.5)*(p[0] + p[1]);
+    direction = p[1] - p[0];
+    extent = ((Real)0.5)*Normalize(direction);
+}
+
+template <int N, typename Real>
+bool Segment<N, Real>::operator==(Segment const& segment) const
+{
+    return p == segment.p;
+}
+
+template <int N, typename Real>
+bool Segment<N, Real>::operator!=(Segment const& segment) const
+{
+    return !operator==(segment);
+}
+
+template <int N, typename Real>
+bool Segment<N, Real>::operator<(Segment const& segment) const
+{
+    return p < segment.p;
+}
+
+template <int N, typename Real>
+bool Segment<N, Real>::operator<=(Segment const& segment) const
+{
+    return operator<(segment) || operator==(segment);
+}
+
+template <int N, typename Real>
+bool Segment<N, Real>::operator>(Segment const& segment) const
+{
+    return !operator<=(segment);
+}
+
+template <int N, typename Real>
+bool Segment<N, Real>::operator>=(Segment const& segment) const
+{
+    return !operator<(segment);
+}
+
+
+}
+#endif
diff --git a/src/geometric-tools/Mathematics/GteTriangle.h b/src/geometric-tools/Mathematics/GteTriangle.h
new file mode 100644
index 0000000000000000000000000000000000000000..366a89cfdd554bbca7b24a15e294b062fd2dd4ff
--- /dev/null
+++ b/src/geometric-tools/Mathematics/GteTriangle.h
@@ -0,0 +1,114 @@
+// David Eberly, Geometric Tools, Redmond WA 98052
+// Copyright (c) 1998-2018
+// Distributed under the Boost Software License, Version 1.0.
+// http://www.boost.org/LICENSE_1_0.txt
+// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
+// File Version: 3.0.0 (2016/06/19)
+
+#pragma once
+#ifndef GTE_TRIANGLE_H
+#define GTE_TRIANGLE_H
+
+#include <Mathematics/GteVector.h>
+
+// The triangle is represented as an array of three vertices.  The dimension
+// N must be 2 or larger.
+
+namespace gte
+{
+
+template <int N, typename Real>
+class Triangle
+{
+public:
+    // Construction and destruction.  The default constructor sets the
+    // vertices to (0,..,0), (1,0,...,0), and (0,1,0,...,0).
+    Triangle();
+    Triangle(Vector<N, Real> const& v0, Vector<N, Real> const& v1,
+        Vector<N, Real> const& v2);
+    Triangle(std::array<Vector<N, Real>, 3> const& inV);
+
+    // Public member access.
+    std::array<Vector<N, Real>, 3> v;
+
+public:
+    // Comparisons to support sorted containers.
+    bool operator==(Triangle const& triangle) const;
+    bool operator!=(Triangle const& triangle) const;
+    bool operator< (Triangle const& triangle) const;
+    bool operator<=(Triangle const& triangle) const;
+    bool operator> (Triangle const& triangle) const;
+    bool operator>=(Triangle const& triangle) const;
+};
+
+// Template aliases for convenience.
+template <typename Real>
+using Triangle2 = Triangle<2, Real>;
+
+template <typename Real>
+using Triangle3 = Triangle<3, Real>;
+
+
+template <int N, typename Real>
+Triangle<N, Real>::Triangle()
+{
+    v[0].MakeZero();
+    v[1].MakeUnit(0);
+    v[2].MakeUnit(1);
+}
+
+template <int N, typename Real>
+Triangle<N, Real>::Triangle(Vector<N, Real> const& v0,
+    Vector<N, Real> const& v1, Vector<N, Real> const& v2)
+{
+    v[0] = v0;
+    v[1] = v1;
+    v[2] = v2;
+}
+
+template <int N, typename Real>
+Triangle<N, Real>::Triangle(std::array<Vector<N, Real>, 3> const& inV)
+    :
+    v(inV)
+{
+}
+
+template <int N, typename Real>
+bool Triangle<N, Real>::operator==(Triangle const& triangle) const
+{
+    return v == triangle.v;
+}
+
+template <int N, typename Real>
+bool Triangle<N, Real>::operator!=(Triangle const& triangle) const
+{
+    return !operator==(triangle);
+}
+
+template <int N, typename Real>
+bool Triangle<N, Real>::operator<(Triangle const& triangle) const
+{
+    return v < triangle.v;
+}
+
+template <int N, typename Real>
+bool Triangle<N, Real>::operator<=(Triangle const& triangle) const
+{
+    return operator<(triangle) || operator==(triangle);
+}
+
+template <int N, typename Real>
+bool Triangle<N, Real>::operator>(Triangle const& triangle) const
+{
+    return !operator<=(triangle);
+}
+
+template <int N, typename Real>
+bool Triangle<N, Real>::operator>=(Triangle const& triangle) const
+{
+    return !operator<(triangle);
+}
+
+
+}
+#endif
diff --git a/src/geometric-tools/Mathematics/GteVector.h b/src/geometric-tools/Mathematics/GteVector.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f96ac7246c110ed9f385686ddf51122ebcbec8a
--- /dev/null
+++ b/src/geometric-tools/Mathematics/GteVector.h
@@ -0,0 +1,695 @@
+// David Eberly, Geometric Tools, Redmond WA 98052
+// Copyright (c) 1998-2018
+// Distributed under the Boost Software License, Version 1.0.
+// http://www.boost.org/LICENSE_1_0.txt
+// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
+// File Version: 3.0.3 (2018/10/05)
+
+#pragma once
+#ifndef GTE_VECTOR_H
+#define GTE_VECTOR_H
+
+#include <GTEngineDEF.h>
+#include <algorithm>
+#include <array>
+#include <cmath>
+#include <initializer_list>
+
+namespace gte
+{
+
+template <int N, typename Real>
+class Vector
+{
+public:
+    // The tuple is uninitialized.
+    Vector();
+
+    // The tuple is fully initialized by the inputs.
+    Vector(std::array<Real, N> const& values);
+
+    // At most N elements are copied from the initializer list, setting any
+    // remaining elements to zero.  Create the zero vector using the syntax
+    //   Vector<N,Real> zero{(Real)0};
+    // WARNING:  The C++ 11 specification states that
+    //   Vector<N,Real> zero{};
+    // will lead to a call of the default constructor, not the initializer
+    // constructor!
+    Vector(std::initializer_list<Real> values);
+
+    // For 0 <= d < N, element d is 1 and all others are 0.  If d is invalid,
+    // the zero vector is created.  This is a convenience for creating the
+    // standard Euclidean basis vectors; see also MakeUnit(int) and Unit(int).
+    Vector(int d);
+
+    // The copy constructor, destructor, and assignment operator are generated
+    // by the compiler.
+
+    // Member access.  The first operator[] returns a const reference rather
+    // than a Real value.  This supports writing via standard file operations
+    // that require a const pointer to data.
+    inline int GetSize() const;  // returns N
+    inline Real const& operator[](int i) const;
+    inline Real& operator[](int i);
+
+    // Comparisons for sorted containers and geometric ordering.
+    inline bool operator==(Vector const& vec) const;
+    inline bool operator!=(Vector const& vec) const;
+    inline bool operator< (Vector const& vec) const;
+    inline bool operator<=(Vector const& vec) const;
+    inline bool operator> (Vector const& vec) const;
+    inline bool operator>=(Vector const& vec) const;
+
+    // Special vectors.
+    void MakeZero();  // All components are 0.
+    void MakeUnit(int d);  // Component d is 1, all others are zero.
+    static Vector Zero();
+    static Vector Unit(int d);
+
+protected:
+    // This data structure takes advantage of the built-in operator[],
+    // range checking, and visualizers in MSVS.
+    std::array<Real, N> mTuple;
+};
+
+// Unary operations.
+template <int N, typename Real>
+Vector<N, Real> operator+(Vector<N, Real> const& v);
+
+template <int N, typename Real>
+Vector<N, Real> operator-(Vector<N, Real> const& v);
+
+// Linear-algebraic operations.
+template <int N, typename Real>
+Vector<N, Real>
+operator+(Vector<N, Real> const& v0, Vector<N, Real> const& v1);
+
+template <int N, typename Real>
+Vector<N, Real>
+operator-(Vector<N, Real> const& v0, Vector<N, Real> const& v1);
+
+template <int N, typename Real>
+Vector<N, Real> operator*(Vector<N, Real> const& v, Real scalar);
+
+template <int N, typename Real>
+Vector<N, Real> operator*(Real scalar, Vector<N, Real> const& v);
+
+template <int N, typename Real>
+Vector<N, Real> operator/(Vector<N, Real> const& v, Real scalar);
+
+template <int N, typename Real>
+Vector<N, Real>& operator+=(Vector<N, Real>& v0, Vector<N, Real> const& v1);
+
+template <int N, typename Real>
+Vector<N, Real>& operator-=(Vector<N, Real>& v0, Vector<N, Real> const& v1);
+
+template <int N, typename Real>
+Vector<N, Real>& operator*=(Vector<N, Real>& v, Real scalar);
+
+template <int N, typename Real>
+Vector<N, Real>& operator/=(Vector<N, Real>& v, Real scalar);
+
+// Componentwise algebraic operations.
+template <int N, typename Real>
+Vector<N, Real>
+operator*(Vector<N, Real> const& v0, Vector<N, Real> const& v1);
+
+template <int N, typename Real>
+Vector<N, Real>
+operator/(Vector<N, Real> const& v0, Vector<N, Real> const& v1);
+
+template <int N, typename Real>
+Vector<N, Real>& operator*=(Vector<N, Real>& v0, Vector<N, Real> const& v1);
+
+template <int N, typename Real>
+Vector<N, Real>& operator/=(Vector<N, Real>& v0, Vector<N, Real> const& v1);
+
+// Geometric operations.  The functions with 'robust' set to 'false' use the
+// standard algorithm for normalizing a vector by computing the length as a
+// square root of the squared length and dividing by it.  The results can be
+// infinite (or NaN) if the length is zero.  When 'robust' is set to 'true',
+// the algorithm is designed to avoid floating-point overflow and sets the
+// normalized vector to zero when the length is zero.
+template <int N, typename Real>
+Real Dot(Vector<N, Real> const& v0, Vector<N, Real> const& v1);
+
+template <int N, typename Real>
+Real Length(Vector<N, Real> const& v, bool robust = false);
+
+template <int N, typename Real>
+Real Normalize(Vector<N, Real>& v, bool robust = false);
+
+// Gram-Schmidt orthonormalization to generate orthonormal vectors from the
+// linearly independent inputs.  The function returns the smallest length of
+// the unnormalized vectors computed during the process.  If this value is
+// nearly zero, it is possible that the inputs are linearly dependent (within
+// numerical round-off errors).  On input, 1 <= numElements <= N and v[0]
+// through v[numElements-1] must be initialized.  On output, the vectors
+// v[0] through v[numElements-1] form an orthonormal set.
+template <int N, typename Real>
+Real Orthonormalize(int numElements, Vector<N, Real>* v, bool robust = false);
+
+// Construct a single vector orthogonal to the nonzero input vector.  If the
+// maximum absolute component occurs at index i, then the orthogonal vector
+// U has u[i] = v[i+1], u[i+1] = -v[i], and all other components zero.  The
+// index addition i+1 is computed modulo N.
+template <int N, typename Real>
+Vector<N, Real> GetOrthogonal(Vector<N, Real> const& v, bool unitLength);
+
+// Compute the axis-aligned bounding box of the vectors.  The return value is
+// 'true' iff the inputs are valid, in which case vmin and vmax have valid
+// values.
+template <int N, typename Real>
+bool ComputeExtremes(int numVectors, Vector<N, Real> const* v,
+    Vector<N, Real>& vmin, Vector<N, Real>& vmax);
+
+// Lift n-tuple v to homogeneous (n+1)-tuple (v,last).
+template <int N, typename Real>
+Vector<N + 1, Real> HLift(Vector<N, Real> const& v, Real last);
+
+// Project homogeneous n-tuple v = (u,v[n-1]) to (n-1)-tuple u.
+template <int N, typename Real>
+Vector<N - 1, Real> HProject(Vector<N, Real> const& v);
+
+// Lift n-tuple v = (w0,w1) to (n+1)-tuple u = (w0,u[inject],w1).  By
+// inference, w0 is a (inject)-tuple [nonexistent when inject=0] and w1 is a
+// (n-inject)-tuple [nonexistent when inject=n].
+template <int N, typename Real>
+Vector<N + 1, Real> Lift(Vector<N, Real> const& v, int inject, Real value);
+
+// Project n-tuple v = (w0,v[reject],w1) to (n-1)-tuple u = (w0,w1).  By
+// inference, w0 is a (reject)-tuple [nonexistent when reject=0] and w1 is a
+// (n-1-reject)-tuple [nonexistent when reject=n-1].
+template <int N, typename Real>
+Vector<N - 1, Real> Project(Vector<N, Real> const& v, int reject);
+
+
+template <int N, typename Real>
+Vector<N, Real>::Vector()
+{
+    // Uninitialized.
+}
+
+template <int N, typename Real>
+Vector<N, Real>::Vector(std::array<Real, N> const& values)
+    :
+    mTuple(values)
+{
+}
+template <int N, typename Real>
+Vector<N, Real>::Vector(std::initializer_list<Real> values)
+{
+    int const numValues = static_cast<int>(values.size());
+    if (N == numValues)
+    {
+        std::copy(values.begin(), values.end(), mTuple.begin());
+    }
+    else if (N > numValues)
+    {
+        std::copy(values.begin(), values.end(), mTuple.begin());
+        std::fill(mTuple.begin() + numValues, mTuple.end(), (Real)0);
+    }
+    else // N < numValues
+    {
+        std::copy(values.begin(), values.begin() + N, mTuple.begin());
+    }
+}
+
+template <int N, typename Real>
+Vector<N, Real>::Vector(int d)
+{
+    MakeUnit(d);
+}
+
+template <int N, typename Real> inline
+int Vector<N, Real>::GetSize() const
+{
+    return N;
+}
+
+template <int N, typename Real> inline
+Real const& Vector<N, Real>::operator[](int i) const
+{
+    return mTuple[i];
+}
+
+template <int N, typename Real> inline
+Real& Vector<N, Real>::operator[](int i)
+{
+    return mTuple[i];
+}
+
+template <int N, typename Real> inline
+bool Vector<N, Real>::operator==(Vector const& vec) const
+{
+    return mTuple == vec.mTuple;
+}
+
+template <int N, typename Real> inline
+bool Vector<N, Real>::operator!=(Vector const& vec) const
+{
+    return mTuple != vec.mTuple;
+}
+
+template <int N, typename Real> inline
+bool Vector<N, Real>::operator<(Vector const& vec) const
+{
+    return mTuple < vec.mTuple;
+}
+
+template <int N, typename Real> inline
+bool Vector<N, Real>::operator<=(Vector const& vec) const
+{
+    return mTuple <= vec.mTuple;
+}
+
+template <int N, typename Real> inline
+bool Vector<N, Real>::operator>(Vector const& vec) const
+{
+    return mTuple > vec.mTuple;
+}
+
+template <int N, typename Real> inline
+bool Vector<N, Real>::operator>=(Vector const& vec) const
+{
+    return mTuple >= vec.mTuple;
+}
+
+template <int N, typename Real>
+void Vector<N, Real>::MakeZero()
+{
+    std::fill(mTuple.begin(), mTuple.end(), (Real)0);
+}
+
+template <int N, typename Real>
+void Vector<N, Real>::MakeUnit(int d)
+{
+    std::fill(mTuple.begin(), mTuple.end(), (Real)0);
+    if (0 <= d && d < N)
+    {
+        mTuple[d] = (Real)1;
+    }
+}
+
+template <int N, typename Real>
+Vector<N, Real> Vector<N, Real>::Zero()
+{
+    Vector<N, Real> v;
+    v.MakeZero();
+    return v;
+}
+
+template <int N, typename Real>
+Vector<N, Real> Vector<N, Real>::Unit(int d)
+{
+    Vector<N, Real> v;
+    v.MakeUnit(d);
+    return v;
+}
+
+
+
+template <int N, typename Real>
+Vector<N, Real> operator+(Vector<N, Real> const& v)
+{
+    return v;
+}
+
+template <int N, typename Real>
+Vector<N, Real> operator-(Vector<N, Real> const& v)
+{
+    Vector<N, Real> result;
+    for (int i = 0; i < N; ++i)
+    {
+        result[i] = -v[i];
+    }
+    return result;
+}
+
+template <int N, typename Real>
+Vector<N, Real> operator+(Vector<N, Real> const& v0,
+    Vector<N, Real> const& v1)
+{
+    Vector<N, Real> result = v0;
+    return result += v1;
+}
+
+template <int N, typename Real>
+Vector<N, Real> operator-(Vector<N, Real> const& v0,
+    Vector<N, Real> const& v1)
+{
+    Vector<N, Real> result = v0;
+    return result -= v1;
+}
+
+template <int N, typename Real>
+Vector<N, Real> operator*(Vector<N, Real> const& v, Real scalar)
+{
+    Vector<N, Real> result = v;
+    return result *= scalar;
+}
+
+template <int N, typename Real>
+Vector<N, Real> operator*(Real scalar, Vector<N, Real> const& v)
+{
+    Vector<N, Real> result = v;
+    return result *= scalar;
+}
+
+template <int N, typename Real>
+Vector<N, Real> operator/(Vector<N, Real> const& v, Real scalar)
+{
+    Vector<N, Real> result = v;
+    return result /= scalar;
+}
+
+template <int N, typename Real>
+Vector<N, Real>& operator+=(Vector<N, Real>& v0, Vector<N, Real> const& v1)
+{
+    for (int i = 0; i < N; ++i)
+    {
+        v0[i] += v1[i];
+    }
+    return v0;
+}
+
+template <int N, typename Real>
+Vector<N, Real>& operator-=(Vector<N, Real>& v0, Vector<N, Real> const& v1)
+{
+    for (int i = 0; i < N; ++i)
+    {
+        v0[i] -= v1[i];
+    }
+    return v0;
+}
+
+template <int N, typename Real>
+Vector<N, Real>& operator*=(Vector<N, Real>& v, Real scalar)
+{
+    for (int i = 0; i < N; ++i)
+    {
+        v[i] *= scalar;
+    }
+    return v;
+}
+
+template <int N, typename Real>
+Vector<N, Real>& operator/=(Vector<N, Real>& v, Real scalar)
+{
+    if (scalar != (Real)0)
+    {
+        Real invScalar = ((Real)1) / scalar;
+        for (int i = 0; i < N; ++i)
+        {
+            v[i] *= invScalar;
+        }
+    }
+    else
+    {
+        for (int i = 0; i < N; ++i)
+        {
+            v[i] = (Real)0;
+        }
+    }
+    return v;
+}
+
+template <int N, typename Real>
+Vector<N, Real> operator*(Vector<N, Real> const& v0,
+    Vector<N, Real> const& v1)
+{
+    Vector<N, Real> result = v0;
+    return result *= v1;
+}
+
+template <int N, typename Real>
+Vector<N, Real> operator/(Vector<N, Real> const& v0,
+    Vector<N, Real> const& v1)
+{
+    Vector<N, Real> result = v0;
+    return result /= v1;
+}
+
+template <int N, typename Real>
+Vector<N, Real>& operator*=(Vector<N, Real>& v0, Vector<N, Real> const& v1)
+{
+    for (int i = 0; i < N; ++i)
+    {
+        v0[i] *= v1[i];
+    }
+    return v0;
+}
+
+template <int N, typename Real>
+Vector<N, Real>& operator/=(Vector<N, Real>& v0, Vector<N, Real> const& v1)
+{
+    for (int i = 0; i < N; ++i)
+    {
+        v0[i] /= v1[i];
+    }
+    return v0;
+}
+
+template <int N, typename Real>
+Real Dot(Vector<N, Real> const& v0, Vector<N, Real> const& v1)
+{
+    Real dot = v0[0] * v1[0];
+    for (int i = 1; i < N; ++i)
+    {
+        dot += v0[i] * v1[i];
+    }
+    return dot;
+}
+
+template <int N, typename Real>
+Real Length(Vector<N, Real> const& v, bool robust)
+{
+    if (robust)
+    {
+        Real maxAbsComp = std::abs(v[0]);
+        for (int i = 1; i < N; ++i)
+        {
+            Real absComp = std::abs(v[i]);
+            if (absComp > maxAbsComp)
+            {
+                maxAbsComp = absComp;
+            }
+        }
+
+        Real length;
+        if (maxAbsComp > (Real)0)
+        {
+            Vector<N, Real> scaled = v / maxAbsComp;
+            length = maxAbsComp * std::sqrt(Dot(scaled, scaled));
+        }
+        else
+        {
+            length = (Real)0;
+        }
+        return length;
+    }
+    else
+    {
+        return std::sqrt(Dot(v, v));
+    }
+}
+
+template <int N, typename Real>
+Real Normalize(Vector<N, Real>& v, bool robust)
+{
+    if (robust)
+    {
+        Real maxAbsComp = std::abs(v[0]);
+        for (int i = 1; i < N; ++i)
+        {
+            Real absComp = std::abs(v[i]);
+            if (absComp > maxAbsComp)
+            {
+                maxAbsComp = absComp;
+            }
+        }
+
+        Real length;
+        if (maxAbsComp > (Real)0)
+        {
+            v /= maxAbsComp;
+            length = std::sqrt(Dot(v, v));
+            v /= length;
+            length *= maxAbsComp;
+        }
+        else
+        {
+            length = (Real)0;
+            for (int i = 0; i < N; ++i)
+            {
+                v[i] = (Real)0;
+            }
+        }
+        return length;
+    }
+    else
+    {
+        Real length = std::sqrt(Dot(v, v));
+        if (length > (Real)0)
+        {
+            v /= length;
+        }
+        else
+        {
+            for (int i = 0; i < N; ++i)
+            {
+                v[i] = (Real)0;
+            }
+        }
+        return length;
+    }
+}
+
+template <int N, typename Real>
+Real Orthonormalize(int numInputs, Vector<N, Real>* v, bool robust)
+{
+    if (v && 1 <= numInputs && numInputs <= N)
+    {
+        Real minLength = Normalize(v[0], robust);
+        for (int i = 1; i < numInputs; ++i)
+        {
+            for (int j = 0; j < i; ++j)
+            {
+                Real dot = Dot(v[i], v[j]);
+                v[i] -= v[j] * dot;
+            }
+            Real length = Normalize(v[i], robust);
+            if (length < minLength)
+            {
+                minLength = length;
+            }
+        }
+        return minLength;
+    }
+
+    return (Real)0;
+}
+
+template <int N, typename Real>
+Vector<N, Real> GetOrthogonal(Vector<N, Real> const& v, bool unitLength)
+{
+    Real cmax = std::abs(v[0]);
+    int imax = 0;
+    for (int i = 1; i < N; ++i)
+    {
+        Real c = std::abs(v[i]);
+        if (c > cmax)
+        {
+            cmax = c;
+            imax = i;
+        }
+    }
+
+    Vector<N, Real> result;
+    result.MakeZero();
+    int inext = imax + 1;
+    if (inext == N)
+    {
+        inext = 0;
+    }
+    result[imax] = v[inext];
+    result[inext] = -v[imax];
+    if (unitLength)
+    {
+        Real sqrDistance = result[imax] * result[imax] + result[inext] * result[inext];
+        Real invLength = ((Real)1) / std::sqrt(sqrDistance);
+        result[imax] *= invLength;
+        result[inext] *= invLength;
+    }
+    return result;
+}
+
+template <int N, typename Real>
+bool ComputeExtremes(int numVectors, Vector<N, Real> const* v,
+    Vector<N, Real>& vmin, Vector<N, Real>& vmax)
+{
+    if (v && numVectors > 0)
+    {
+        vmin = v[0];
+        vmax = vmin;
+        for (int j = 1; j < numVectors; ++j)
+        {
+            Vector<N, Real> const& vec = v[j];
+            for (int i = 0; i < N; ++i)
+            {
+                if (vec[i] < vmin[i])
+                {
+                    vmin[i] = vec[i];
+                }
+                else if (vec[i] > vmax[i])
+                {
+                    vmax[i] = vec[i];
+                }
+            }
+        }
+        return true;
+    }
+
+    return false;
+}
+
+template <int N, typename Real>
+Vector<N + 1, Real> HLift(Vector<N, Real> const& v, Real last)
+{
+    Vector<N + 1, Real> result;
+    for (int i = 0; i < N; ++i)
+    {
+        result[i] = v[i];
+    }
+    result[N] = last;
+    return result;
+}
+
+template <int N, typename Real>
+Vector<N - 1, Real> HProject(Vector<N, Real> const& v)
+{
+    static_assert(N >= 2, "Invalid dimension.");
+    Vector<N - 1, Real> result;
+    for (int i = 0; i < N - 1; ++i)
+    {
+        result[i] = v[i];
+    }
+    return result;
+}
+
+template <int N, typename Real>
+Vector<N + 1, Real> Lift(Vector<N, Real> const& v, int inject, Real value)
+{
+    Vector<N + 1, Real> result;
+    int i;
+    for (i = 0; i < inject; ++i)
+    {
+        result[i] = v[i];
+    }
+    result[i] = value;
+    int j = i;
+    for (++j; i < N; ++i, ++j)
+    {
+        result[j] = v[i];
+    }
+    return result;
+}
+
+template <int N, typename Real>
+Vector<N - 1, Real> Project(Vector<N, Real> const& v, int reject)
+{
+    static_assert(N >= 2, "Invalid dimension.");
+    Vector<N - 1, Real> result;
+    for (int i = 0, j = 0; i < N - 1; ++i, ++j)
+    {
+        if (j == reject)
+        {
+            ++j;
+        }
+        result[i] = v[j];
+    }
+    return result;
+}
+
+}
+#endif
diff --git a/src/geometric-tools/Mathematics/GteVector3.h b/src/geometric-tools/Mathematics/GteVector3.h
new file mode 100644
index 0000000000000000000000000000000000000000..0b92ff5e1aa7507e66708fd8e1456ef41b5eeda2
--- /dev/null
+++ b/src/geometric-tools/Mathematics/GteVector3.h
@@ -0,0 +1,385 @@
+// David Eberly, Geometric Tools, Redmond WA 98052
+// Copyright (c) 1998-2018
+// Distributed under the Boost Software License, Version 1.0.
+// http://www.boost.org/LICENSE_1_0.txt
+// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
+// File Version: 3.0.2 (2018/10/04)
+
+#pragma once
+#ifndef GTE_VECTOR3_H
+#define GTE_VECTOR3_H
+
+#include <Mathematics/GteVector.h>
+
+namespace gte
+{
+
+// Template alias for convenience.
+template <typename Real>
+using Vector3 = Vector<3, Real>;
+
+// Cross, UnitCross, and DotCross have a template parameter N that should
+// be 3 or 4.  The latter case supports affine vectors in 4D (last component
+// w = 0) when you want to use 4-tuples and 4x4 matrices for affine algebra.
+
+// Compute the cross product using the formal determinant:
+//   cross = det{{e0,e1,e2},{x0,x1,x2},{y0,y1,y2}}
+//         = (x1*y2-x2*y1, x2*y0-x0*y2, x0*y1-x1*y0)
+// where e0 = (1,0,0), e1 = (0,1,0), e2 = (0,0,1), v0 = (x0,x1,x2), and
+// v1 = (y0,y1,y2).
+template <int N, typename Real>
+Vector<N,Real> Cross(Vector<N,Real> const& v0, Vector<N,Real> const& v1);
+
+// Compute the normalized cross product.
+template <int N, typename Real>
+Vector<N, Real> UnitCross(Vector<N,Real> const& v0, Vector<N,Real> const& v1,
+    bool robust = false);
+
+// Compute Dot((x0,x1,x2),Cross((y0,y1,y2),(z0,z1,z2)), the triple scalar
+// product of three vectors, where v0 = (x0,x1,x2), v1 = (y0,y1,y2), and
+// v2 is (z0,z1,z2).
+template <int N, typename Real>
+Real DotCross(Vector<N,Real> const& v0, Vector<N,Real> const& v1,
+    Vector<N,Real> const& v2);
+
+// Compute a right-handed orthonormal basis for the orthogonal complement
+// of the input vectors.  The function returns the smallest length of the
+// unnormalized vectors computed during the process.  If this value is nearly
+// zero, it is possible that the inputs are linearly dependent (within
+// numerical round-off errors).  On input, numInputs must be 1 or 2 and
+// v[0] through v[numInputs-1] must be initialized.  On output, the
+// vectors v[0] through v[2] form an orthonormal set.
+template <typename Real>
+Real ComputeOrthogonalComplement(int numInputs, Vector3<Real>* v, bool robust = false);
+
+// Compute the barycentric coordinates of the point P with respect to the
+// tetrahedron <V0,V1,V2,V3>, P = b0*V0 + b1*V1 + b2*V2 + b3*V3, where
+// b0 + b1 + b2 + b3 = 1.  The return value is 'true' iff {V0,V1,V2,V3} is
+// a linearly independent set.  Numerically, this is measured by
+// |det[V0 V1 V2 V3]| <= epsilon.  The values bary[] are valid only when the
+// return value is 'true' but set to zero when the return value is 'false'.
+template <typename Real>
+bool ComputeBarycentrics(Vector3<Real> const& p, Vector3<Real> const& v0,
+    Vector3<Real> const& v1, Vector3<Real> const& v2, Vector3<Real> const& v3,
+    Real bary[4], Real epsilon = (Real)0);
+
+// Get intrinsic information about the input array of vectors.  The return
+// value is 'true' iff the inputs are valid (numVectors > 0, v is not null,
+// and epsilon >= 0), in which case the class members are valid.
+template <typename Real>
+class IntrinsicsVector3
+{
+public:
+    // The constructor sets the class members based on the input set.
+    IntrinsicsVector3(int numVectors, Vector3<Real> const* v, Real inEpsilon);
+
+    // A nonnegative tolerance that is used to determine the intrinsic
+    // dimension of the set.
+    Real epsilon;
+
+    // The intrinsic dimension of the input set, computed based on the
+    // nonnegative tolerance mEpsilon.
+    int dimension;
+
+    // Axis-aligned bounding box of the input set.  The maximum range is
+    // the larger of max[0]-min[0], max[1]-min[1], and max[2]-min[2].
+    Real min[3], max[3];
+    Real maxRange;
+
+    // Coordinate system.  The origin is valid for any dimension d.  The
+    // unit-length direction vector is valid only for 0 <= i < d.  The
+    // extreme index is relative to the array of input points, and is also
+    // valid only for 0 <= i < d.  If d = 0, all points are effectively
+    // the same, but the use of an epsilon may lead to an extreme index
+    // that is not zero.  If d = 1, all points effectively lie on a line
+    // segment.  If d = 2, all points effectively line on a plane.  If
+    // d = 3, the points are not coplanar.
+    Vector3<Real> origin;
+    Vector3<Real> direction[3];
+
+    // The indices that define the maximum dimensional extents.  The
+    // values extreme[0] and extreme[1] are the indices for the points
+    // that define the largest extent in one of the coordinate axis
+    // directions.  If the dimension is 2, then extreme[2] is the index
+    // for the point that generates the largest extent in the direction
+    // perpendicular to the line through the points corresponding to
+    // extreme[0] and extreme[1].  Furthermore, if the dimension is 3,
+    // then extreme[3] is the index for the point that generates the
+    // largest extent in the direction perpendicular to the triangle
+    // defined by the other extreme points.  The tetrahedron formed by the
+    // points V[extreme[0]], V[extreme[1]], V[extreme[2]], and
+    // V[extreme[3]] is clockwise or counterclockwise, the condition
+    // stored in extremeCCW.
+    int extreme[4];
+    bool extremeCCW;
+};
+
+
+template <int N, typename Real>
+Vector<N, Real> Cross(Vector<N, Real> const& v0, Vector<N, Real> const& v1)
+{
+    static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
+
+    Vector<N, Real> result;
+    result.MakeZero();
+    result[0] = v0[1] * v1[2] - v0[2] * v1[1];
+    result[1] = v0[2] * v1[0] - v0[0] * v1[2];
+    result[2] = v0[0] * v1[1] - v0[1] * v1[0];
+    return result;
+}
+
+template <int N, typename Real>
+Vector<N, Real> UnitCross(Vector<N, Real> const& v0, Vector<N, Real> const& v1, bool robust)
+{
+    static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
+
+    Vector<N, Real> unitCross = Cross(v0, v1);
+    Normalize(unitCross, robust);
+    return unitCross;
+}
+
+template <int N, typename Real>
+Real DotCross(Vector<N, Real> const& v0, Vector<N, Real> const& v1,
+    Vector<N, Real> const& v2)
+{
+    static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
+
+    return Dot(v0, Cross(v1, v2));
+}
+
+template <typename Real>
+Real ComputeOrthogonalComplement(int numInputs, Vector3<Real>* v, bool robust)
+{
+    if (numInputs == 1)
+    {
+        if (std::abs(v[0][0]) > std::abs(v[0][1]))
+        {
+            v[1] = { -v[0][2], (Real)0, +v[0][0] };
+        }
+        else
+        {
+            v[1] = { (Real)0, +v[0][2], -v[0][1] };
+        }
+        numInputs = 2;
+    }
+
+    if (numInputs == 2)
+    {
+        v[2] = Cross(v[0], v[1]);
+        return Orthonormalize<3, Real>(3, v, robust);
+    }
+
+    return (Real)0;
+}
+
+template <typename Real>
+bool ComputeBarycentrics(Vector3<Real> const& p, Vector3<Real> const& v0,
+    Vector3<Real> const& v1, Vector3<Real> const& v2, Vector3<Real> const& v3,
+    Real bary[4], Real epsilon)
+{
+    // Compute the vectors relative to V3 of the tetrahedron.
+    Vector3<Real> diff[4] = { v0 - v3, v1 - v3, v2 - v3, p - v3 };
+
+    Real det = DotCross(diff[0], diff[1], diff[2]);
+    if (det < -epsilon || det > epsilon)
+    {
+        Real invDet = ((Real)1) / det;
+        bary[0] = DotCross(diff[3], diff[1], diff[2]) * invDet;
+        bary[1] = DotCross(diff[3], diff[2], diff[0]) * invDet;
+        bary[2] = DotCross(diff[3], diff[0], diff[1]) * invDet;
+        bary[3] = (Real)1 - bary[0] - bary[1] - bary[2];
+        return true;
+    }
+
+    for (int i = 0; i < 4; ++i)
+    {
+        bary[i] = (Real)0;
+    }
+    return false;
+}
+
+template <typename Real>
+IntrinsicsVector3<Real>::IntrinsicsVector3(int numVectors,
+    Vector3<Real> const* v, Real inEpsilon)
+    :
+    epsilon(inEpsilon),
+    dimension(0),
+    maxRange((Real)0),
+    origin({ (Real)0, (Real)0, (Real)0 }),
+    extremeCCW(false)
+{
+    min[0] = (Real)0;
+    min[1] = (Real)0;
+    min[2] = (Real)0;
+    direction[0] = { (Real)0, (Real)0, (Real)0 };
+    direction[1] = { (Real)0, (Real)0, (Real)0 };
+    direction[2] = { (Real)0, (Real)0, (Real)0 };
+    extreme[0] = 0;
+    extreme[1] = 0;
+    extreme[2] = 0;
+    extreme[3] = 0;
+
+    if (numVectors > 0 && v && epsilon >= (Real)0)
+    {
+        // Compute the axis-aligned bounding box for the input vectors.  Keep
+        // track of the indices into 'vectors' for the current min and max.
+        int j, indexMin[3], indexMax[3];
+        for (j = 0; j < 3; ++j)
+        {
+            min[j] = v[0][j];
+            max[j] = min[j];
+            indexMin[j] = 0;
+            indexMax[j] = 0;
+        }
+
+        int i;
+        for (i = 1; i < numVectors; ++i)
+        {
+            for (j = 0; j < 3; ++j)
+            {
+                if (v[i][j] < min[j])
+                {
+                    min[j] = v[i][j];
+                    indexMin[j] = i;
+                }
+                else if (v[i][j] > max[j])
+                {
+                    max[j] = v[i][j];
+                    indexMax[j] = i;
+                }
+            }
+        }
+
+        // Determine the maximum range for the bounding box.
+        maxRange = max[0] - min[0];
+        extreme[0] = indexMin[0];
+        extreme[1] = indexMax[0];
+        Real range = max[1] - min[1];
+        if (range > maxRange)
+        {
+            maxRange = range;
+            extreme[0] = indexMin[1];
+            extreme[1] = indexMax[1];
+        }
+        range = max[2] - min[2];
+        if (range > maxRange)
+        {
+            maxRange = range;
+            extreme[0] = indexMin[2];
+            extreme[1] = indexMax[2];
+        }
+
+        // The origin is either the vector of minimum x0-value, vector of
+        // minimum x1-value, or vector of minimum x2-value.
+        origin = v[extreme[0]];
+
+        // Test whether the vector set is (nearly) a vector.
+        if (maxRange <= epsilon)
+        {
+            dimension = 0;
+            for (j = 0; j < 3; ++j)
+            {
+                extreme[j + 1] = extreme[0];
+            }
+            return;
+        }
+
+        // Test whether the vector set is (nearly) a line segment.  We need
+        // {direction[2],direction[3]} to span the orthogonal complement of
+        // direction[0].
+        direction[0] = v[extreme[1]] - origin;
+        Normalize(direction[0], false);
+        if (std::abs(direction[0][0]) > std::abs(direction[0][1]))
+        {
+            direction[1][0] = -direction[0][2];
+            direction[1][1] = (Real)0;
+            direction[1][2] = +direction[0][0];
+        }
+        else
+        {
+            direction[1][0] = (Real)0;
+            direction[1][1] = +direction[0][2];
+            direction[1][2] = -direction[0][1];
+        }
+        Normalize(direction[1], false);
+        direction[2] = Cross(direction[0], direction[1]);
+
+        // Compute the maximum distance of the points from the line
+        // origin+t*direction[0].
+        Real maxDistance = (Real)0;
+        Real distance, dot;
+        extreme[2] = extreme[0];
+        for (i = 0; i < numVectors; ++i)
+        {
+            Vector3<Real> diff = v[i] - origin;
+            dot = Dot(direction[0], diff);
+            Vector3<Real> proj = diff - dot * direction[0];
+            distance = Length(proj, false);
+            if (distance > maxDistance)
+            {
+                maxDistance = distance;
+                extreme[2] = i;
+            }
+        }
+
+        if (maxDistance <= epsilon*maxRange)
+        {
+            // The points are (nearly) on the line origin+t*direction[0].
+            dimension = 1;
+            extreme[2] = extreme[1];
+            extreme[3] = extreme[1];
+            return;
+        }
+
+        // Test whether the vector set is (nearly) a planar polygon.  The
+        // point v[extreme[2]] is farthest from the line: origin + 
+        // t*direction[0].  The vector v[extreme[2]]-origin is not
+        // necessarily perpendicular to direction[0], so project out the
+        // direction[0] component so that the result is perpendicular to
+        // direction[0].
+        direction[1] = v[extreme[2]] - origin;
+        dot = Dot(direction[0], direction[1]);
+        direction[1] -= dot * direction[0];
+        Normalize(direction[1], false);
+
+        // We need direction[2] to span the orthogonal complement of
+        // {direction[0],direction[1]}.
+        direction[2] = Cross(direction[0], direction[1]);
+
+        // Compute the maximum distance of the points from the plane
+        // origin+t0*direction[0]+t1*direction[1].
+        maxDistance = (Real)0;
+        Real maxSign = (Real)0;
+        extreme[3] = extreme[0];
+        for (i = 0; i < numVectors; ++i)
+        {
+            Vector3<Real> diff = v[i] - origin;
+            distance = Dot(direction[2], diff);
+            Real sign = (distance >(Real)0 ? (Real)1 :
+                (distance < (Real)0 ? (Real)-1 : (Real)0));
+            distance = std::abs(distance);
+            if (distance > maxDistance)
+            {
+                maxDistance = distance;
+                maxSign = sign;
+                extreme[3] = i;
+            }
+        }
+
+        if (maxDistance <= epsilon * maxRange)
+        {
+            // The points are (nearly) on the plane origin+t0*direction[0]
+            // +t1*direction[1].
+            dimension = 2;
+            extreme[3] = extreme[2];
+            return;
+        }
+
+        dimension = 3;
+        extremeCCW = (maxSign > (Real)0);
+        return;
+    }
+}
+
+}
+#endif
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index f81a4de87a4b4898e054b8cdbd415197c6918ef5..b13debdca5fab5007507cb0ad190822bf4dae013 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -18,6 +18,7 @@ macro(add_fcl_test test_name)
 endmacro(add_fcl_test)
 
 include_directories(${CMAKE_CURRENT_BINARY_DIR})
+include_directories(${PROJECT_SOURCE_DIR}/src/geometric-tools)
 include_directories(${Boost_INCLUDE_DIRS})
 
 
@@ -46,6 +47,8 @@ add_fcl_test(test_fcl_bvh_models test_fcl_bvh_models.cpp test_fcl_utility.cpp)
 add_fcl_test(test_fcl_profiling test_fcl_profiling.cpp test_fcl_utility.cpp)
 PKG_CONFIG_USE_DEPENDENCY(test_fcl_profiling assimp)
 
+add_fcl_test(test_fcl_gjk test_fcl_gjk.cpp)
+
 ## Benchmark
 add_executable(benchmark benchmark.cpp test_fcl_utility.cpp)
 target_link_libraries(benchmark hpp-fcl ${Boost_LIBRARIES})
diff --git a/test/benchmark/test_fcl_gjk.output b/test/benchmark/test_fcl_gjk.output
new file mode 100644
index 0000000000000000000000000000000000000000..ee02078dcc52a67836eacf5618e616c7d27cd911
--- /dev/null
+++ b/test/benchmark/test_fcl_gjk.output
@@ -0,0 +1,15 @@
+Result after running test_fcl_gjk in Release mode.
+
+nCol = 2831
+nDiff = 41
+Total time gjk: 21461
+Total time gte: 59498
+Number times GJK better than Geometric tools: 9988
+-- Collisions -------------------------
+Total time gjk: 5219
+Total time gte: 14334
+Number times GJK better than Geometric tools: 2828
+-- No collisions -------------------------
+Total time gjk: 16242
+Total time gte: 45164
+Number times GJK better than Geometric tools: 7160
diff --git a/test/gjk-geometric-tools-benchmark b/test/gjk-geometric-tools-benchmark
new file mode 100644
index 0000000000000000000000000000000000000000..4104d7511f78c3d9f22b4b16fe63395dcacdd5e5
--- /dev/null
+++ b/test/gjk-geometric-tools-benchmark
@@ -0,0 +1,15 @@
+Result after running test_fcl_gjk.cpp in Release mode.
+
+nCol = 2831
+nDiff = 41
+Total time gjk: 21461
+Total time gte: 59498
+Number times GJK better than Geometric tools: 9988
+-- Collisions -------------------------
+Total time gjk: 5219
+Total time gte: 14334
+Number times GJK better than Geometric tools: 2828
+-- No collisions -------------------------
+Total time gjk: 16242
+Total time gte: 45164
+Number times GJK better than Geometric tools: 7160
diff --git a/test/test_fcl_gjk.cpp b/test/test_fcl_gjk.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ef48b55e630445d782e2a2035dbc53dbbb355c69
--- /dev/null
+++ b/test/test_fcl_gjk.cpp
@@ -0,0 +1,240 @@
+/*
+ *  Software License Agreement (BSD License)
+ *
+ *  Copyright (c) 2018, CNRS-LAAS.
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of Willow Garage, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \author Florent Lamiraux <florent@laas.fr> */
+
+#define BOOST_TEST_MODULE FCL_GJK
+#define BOOST_TEST_DYN_LINK
+
+#include <time.h>
+#include <boost/test/unit_test.hpp>
+#include <boost/utility/binary.hpp>
+
+#include <hpp/fcl/narrowphase/narrowphase.h>
+#include <hpp/fcl/shape/geometric_shapes.h>
+#include <Mathematics/GteDistTriangle3Triangle3.h>
+
+using fcl::GJKSolver_indep;
+using fcl::TriangleP;
+using fcl::Vec3f;
+using fcl::Transform3f;
+using fcl::Matrix3f;
+using fcl::FCL_REAL;
+using gte::DCPQuery;
+using gte::Triangle3;
+using gte::Vector3;
+
+typedef DCPQuery <FCL_REAL, Triangle3 <FCL_REAL>, Triangle3 <FCL_REAL> >
+Query_t;
+
+struct Result
+{
+  bool collision;
+  clock_t timeGjk;
+  clock_t timeGte;
+}; // struct benchmark
+
+typedef std::vector <Result> Results_t;
+
+BOOST_AUTO_TEST_CASE(distance_triangle_triangle_1)
+{
+  std::size_t N = 10000;
+  GJKSolver_indep solver;
+  Transform3f tf1, tf2;
+  Vec3f p1, p2, a1, a2;
+  Matrix3f M;
+  FCL_REAL distance (sqrt (-1));
+  clock_t start, end;
+
+  std::size_t nCol = 0, nDiff = 0;
+  FCL_REAL eps = 1e-7;
+  Results_t results (N);
+  for (std::size_t i=0; i<N; ++i) {
+    Vec3f P1 (Vec3f::Random ()), P2 (Vec3f::Random ()), P3 (Vec3f::Random ());
+    Vec3f Q1 (Vec3f::Random ()), Q2 (Vec3f::Random ()), Q3 (Vec3f::Random ());
+    TriangleP tri1 (P1, P2, P3);
+    TriangleP tri2 (Q1, Q2, Q3);
+
+    start = clock ();
+    bool res = solver.shapeDistance (tri1, tf1, tri2, tf2, &distance, &p1, &p2);
+    end = clock ();
+    results [i].timeGjk = end - start;
+    results [i].collision = !res;
+    assert (res != (distance < 0));
+    if (distance >= 0) {
+      // Compute vectors between vertices
+      Vec3f u1 (P2 - P1);
+      Vec3f v1 (P3 - P1);
+      Vec3f w1 (u1.cross (v1));
+      Vec3f u2 (Q2 - Q1);
+      Vec3f v2 (Q3 - Q1);
+      Vec3f w2 (u2.cross (v2));
+      // Check that closest points are on triangles
+      // Compute a1 such that p1 = P1 + a11 u1 + b11 v1 + c11 u1 x v1
+      assert (w1.squaredNorm () > eps*eps);
+      M.col (0) = u1; M.col (1) = v1; M.col (2) = w1;
+      a1 = M.inverse () * (p1 - P1);
+      assert (fabs (a1 [2]) < eps);
+      assert (a1 [0] >= -eps);
+      assert (a1 [1] >= -eps);
+      assert (a1 [0] + a1 [1] <= 1+eps);
+      assert (w2.squaredNorm () > eps*eps);
+      M.col (0) = u2; M.col (1) = v2; M.col (2) = w2;
+      a2 = M.inverse () * (p2 - Q1);
+      assert (fabs (a2 [2]) < eps);
+      assert (a2 [0] >= -eps);
+      assert (a2 [1] >= -eps);
+      assert (a2 [0] + a2 [1] <= 1+eps);
+    } else {
+      ++nCol;
+    }
+    // Using geometric tools
+    Query_t query;
+    Vector3 <FCL_REAL> gteP1 = {P1 [0], P1 [1], P1 [2]};
+    Vector3 <FCL_REAL> gteP2 = {P2 [0], P2 [1], P2 [2]};
+    Vector3 <FCL_REAL> gteP3 = {P3 [0], P3 [1], P3 [2]};
+    Vector3 <FCL_REAL> gteQ1 = {Q1 [0], Q1 [1], Q1 [2]};
+    Vector3 <FCL_REAL> gteQ2 = {Q2 [0], Q2 [1], Q2 [2]};
+    Vector3 <FCL_REAL> gteQ3 = {Q3 [0], Q3 [1], Q3 [2]};
+    Triangle3 <FCL_REAL> gteTri1 (gteP1, gteP2, gteP3);
+    Triangle3 <FCL_REAL> gteTri2 (gteQ1, gteQ2, gteQ3);
+    start = clock ();
+    Query_t::Result gteRes = query (gteTri1, gteTri2);
+    end = clock ();
+    results [i].timeGte = end - start;
+
+    Vector3 <FCL_REAL> gte_p1 = gteRes.closestPoint [0];
+    Vector3 <FCL_REAL> gte_p2 = gteRes.closestPoint [1];
+    Vector3 <FCL_REAL> gte_p2_p1 = gte_p2 - gte_p1;
+    // assert (((distance < 0) && (gteRes.distance == 0)) ||
+    //         ((distance > 0) && (gteRes.distance > 0)));
+    assert (fabs (gteRes.sqrDistance - Dot (gte_p2_p1, gte_p2_p1)) < eps);
+    if ((distance >= 0) && (fabs (distance - gteRes.distance) >= eps)) {
+      ++nDiff;
+    } else {
+      assert ((distance < 0) ||
+              ((fabs (gte_p1 [0] - p1 [0]) < eps) &&
+               (fabs (gte_p1 [1] - p1 [1]) < eps) &&
+               (fabs (gte_p1 [2] - p1 [2]) < eps) &&
+               (fabs (gte_p2 [0] - p2 [0]) < eps) &&
+               (fabs (gte_p2 [1] - p2 [1]) < eps) &&
+               (fabs (gte_p2 [2] - p2 [2]) < eps)) ||
+              ((fabs (gte_p1 [0] - p2 [0]) < eps) &&
+               (fabs (gte_p1 [1] - p2 [1]) < eps) &&
+               (fabs (gte_p1 [2] - p2 [2]) < eps) &&
+               (fabs (gte_p2 [0] - p1 [0]) < eps) &&
+               (fabs (gte_p2 [1] - p1 [1]) < eps) &&
+               (fabs (gte_p2 [2] - p1 [2]) < eps)));
+    }
+#if 0
+    // Compute vectors between vertices
+    Vector3 <FCL_REAL> gte_u1 (gteP2 - gteP1);
+    Vector3 <FCL_REAL> gte_v1 (gteP3 - gteP1);
+    Vector3 <FCL_REAL> gte_w1 (Cross (gte_u1, gte_v1));
+    Vector3 <FCL_REAL> gte_u2 (gteQ2 - gteQ1);
+    Vector3 <FCL_REAL> gte_v2 (gteQ3 - gteQ1);
+    Vector3 <FCL_REAL> gte_w2 (Cross (gte_u2, gte_v2));
+    // Check that closest points are on triangles
+    // Compute a1 such that p1 = P1 + a11 u1 + b11 v1 + c11 u1 x v1
+    assert (std::sqrt(Dot(gte_w1, gte_w1)) > eps*eps);
+    M (0,0) = gte_u1 [0]; M (1,0) = gte_u1 [1]; M (2,0) = gte_u1 [2];
+    M (0,1) = gte_v1 [0]; M (1,1) = gte_v1 [1]; M (2,1) = gte_v1 [2];
+    M (0,2) = gte_w1 [0]; M (1,2) = gte_w1 [1]; M (2,2) = gte_w1 [2];
+    p1 [0] = gte_p1 [0]; p1 [1] = gte_p1 [1]; p1 [2] = gte_p1 [2];
+    a1 = M.inverse () * (p1 - P1);
+    assert (fabs (a1 [2]) < eps);
+    assert (a1 [0] >= -eps);
+    assert (a1 [1] >= -eps);
+    assert (a1 [0] + a1 [1] <= 1+eps);
+    // Check whether closest point is on triangle edges
+    if ((a1 [0] > eps) && (a1 [1] > eps) && (a1 [0] + a1 [1] < 1 - eps)) {
+      std::cerr << "a1 = " << a1.transpose () << std::endl;
+    }
+    assert (std::sqrt(Dot(gte_w2, gte_w2)) > eps*eps);
+    M (0,0) = gte_u2 [0]; M (1,0) = gte_u2 [1]; M (2,0) = gte_u2 [2];
+    M (0,1) = gte_v2 [0]; M (1,1) = gte_v2 [1]; M (2,1) = gte_v2 [2];
+    M (0,2) = gte_w2 [0]; M (1,2) = gte_w2 [1]; M (2,2) = gte_w2 [2];
+    p2 [0] = gte_p2 [0]; p2 [1] = gte_p2 [1]; p2 [2] = gte_p2 [2];
+    a2 = M.inverse () * (p2 - Q1);
+    assert (fabs (a2 [2]) < eps);
+    assert (a2 [0] >= -eps);
+    assert (a2 [1] >= -eps);
+    assert (a2 [0] + a2 [1] <= 1+eps);
+    // Check whether closest point is on triangle edges
+    if ((a2 [0] > eps) && (a2 [1] > eps) && (a2 [0] + a2 [1] < 1 - eps)) {
+      std::cerr << "a2 = " << a2.transpose () << std::endl;
+    }
+#endif
+  }
+  std::cerr << "nCol = " << nCol << std::endl;
+  std::cerr << "nDiff = " << nDiff << std::endl;
+  // statistics
+  clock_t totalTimeGjk = 0, totalTimeGte = 0;
+  clock_t totalTimeGjkColl = 0, totalTimeGteColl = 0;
+  clock_t totalTimeGjkNoColl = 0, totalTimeGteNoColl = 0;
+  std::size_t nGjkBetterThanGteColl = 0;
+  std::size_t nGjkBetterThanGteNoColl = 0;
+  for (std::size_t i=0; i<N; ++i) {
+    if (results [i].collision) {
+      totalTimeGjkColl += results [i].timeGjk;
+      totalTimeGteColl += results [i].timeGte;
+      if ((results [i].timeGjk < results [i].timeGte)) {
+        ++ nGjkBetterThanGteColl;
+      }
+    } else {
+      totalTimeGjkNoColl += results [i].timeGjk;
+      totalTimeGteNoColl += results [i].timeGte;
+      if ((results [i].timeGjk < results [i].timeGte)) {
+        ++ nGjkBetterThanGteNoColl;
+      }
+    }
+  }
+  std::cerr << "Total time gjk: " << totalTimeGjkNoColl + totalTimeGjkColl
+            << std::endl;
+  std::cerr << "Total time gte: " << totalTimeGteNoColl + totalTimeGteColl
+            << std::endl;
+  std::cerr << "Number times GJK better than Geometric tools: "
+            << nGjkBetterThanGteNoColl + nGjkBetterThanGteColl << std::endl;
+  std::cerr << "-- Collisions -------------------------" << std::endl;
+  std::cerr << "Total time gjk: " << totalTimeGjkColl << std::endl;
+  std::cerr << "Total time gte: " << totalTimeGteColl << std::endl;
+  std::cerr << "Number times GJK better than Geometric tools: "
+            << nGjkBetterThanGteColl << std::endl;
+  std::cerr << "-- No collisions -------------------------" << std::endl;
+  std::cerr << "Total time gjk: " << totalTimeGjkNoColl << std::endl;
+  std::cerr << "Total time gte: " << totalTimeGteNoColl << std::endl;
+  std::cerr << "Number times GJK better than Geometric tools: "
+            << nGjkBetterThanGteNoColl << std::endl;
+
+}