commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From er...@apache.org
Subject [commons-geometry] 01/03: GEOMETRY-11: replacing double tolerance values with DoublePrecisionContext class
Date Tue, 05 Feb 2019 12:15:37 GMT
This is an automated email from the ASF dual-hosted git repository.

erans pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-geometry.git

commit 6e83c6a08a36a644a978d1448bf0d1265e4a5984
Author: Matt Juntunen <matt.juntunen@hotmail.com>
AuthorDate: Fri Feb 1 19:05:58 2019 -0500

    GEOMETRY-11: replacing double tolerance values with DoublePrecisionContext class
---
 commons-geometry-core/pom.xml                      |   7 +
 .../geometry/core/partitioning/AbstractRegion.java |  39 +--
 .../geometry/core/partitioning/BSPTree.java        |  16 +-
 .../geometry/core/partitioning/Hyperplane.java     |   9 +-
 .../core/precision/DoublePrecisionContext.java     | 120 +++++++
 .../precision/EpsilonDoublePrecisionContext.java   | 108 ++++++
 .../geometry/core/precision/package-info.java      |  23 ++
 .../geometry/core/partitioning/TreeBuilder.java    |  59 ++--
 .../geometry/core/partitioning/TreeDumper.java     |   4 +-
 .../core/precision/DoublePrecisionContextTest.java | 132 ++++++++
 .../EpsilonDoublePrecisionContextTest.java         | 213 ++++++++++++
 .../commons/geometry/enclosing/WelzlEncloser.java  |  15 +-
 .../threed/enclosing/SphereGenerator.java          |   9 +-
 .../geometry/enclosing/WelzlEncloser2DTest.java    |  13 +-
 .../geometry/enclosing/WelzlEncloser3DTest.java    |  17 +-
 .../geometry/euclidean/oned/IntervalsSet.java      |  37 +-
 .../geometry/euclidean/oned/OrientedPoint.java     |  17 +-
 .../geometry/euclidean/oned/SubOrientedPoint.java  |  11 +-
 .../commons/geometry/euclidean/threed/Line.java    |  27 +-
 .../euclidean/threed/OutlineExtractor.java         |  25 +-
 .../commons/geometry/euclidean/threed/Plane.java   |  52 +--
 .../geometry/euclidean/threed/PolyhedronsSet.java  |  65 ++--
 .../commons/geometry/euclidean/threed/SubLine.java |  17 +-
 .../geometry/euclidean/threed/SubPlane.java        |  19 +-
 .../commons/geometry/euclidean/twod/Line.java      |  45 +--
 .../geometry/euclidean/twod/NestedLoops.java       |  25 +-
 .../geometry/euclidean/twod/PolygonsSet.java       |  90 +++--
 .../commons/geometry/euclidean/twod/SubLine.java   |  33 +-
 .../core/partitioning/CharacterizationTest.java    |  18 +-
 .../geometry/euclidean/EuclideanTestUtils.java     |  67 ++--
 .../geometry/euclidean/internal/MatricesTest.java  |   5 -
 .../geometry/euclidean/oned/IntervalsSetTest.java  | 250 +++++++-------
 .../geometry/euclidean/oned/OrientedPointTest.java |  37 +-
 .../euclidean/oned/SubOrientedPointTest.java       |  55 +--
 .../geometry/euclidean/threed/LineTest.java        |  65 ++--
 .../geometry/euclidean/threed/OBJWriter.java       |  57 ++--
 .../geometry/euclidean/threed/PlaneTest.java       |  57 ++--
 .../euclidean/threed/PolyhedronsSetTest.java       | 338 ++++++++++---------
 .../geometry/euclidean/threed/SubLineTest.java     |  71 ++--
 .../threed/rotation/AxisSequenceTest.java          |   1 -
 .../commons/geometry/euclidean/twod/LineTest.java  |  37 +-
 .../geometry/euclidean/twod/NestedLoopsTest.java   |   9 +-
 .../geometry/euclidean/twod/PolygonsSetTest.java   | 275 +++++++--------
 .../geometry/euclidean/twod/SegmentTest.java       |  17 +-
 .../geometry/euclidean/twod/SubLineTest.java       |  73 ++--
 .../geometry/euclidean/threed/issue-1211.bsp       |  13 +-
 .../twod/hull/AbstractConvexHullGenerator2D.java   |  31 +-
 .../geometry/euclidean/twod/hull/ConvexHull2D.java |  22 +-
 .../euclidean/twod/hull/MonotoneChain.java         |  24 +-
 .../twod/hull/AklToussaintHeuristicTest.java       |   3 -
 .../euclidean/twod/hull/MonotoneChainTest.java     |   3 +-
 .../commons/geometry/spherical/oned/Arc.java       |  31 +-
 .../commons/geometry/spherical/oned/ArcsSet.java   |  49 +--
 .../geometry/spherical/oned/LimitAngle.java        |  19 +-
 .../commons/geometry/spherical/twod/Circle.java    |  43 +--
 .../commons/geometry/spherical/twod/Edge.java      |  11 +-
 .../geometry/spherical/twod/EdgesBuilder.java      |  17 +-
 .../spherical/twod/PropertiesComputer.java         |  13 +-
 .../spherical/twod/SphericalPolygonsSet.java       |  80 +++--
 .../commons/geometry/spherical/twod/SubCircle.java |   4 +-
 .../geometry/spherical/SphericalTestUtils.java     |  24 +-
 .../commons/geometry/spherical/oned/ArcTest.java   |  52 +--
 .../geometry/spherical/oned/ArcsSetTest.java       | 371 +++++++++++----------
 .../geometry/spherical/oned/LimitAngleTest.java    |  17 +-
 .../geometry/spherical/twod/CircleTest.java        | 107 +++---
 .../spherical/twod/SphericalPolygonsSetTest.java   | 196 ++++++-----
 .../geometry/spherical/twod/SubCircleTest.java     |  66 ++--
 67 files changed, 2332 insertions(+), 1543 deletions(-)

diff --git a/commons-geometry-core/pom.xml b/commons-geometry-core/pom.xml
index 59d62b5..82fd82c 100644
--- a/commons-geometry-core/pom.xml
+++ b/commons-geometry-core/pom.xml
@@ -42,6 +42,13 @@
     <!-- Workaround to avoid duplicating config files. -->
     <geometry.parent.dir>${basedir}/..</geometry.parent.dir>
   </properties>
+  
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-numbers-core</artifactId>
+    </dependency>
+  </dependencies>
 
   <build>
     <plugins>
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/AbstractRegion.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/AbstractRegion.java
index ff923d6..d3047c8 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/AbstractRegion.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/AbstractRegion.java
@@ -25,6 +25,7 @@ import java.util.Map;
 import java.util.TreeSet;
 
 import org.apache.commons.geometry.core.Point;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 
 /** Abstract class for all regions, independent of geometry type or dimension.
 
@@ -36,8 +37,8 @@ public abstract class AbstractRegion<P extends Point<P>, S extends Point<S>> imp
     /** Inside/Outside BSP tree. */
     private BSPTree<P> tree;
 
-    /** Tolerance below which points are considered to belong to hyperplanes. */
-    private final double tolerance;
+    /** Precision context used to determine floating point equality. */
+    private final DoublePrecisionContext precision;
 
     /** Size of the instance. */
     private double size;
@@ -46,11 +47,11 @@ public abstract class AbstractRegion<P extends Point<P>, S extends Point<S>> imp
     private P barycenter;
 
     /** Build a region representing the whole space.
-     * @param tolerance tolerance below which points are considered identical.
+     * @param precision precision context used to compare floating point numbers
      */
-    protected AbstractRegion(final double tolerance) {
+    protected AbstractRegion(final DoublePrecisionContext precision) {
         this.tree      = new BSPTree<>(Boolean.TRUE);
-        this.tolerance = tolerance;
+        this.precision = precision;
     }
 
     /** Build a region from an inside/outside BSP tree.
@@ -64,11 +65,11 @@ public abstract class AbstractRegion<P extends Point<P>, S extends Point<S>> imp
      * internal nodes representing the boundary as specified in the
      * {@link #getTree getTree} method).</p>
      * @param tree inside/outside BSP tree representing the region
-     * @param tolerance tolerance below which points are considered identical.
+     * @param precision precision context used to compare floating point values
      */
-    protected AbstractRegion(final BSPTree<P> tree, final double tolerance) {
+    protected AbstractRegion(final BSPTree<P> tree, final DoublePrecisionContext precision) {
         this.tree      = tree;
-        this.tolerance = tolerance;
+        this.precision = precision;
     }
 
     /** Build a Region from a Boundary REPresentation (B-rep).
@@ -89,11 +90,11 @@ public abstract class AbstractRegion<P extends Point<P>, S extends Point<S>> imp
      * space.</p>
      * @param boundary collection of boundary elements, as a
      * collection of {@link SubHyperplane SubHyperplane} objects
-     * @param tolerance tolerance below which points are considered identical.
+     * @param precision precision context used to compare floating point values
      */
-    protected AbstractRegion(final Collection<SubHyperplane<P>> boundary, final double tolerance) {
+    protected AbstractRegion(final Collection<SubHyperplane<P>> boundary, final DoublePrecisionContext precision) {
 
-        this.tolerance = tolerance;
+        this.precision = precision;
 
         if (boundary.size() == 0) {
 
@@ -152,10 +153,10 @@ public abstract class AbstractRegion<P extends Point<P>, S extends Point<S>> imp
     /** Build a convex region from an array of bounding hyperplanes.
      * @param hyperplanes array of bounding hyperplanes (if null, an
      * empty region will be built)
-     * @param tolerance tolerance below which points are considered identical.
+     * @param precision precision context used to compare floating point values
      */
-    public AbstractRegion(final Hyperplane<P>[] hyperplanes, final double tolerance) {
-        this.tolerance = tolerance;
+    public AbstractRegion(final Hyperplane<P>[] hyperplanes, final DoublePrecisionContext precision) {
+        this.precision = precision;
         if ((hyperplanes == null) || (hyperplanes.length == 0)) {
             tree = new BSPTree<>(Boolean.FALSE);
         } else {
@@ -183,11 +184,11 @@ public abstract class AbstractRegion<P extends Point<P>, S extends Point<S>> imp
     @Override
     public abstract AbstractRegion<P, S> buildNew(BSPTree<P> newTree);
 
-    /** Get the tolerance below which points are considered to belong to hyperplanes.
-     * @return tolerance below which points are considered to belong to hyperplanes
+    /** Get the object used to determine floating point equality for this region.
+     * @return the floating point precision context for the instance
      */
-    public double getTolerance() {
-        return tolerance;
+    public DoublePrecisionContext getPrecision() {
+        return precision;
     }
 
     /** Recursively build a tree by inserting cut sub-hyperplanes.
@@ -324,7 +325,7 @@ public abstract class AbstractRegion<P extends Point<P>, S extends Point<S>> imp
      * OUTSIDE} or {@link Region.Location#BOUNDARY BOUNDARY}
      */
     protected Location checkPoint(final BSPTree<P> node, final P point) {
-        final BSPTree<P> cell = node.getCell(point, tolerance);
+        final BSPTree<P> cell = node.getCell(point, precision);
         if (cell.getCut() == null) {
             // the point is in the interior of a cell, just check the attribute
             return ((Boolean) cell.getAttribute()) ? Location.INSIDE : Location.OUTSIDE;
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/BSPTree.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/BSPTree.java
index e74614b..9a00a89 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/BSPTree.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/BSPTree.java
@@ -21,6 +21,7 @@ import java.util.List;
 
 import org.apache.commons.geometry.core.Point;
 import org.apache.commons.geometry.core.partitioning.BSPTreeVisitor.Order;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 
 /** This class represent a Binary Space Partition tree.
 
@@ -305,11 +306,11 @@ public class BSPTree<P extends Point<P>> {
      * interior of the node, if the cell is an internal node the points
      * belongs to the node cut sub-hyperplane.</p>
      * @param point point to check
-     * @param tolerance tolerance below which points close to a cut hyperplane
-     * are considered to belong to the hyperplane itself
+     * @param precision precision context used to determine which points
+     * close to a cut hyperplane are considered to belong to the hyperplane itself
      * @return the tree cell to which the point belongs
      */
-    public BSPTree<P> getCell(final P point, final double tolerance) {
+    public BSPTree<P> getCell(final P point, final DoublePrecisionContext precision) {
 
         if (cut == null) {
             return this;
@@ -318,14 +319,15 @@ public class BSPTree<P extends Point<P>> {
         // position of the point with respect to the cut hyperplane
         final double offset = cut.getHyperplane().getOffset(point);
 
-        if (Math.abs(offset) < tolerance) {
+        final int comparison = precision.compare(offset, 0.0);
+        if (comparison == 0) {
             return this;
-        } else if (offset <= 0) {
+        } else if (comparison < 0) {
             // point is on the minus side of the cut hyperplane
-            return minus.getCell(point, tolerance);
+            return minus.getCell(point, precision);
         } else {
             // point is on the plus side of the cut hyperplane
-            return plus.getCell(point, tolerance);
+            return plus.getCell(point, precision);
         }
 
     }
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/Hyperplane.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/Hyperplane.java
index a8b0151..28d9d12 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/Hyperplane.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/Hyperplane.java
@@ -17,6 +17,7 @@
 package org.apache.commons.geometry.core.partitioning;
 
 import org.apache.commons.geometry.core.Point;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 
 /** This interface represents an hyperplane of a space.
 
@@ -64,10 +65,12 @@ public interface Hyperplane<P extends Point<P>> {
      */
     P project(P point);
 
-    /** Get the tolerance below which points are considered to belong to the hyperplane.
-     * @return tolerance below which points are considered to belong to the hyperplane
+    /** Get the object used to determine floating point equality for this hyperplane.
+     * This determines which points belong to the hyperplane and which do not, or pictured
+     * another way, the "thickness" of the hyperplane.
+     * @return the floating point precision context for the instance
      */
-    double getTolerance();
+    DoublePrecisionContext getPrecision();
 
     /** Check if the instance has the same orientation as another hyperplane.
      * <p>This method is expected to be called on parallel hyperplanes. The
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/precision/DoublePrecisionContext.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/precision/DoublePrecisionContext.java
new file mode 100644
index 0000000..1d36953
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/precision/DoublePrecisionContext.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.geometry.core.precision;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+/** Class encapsulating the concept of comparison operations for doubles.
+ */
+public abstract class DoublePrecisionContext implements Comparator<Double>, Serializable {
+
+    /** Serializable identifier */
+    private static final long serialVersionUID = 20190121L;
+
+    /** Return true if the given values are considered equal to each other.
+     * @param a first value
+     * @param b second value
+     * @return true if the given values are considered equal
+     */
+    public boolean areEqual(final double a, final double b) {
+        return compare(a, b) == 0;
+    }
+
+    /** Return true if the given value is considered equal to zero. This is
+     * equivalent {@code context.areEqual(n, 0.0)} but with a more explicit
+     * method name.
+     * @param n the number to compare to zero
+     * @return true if the argument is considered equal to zero.
+     */
+    public boolean isZero(final double n) {
+        return areEqual(n, 0.0);
+    }
+
+    /**
+     * Return true if the first argument is strictly less than the second.
+     * @param a first value
+     * @param b second value
+     * @return true if {@code a < b}
+     */
+    public boolean isLessThan(final double a, final double b) {
+        return compare(a, b) < 0;
+    }
+
+    /**
+     * Return true if the first argument is less than or equal to the second.
+     * @param a first value
+     * @param b second value
+     * @return true if {@code a <= b}
+     */
+    public boolean isLessThanOrEqual(final double a, final double b) {
+        return compare(a, b) <= 0;
+    }
+
+    /**
+     * Return true if the first argument is strictly greater than the second.
+     * @param a first value
+     * @param b second value
+     * @return true if {@code a > b}
+     */
+    public boolean isGreaterThan(final double a, final double b) {
+        return compare(a, b) > 0;
+    }
+
+    /**
+     * Return true if the first argument is greater than or equal to the second.
+     * @param a first value
+     * @param b second value
+     * @return true if {@code a >= b}
+     */
+    public boolean isGreaterThanOrEqual(final double a, final double b) {
+        return compare(a, b) >= 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int compare(final Double a, final Double b) {
+        return compare(a.doubleValue(), b.doubleValue());
+    }
+
+    /** Compare two double values. The returned value is
+     * <ul>
+     *  <li>
+     *   {@code 0} if the arguments are considered equal,
+     *  </li>
+     *  <li>
+     *   {@code -1} if {@code a < b},
+     *  </li>
+     *  <li>
+     *   {@code +1} if {@code a > b} or if either value is NaN.
+     *  </li>
+     * </ul>
+     *
+     * @param a first value
+     * @param b second value
+     * @return {@code 0} if the values are considered equal, {@code -1} if the
+     *      first is smaller than the second, {@code 1} is the first is larger
+     *      than the second or either value is NaN.
+     */
+    public abstract int compare(final double a, final double b);
+
+    /** Get the largest positive double value that is still considered equal
+     * to zero by this instance.
+     * @return the largest positive double value still considered equal to zero
+     */
+    public abstract double getMaxZero();
+}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/precision/EpsilonDoublePrecisionContext.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/precision/EpsilonDoublePrecisionContext.java
new file mode 100644
index 0000000..c26f502
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/precision/EpsilonDoublePrecisionContext.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.geometry.core.precision;
+
+import org.apache.commons.numbers.core.Precision;
+
+/** Simple {@link DoublePrecisionContext} subclass that uses an absolute epsilon value to
+ * determine equality between doubles.
+ *
+ * <p>This class uses the {@link Precision#compareTo(double, double, double)} method to compare
+ * numbers. Two values are considered equal if there is no floating point
+ * value strictly between them or if their numerical difference is less than or equal
+ * to the configured epsilon value.</p>
+ *
+ * @see Precision#compareTo(double, double, double)
+ */
+public class EpsilonDoublePrecisionContext extends DoublePrecisionContext {
+
+    /** Serializable identifier */
+    private static final long serialVersionUID = 20190119L;
+
+    /** Epsilon value. */
+    private final double epsilon;
+
+    /** Simple constructor.
+     * @param eps Epsilon value. Numbers are considered equal if there is no
+     *      floating point value strictly between them or if their difference is less
+     *      than or equal to this value.
+     */
+    public EpsilonDoublePrecisionContext(final double eps) {
+        this.epsilon = eps;
+    }
+
+    /** Get the epsilon value for the instance. Numbers are considered equal if there
+     * is no floating point value strictly between them or if their difference is less
+     * than or equal to this value.
+     * @return the epsilon value for the instance
+     */
+    public double getEpsilon() {
+        return epsilon;
+    }
+
+    /** {@inheritDoc}
+     * This value is equal to the epsilon value for the instance.
+     * @see #getEpsilon()
+     */
+    @Override
+    public double getMaxZero() {
+        return epsilon;
+    }
+
+    /** {@inheritDoc} **/
+    @Override
+    public int compare(double a, double b) {
+        return Precision.compareTo(a, b, epsilon);
+    }
+
+    /** {@inheritDoc} **/
+    @Override
+    public int hashCode() {
+        int result = 31;
+        result += 17 * Double.hashCode(epsilon);
+
+        return result;
+    }
+
+    /** {@inheritDoc} **/
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof EpsilonDoublePrecisionContext)) {
+            return false;
+        }
+
+        EpsilonDoublePrecisionContext other = (EpsilonDoublePrecisionContext) obj;
+
+        return this.epsilon == other.epsilon;
+    }
+
+    /** {@inheritDoc} **/
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(this.getClass().getSimpleName())
+            .append("[")
+            .append("epsilon= ")
+            .append(epsilon)
+            .append("]");
+
+        return sb.toString();
+    }
+}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/precision/package-info.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/precision/package-info.java
new file mode 100644
index 0000000..ee924b5
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/precision/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ *
+ * <p>
+ * This package contains classes related to floating-point precision.
+ * </p>
+ */
+package org.apache.commons.geometry.core.precision;
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/TreeBuilder.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/TreeBuilder.java
index 3ad8e8e..81d03af 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/TreeBuilder.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/TreeBuilder.java
@@ -16,19 +16,22 @@
  */
 package org.apache.commons.geometry.core.partitioning;
 
-import java.io.IOException;
 import java.text.ParseException;
 import java.util.StringTokenizer;
 
 import org.apache.commons.geometry.core.Point;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 
 /** Local class for building an {@link AbstractRegion} tree.
  * @param <P> Point type defining the space
  */
 public abstract class TreeBuilder<P extends Point<P>> {
 
-    /** Keyword for tolerance. */
-    private static final String TOLERANCE = "tolerance";
+    /** Default epsilon value for use when no value is specified
+     * in the constructor.
+     */
+    private static final double DEFAULT_EPS = 1e-10;
 
     /** Keyword for internal nodes. */
     private static final String INTERNAL  = "internal";
@@ -51,25 +54,34 @@ public abstract class TreeBuilder<P extends Point<P>> {
     /** Tree root. */
     private BSPTree<P> root;
 
-    /** Tolerance. */
-    private final double tolerance;
+    /** Precision. */
+    private final DoublePrecisionContext precision;
 
     /** Tokenizer parsing string representation. */
     private final StringTokenizer tokenizer;
 
+    /** Constructor using a default precision context.
+     * @param type type of the expected representation
+     * @param str the tree string representation
+     * @exception ParseException if the string cannot be parsed
+     */
+    public TreeBuilder(final String type, final String str) throws ParseException {
+        this(type, str, new EpsilonDoublePrecisionContext(DEFAULT_EPS));
+    }
+
     /** Simple constructor.
      * @param type type of the expected representation
-     * @param reader reader for the string representation
-     * @exception IOException if the string cannot be read
+     * @param str the tree string representation
+     * @param precision precision context for determining floating point equality
      * @exception ParseException if the string cannot be parsed
      */
-    public TreeBuilder(final String type, final String s)
-        throws IOException, ParseException {
+    public TreeBuilder(final String type, final String str, final DoublePrecisionContext precision)
+        throws ParseException {
+        this.precision = precision;
+
         root = null;
-        tokenizer = new StringTokenizer(s);
+        tokenizer = new StringTokenizer(str);
         getWord(type);
-        getWord(TOLERANCE);
-        tolerance = getNumber();
         getWord(PLUS);
         root = new BSPTree<>();
         parseTree(root);
@@ -80,11 +92,10 @@ public abstract class TreeBuilder<P extends Point<P>> {
 
     /** Parse a tree.
      * @param node start node
-     * @exception IOException if the string cannot be read
      * @exception ParseException if the string cannot be parsed
      */
     private void parseTree(final BSPTree<P> node)
-        throws IOException, ParseException {
+        throws ParseException {
         if (INTERNAL.equals(getWord(INTERNAL, LEAF))) {
             // this is an internal node, it has a cut sub-hyperplane (stored as a whole hyperplane)
             // then a minus tree, then a plus tree
@@ -102,11 +113,10 @@ public abstract class TreeBuilder<P extends Point<P>> {
     /** Get next word.
      * @param allowed allowed values
      * @return parsed word
-     * @exception IOException if the string cannot be read
      * @exception ParseException if the string cannot be parsed
      */
     protected String getWord(final String ... allowed)
-        throws IOException, ParseException {
+        throws ParseException {
         final String token = tokenizer.nextToken();
         for (final String a : allowed) {
             if (a.equals(token)) {
@@ -118,21 +128,19 @@ public abstract class TreeBuilder<P extends Point<P>> {
 
     /** Get next number.
      * @return parsed number
-     * @exception IOException if the string cannot be read
      * @exception NumberFormatException if the string cannot be parsed
      */
     protected double getNumber()
-        throws IOException, NumberFormatException {
+        throws NumberFormatException {
         return Double.parseDouble(tokenizer.nextToken());
     }
 
     /** Get next boolean.
      * @return parsed boolean
-     * @exception IOException if the string cannot be read
      * @exception ParseException if the string cannot be parsed
      */
     protected boolean getBoolean()
-        throws IOException, ParseException {
+        throws ParseException {
         return getWord(TRUE, FALSE).equals(TRUE);
     }
 
@@ -143,19 +151,18 @@ public abstract class TreeBuilder<P extends Point<P>> {
         return root;
     }
 
-    /** Get the tolerance.
-     * @return tolerance
+    /** Get the precision.
+     * @return precision
      */
-    public double getTolerance() {
-        return tolerance;
+    public DoublePrecisionContext getPrecision() {
+        return precision;
     }
 
     /** Parse an hyperplane.
      * @return next hyperplane from the stream
-     * @exception IOException if the string cannot be read
      * @exception ParseException if the string cannot be parsed
      */
     protected abstract Hyperplane<P> parseHyperplane()
-        throws IOException, ParseException;
+        throws ParseException;
 
 }
\ No newline at end of file
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/TreeDumper.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/TreeDumper.java
index 6c1285f..db94a9c 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/TreeDumper.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/TreeDumper.java
@@ -36,14 +36,12 @@ public abstract class TreeDumper<P extends Point<P>> implements BSPTreeVisitor<P
 
     /** Simple constructor.
      * @param type type of the region to dump
-     * @param tolerance tolerance of the region
      */
-    public TreeDumper(final String type, final double tolerance) {
+    public TreeDumper(final String type) {
         this.dump      = new StringBuilder();
         this.formatter = new Formatter(dump, Locale.US);
         this.prefix    = "";
         formatter.format("%s%n", type);
-        formatter.format("tolerance %22.15e%n", tolerance);
     }
 
     /** Get the string representation of the tree.
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/precision/DoublePrecisionContextTest.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/precision/DoublePrecisionContextTest.java
new file mode 100644
index 0000000..f203e6d
--- /dev/null
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/precision/DoublePrecisionContextTest.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.geometry.core.precision;
+
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class DoublePrecisionContextTest {
+
+    private StubContext ctx = new StubContext();
+
+    @Test
+    public void testAreEqual() {
+        // act/assert
+        Assert.assertTrue(ctx.areEqual(0.0, 0.0));
+        Assert.assertTrue(ctx.areEqual(1.0, 1.0));
+        Assert.assertTrue(ctx.areEqual(-1.0, -1.0));
+
+        Assert.assertFalse(ctx.areEqual(1.0, -1.0));
+        Assert.assertFalse(ctx.areEqual(1.0, Math.nextUp(1.0)));
+        Assert.assertFalse(ctx.areEqual(-1.0, Math.nextDown(1.0)));
+    }
+
+    @Test
+    public void testIsZero() {
+        // act/assert
+        Assert.assertTrue(ctx.isZero(0.0));
+
+        Assert.assertFalse(ctx.isZero(Math.nextUp(0.0)));
+        Assert.assertFalse(ctx.isZero(Math.nextDown(-0.0)));
+    }
+
+    @Test
+    public void testIsLessThan() {
+        // act/assert
+        Assert.assertTrue(ctx.isLessThan(1, 2));
+        Assert.assertTrue(ctx.isLessThan(-2, -1));
+
+        Assert.assertFalse(ctx.isLessThan(1, 1));
+        Assert.assertFalse(ctx.isLessThan(-1, -1));
+        Assert.assertFalse(ctx.isLessThan(2, 1));
+        Assert.assertFalse(ctx.isLessThan(-1, -2));
+    }
+
+    @Test
+    public void testIsLessThanOrEqual() {
+        // act/assert
+        Assert.assertTrue(ctx.isLessThanOrEqual(1, 2));
+        Assert.assertTrue(ctx.isLessThanOrEqual(-2, -1));
+        Assert.assertTrue(ctx.isLessThanOrEqual(1, 1));
+        Assert.assertTrue(ctx.isLessThanOrEqual(-1, -1));
+
+        Assert.assertFalse(ctx.isLessThanOrEqual(2, 1));
+        Assert.assertFalse(ctx.isLessThanOrEqual(-1, -2));
+    }
+
+    @Test
+    public void testIsGreaterThan() {
+        // act/assert
+        Assert.assertTrue(ctx.isGreaterThan(2, 1));
+        Assert.assertTrue(ctx.isGreaterThan(-1, -2));
+
+        Assert.assertFalse(ctx.isGreaterThan(1, 1));
+        Assert.assertFalse(ctx.isGreaterThan(-1, -1));
+        Assert.assertFalse(ctx.isGreaterThan(1, 2));
+        Assert.assertFalse(ctx.isGreaterThan(-2, -1));
+    }
+
+    @Test
+    public void testIsGreaterThanOrEqual() {
+        // act/assert
+        Assert.assertTrue(ctx.isGreaterThanOrEqual(2, 1));
+        Assert.assertTrue(ctx.isGreaterThanOrEqual(-1, -2));
+        Assert.assertTrue(ctx.isGreaterThanOrEqual(1, 1));
+        Assert.assertTrue(ctx.isGreaterThanOrEqual(-1, -1));
+
+        Assert.assertFalse(ctx.isGreaterThanOrEqual(1, 2));
+        Assert.assertFalse(ctx.isGreaterThanOrEqual(-2, -1));
+    }
+
+    @Test
+    public void testCompare() {
+        // act/assert
+        Assert.assertEquals(0, ctx.compare(1, 1));
+        Assert.assertEquals(-1, ctx.compare(1, 2));
+        Assert.assertEquals(1, ctx.compare(2, 1));
+
+        Assert.assertEquals(0, ctx.compare(-1, -1));
+        Assert.assertEquals(1, ctx.compare(-1, -2));
+        Assert.assertEquals(-1, ctx.compare(-2, -1));
+    }
+
+    @Test
+    public void testCompare_wrapper() {
+        // act/assert
+        Assert.assertEquals(0, ctx.compare(new Double(1), new Double(1)));
+        Assert.assertEquals(-1, ctx.compare(new Double(1), new Double(2)));
+        Assert.assertEquals(1, ctx.compare(new Double(2), new Double(1)));
+
+        Assert.assertEquals(0, ctx.compare(new Double(-1), new Double(-1)));
+        Assert.assertEquals(1, ctx.compare(new Double(-1), new Double(-2)));
+        Assert.assertEquals(-1, ctx.compare(new Double(-2), new Double(-1)));
+    }
+
+    private static class StubContext extends DoublePrecisionContext {
+
+        @Override
+        public double getMaxZero() {
+            return 0.0;
+        }
+
+        @Override
+        public int compare(double a, double b) {
+            return Double.compare(a, b);
+        }
+    }
+}
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/precision/EpsilonDoublePrecisionContextTest.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/precision/EpsilonDoublePrecisionContextTest.java
new file mode 100644
index 0000000..b94052b
--- /dev/null
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/precision/EpsilonDoublePrecisionContextTest.java
@@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.geometry.core.precision;
+
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class EpsilonDoublePrecisionContextTest {
+
+    @Test
+    public void testGetters() {
+        // arrange
+        double eps = 1e-6;
+
+        // act
+        EpsilonDoublePrecisionContext ctx = new EpsilonDoublePrecisionContext(eps);
+
+        // assert
+        Assert.assertEquals(ctx.getEpsilon(), eps, 0.0);
+        Assert.assertEquals(ctx.getMaxZero(), eps, 0.0);
+    }
+
+    @Test
+    public void testCompare_compareToZero() {
+        // arrange
+        double eps = 1e-2;
+
+        EpsilonDoublePrecisionContext ctx = new EpsilonDoublePrecisionContext(eps);
+
+        // act/assert
+        Assert.assertEquals(0, ctx.compare(0.0, 0.0));
+        Assert.assertEquals(0, ctx.compare(+0.0, -0.0));
+        Assert.assertEquals(0, ctx.compare(eps, -0.0));
+        Assert.assertEquals(0, ctx.compare(+0.0, eps));
+
+        Assert.assertEquals(0, ctx.compare(-eps, -0.0));
+        Assert.assertEquals(0, ctx.compare(+0.0, -eps));
+
+        Assert.assertEquals(-1, ctx.compare(0.0, 1.0));
+        Assert.assertEquals(1, ctx.compare(1.0, 0.0));
+
+        Assert.assertEquals(1, ctx.compare(0.0, -1.0));
+        Assert.assertEquals(-1, ctx.compare(-1.0, 0.0));
+    }
+
+    @Test
+    public void testCompare_compareNonZero() {
+        // arrange
+        double eps = 1e-5;
+        double small = 1e-3;
+        double big = 1e100;
+
+        EpsilonDoublePrecisionContext ctx = new EpsilonDoublePrecisionContext(eps);
+
+        // act/assert
+        Assert.assertEquals(0, ctx.compare(eps, 2 * eps));
+        Assert.assertEquals(0, ctx.compare(-2 * eps, -eps));
+
+        Assert.assertEquals(0, ctx.compare(small, small + (0.9 * eps)));
+        Assert.assertEquals(0, ctx.compare(-small - (0.9 * eps), -small));
+
+        Assert.assertEquals(0, ctx.compare(big, nextUp(big, 1)));
+        Assert.assertEquals(0, ctx.compare(nextDown(-big, 1), -big));
+
+        Assert.assertEquals(-1, ctx.compare(small, small + (1.1 * eps)));
+        Assert.assertEquals(1, ctx.compare(-small, -small - (1.1 * eps)));
+
+        Assert.assertEquals(-1, ctx.compare(big, nextUp(big, 2)));
+        Assert.assertEquals(1, ctx.compare(-big, nextDown(-big, 2)));
+    }
+
+    @Test
+    public void testCompare_NaN() {
+        // arrange
+        EpsilonDoublePrecisionContext ctx = new EpsilonDoublePrecisionContext(1e-6);
+
+        // act/assert
+        Assert.assertEquals(1, ctx.compare(0, Double.NaN));
+        Assert.assertEquals(1, ctx.compare(Double.NaN, 0));
+        Assert.assertEquals(1, ctx.compare(Double.NaN, Double.NaN));
+
+        Assert.assertEquals(1, ctx.compare(Double.POSITIVE_INFINITY, Double.NaN));
+        Assert.assertEquals(1, ctx.compare(Double.NaN, Double.POSITIVE_INFINITY));
+
+        Assert.assertEquals(1, ctx.compare(Double.NEGATIVE_INFINITY, Double.NaN));
+        Assert.assertEquals(1, ctx.compare(Double.NaN, Double.NEGATIVE_INFINITY));
+    }
+
+    @Test
+    public void testCompare_infinity() {
+        // arrange
+        EpsilonDoublePrecisionContext ctx = new EpsilonDoublePrecisionContext(1e-6);
+
+        // act/assert
+        Assert.assertEquals(-1, ctx.compare(0, Double.POSITIVE_INFINITY));
+        Assert.assertEquals(1, ctx.compare(Double.POSITIVE_INFINITY, 0));
+        Assert.assertEquals(0, ctx.compare(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
+
+        Assert.assertEquals(1, ctx.compare(0, Double.NEGATIVE_INFINITY));
+        Assert.assertEquals(-1, ctx.compare(Double.NEGATIVE_INFINITY, 0));
+        Assert.assertEquals(0, ctx.compare(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
+    }
+
+    @Test
+    public void testGetMaxZero_isZeroEqualityThreshold() {
+        // arrange
+        double eps = 1e-2;
+
+        EpsilonDoublePrecisionContext ctx = new EpsilonDoublePrecisionContext(eps);
+
+        double maxZero = ctx.getMaxZero();
+
+        // act/assert
+        Assert.assertTrue(ctx.isZero(maxZero));
+        Assert.assertTrue(ctx.isZero(nextDown(maxZero, 1)));
+        Assert.assertFalse(ctx.isZero(nextUp(maxZero, 1)));
+
+        Assert.assertTrue(ctx.isZero(-maxZero));
+        Assert.assertTrue(ctx.isZero(nextUp(-maxZero, 1)));
+        Assert.assertFalse(ctx.isZero(nextDown(-maxZero, 1)));
+    }
+
+    @Test
+    public void testHashCode() {
+        // arrange
+        EpsilonDoublePrecisionContext a = new EpsilonDoublePrecisionContext(1e-6);
+        EpsilonDoublePrecisionContext b = new EpsilonDoublePrecisionContext(1e-7);
+        EpsilonDoublePrecisionContext c = new EpsilonDoublePrecisionContext(1e-6);
+
+        // act/assert
+        Assert.assertEquals(a.hashCode(), a.hashCode());
+        Assert.assertEquals(a.hashCode(), c.hashCode());
+
+        Assert.assertNotEquals(a.hashCode(), b.hashCode());
+    }
+
+    @Test
+    public void testEquals() {
+        // arrange
+        EpsilonDoublePrecisionContext a = new EpsilonDoublePrecisionContext(1e-6);
+        EpsilonDoublePrecisionContext b = new EpsilonDoublePrecisionContext(1e-7);
+        EpsilonDoublePrecisionContext c = new EpsilonDoublePrecisionContext(1e-6);
+
+        // act/assert
+        Assert.assertFalse(a.equals(null));
+        Assert.assertFalse(a.equals(new Object()));
+        Assert.assertFalse(a.equals(b));
+        Assert.assertFalse(b.equals(a));
+
+        Assert.assertTrue(a.equals(a));
+        Assert.assertTrue(a.equals(c));
+    }
+
+    @Test
+    public void testToString() {
+        // arrange
+        EpsilonDoublePrecisionContext a = new EpsilonDoublePrecisionContext(1d);
+
+        // act
+        String str = a.toString();
+
+        // assert
+        Assert.assertTrue(str.contains("EpsilonDoublePrecisionContext"));
+        Assert.assertTrue(str.contains("epsilon= 1"));
+    }
+
+    /**
+     * Increments the given double value {@code count} number of times
+     * using {@link Math#nextUp(double)}.
+     * @param n
+     * @param count
+     * @return
+     */
+    private static double nextUp(double n, int count) {
+        double result = n;
+        for (int i=0; i<count; ++i) {
+            result = Math.nextUp(result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Decrements the given double value {@code count} number of times
+     * using {@link Math#nextDown(double)}.
+     * @param n
+     * @param count
+     * @return
+     */
+    private static double nextDown(double n, int count) {
+        double result = n;
+        for (int i=0; i<count; ++i) {
+            result = Math.nextDown(result);
+        }
+
+        return result;
+    }
+}
diff --git a/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/WelzlEncloser.java b/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/WelzlEncloser.java
index 65dbc2a..b4b2876 100644
--- a/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/WelzlEncloser.java
+++ b/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/WelzlEncloser.java
@@ -21,6 +21,7 @@ import java.util.List;
 
 import org.apache.commons.geometry.core.Point;
 import org.apache.commons.geometry.core.internal.GeometryInternalError;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 
 /** Class implementing Emo Welzl algorithm to find the smallest enclosing ball in linear time.
  * <p>
@@ -39,18 +40,18 @@ import org.apache.commons.geometry.core.internal.GeometryInternalError;
  */
 public class WelzlEncloser<P extends Point<P>> implements Encloser<P> {
 
-    /** Tolerance below which points are consider to be identical. */
-    private final double tolerance;
+    /** Precision context used to compare floating point numbers. */
+    private final DoublePrecisionContext precision;
 
     /** Generator for balls on support. */
     private final SupportBallGenerator<P> generator;
 
     /** Simple constructor.
-     * @param tolerance below which points are consider to be identical
+     * @param precision precision context used to compare floating point values
      * @param generator generator for balls on support
      */
-    public WelzlEncloser(final double tolerance, final SupportBallGenerator<P> generator) {
-        this.tolerance = tolerance;
+    public WelzlEncloser(final DoublePrecisionContext precision, final SupportBallGenerator<P> generator) {
+        this.precision = precision;
         this.generator = generator;
     }
 
@@ -87,7 +88,7 @@ public class WelzlEncloser<P extends Point<P>> implements Encloser<P> {
             // select the point farthest to current ball
             final P farthest = selectFarthest(points, ball);
 
-            if (ball.contains(farthest, tolerance)) {
+            if (ball.contains(farthest, precision.getMaxZero())) {
                 // we have found a ball containing all points
                 return ball;
             }
@@ -129,7 +130,7 @@ public class WelzlEncloser<P extends Point<P>> implements Encloser<P> {
 
             for (int i = 0; i < nbExtreme; ++i) {
                 final P pi = extreme.get(i);
-                if (!ball.contains(pi, tolerance)) {
+                if (!ball.contains(pi, precision.getMaxZero())) {
 
                     // we have found an outside point,
                     // enlarge the ball by adding it to the support
diff --git a/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/euclidean/threed/enclosing/SphereGenerator.java b/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/euclidean/threed/enclosing/SphereGenerator.java
index 80c9dbd..471fab8 100644
--- a/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/euclidean/threed/enclosing/SphereGenerator.java
+++ b/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/euclidean/threed/enclosing/SphereGenerator.java
@@ -19,6 +19,8 @@ package org.apache.commons.geometry.euclidean.threed.enclosing;
 import java.util.Arrays;
 import java.util.List;
 
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.enclosing.EnclosingBall;
 import org.apache.commons.geometry.enclosing.SupportBallGenerator;
 import org.apache.commons.geometry.euclidean.threed.Plane;
@@ -31,6 +33,9 @@ import org.apache.commons.numbers.fraction.BigFraction;
  */
 public class SphereGenerator implements SupportBallGenerator<Vector3D> {
 
+    /** Base epsilon value */
+    private static final double BASE_EPS = 1e-10;
+
     /** {@inheritDoc} */
     @Override
     public EnclosingBall<Vector3D> ballOnSupport(final List<Vector3D> support) {
@@ -52,8 +57,8 @@ public class SphereGenerator implements SupportBallGenerator<Vector3D> {
                     if (support.size() < 4) {
 
                         // delegate to 2D disk generator
-                        final Plane p = new Plane(vA, vB, vC,
-                                                  1.0e-10 * (norm1(vA) + norm1(vB) + norm1(vC)));
+                        final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(BASE_EPS * (norm1(vA) + norm1(vB) + norm1(vC)));
+                        final Plane p = new Plane(vA, vB, vC, precision);
                         final EnclosingBall<Vector2D> disk =
                                 new DiskGenerator().ballOnSupport(Arrays.asList(p.toSubSpace(vA),
                                                                                 p.toSubSpace(vB),
diff --git a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/WelzlEncloser2DTest.java b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/WelzlEncloser2DTest.java
index 6d0f0e8..9400271 100644
--- a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/WelzlEncloser2DTest.java
+++ b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/WelzlEncloser2DTest.java
@@ -20,6 +20,8 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.twod.Vector2D;
 import org.apache.commons.geometry.euclidean.twod.enclosing.DiskGenerator;
 import org.apache.commons.rng.UniformRandomProvider;
@@ -30,11 +32,16 @@ import org.junit.Test;
 
 public class WelzlEncloser2DTest {
 
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
+
     @Test
     public void testNullList() {
         DiskGenerator generator = new DiskGenerator();
         WelzlEncloser<Vector2D> encloser =
-                new WelzlEncloser<>(1.0e-10, generator);
+                new WelzlEncloser<>(TEST_PRECISION, generator);
         EnclosingBall<Vector2D> ball = encloser.enclose(null);
         Assert.assertTrue(ball.getRadius() < 0);
     }
@@ -43,7 +50,7 @@ public class WelzlEncloser2DTest {
     public void testNoPoints() {
         DiskGenerator generator = new DiskGenerator();
         WelzlEncloser<Vector2D> encloser =
-                new WelzlEncloser<>(1.0e-10, generator);
+                new WelzlEncloser<>(TEST_PRECISION, generator);
         EnclosingBall<Vector2D> ball = encloser.enclose(new ArrayList<Vector2D>());
         Assert.assertTrue(ball.getRadius() < 0);
     }
@@ -148,7 +155,7 @@ public class WelzlEncloser2DTest {
     private EnclosingBall<Vector2D> checkDisk(List<Vector2D> points) {
 
         WelzlEncloser<Vector2D> encloser =
-                new WelzlEncloser<>(1.0e-10, new DiskGenerator());
+                new WelzlEncloser<>(TEST_PRECISION, new DiskGenerator());
         EnclosingBall<Vector2D> disk = encloser.enclose(points);
 
         // all points are enclosed
diff --git a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/WelzlEncloser3DTest.java b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/WelzlEncloser3DTest.java
index 73b9718..d353b67 100644
--- a/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/WelzlEncloser3DTest.java
+++ b/commons-geometry-enclosing/src/test/java/org/apache/commons/geometry/enclosing/WelzlEncloser3DTest.java
@@ -20,6 +20,8 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.threed.Vector3D;
 import org.apache.commons.geometry.euclidean.threed.enclosing.SphereGenerator;
 import org.apache.commons.rng.UniformRandomProvider;
@@ -31,11 +33,16 @@ import org.junit.Test;
 
 public class WelzlEncloser3DTest {
 
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
+
     @Test
     public void testNullList() {
         SphereGenerator generator = new SphereGenerator();
         WelzlEncloser<Vector3D> encloser =
-                new WelzlEncloser<>(1.0e-10, generator);
+                new WelzlEncloser<>(TEST_PRECISION, generator);
         EnclosingBall<Vector3D> ball = encloser.enclose(null);
         Assert.assertTrue(ball.getRadius() < 0);
     }
@@ -44,7 +51,7 @@ public class WelzlEncloser3DTest {
     public void testNoPoints() {
         SphereGenerator generator = new SphereGenerator();
         WelzlEncloser<Vector3D> encloser =
-                new WelzlEncloser<>(1.0e-10, generator);
+                new WelzlEncloser<>(TEST_PRECISION, generator);
         EnclosingBall<Vector3D> ball = encloser.enclose(new ArrayList<Vector3D>());
         Assert.assertTrue(ball.getRadius() < 0);
     }
@@ -64,7 +71,7 @@ public class WelzlEncloser3DTest {
                               Vector3D.of(-7.140322188726825, -16.574152894557717,  11.710305611121410),
                               Vector3D.of(-7.141116131477088, -16.574061164624560,  11.712938509321699));
         WelzlEncloser<Vector3D> encloser =
-                new WelzlEncloser<>(1.0e-10, new SphereGenerator());
+                new WelzlEncloser<>(TEST_PRECISION, new SphereGenerator());
         EnclosingBall<Vector3D> ball = encloser.enclose(list);
         Assert.assertTrue(ball.getRadius() > 0);
     }
@@ -93,7 +100,7 @@ public class WelzlEncloser3DTest {
                               Vector3D.of( -0.98034899533935820,  -3.34004481162763960,  13.03245014017556800));
 
         WelzlEncloser<Vector3D> encloser =
-                new WelzlEncloser<>(1.0e-10, new SphereGenerator());
+                new WelzlEncloser<>(TEST_PRECISION, new SphereGenerator());
         EnclosingBall<Vector3D> ball = encloser.enclose(list);
         Assert.assertTrue(ball.getRadius() > 0);
     }
@@ -155,7 +162,7 @@ public class WelzlEncloser3DTest {
     private EnclosingBall<Vector3D> checkSphere(List<Vector3D> points) {
 
         WelzlEncloser<Vector3D> encloser =
-                new WelzlEncloser<>(1.0e-10, new SphereGenerator());
+                new WelzlEncloser<>(TEST_PRECISION, new SphereGenerator());
         EnclosingBall<Vector3D> Sphere = encloser.enclose(points);
 
         // all points are enclosed
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/IntervalsSet.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/IntervalsSet.java
index ae6d8dc..bb86ed6 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/IntervalsSet.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/IntervalsSet.java
@@ -26,16 +26,17 @@ import org.apache.commons.geometry.core.partitioning.AbstractRegion;
 import org.apache.commons.geometry.core.partitioning.BSPTree;
 import org.apache.commons.geometry.core.partitioning.BoundaryProjection;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 
 /** This class represents a 1D region: a set of intervals.
  */
 public class IntervalsSet extends AbstractRegion<Vector1D, Vector1D> implements Iterable<double[]> {
 
     /** Build an intervals set representing the whole real line.
-     * @param tolerance tolerance below which points are considered identical.
+     * @param precision precision context used to compare floating point values
      */
-    public IntervalsSet(final double tolerance) {
-        super(tolerance);
+    public IntervalsSet(final DoublePrecisionContext precision) {
+        super(precision);
     }
 
     /** Build an intervals set corresponding to a single interval.
@@ -43,10 +44,10 @@ public class IntervalsSet extends AbstractRegion<Vector1D, Vector1D> implements
      * to {@code upper} (may be {@code Double.NEGATIVE_INFINITY})
      * @param upper upper bound of the interval, must be greater or equal
      * to {@code lower} (may be {@code Double.POSITIVE_INFINITY})
-     * @param tolerance tolerance below which points are considered identical.
+     * @param precision precision context used to compare floating point values
      */
-    public IntervalsSet(final double lower, final double upper, final double tolerance) {
-        super(buildTree(lower, upper, tolerance), tolerance);
+    public IntervalsSet(final double lower, final double upper, final DoublePrecisionContext precision) {
+        super(buildTree(lower, upper, precision), precision);
     }
 
     /** Build an intervals set from an inside/outside BSP tree.
@@ -57,10 +58,10 @@ public class IntervalsSet extends AbstractRegion<Vector1D, Vector1D> implements
      * recommended to use the predefined constants
      * {@code Boolean.TRUE} and {@code Boolean.FALSE}</p>
      * @param tree inside/outside BSP tree representing the intervals set
-     * @param tolerance tolerance below which points are considered identical.
+     * @param precision precision context used to compare floating point values
      */
-    public IntervalsSet(final BSPTree<Vector1D> tree, final double tolerance) {
-        super(tree, tolerance);
+    public IntervalsSet(final BSPTree<Vector1D> tree, final DoublePrecisionContext precision) {
+        super(tree, precision);
     }
 
     /** Build an intervals set from a Boundary REPresentation (B-rep).
@@ -81,11 +82,11 @@ public class IntervalsSet extends AbstractRegion<Vector1D, Vector1D> implements
      * <p>If the boundary is empty, the region will represent the whole
      * space.</p>
      * @param boundary collection of boundary elements
-     * @param tolerance tolerance below which points are considered identical.
+     * @param precision precision context used to compare floating point values
      */
     public IntervalsSet(final Collection<SubHyperplane<Vector1D>> boundary,
-                        final double tolerance) {
-        super(boundary, tolerance);
+                        final DoublePrecisionContext precision) {
+        super(boundary, precision);
     }
 
     /** Build an inside/outside tree representing a single interval.
@@ -93,11 +94,11 @@ public class IntervalsSet extends AbstractRegion<Vector1D, Vector1D> implements
      * to {@code upper} (may be {@code Double.NEGATIVE_INFINITY})
      * @param upper upper bound of the interval, must be greater or equal
      * to {@code lower} (may be {@code Double.POSITIVE_INFINITY})
-     * @param tolerance tolerance below which points are considered identical.
+     * @param precision precision context used to compare floating point values
      * @return the built tree
      */
     private static BSPTree<Vector1D> buildTree(final double lower, final double upper,
-                                                  final double tolerance) {
+                                                  final DoublePrecisionContext precision) {
         if (Double.isInfinite(lower) && (lower < 0)) {
             if (Double.isInfinite(upper) && (upper > 0)) {
                 // the tree must cover the whole real line
@@ -105,14 +106,14 @@ public class IntervalsSet extends AbstractRegion<Vector1D, Vector1D> implements
             }
             // the tree must be open on the negative infinity side
             final SubHyperplane<Vector1D> upperCut =
-                new OrientedPoint(Vector1D.of(upper), true, tolerance).wholeHyperplane();
+                new OrientedPoint(Vector1D.of(upper), true, precision).wholeHyperplane();
             return new BSPTree<>(upperCut,
                                new BSPTree<Vector1D>(Boolean.FALSE),
                                new BSPTree<Vector1D>(Boolean.TRUE),
                                null);
         }
         final SubHyperplane<Vector1D> lowerCut =
-            new OrientedPoint(Vector1D.of(lower), false, tolerance).wholeHyperplane();
+            new OrientedPoint(Vector1D.of(lower), false, precision).wholeHyperplane();
         if (Double.isInfinite(upper) && (upper > 0)) {
             // the tree must be open on the positive infinity side
             return new BSPTree<>(lowerCut,
@@ -123,7 +124,7 @@ public class IntervalsSet extends AbstractRegion<Vector1D, Vector1D> implements
 
         // the tree must be bounded on the two sides
         final SubHyperplane<Vector1D> upperCut =
-            new OrientedPoint(Vector1D.of(upper), true, tolerance).wholeHyperplane();
+            new OrientedPoint(Vector1D.of(upper), true, precision).wholeHyperplane();
         return new BSPTree<>(lowerCut,
                                         new BSPTree<Vector1D>(Boolean.FALSE),
                                         new BSPTree<>(upperCut,
@@ -137,7 +138,7 @@ public class IntervalsSet extends AbstractRegion<Vector1D, Vector1D> implements
     /** {@inheritDoc} */
     @Override
     public IntervalsSet buildNew(final BSPTree<Vector1D> tree) {
-        return new IntervalsSet(tree, getTolerance());
+        return new IntervalsSet(tree, getPrecision());
     }
 
     /** {@inheritDoc} */
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/OrientedPoint.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/OrientedPoint.java
index 79bcb53..1a8b338 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/OrientedPoint.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/OrientedPoint.java
@@ -17,6 +17,7 @@
 package org.apache.commons.geometry.euclidean.oned;
 
 import org.apache.commons.geometry.core.partitioning.Hyperplane;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 
 /** This class represents a 1D oriented hyperplane.
  * <p>An hyperplane in 1D is a simple point, its orientation being a
@@ -31,19 +32,19 @@ public class OrientedPoint implements Hyperplane<Vector1D> {
     /** Orientation. */
     private boolean direct;
 
-    /** Tolerance below which points are considered to belong to the hyperplane. */
-    private final double tolerance;
+    /** Precision context used to compare floating point numbers. */
+    private final DoublePrecisionContext precision;
 
     /** Simple constructor.
      * @param location location of the hyperplane
      * @param direct if true, the plus side of the hyperplane is towards
      * abscissas greater than {@code location}
-     * @param tolerance tolerance below which points are considered to belong to the hyperplane
+     * @param precision precision context used to compare floating point values
      */
-    public OrientedPoint(final Vector1D location, final boolean direct, final double tolerance) {
+    public OrientedPoint(final Vector1D location, final boolean direct, final DoublePrecisionContext precision) {
         this.location  = location;
         this.direct    = direct;
-        this.tolerance = tolerance;
+        this.precision = precision;
     }
 
     /** Copy the instance.
@@ -85,7 +86,7 @@ public class OrientedPoint implements Hyperplane<Vector1D> {
      */
     @Override
     public IntervalsSet wholeSpace() {
-        return new IntervalsSet(tolerance);
+        return new IntervalsSet(precision);
     }
 
     /** {@inheritDoc} */
@@ -102,8 +103,8 @@ public class OrientedPoint implements Hyperplane<Vector1D> {
 
     /** {@inheritDoc} */
     @Override
-    public double getTolerance() {
-        return tolerance;
+    public DoublePrecisionContext getPrecision() {
+        return precision;
     }
 
     /** Get the hyperplane location on the real line.
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/SubOrientedPoint.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/SubOrientedPoint.java
index 3945b28..e228fb0 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/SubOrientedPoint.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/SubOrientedPoint.java
@@ -19,6 +19,7 @@ package org.apache.commons.geometry.euclidean.oned;
 import org.apache.commons.geometry.core.partitioning.AbstractSubHyperplane;
 import org.apache.commons.geometry.core.partitioning.Hyperplane;
 import org.apache.commons.geometry.core.partitioning.Region;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 
 /** This class represents sub-hyperplane for {@link OrientedPoint}.
  * <p>An hyperplane in 1D is a simple point, its orientation being a
@@ -61,12 +62,14 @@ public class SubOrientedPoint extends AbstractSubHyperplane<Vector1D, Vector1D>
         final OrientedPoint thisHyperplane = (OrientedPoint) getHyperplane();
         final double global = hyperplane.getOffset(thisHyperplane.getLocation());
 
-        // use the tolerance value from our parent hyperplane to determine equality
-        final double tolerance = thisHyperplane.getTolerance();
+        // use the precision context from our parent hyperplane to determine equality
+        final DoublePrecisionContext precision = thisHyperplane.getPrecision();
 
-        if (global < -tolerance) {
+        int comparison = precision.compare(global, 0.0);
+
+        if (comparison < 0) {
             return new SplitSubHyperplane<Vector1D>(null, this);
-        } else if (global > tolerance) {
+        } else if (comparison > 0) {
             return new SplitSubHyperplane<Vector1D>(this, null);
         } else {
             return new SplitSubHyperplane<Vector1D>(null, null);
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Line.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Line.java
index 2f036a3..b587eb2 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Line.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Line.java
@@ -17,6 +17,7 @@
 package org.apache.commons.geometry.euclidean.threed;
 
 import org.apache.commons.geometry.core.partitioning.Embedding;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.oned.IntervalsSet;
 import org.apache.commons.geometry.euclidean.oned.Vector1D;
 import org.apache.commons.numbers.core.Precision;
@@ -38,19 +39,19 @@ public class Line implements Embedding<Vector3D, Vector1D> {
     /** Line point closest to the origin. */
     private Vector3D zero;
 
-    /** Tolerance below which points are considered identical. */
-    private final double tolerance;
+    /** Precision context used to compare floating point numbers. */
+    private final DoublePrecisionContext precision;
 
     /** Build a line from two points.
      * @param p1 first point belonging to the line (this can be any point)
      * @param p2 second point belonging to the line (this can be any point, different from p1)
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      * @exception IllegalArgumentException if the points are equal
      */
-    public Line(final Vector3D p1, final Vector3D p2, final double tolerance)
+    public Line(final Vector3D p1, final Vector3D p2, final DoublePrecisionContext precision)
         throws IllegalArgumentException {
         reset(p1, p2);
-        this.tolerance = tolerance;
+        this.precision = precision;
     }
 
     /** Copy constructor.
@@ -61,7 +62,7 @@ public class Line implements Embedding<Vector3D, Vector1D> {
     public Line(final Line line) {
         this.direction = line.direction;
         this.zero      = line.zero;
-        this.tolerance = line.tolerance;
+        this.precision = line.precision;
     }
 
     /** Reset the instance as if built from two points.
@@ -79,11 +80,11 @@ public class Line implements Embedding<Vector3D, Vector1D> {
         this.zero = Vector3D.linearCombination(1.0, p1, -p1.dot(delta) / norm2, delta);
     }
 
-    /** Get the tolerance below which points are considered identical.
-     * @return tolerance below which points are considered identical
+    /** Get the object used to determine floating point equality for this instance.
+     * @return the floating point precision context for the instance
      */
-    public double getTolerance() {
-        return tolerance;
+    public DoublePrecisionContext getPrecision() {
+        return precision;
     }
 
     /** Get a line with reversed direction.
@@ -157,7 +158,7 @@ public class Line implements Embedding<Vector3D, Vector1D> {
      */
     public boolean isSimilarTo(final Line line) {
         final double angle = direction.angle(line.direction);
-        return ((angle < tolerance) || (angle > (Math.PI - tolerance))) && contains(line.zero);
+        return (precision.isZero(angle) || precision.areEqual(angle, Math.PI)) && contains(line.zero);
     }
 
     /** Check if the instance contains a point.
@@ -165,7 +166,7 @@ public class Line implements Embedding<Vector3D, Vector1D> {
      * @return true if p belongs to the line
      */
     public boolean contains(final Vector3D p) {
-        return distance(p) < tolerance;
+        return precision.isZero(distance(p));
     }
 
     /** Compute the distance between the instance and a point.
@@ -233,7 +234,7 @@ public class Line implements Embedding<Vector3D, Vector1D> {
      * @return a sub-line covering the whole line
      */
     public SubLine wholeLine() {
-        return new SubLine(this, new IntervalsSet(tolerance));
+        return new SubLine(this, new IntervalsSet(precision));
     }
 
 }
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/OutlineExtractor.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/OutlineExtractor.java
index 3ea8376..c1a4eb2 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/OutlineExtractor.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/OutlineExtractor.java
@@ -24,8 +24,9 @@ import org.apache.commons.geometry.core.partitioning.BSPTreeVisitor;
 import org.apache.commons.geometry.core.partitioning.BoundaryAttribute;
 import org.apache.commons.geometry.core.partitioning.RegionFactory;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
-import org.apache.commons.geometry.euclidean.twod.Vector2D;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.twod.PolygonsSet;
+import org.apache.commons.geometry.euclidean.twod.Vector2D;
 
 /** Extractor for {@link PolygonsSet polyhedrons sets} outlines.
  * <p>This class extracts the 2D outlines from {{@link PolygonsSet
@@ -59,7 +60,7 @@ public class OutlineExtractor {
     public Vector2D[][] getOutline(final PolyhedronsSet polyhedronsSet) {
 
         // project all boundary facets into one polygons set
-        final BoundaryProjector projector = new BoundaryProjector(polyhedronsSet.getTolerance());
+        final BoundaryProjector projector = new BoundaryProjector(polyhedronsSet.getPrecision());
         polyhedronsSet.getTree(true).visit(projector);
         final PolygonsSet projected = projector.getProjected();
 
@@ -120,15 +121,15 @@ public class OutlineExtractor {
         /** Projection of the polyhedrons set on the plane. */
         private PolygonsSet projected;
 
-        /** Tolerance below which points are considered identical. */
-        private final double tolerance;
+        /** Precision context used to compare floating point numbers. */
+        private final DoublePrecisionContext precision;
 
         /** Simple constructor.
-         * @param tolerance tolerance below which points are considered identical
+         * @param precision precision context used to compare floating point values
          */
-        BoundaryProjector(final double tolerance) {
-            this.projected = new PolygonsSet(new BSPTree<Vector2D>(Boolean.FALSE), tolerance);
-            this.tolerance = tolerance;
+        BoundaryProjector(final DoublePrecisionContext precision) {
+            this.projected = new PolygonsSet(new BSPTree<Vector2D>(Boolean.FALSE), precision);
+            this.precision = precision;
         }
 
         /** {@inheritDoc} */
@@ -213,7 +214,7 @@ public class OutlineExtractor {
                         final Vector2D  cPoint    = Vector2D.of(current3D.dot(u),
                                                                  current3D.dot(v));
                         final org.apache.commons.geometry.euclidean.twod.Line line =
-                            new org.apache.commons.geometry.euclidean.twod.Line(pPoint, cPoint, tolerance);
+                            new org.apache.commons.geometry.euclidean.twod.Line(pPoint, cPoint, precision);
                         SubHyperplane<Vector2D> edge = line.wholeHyperplane();
 
                         if (closed || (previous != 1)) {
@@ -221,7 +222,7 @@ public class OutlineExtractor {
                             // it defines one bounding point of the edge
                             final double angle = line.getAngle() + 0.5 * Math.PI;
                             final org.apache.commons.geometry.euclidean.twod.Line l =
-                                new org.apache.commons.geometry.euclidean.twod.Line(pPoint, angle, tolerance);
+                                new org.apache.commons.geometry.euclidean.twod.Line(pPoint, angle, precision);
                             edge = edge.split(l).getPlus();
                         }
 
@@ -230,7 +231,7 @@ public class OutlineExtractor {
                             // it defines one bounding point of the edge
                             final double angle = line.getAngle() + 0.5 * Math.PI;
                             final org.apache.commons.geometry.euclidean.twod.Line l =
-                                new org.apache.commons.geometry.euclidean.twod.Line(cPoint, angle, tolerance);
+                                new org.apache.commons.geometry.euclidean.twod.Line(cPoint, angle, precision);
                             edge = edge.split(l).getMinus();
                         }
 
@@ -242,7 +243,7 @@ public class OutlineExtractor {
 
                     }
                 }
-                final PolygonsSet projectedFacet = new PolygonsSet(edges, tolerance);
+                final PolygonsSet projectedFacet = new PolygonsSet(edges, precision);
 
                 // add the contribution of the facet to the global outline
                 projected = (PolygonsSet) new RegionFactory<Vector2D>().union(projected, projectedFacet);
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Plane.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Plane.java
index b1f2955..7bc7bc3 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Plane.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Plane.java
@@ -19,6 +19,7 @@ package org.apache.commons.geometry.euclidean.threed;
 import org.apache.commons.geometry.core.exception.IllegalNormException;
 import org.apache.commons.geometry.core.partitioning.Embedding;
 import org.apache.commons.geometry.core.partitioning.Hyperplane;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.internal.Vectors;
 import org.apache.commons.geometry.euclidean.oned.Vector1D;
 import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
@@ -44,18 +45,18 @@ public class Plane implements Hyperplane<Vector3D>, Embedding<Vector3D, Vector2D
     /** Third vector of the plane frame (plane normal). */
     private Vector3D w;
 
-    /** Tolerance below which points are considered identical. */
-    private final double tolerance;
+    /** Precision context used to compare floating point numbers. */
+    private final DoublePrecisionContext precision;
 
     /** Build a plane normal to a given direction and containing the origin.
      * @param normal normal direction to the plane
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      * @exception IllegalArgumentException if the normal norm is too small
      */
-    public Plane(final Vector3D normal, final double tolerance)
+    public Plane(final Vector3D normal, final DoublePrecisionContext precision)
         throws IllegalArgumentException {
         setNormal(normal);
-        this.tolerance = tolerance;
+        this.precision = precision;
         originOffset = 0;
         setFrame();
     }
@@ -63,13 +64,13 @@ public class Plane implements Hyperplane<Vector3D>, Embedding<Vector3D, Vector2D
     /** Build a plane from a point and a normal.
      * @param p point belonging to the plane
      * @param normal normal direction to the plane
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      * @exception IllegalArgumentException if the normal norm is too small
      */
-    public Plane(final Vector3D p, final Vector3D normal, final double tolerance)
+    public Plane(final Vector3D p, final Vector3D normal, final DoublePrecisionContext precision)
         throws IllegalArgumentException {
         setNormal(normal);
-        this.tolerance = tolerance;
+        this.precision = precision;
         this.originOffset = -p.dot(w);
         setFrame();
     }
@@ -80,12 +81,12 @@ public class Plane implements Hyperplane<Vector3D>, Embedding<Vector3D, Vector2D
      * @param p1 first point belonging to the plane
      * @param p2 second point belonging to the plane
      * @param p3 third point belonging to the plane
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      * @exception IllegalArgumentException if the points do not constitute a plane
      */
-    public Plane(final Vector3D p1, final Vector3D p2, final Vector3D p3, final double tolerance)
+    public Plane(final Vector3D p1, final Vector3D p2, final Vector3D p3, final DoublePrecisionContext precision)
         throws IllegalArgumentException {
-        this(p1, p2.subtract(p1).cross(p3.subtract(p1)), tolerance);
+        this(p1, p2.subtract(p1).cross(p3.subtract(p1)), precision);
     }
 
     /** Copy constructor.
@@ -100,7 +101,7 @@ public class Plane implements Hyperplane<Vector3D>, Embedding<Vector3D, Vector2D
         u            = plane.u;
         v            = plane.v;
         w            = plane.w;
-        tolerance    = plane.tolerance;
+        precision    = plane.precision;
     }
 
     /** Copy the instance.
@@ -211,8 +212,8 @@ public class Plane implements Hyperplane<Vector3D>, Embedding<Vector3D, Vector2D
 
     /** {@inheritDoc} */
     @Override
-    public double getTolerance() {
-        return tolerance;
+    public DoublePrecisionContext getPrecision() {
+        return precision;
     }
 
     /** Revert the plane.
@@ -275,8 +276,9 @@ public class Plane implements Hyperplane<Vector3D>, Embedding<Vector3D, Vector2D
      */
     public boolean isSimilarTo(final Plane plane) {
         final double angle = w.angle(plane.w);
-        return ((angle < 1.0e-10) && (Math.abs(originOffset - plane.originOffset) < tolerance)) ||
-               (((angle + 1.0e-10) > Math.PI) && (Math.abs(originOffset + plane.originOffset) < tolerance));
+
+        return ((precision.isZero(angle)) && precision.areEqual(originOffset, plane.originOffset)) ||
+                ((precision.areEqual(angle, Math.PI)) && precision.areEqual(originOffset, -plane.originOffset));
     }
 
     /** Rotate the plane around the specified point.
@@ -289,7 +291,7 @@ public class Plane implements Hyperplane<Vector3D>, Embedding<Vector3D, Vector2D
 
         final Vector3D delta = origin.subtract(center);
         final Plane plane = new Plane(center.add(rotation.apply(delta)),
-                                      rotation.apply(w), tolerance);
+                                      rotation.apply(w), precision);
 
         // make sure the frame is transformed as desired
         plane.u = rotation.apply(u);
@@ -306,7 +308,7 @@ public class Plane implements Hyperplane<Vector3D>, Embedding<Vector3D, Vector2D
      */
     public Plane translate(final Vector3D translation) {
 
-        final Plane plane = new Plane(origin.add(translation), w, tolerance);
+        final Plane plane = new Plane(origin.add(translation), w, precision);
 
         // make sure the frame is transformed as desired
         plane.u = u;
@@ -324,7 +326,7 @@ public class Plane implements Hyperplane<Vector3D>, Embedding<Vector3D, Vector2D
     public Vector3D intersection(final Line line) {
         final Vector3D direction = line.getDirection();
         final double   dot       = w.dot(direction);
-        if (Math.abs(dot) < 1.0e-10) {
+        if (precision.isZero(dot)) {
             return null;
         }
         final Vector3D point = line.toSpace(Vector1D.ZERO);
@@ -339,11 +341,11 @@ public class Plane implements Hyperplane<Vector3D>, Embedding<Vector3D, Vector2D
      */
     public Line intersection(final Plane other) {
         final Vector3D direction = w.cross(other.w);
-        if (direction.norm() < tolerance) {
+        if (precision.isZero(direction.norm())) {
             return null;
         }
-        final Vector3D point = intersection(this, other, new Plane(direction, tolerance));
-        return new Line(point, point.add(direction), tolerance);
+        final Vector3D point = intersection(this, other, new Plane(direction, precision));
+        return new Line(point, point.add(direction), precision);
     }
 
     /** Get the intersection point of three planes.
@@ -393,7 +395,7 @@ public class Plane implements Hyperplane<Vector3D>, Embedding<Vector3D, Vector2D
      */
     @Override
     public SubPlane wholeHyperplane() {
-        return new SubPlane(this, new PolygonsSet(tolerance));
+        return new SubPlane(this, new PolygonsSet(precision));
     }
 
     /** Build a region covering the whole space.
@@ -402,7 +404,7 @@ public class Plane implements Hyperplane<Vector3D>, Embedding<Vector3D, Vector2D
      */
     @Override
     public PolyhedronsSet wholeSpace() {
-        return new PolyhedronsSet(tolerance);
+        return new PolyhedronsSet(precision);
     }
 
     /** Check if the instance contains a point.
@@ -410,7 +412,7 @@ public class Plane implements Hyperplane<Vector3D>, Embedding<Vector3D, Vector2D
      * @return true if p belongs to the plane
      */
     public boolean contains(final Vector3D p) {
-        return Math.abs(getOffset(p)) < tolerance;
+        return precision.isZero(getOffset(p));
     }
 
     /** Get the offset (oriented distance) of a parallel plane.
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/PolyhedronsSet.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/PolyhedronsSet.java
index b52e3e5..43d8ce6 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/PolyhedronsSet.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/PolyhedronsSet.java
@@ -32,21 +32,22 @@ import org.apache.commons.geometry.core.partitioning.Region;
 import org.apache.commons.geometry.core.partitioning.RegionFactory;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
 import org.apache.commons.geometry.core.partitioning.Transform;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.oned.Vector1D;
 import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
-import org.apache.commons.geometry.euclidean.twod.Vector2D;
 import org.apache.commons.geometry.euclidean.twod.PolygonsSet;
 import org.apache.commons.geometry.euclidean.twod.SubLine;
+import org.apache.commons.geometry.euclidean.twod.Vector2D;
 
 /** This class represents a 3D region: a set of polyhedrons.
  */
 public class PolyhedronsSet extends AbstractRegion<Vector3D, Vector2D> {
 
     /** Build a polyhedrons set representing the whole real line.
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      */
-    public PolyhedronsSet(final double tolerance) {
-        super(tolerance);
+    public PolyhedronsSet(final DoublePrecisionContext precision) {
+        super(precision);
     }
 
     /** Build a polyhedrons set from a BSP tree.
@@ -67,10 +68,10 @@ public class PolyhedronsSet extends AbstractRegion<Vector3D, Vector2D> {
      * use only. The caller does have the responsibility to provided correct arguments.
      * </p>
      * @param tree inside/outside BSP tree representing the region
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      */
-    public PolyhedronsSet(final BSPTree<Vector3D> tree, final double tolerance) {
-        super(tree, tolerance);
+    public PolyhedronsSet(final BSPTree<Vector3D> tree, final DoublePrecisionContext precision) {
+        super(tree, precision);
     }
 
     /** Build a polyhedrons set from a Boundary REPresentation (B-rep) specified by sub-hyperplanes.
@@ -91,11 +92,11 @@ public class PolyhedronsSet extends AbstractRegion<Vector3D, Vector2D> {
      * space.</p>
      * @param boundary collection of boundary elements, as a
      * collection of {@link SubHyperplane SubHyperplane} objects
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      */
     public PolyhedronsSet(final Collection<SubHyperplane<Vector3D>> boundary,
-                          final double tolerance) {
-        super(boundary, tolerance);
+                          final DoublePrecisionContext precision) {
+        super(boundary, precision);
     }
 
     /** Build a polyhedrons set from a Boundary REPresentation (B-rep) specified by connected vertices.
@@ -112,12 +113,12 @@ public class PolyhedronsSet extends AbstractRegion<Vector3D, Vector2D> {
      * </p>
      * @param vertices list of polyhedrons set vertices
      * @param facets list of facets, as vertices indices in the vertices list
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      * @exception IllegalArgumentException if some basic sanity checks fail
      */
     public PolyhedronsSet(final List<Vector3D> vertices, final List<int[]> facets,
-                          final double tolerance) {
-        super(buildBoundary(vertices, facets, tolerance), tolerance);
+                          final DoublePrecisionContext precision) {
+        super(buildBoundary(vertices, facets, precision), precision);
     }
 
     /** Build a parallellepipedic box.
@@ -127,13 +128,13 @@ public class PolyhedronsSet extends AbstractRegion<Vector3D, Vector2D> {
      * @param yMax high bound along the y direction
      * @param zMin low bound along the z direction
      * @param zMax high bound along the z direction
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      */
     public PolyhedronsSet(final double xMin, final double xMax,
                           final double yMin, final double yMax,
                           final double zMin, final double zMax,
-                          final double tolerance) {
-        super(buildBoundary(xMin, xMax, yMin, yMax, zMin, zMax, tolerance), tolerance);
+                          final DoublePrecisionContext precision) {
+        super(buildBoundary(xMin, xMax, yMin, yMax, zMin, zMax, precision), precision);
     }
 
     /** Build a parallellepipedic box boundary.
@@ -143,23 +144,23 @@ public class PolyhedronsSet extends AbstractRegion<Vector3D, Vector2D> {
      * @param yMax high bound along the y direction
      * @param zMin low bound along the z direction
      * @param zMax high bound along the z direction
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      * @return boundary tree
      */
     private static BSPTree<Vector3D> buildBoundary(final double xMin, final double xMax,
                                                       final double yMin, final double yMax,
                                                       final double zMin, final double zMax,
-                                                      final double tolerance) {
-        if ((xMin >= xMax - tolerance) || (yMin >= yMax - tolerance) || (zMin >= zMax - tolerance)) {
+                                                      final DoublePrecisionContext precision) {
+        if (precision.areEqual(xMin, xMax) || precision.areEqual(yMin, yMax) || precision.areEqual(zMin, zMax)) {
             // too thin box, build an empty polygons set
             return new BSPTree<>(Boolean.FALSE);
         }
-        final Plane pxMin = new Plane(Vector3D.of(xMin, 0,    0),   Vector3D.MINUS_X, tolerance);
-        final Plane pxMax = new Plane(Vector3D.of(xMax, 0,    0),   Vector3D.PLUS_X,  tolerance);
-        final Plane pyMin = new Plane(Vector3D.of(0,    yMin, 0),   Vector3D.MINUS_Y, tolerance);
-        final Plane pyMax = new Plane(Vector3D.of(0,    yMax, 0),   Vector3D.PLUS_Y,  tolerance);
-        final Plane pzMin = new Plane(Vector3D.of(0,    0,   zMin), Vector3D.MINUS_Z, tolerance);
-        final Plane pzMax = new Plane(Vector3D.of(0,    0,   zMax), Vector3D.PLUS_Z,  tolerance);
+        final Plane pxMin = new Plane(Vector3D.of(xMin, 0,    0),   Vector3D.MINUS_X, precision);
+        final Plane pxMax = new Plane(Vector3D.of(xMax, 0,    0),   Vector3D.PLUS_X,  precision);
+        final Plane pyMin = new Plane(Vector3D.of(0,    yMin, 0),   Vector3D.MINUS_Y, precision);
+        final Plane pyMax = new Plane(Vector3D.of(0,    yMax, 0),   Vector3D.PLUS_Y,  precision);
+        final Plane pzMin = new Plane(Vector3D.of(0,    0,   zMin), Vector3D.MINUS_Z, precision);
+        final Plane pzMax = new Plane(Vector3D.of(0,    0,   zMax), Vector3D.PLUS_Z,  precision);
         final Region<Vector3D> boundary =
         new RegionFactory<Vector3D>().buildConvex(pxMin, pxMax, pyMin, pyMax, pzMin, pzMax);
         return boundary.getTree(false);
@@ -168,19 +169,19 @@ public class PolyhedronsSet extends AbstractRegion<Vector3D, Vector2D> {
     /** Build boundary from vertices and facets.
      * @param vertices list of polyhedrons set vertices
      * @param facets list of facets, as vertices indices in the vertices list
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      * @return boundary as a list of sub-hyperplanes
      * @exception IllegalArgumentException if some basic sanity checks fail
      */
     private static List<SubHyperplane<Vector3D>> buildBoundary(final List<Vector3D> vertices,
                                                                   final List<int[]> facets,
-                                                                  final double tolerance) {
+                                                                  final DoublePrecisionContext precision) {
 
         // check vertices distances
         for (int i = 0; i < vertices.size() - 1; ++i) {
             final Vector3D vi = vertices.get(i);
             for (int j = i + 1; j < vertices.size(); ++j) {
-                if (vi.distance(vertices.get(j)) <= tolerance) {
+                if (precision.isZero(vi.distance(vertices.get(j)))) {
                     throw new IllegalArgumentException("Vertices are too close near point " + vi);
                 }
             }
@@ -218,7 +219,7 @@ public class PolyhedronsSet extends AbstractRegion<Vector3D, Vector2D> {
 
             // define facet plane from the first 3 points
             Plane plane = new Plane(vertices.get(facet[0]), vertices.get(facet[1]), vertices.get(facet[2]),
-                                    tolerance);
+                                    precision);
 
             // check all points are in the plane
             final Vector2D[] two2Points = new Vector2D[facet.length];
@@ -231,7 +232,7 @@ public class PolyhedronsSet extends AbstractRegion<Vector3D, Vector2D> {
             }
 
             // create the polygonal facet
-            boundary.add(new SubPlane(plane, new PolygonsSet(tolerance, two2Points)));
+            boundary.add(new SubPlane(plane, new PolygonsSet(precision, two2Points)));
 
         }
 
@@ -328,7 +329,7 @@ public class PolyhedronsSet extends AbstractRegion<Vector3D, Vector2D> {
     /** {@inheritDoc} */
     @Override
     public PolyhedronsSet buildNew(final BSPTree<Vector3D> tree) {
-        return new PolyhedronsSet(tree, getTolerance());
+        return new PolyhedronsSet(tree, getPrecision());
     }
 
     /** {@inheritDoc} */
@@ -494,7 +495,7 @@ public class PolyhedronsSet extends AbstractRegion<Vector3D, Vector2D> {
 
         // establish search order
         final double offset = plane.getOffset(point);
-        final boolean in    = Math.abs(offset) < getTolerance();
+        final boolean in    = getPrecision().isZero(Math.abs(offset));
         final BSPTree<Vector3D> near;
         final BSPTree<Vector3D> far;
         if (offset < 0) {
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubLine.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubLine.java
index 823b6a7..adb0194 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubLine.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubLine.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.commons.geometry.core.partitioning.Region.Location;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.oned.Interval;
 import org.apache.commons.geometry.euclidean.oned.IntervalsSet;
 import org.apache.commons.geometry.euclidean.oned.Vector1D;
@@ -46,12 +47,12 @@ public class SubLine {
     /** Create a sub-line from two endpoints.
      * @param start start point
      * @param end end point
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      * @exception IllegalArgumentException if the points are equal
      */
-    public SubLine(final Vector3D start, final Vector3D end, final double tolerance)
+    public SubLine(final Vector3D start, final Vector3D end, final DoublePrecisionContext precision)
         throws IllegalArgumentException {
-        this(new Line(start, end, tolerance), buildIntervalSet(start, end, tolerance));
+        this(new Line(start, end, precision), buildIntervalSet(start, end, precision));
     }
 
     /** Create a sub-line from a segment.
@@ -60,7 +61,7 @@ public class SubLine {
      */
     public SubLine(final Segment segment) {
         this(segment.getLine(),
-             buildIntervalSet(segment.getStart(), segment.getEnd(), segment.getLine().getTolerance()));
+             buildIntervalSet(segment.getStart(), segment.getEnd(), segment.getLine().getPrecision()));
     }
 
     /** Get the endpoints of the sub-line.
@@ -132,15 +133,15 @@ public class SubLine {
      * @param start start point
      * @param end end point
      * @return an interval set
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      * @exception IllegalArgumentException if the points are equal
      */
-    private static IntervalsSet buildIntervalSet(final Vector3D start, final Vector3D end, final double tolerance)
+    private static IntervalsSet buildIntervalSet(final Vector3D start, final Vector3D end, final DoublePrecisionContext precision)
         throws IllegalArgumentException {
-        final Line line = new Line(start, end, tolerance);
+        final Line line = new Line(start, end, precision);
         return new IntervalsSet(line.toSubSpace(start).getX(),
                                 line.toSubSpace(end).getX(),
-                                tolerance);
+                                precision);
     }
 
 }
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubPlane.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubPlane.java
index 485f514..da6d154 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubPlane.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubPlane.java
@@ -21,9 +21,10 @@ import org.apache.commons.geometry.core.partitioning.BSPTree;
 import org.apache.commons.geometry.core.partitioning.Hyperplane;
 import org.apache.commons.geometry.core.partitioning.Region;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.oned.Vector1D;
-import org.apache.commons.geometry.euclidean.twod.Vector2D;
 import org.apache.commons.geometry.euclidean.twod.PolygonsSet;
+import org.apache.commons.geometry.euclidean.twod.Vector2D;
 
 /** This class represents a sub-hyperplane for {@link Plane}.
  */
@@ -57,14 +58,16 @@ public class SubPlane extends AbstractSubHyperplane<Vector3D, Vector2D> {
         final Plane otherPlane = (Plane) hyperplane;
         final Plane thisPlane  = (Plane) getHyperplane();
         final Line  inter      = otherPlane.intersection(thisPlane);
-        final double tolerance = thisPlane.getTolerance();
+        final DoublePrecisionContext precision = thisPlane.getPrecision();
 
         if (inter == null) {
             // the hyperplanes are parallel
             final double global = otherPlane.getOffset(thisPlane);
-            if (global < -tolerance) {
+            final int comparison = precision.compare(global, 0.0);
+
+            if (comparison < 0) {
                 return new SplitSubHyperplane<>(null, this);
-            } else if (global > tolerance) {
+            } else if (comparison > 0) {
                 return new SplitSubHyperplane<>(this, null);
             } else {
                 return new SplitSubHyperplane<>(null, null);
@@ -81,9 +84,9 @@ public class SubPlane extends AbstractSubHyperplane<Vector3D, Vector2D> {
             q           = tmp;
         }
         final SubHyperplane<Vector2D> l2DMinus =
-            new org.apache.commons.geometry.euclidean.twod.Line(p, q, tolerance).wholeHyperplane();
+            new org.apache.commons.geometry.euclidean.twod.Line(p, q, precision).wholeHyperplane();
         final SubHyperplane<Vector2D> l2DPlus =
-            new org.apache.commons.geometry.euclidean.twod.Line(q, p, tolerance).wholeHyperplane();
+            new org.apache.commons.geometry.euclidean.twod.Line(q, p, precision).wholeHyperplane();
 
         final BSPTree<Vector2D> splitTree = getRemainingRegion().getTree(false).split(l2DMinus);
         final BSPTree<Vector2D> plusTree  = getRemainingRegion().isEmpty(splitTree.getPlus()) ?
@@ -96,8 +99,8 @@ public class SubPlane extends AbstractSubHyperplane<Vector3D, Vector2D> {
                                                    new BSPTree<>(l2DMinus, new BSPTree<Vector2D>(Boolean.FALSE),
                                                                             splitTree.getMinus(), null);
 
-        return new SplitSubHyperplane<>(new SubPlane(thisPlane.copySelf(), new PolygonsSet(plusTree, tolerance)),
-                                                   new SubPlane(thisPlane.copySelf(), new PolygonsSet(minusTree, tolerance)));
+        return new SplitSubHyperplane<>(new SubPlane(thisPlane.copySelf(), new PolygonsSet(plusTree, precision)),
+                                                   new SubPlane(thisPlane.copySelf(), new PolygonsSet(minusTree, precision)));
 
     }
 
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Line.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Line.java
index 357d6ee..c0bc87e 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Line.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Line.java
@@ -20,6 +20,7 @@ import org.apache.commons.geometry.core.partitioning.Embedding;
 import org.apache.commons.geometry.core.partitioning.Hyperplane;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
 import org.apache.commons.geometry.core.partitioning.Transform;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.oned.IntervalsSet;
 import org.apache.commons.geometry.euclidean.oned.OrientedPoint;
 import org.apache.commons.geometry.euclidean.oned.Vector1D;
@@ -63,8 +64,8 @@ public class Line implements Hyperplane<Vector2D>, Embedding<Vector2D, Vector1D>
     /** Offset of the frame origin. */
     private double originOffset;
 
-    /** Tolerance below which points are considered identical. */
-    private final double tolerance;
+    /** Precision context used to compare floating point numbers. */
+    private final DoublePrecisionContext precision;
 
     /** Reverse line. */
     private Line reverse;
@@ -73,21 +74,21 @@ public class Line implements Hyperplane<Vector2D>, Embedding<Vector2D, Vector1D>
      * <p>The line is oriented from p1 to p2</p>
      * @param p1 first point
      * @param p2 second point
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      */
-    public Line(final Vector2D p1, final Vector2D p2, final double tolerance) {
+    public Line(final Vector2D p1, final Vector2D p2, final DoublePrecisionContext precision) {
         reset(p1, p2);
-        this.tolerance = tolerance;
+        this.precision = precision;
     }
 
     /** Build a line from a point and an angle.
      * @param p point belonging to the line
      * @param angle angle of the line with respect to abscissa axis
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      */
-    public Line(final Vector2D p, final double angle, final double tolerance) {
+    public Line(final Vector2D p, final double angle, final DoublePrecisionContext precision) {
         reset(p, angle);
-        this.tolerance = tolerance;
+        this.precision = precision;
     }
 
     /** Build a line from its internal characteristics.
@@ -95,15 +96,15 @@ public class Line implements Hyperplane<Vector2D>, Embedding<Vector2D, Vector1D>
      * @param cos cosine of the angle
      * @param sin sine of the angle
      * @param originOffset offset of the origin
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      */
     private Line(final double angle, final double cos, final double sin,
-                 final double originOffset, final double tolerance) {
+                 final double originOffset, final DoublePrecisionContext precision) {
         this.angle        = angle;
         this.cos          = cos;
         this.sin          = sin;
         this.originOffset = originOffset;
-        this.tolerance    = tolerance;
+        this.precision    = precision;
         this.reverse      = null;
     }
 
@@ -117,7 +118,7 @@ public class Line implements Hyperplane<Vector2D>, Embedding<Vector2D, Vector1D>
         cos          = line.cos;
         sin          = line.sin;
         originOffset = line.originOffset;
-        tolerance    = line.tolerance;
+        precision    = line.precision;
         reverse      = null;
     }
 
@@ -203,7 +204,7 @@ public class Line implements Hyperplane<Vector2D>, Embedding<Vector2D, Vector1D>
     public Line getReverse() {
         if (reverse == null) {
             reverse = new Line((angle < Math.PI) ? (angle + Math.PI) : (angle - Math.PI),
-                               -cos, -sin, -originOffset, tolerance);
+                               -cos, -sin, -originOffset, precision);
             reverse.reverse = this;
         }
         return reverse;
@@ -230,7 +231,7 @@ public class Line implements Hyperplane<Vector2D>, Embedding<Vector2D, Vector1D>
      */
     public Vector2D intersection(final Line other) {
         final double d = LinearCombination.value(sin, other.cos, -other.sin, cos);
-        if (Math.abs(d) < tolerance) {
+        if (precision.isZero(d)) {
             return null;
         }
         return Vector2D.of(LinearCombination.value(cos, other.originOffset, -other.cos, originOffset) / d,
@@ -245,14 +246,14 @@ public class Line implements Hyperplane<Vector2D>, Embedding<Vector2D, Vector1D>
 
     /** {@inheritDoc} */
     @Override
-    public double getTolerance() {
-        return tolerance;
+    public DoublePrecisionContext getPrecision() {
+        return precision;
     }
 
     /** {@inheritDoc} */
     @Override
     public SubLine wholeHyperplane() {
-        return new SubLine(this, new IntervalsSet(tolerance));
+        return new SubLine(this, new IntervalsSet(precision));
     }
 
     /** Build a region covering the whole space.
@@ -261,7 +262,7 @@ public class Line implements Hyperplane<Vector2D>, Embedding<Vector2D, Vector1D>
      */
     @Override
     public PolygonsSet wholeSpace() {
-        return new PolygonsSet(tolerance);
+        return new PolygonsSet(precision);
     }
 
     /** Get the offset (oriented distance) of a parallel line.
@@ -310,7 +311,7 @@ public class Line implements Hyperplane<Vector2D>, Embedding<Vector2D, Vector1D>
      * @return true if p belongs to the line
      */
     public boolean contains(final Vector2D p) {
-        return Math.abs(getOffset(p)) < tolerance;
+        return precision.isZero(getOffset(p));
     }
 
     /** Compute the distance between the instance and a point.
@@ -331,7 +332,7 @@ public class Line implements Hyperplane<Vector2D>, Embedding<Vector2D, Vector1D>
      * (they can have either the same or opposite orientations)
      */
     public boolean isParallelTo(final Line line) {
-        return Math.abs(LinearCombination.value(sin, line.cos, -cos, line.sin)) < tolerance;
+        return precision.isZero(LinearCombination.value(sin, line.cos, -cos, line.sin));
     }
 
     /** Translate the line to force it passing by a point.
@@ -482,7 +483,7 @@ public class Line implements Hyperplane<Vector2D>, Embedding<Vector2D, Vector1D>
             final double inv     = 1.0 / Math.sqrt(rSin * rSin + rCos * rCos);
             return new Line(Math.PI + Math.atan2(-rSin, -rCos),
                             inv * rCos, inv * rSin,
-                            inv * rOffset, line.tolerance);
+                            inv * rOffset, line.precision);
         }
 
         /** {@inheritDoc} */
@@ -495,7 +496,7 @@ public class Line implements Hyperplane<Vector2D>, Embedding<Vector2D, Vector1D>
             final Line transformedLine = (Line) transformed;
             final Vector1D newLoc =
                 transformedLine.toSubSpace(apply(originalLine.toSpace(op.getLocation())));
-            return new OrientedPoint(newLoc, op.isDirect(), originalLine.tolerance).wholeHyperplane();
+            return new OrientedPoint(newLoc, op.isDirect(), originalLine.precision).wholeHyperplane();
         }
 
     }
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/NestedLoops.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/NestedLoops.java
index 82db8d8..6f15bd9 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/NestedLoops.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/NestedLoops.java
@@ -23,6 +23,7 @@ import java.util.List;
 import org.apache.commons.geometry.core.partitioning.Region;
 import org.apache.commons.geometry.core.partitioning.RegionFactory;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.oned.IntervalsSet;
 
 /** This class represent a tree of nested 2D boundary loops.
@@ -54,28 +55,28 @@ class NestedLoops {
     /** Indicator for original loop orientation. */
     private boolean originalIsClockwise;
 
-    /** Tolerance below which points are considered identical. */
-    private final double tolerance;
+    /** Precision context used to compare floating point numbers. */
+    private final DoublePrecisionContext precision;
 
     /** Simple Constructor.
      * <p>Build an empty tree of nested loops. This instance will become
      * the root node of a complete tree, it is not associated with any
      * loop by itself, the outermost loops are in the root tree child
      * nodes.</p>
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      */
-    NestedLoops(final double tolerance) {
+    NestedLoops(final DoublePrecisionContext precision) {
         this.surrounded = new ArrayList<>();
-        this.tolerance  = tolerance;
+        this.precision  = precision;
     }
 
     /** Constructor.
      * <p>Build a tree node with neither parent nor children</p>
      * @param loop boundary loop (will be reversed in place if needed)
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      * @exception IllegalArgumentException if an outline has an open boundary loop
      */
-    private NestedLoops(final Vector2D[] loop, final double tolerance)
+    private NestedLoops(final Vector2D[] loop, DoublePrecisionContext precision)
         throws IllegalArgumentException {
 
         if (loop[0] == null) {
@@ -84,7 +85,7 @@ class NestedLoops {
 
         this.loop       = loop;
         this.surrounded = new ArrayList<>();
-        this.tolerance  = tolerance;
+        this.precision  = precision;
 
         // build the polygon defined by the loop
         final ArrayList<SubHyperplane<Vector2D>> edges = new ArrayList<>();
@@ -92,14 +93,14 @@ class NestedLoops {
         for (int i = 0; i < loop.length; ++i) {
             final Vector2D previous = current;
             current = loop[i];
-            final Line   line   = new Line(previous, current, tolerance);
+            final Line   line   = new Line(previous, current, precision);
             final IntervalsSet region =
                 new IntervalsSet(line.toSubSpace(previous).getX(),
                                  line.toSubSpace(current).getX(),
-                                 tolerance);
+                                 precision);
             edges.add(new SubLine(line, region));
         }
-        polygon = new PolygonsSet(edges, tolerance);
+        polygon = new PolygonsSet(edges, precision);
 
         // ensure the polygon encloses a finite region of the plane
         if (Double.isInfinite(polygon.getSize())) {
@@ -117,7 +118,7 @@ class NestedLoops {
      * boundary loops or open boundary loops
      */
     public void add(final Vector2D[] bLoop) {
-        add(new NestedLoops(bLoop, tolerance));
+        add(new NestedLoops(bLoop, precision));
     }
 
     /** Add a loop in a tree.
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/PolygonsSet.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/PolygonsSet.java
index a5cea50..119e456 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/PolygonsSet.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/PolygonsSet.java
@@ -28,6 +28,7 @@ import org.apache.commons.geometry.core.partitioning.BoundaryAttribute;
 import org.apache.commons.geometry.core.partitioning.Hyperplane;
 import org.apache.commons.geometry.core.partitioning.Side;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.oned.Interval;
 import org.apache.commons.geometry.euclidean.oned.IntervalsSet;
 import org.apache.commons.geometry.euclidean.oned.Vector1D;
@@ -41,10 +42,10 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
     private Vector2D[][] vertices;
 
     /** Build a polygons set representing the whole plane.
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      */
-    public PolygonsSet(final double tolerance) {
-        super(tolerance);
+    public PolygonsSet(final DoublePrecisionContext precision) {
+        super(precision);
     }
 
     /** Build a polygons set from a BSP tree.
@@ -65,10 +66,10 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
      * use only. The caller does have the responsibility to provided correct arguments.
      * </p>
      * @param tree inside/outside BSP tree representing the region
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      */
-    public PolygonsSet(final BSPTree<Vector2D> tree, final double tolerance) {
-        super(tree, tolerance);
+    public PolygonsSet(final BSPTree<Vector2D> tree, final DoublePrecisionContext precision) {
+        super(tree, precision);
     }
 
     /** Build a polygons set from a Boundary REPresentation (B-rep).
@@ -90,10 +91,10 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
      * space.</p>
      * @param boundary collection of boundary elements, as a
      * collection of {@link SubHyperplane SubHyperplane} objects
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      */
-    public PolygonsSet(final Collection<SubHyperplane<Vector2D>> boundary, final double tolerance) {
-        super(boundary, tolerance);
+    public PolygonsSet(final Collection<SubHyperplane<Vector2D>> boundary, final DoublePrecisionContext precision) {
+        super(boundary, precision);
     }
 
     /** Build a parallellepipedic box.
@@ -101,12 +102,12 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
      * @param xMax high bound along the x direction
      * @param yMin low bound along the y direction
      * @param yMax high bound along the y direction
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      */
     public PolygonsSet(final double xMin, final double xMax,
                        final double yMin, final double yMax,
-                       final double tolerance) {
-        super(boxBoundary(xMin, xMax, yMin, yMax, tolerance), tolerance);
+                       final DoublePrecisionContext precision) {
+        super(boxBoundary(xMin, xMax, yMin, yMax, precision), precision);
     }
 
     /** Build a polygon from a simple list of vertices.
@@ -117,7 +118,7 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
      * <p>This constructor does not handle polygons with a boundary
      * forming several disconnected paths (such as polygons with holes).</p>
      * <p>For cases where this simple constructor applies, it is expected to
-     * be numerically more robust than the {@link #PolygonsSet(Collection,double) general
+     * be numerically more robust than the {@link #PolygonsSet(Collection, DoublePrecisionContext) general
      * constructor} using {@link SubHyperplane subhyperplanes}.</p>
      * <p>If the list is empty, the region will represent the whole
      * space.</p>
@@ -135,12 +136,11 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
      * most accurate detail needed is a good value for the {@code hyperplaneThickness}
      * parameter.
      * </p>
-     * @param hyperplaneThickness tolerance below which points are considered to
-     * belong to the hyperplane (which is therefore more a slab)
+     * @param precision precision context used to compare floating point values
      * @param vertices vertices of the simple loop boundary
      */
-    public PolygonsSet(final double hyperplaneThickness, final Vector2D ... vertices) {
-        super(verticesToTree(hyperplaneThickness, vertices), hyperplaneThickness);
+    public PolygonsSet(final DoublePrecisionContext precision, final Vector2D ... vertices) {
+        super(verticesToTree(precision, vertices), precision);
     }
 
     /** Create a list of hyperplanes representing the boundary of a box.
@@ -148,13 +148,13 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
      * @param xMax high bound along the x direction
      * @param yMin low bound along the y direction
      * @param yMax high bound along the y direction
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      * @return boundary of the box
      */
     private static Line[] boxBoundary(final double xMin, final double xMax,
                                       final double yMin, final double yMax,
-                                      final double tolerance) {
-        if ((xMin >= xMax - tolerance) || (yMin >= yMax - tolerance)) {
+                                      final DoublePrecisionContext precision) {
+        if (precision.areEqual(xMin, xMax) || precision.areEqual(yMin, yMax)) {
             // too thin box, build an empty polygons set
             return null;
         }
@@ -163,10 +163,10 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
         final Vector2D maxMin = Vector2D.of(xMax, yMin);
         final Vector2D maxMax = Vector2D.of(xMax, yMax);
         return new Line[] {
-            new Line(minMin, maxMin, tolerance),
-            new Line(maxMin, maxMax, tolerance),
-            new Line(maxMax, minMax, tolerance),
-            new Line(minMax, minMin, tolerance)
+            new Line(minMin, maxMin, precision),
+            new Line(maxMin, maxMax, precision),
+            new Line(maxMax, minMax, precision),
+            new Line(minMax, minMin, precision)
         };
     }
 
@@ -180,12 +180,11 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
      * <p>For cases where this simple constructor applies, it is expected to
      * be numerically more robust than the {@link #PolygonsSet(Collection,double) general
      * constructor} using {@link SubHyperplane subhyperplanes}.</p>
-     * @param hyperplaneThickness tolerance below which points are consider to
-     * belong to the hyperplane (which is therefore more a slab)
+     * @param precision precision context used to compare floating point values
      * @param vertices vertices of the simple loop boundary
      * @return the BSP tree of the input vertices
      */
-    private static BSPTree<Vector2D> verticesToTree(final double hyperplaneThickness,
+    private static BSPTree<Vector2D> verticesToTree(final DoublePrecisionContext precision,
                                                        final Vector2D ... vertices) {
 
         final int n = vertices.length;
@@ -213,7 +212,7 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
             // with the current one
             Line line = start.sharedLineWith(end);
             if (line == null) {
-                line = new Line(start.getLocation(), end.getLocation(), hyperplaneThickness);
+                line = new Line(start.getLocation(), end.getLocation(), precision);
             }
 
             // create the edge and store it
@@ -222,7 +221,7 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
             // check if another vertex also happens to be on this line
             for (final Vertex vertex : vArray) {
                 if (vertex != start && vertex != end &&
-                    Math.abs(line.getOffset(vertex.getLocation())) <= hyperplaneThickness) {
+                    precision.isZero(line.getOffset(vertex.getLocation()))) {
                     vertex.bindWith(line);
                 }
             }
@@ -231,21 +230,20 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
 
         // build the tree top-down
         final BSPTree<Vector2D> tree = new BSPTree<>();
-        insertEdges(hyperplaneThickness, tree, edges);
+        insertEdges(precision, tree, edges);
 
         return tree;
 
     }
 
     /** Recursively build a tree by inserting cut sub-hyperplanes.
-     * @param hyperplaneThickness tolerance below which points are consider to
-     * belong to the hyperplane (which is therefore more a slab)
+     * @param precision precision context used to compare floating point values
      * @param node current tree node (it is a leaf node at the beginning
      * of the call)
      * @param edges list of edges to insert in the cell defined by this node
      * (excluding edges not belonging to the cell defined by this node)
      */
-    private static void insertEdges(final double hyperplaneThickness,
+    private static void insertEdges(final DoublePrecisionContext precision,
                                     final BSPTree<Vector2D> node,
                                     final List<Edge> edges) {
 
@@ -285,9 +283,9 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
             if (edge != inserted) {
                 final double startOffset = inserted.getLine().getOffset(edge.getStart().getLocation());
                 final double endOffset   = inserted.getLine().getOffset(edge.getEnd().getLocation());
-                Side startSide = (Math.abs(startOffset) <= hyperplaneThickness) ?
+                Side startSide = precision.isZero(Math.abs(startOffset)) ?
                                  Side.HYPER : ((startOffset < 0) ? Side.MINUS : Side.PLUS);
-                Side endSide   = (Math.abs(endOffset) <= hyperplaneThickness) ?
+                Side endSide   = precision.isZero(endOffset) ?
                                  Side.HYPER : ((endOffset < 0) ? Side.MINUS : Side.PLUS);
                 switch (startSide) {
                     case PLUS:
@@ -323,12 +321,12 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
 
         // recurse through lower levels
         if (!plusList.isEmpty()) {
-            insertEdges(hyperplaneThickness, node.getPlus(),  plusList);
+            insertEdges(precision, node.getPlus(),  plusList);
         } else {
             node.getPlus().setAttribute(Boolean.FALSE);
         }
         if (!minusList.isEmpty()) {
-            insertEdges(hyperplaneThickness, node.getMinus(), minusList);
+            insertEdges(precision, node.getMinus(), minusList);
         } else {
             node.getMinus().setAttribute(Boolean.TRUE);
         }
@@ -528,7 +526,7 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
     /** {@inheritDoc} */
     @Override
     public PolygonsSet buildNew(final BSPTree<Vector2D> tree) {
-        return new PolygonsSet(tree, getTolerance());
+        return new PolygonsSet(tree, getPrecision());
     }
 
     /** {@inheritDoc} */
@@ -616,7 +614,7 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
             } else {
 
                 // build the unconnected segments
-                final SegmentsBuilder visitor = new SegmentsBuilder(getTolerance());
+                final SegmentsBuilder visitor = new SegmentsBuilder(getPrecision());
                 getTree(true).visit(visitor);
                 final List<ConnectableSegment> segments = visitor.getSegments();
 
@@ -783,7 +781,7 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
                         }
                     }
                 }
-                if (min <= getTolerance()) {
+                if (getPrecision().isZero(min)) {
                     // connect the two segments
                     segment.setNext(selectedNext);
                     selectedNext.setPrevious(segment);
@@ -989,17 +987,17 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
     /** Visitor building segments. */
     private static class SegmentsBuilder implements BSPTreeVisitor<Vector2D> {
 
-        /** Tolerance for close nodes connection. */
-        private final double tolerance;
+        /** Object used to determine floating point equality */
+        private final DoublePrecisionContext precision;
 
         /** Built segments. */
         private final List<ConnectableSegment> segments;
 
         /** Simple constructor.
-         * @param tolerance tolerance for close nodes connection
+         * @param precision precision context used to compare floating point values
          */
-        SegmentsBuilder(final double tolerance) {
-            this.tolerance = tolerance;
+        SegmentsBuilder(final DoublePrecisionContext precision) {
+            this.precision = precision;
             this.segments  = new ArrayList<>();
         }
 
@@ -1084,7 +1082,7 @@ public class PolygonsSet extends AbstractRegion<Vector2D, Vector1D> {
                     }
                 }
 
-                if (min <= tolerance) {
+                if (precision.isZero(min)) {
                     return selected;
                 }
             }
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/SubLine.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/SubLine.java
index acf0ea3..f527b98 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/SubLine.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/SubLine.java
@@ -24,6 +24,7 @@ import org.apache.commons.geometry.core.partitioning.BSPTree;
 import org.apache.commons.geometry.core.partitioning.Hyperplane;
 import org.apache.commons.geometry.core.partitioning.Region;
 import org.apache.commons.geometry.core.partitioning.Region.Location;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
 import org.apache.commons.geometry.euclidean.oned.Interval;
 import org.apache.commons.geometry.euclidean.oned.IntervalsSet;
@@ -46,10 +47,10 @@ public class SubLine extends AbstractSubHyperplane<Vector2D, Vector1D> {
     /** Create a sub-line from two endpoints.
      * @param start start point
      * @param end end point
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      */
-    public SubLine(final Vector2D start, final Vector2D end, final double tolerance) {
-        super(new Line(start, end, tolerance), buildIntervalSet(start, end, tolerance));
+    public SubLine(final Vector2D start, final Vector2D end, final DoublePrecisionContext precision) {
+        super(new Line(start, end, precision), buildIntervalSet(start, end, precision));
     }
 
     /** Create a sub-line from a segment.
@@ -57,7 +58,7 @@ public class SubLine extends AbstractSubHyperplane<Vector2D, Vector1D> {
      */
     public SubLine(final Segment segment) {
         super(segment.getLine(),
-              buildIntervalSet(segment.getStart(), segment.getEnd(), segment.getLine().getTolerance()));
+              buildIntervalSet(segment.getStart(), segment.getEnd(), segment.getLine().getPrecision()));
     }
 
     /** Get the endpoints of the sub-line.
@@ -133,14 +134,14 @@ public class SubLine extends AbstractSubHyperplane<Vector2D, Vector1D> {
     /** Build an interval set from two points.
      * @param start start point
      * @param end end point
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point values
      * @return an interval set
      */
-    private static IntervalsSet buildIntervalSet(final Vector2D start, final Vector2D end, final double tolerance) {
-        final Line line = new Line(start, end, tolerance);
+    private static IntervalsSet buildIntervalSet(final Vector2D start, final Vector2D end, final DoublePrecisionContext precision) {
+        final Line line = new Line(start, end, precision);
         return new IntervalsSet(line.toSubSpace(start).getX(),
                                 line.toSubSpace(end).getX(),
-                                tolerance);
+                                precision);
     }
 
     /** {@inheritDoc} */
@@ -157,14 +158,16 @@ public class SubLine extends AbstractSubHyperplane<Vector2D, Vector1D> {
         final Line    thisLine  = (Line) getHyperplane();
         final Line    otherLine = (Line) hyperplane;
         final Vector2D crossing = thisLine.intersection(otherLine);
-        final double tolerance  = thisLine.getTolerance();
+        final DoublePrecisionContext precision = thisLine.getPrecision();
 
         if (crossing == null) {
             // the lines are parallel
             final double global = otherLine.getOffset(thisLine);
-            if (global < -tolerance) {
+            final int comparison = precision.compare(global, 0.0);
+
+            if (comparison < 0) {
                 return new SplitSubHyperplane<>(null, this);
-            } else if (global > tolerance) {
+            } else if (comparison > 0) {
                 return new SplitSubHyperplane<>(this, null);
             } else {
                 return new SplitSubHyperplane<>(null, null);
@@ -175,9 +178,9 @@ public class SubLine extends AbstractSubHyperplane<Vector2D, Vector1D> {
         final boolean direct = Math.sin(thisLine.getAngle() - otherLine.getAngle()) < 0;
         final Vector1D x      = thisLine.toSubSpace(crossing);
         final SubHyperplane<Vector1D> subPlus  =
-                new OrientedPoint(x, !direct, tolerance).wholeHyperplane();
+                new OrientedPoint(x, !direct, precision).wholeHyperplane();
         final SubHyperplane<Vector1D> subMinus =
-                new OrientedPoint(x,  direct, tolerance).wholeHyperplane();
+                new OrientedPoint(x,  direct, precision).wholeHyperplane();
 
         final BSPTree<Vector1D> splitTree = getRemainingRegion().getTree(false).split(subMinus);
         final BSPTree<Vector1D> plusTree  = getRemainingRegion().isEmpty(splitTree.getPlus()) ?
@@ -188,8 +191,8 @@ public class SubLine extends AbstractSubHyperplane<Vector2D, Vector1D> {
                                                new BSPTree<Vector1D>(Boolean.FALSE) :
                                                new BSPTree<>(subMinus, new BSPTree<Vector1D>(Boolean.FALSE),
                                                                         splitTree.getMinus(), null);
-        return new SplitSubHyperplane<>(new SubLine(thisLine.copySelf(), new IntervalsSet(plusTree, tolerance)),
-                                                   new SubLine(thisLine.copySelf(), new IntervalsSet(minusTree, tolerance)));
+        return new SplitSubHyperplane<>(new SubLine(thisLine.copySelf(), new IntervalsSet(plusTree, precision)),
+                                                   new SubLine(thisLine.copySelf(), new IntervalsSet(minusTree, precision)));
 
     }
 
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/core/partitioning/CharacterizationTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/core/partitioning/CharacterizationTest.java
index 00ab8ef..5f13fb4 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/core/partitioning/CharacterizationTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/core/partitioning/CharacterizationTest.java
@@ -18,6 +18,8 @@ package org.apache.commons.geometry.core.partitioning;
 
 import java.util.Iterator;
 
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.oned.IntervalsSet;
 import org.apache.commons.geometry.euclidean.twod.Line;
 import org.apache.commons.geometry.euclidean.twod.PolygonsSet;
@@ -32,7 +34,9 @@ import org.junit.Test;
  */
 public class CharacterizationTest {
 
-    private static final double TEST_TOLERANCE = 1e-10;
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION = new EpsilonDoublePrecisionContext(TEST_EPS);
 
     @Test
     public void testCharacterize_insideLeaf() {
@@ -352,7 +356,7 @@ public class CharacterizationTest {
     @Test
     public void testCharacterize_onHyperplane_box() {
         // arrange
-        PolygonsSet poly = new PolygonsSet(0, 1, 0, 1, TEST_TOLERANCE);
+        PolygonsSet poly = new PolygonsSet(0, 1, 0, 1, TEST_PRECISION);
         BSPTree<Vector2D> tree = poly.getTree(false);
 
         SubLine sub = buildSubLine(Vector2D.of(2, 0), Vector2D.of(-2, 0));
@@ -405,19 +409,19 @@ public class CharacterizationTest {
     }
 
     private Line buildLine(Vector2D p1, Vector2D p2) {
-        return new Line(p1, p2, TEST_TOLERANCE);
+        return new Line(p1, p2, TEST_PRECISION);
     }
 
     private SubLine buildSubLine(Vector2D start, Vector2D end) {
-        Line line = new Line(start, end, TEST_TOLERANCE);
+        Line line = new Line(start, end, TEST_PRECISION);
         double lower = (line.toSubSpace(start)).getX();
         double upper = (line.toSubSpace(end)).getX();
-        return new SubLine(line, new IntervalsSet(lower, upper, TEST_TOLERANCE));
+        return new SubLine(line, new IntervalsSet(lower, upper, TEST_PRECISION));
     }
 
     private void assertVectorEquals(Vector2D expected, Vector2D actual) {
         String msg = "Expected vector to equal " + expected + " but was " + actual + ";";
-        Assert.assertEquals(msg, expected.getX(), actual.getX(), TEST_TOLERANCE);
-        Assert.assertEquals(msg, expected.getY(), actual.getY(), TEST_TOLERANCE);
+        Assert.assertEquals(msg, expected.getX(), actual.getX(), TEST_EPS);
+        Assert.assertEquals(msg, expected.getY(), actual.getY(), TEST_EPS);
     }
 }
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/EuclideanTestUtils.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/EuclideanTestUtils.java
index 1225931..b79e382 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/EuclideanTestUtils.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/EuclideanTestUtils.java
@@ -16,7 +16,6 @@
  */
 package org.apache.commons.geometry.euclidean;
 
-import java.io.IOException;
 import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -27,6 +26,7 @@ import org.apache.commons.geometry.core.partitioning.Hyperplane;
 import org.apache.commons.geometry.core.partitioning.TreeBuilder;
 import org.apache.commons.geometry.core.partitioning.TreeDumper;
 import org.apache.commons.geometry.core.partitioning.TreePrinter;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.oned.IntervalsSet;
 import org.apache.commons.geometry.euclidean.oned.OrientedPoint;
 import org.apache.commons.geometry.euclidean.oned.SubOrientedPoint;
@@ -217,13 +217,13 @@ public class EuclideanTestUtils {
      * @return string representation of the region
      */
     public static String dump(final IntervalsSet intervalsSet) {
-        final TreeDumper<Vector1D> visitor = new TreeDumper<Vector1D>("IntervalsSet", intervalsSet.getTolerance()) {
+        final TreeDumper<Vector1D> visitor = new TreeDumper<Vector1D>("IntervalsSet") {
 
             /** {@inheritDoc} */
             @Override
             protected void formatHyperplane(final Hyperplane<Vector1D> hyperplane) {
                 final OrientedPoint h = (OrientedPoint) hyperplane;
-                getFormatter().format("%22.15e %b %22.15e", h.getLocation().getX(), h.isDirect(), h.getTolerance());
+                getFormatter().format("%22.15e %b", h.getLocation().getX(), h.isDirect());
             }
 
         };
@@ -238,15 +238,15 @@ public class EuclideanTestUtils {
      * @return string representation of the region
      */
     public static String dump(final PolygonsSet polygonsSet) {
-        final TreeDumper<Vector2D> visitor = new TreeDumper<Vector2D>("PolygonsSet", polygonsSet.getTolerance()) {
+        final TreeDumper<Vector2D> visitor = new TreeDumper<Vector2D>("PolygonsSet") {
 
             /** {@inheritDoc} */
             @Override
             protected void formatHyperplane(final Hyperplane<Vector2D> hyperplane) {
                 final Line h = (Line) hyperplane;
                 final Vector2D p = h.toSpace(Vector1D.ZERO);
-                getFormatter().format("%22.15e %22.15e %22.15e %22.15e",
-                                      p.getX(), p.getY(), h.getAngle(), h.getTolerance());
+                getFormatter().format("%22.15e %22.15e %22.15e",
+                                      p.getX(), p.getY(), h.getAngle());
             }
 
         };
@@ -261,17 +261,16 @@ public class EuclideanTestUtils {
      * @return string representation of the region
      */
     public static String dump(final PolyhedronsSet polyhedronsSet) {
-        final TreeDumper<Vector3D> visitor = new TreeDumper<Vector3D>("PolyhedronsSet", polyhedronsSet.getTolerance()) {
+        final TreeDumper<Vector3D> visitor = new TreeDumper<Vector3D>("PolyhedronsSet") {
 
             /** {@inheritDoc} */
             @Override
             protected void formatHyperplane(final Hyperplane<Vector3D> hyperplane) {
                 final Plane h = (Plane) hyperplane;
                 final Vector3D p = h.toSpace(Vector2D.ZERO);
-                getFormatter().format("%22.15e %22.15e %22.15e %22.15e %22.15e %22.15e %22.15e",
+                getFormatter().format("%22.15e %22.15e %22.15e %22.15e %22.15e %22.15e",
                                       p.getX(), p.getY(), p.getZ(),
-                                      h.getNormal().getX(), h.getNormal().getY(), h.getNormal().getZ(),
-                                      h.getTolerance());
+                                      h.getNormal().getX(), h.getNormal().getY(), h.getNormal().getZ());
             }
 
         };
@@ -282,72 +281,72 @@ public class EuclideanTestUtils {
     /**
      * Parse a string representation of an {@link IntervalsSet}.
      *
-     * @param s string to parse
+     * @param str string to parse
+     * @param precision precision context to use for the region
      * @return parsed region
-     * @exception IOException    if the string cannot be read
      * @exception ParseException if the string cannot be parsed
      */
-    public static IntervalsSet parseIntervalsSet(final String s)
-        throws IOException, ParseException {
-        final TreeBuilder<Vector1D> builder = new TreeBuilder<Vector1D>("IntervalsSet", s) {
+    public static IntervalsSet parseIntervalsSet(final String str, final DoublePrecisionContext precision)
+        throws ParseException {
+        final TreeBuilder<Vector1D> builder = new TreeBuilder<Vector1D>("IntervalsSet", str, precision) {
 
             /** {@inheritDoc} */
             @Override
             public OrientedPoint parseHyperplane()
-                throws IOException, ParseException {
-                return new OrientedPoint(Vector1D.of(getNumber()), getBoolean(), getNumber());
+                throws ParseException {
+                return new OrientedPoint(Vector1D.of(getNumber()), getBoolean(), getPrecision());
             }
 
         };
-        return new IntervalsSet(builder.getTree(), builder.getTolerance());
+        return new IntervalsSet(builder.getTree(), builder.getPrecision());
     }
 
     /**
      * Parse a string representation of a {@link PolygonsSet}.
      *
-     * @param s string to parse
+     * @param str string to parse
+     * @param precision precision context to use for the region
      * @return parsed region
-     * @exception IOException    if the string cannot be read
      * @exception ParseException if the string cannot be parsed
      */
-    public static PolygonsSet parsePolygonsSet(final String s)
-        throws IOException, ParseException {
-        final TreeBuilder<Vector2D> builder = new TreeBuilder<Vector2D>("PolygonsSet", s) {
+    public static PolygonsSet parsePolygonsSet(final String str, final DoublePrecisionContext precision)
+        throws ParseException {
+        final TreeBuilder<Vector2D> builder = new TreeBuilder<Vector2D>("PolygonsSet", str, precision) {
 
             /** {@inheritDoc} */
             @Override
             public Line parseHyperplane()
-                throws IOException, ParseException {
-                return new Line(Vector2D.of(getNumber(), getNumber()), getNumber(), getNumber());
+                throws ParseException {
+                return new Line(Vector2D.of(getNumber(), getNumber()), getNumber(), getPrecision());
             }
 
         };
-        return new PolygonsSet(builder.getTree(), builder.getTolerance());
+        return new PolygonsSet(builder.getTree(), builder.getPrecision());
     }
 
     /**
      * Parse a string representation of a {@link PolyhedronsSet}.
      *
-     * @param s string to parse
+     * @param str string to parse
+     * @param precision precision context to use for the region
      * @return parsed region
-     * @exception IOException    if the string cannot be read
      * @exception ParseException if the string cannot be parsed
      */
-    public static PolyhedronsSet parsePolyhedronsSet(final String s)
-        throws IOException, ParseException {
-        final TreeBuilder<Vector3D> builder = new TreeBuilder<Vector3D>("PolyhedronsSet", s) {
+    public static PolyhedronsSet parsePolyhedronsSet(final String str, final DoublePrecisionContext precision)
+        throws ParseException {
+        final TreeBuilder<Vector3D> builder = new TreeBuilder<Vector3D>("PolyhedronsSet", str, precision) {
 
             /** {@inheritDoc} */
             @Override
             public Plane parseHyperplane()
-                throws IOException, ParseException {
+                throws ParseException {
                 return new Plane(Vector3D.of(getNumber(), getNumber(), getNumber()),
                                  Vector3D.of(getNumber(), getNumber(), getNumber()),
-                                 getNumber());
+                                 getPrecision());
             }
 
         };
-        return new PolyhedronsSet(builder.getTree(), builder.getTolerance());
+        return new PolyhedronsSet(builder.getTree(), builder.getPrecision());
     }
 
     /**
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/internal/MatricesTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/internal/MatricesTest.java
index 77fa3a4..a16b721 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/internal/MatricesTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/internal/MatricesTest.java
@@ -16,14 +16,9 @@
  */
 package org.apache.commons.geometry.euclidean.internal;
 
-
-import org.apache.commons.geometry.core.Geometry;
-import org.apache.commons.geometry.euclidean.threed.Vector3D;
-import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
 import org.junit.Assert;
 import org.junit.Test;
 
-
 public class MatricesTest {
 
     private static final double EPS = 1e-12;
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/IntervalsSetTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/IntervalsSetTest.java
index a72f280..53cc2c3 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/IntervalsSetTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/IntervalsSetTest.java
@@ -24,27 +24,31 @@ import org.apache.commons.geometry.core.partitioning.BoundaryProjection;
 import org.apache.commons.geometry.core.partitioning.Region;
 import org.apache.commons.geometry.core.partitioning.RegionFactory;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
-import org.apache.commons.numbers.core.Precision;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class IntervalsSetTest {
 
-    private static final double TEST_TOLERANCE = 1e-15;
+    private static final double TEST_EPS = 1e-15;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
 
     @Test
     public void testInterval_wholeNumberLine() {
         // act
-        IntervalsSet set = new IntervalsSet(TEST_TOLERANCE);
+        IntervalsSet set = new IntervalsSet(TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
         EuclideanTestUtils.assertNegativeInfinity(set.getInf());
         EuclideanTestUtils.assertPositiveInfinity(set.getSup());
         EuclideanTestUtils.assertPositiveInfinity(set.getSize());
-        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_EPS);
 
         BSPTree<Vector1D> tree = set.getTree(true);
         Assert.assertEquals(Boolean.TRUE, tree.getAttribute());
@@ -54,7 +58,7 @@ public class IntervalsSetTest {
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(1, intervals.size());
-        assertInterval(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, intervals.get(0), TEST_TOLERANCE);
+        assertInterval(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, intervals.get(0), TEST_EPS);
 
         assertLocation(Region.Location.INSIDE, set, Double.NEGATIVE_INFINITY);
         assertLocation(Region.Location.INSIDE, set, 0.0);
@@ -64,15 +68,15 @@ public class IntervalsSetTest {
     @Test
     public void testInterval_doubleOpenInterval() {
         // act
-        IntervalsSet set = new IntervalsSet(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_TOLERANCE);
+        IntervalsSet set = new IntervalsSet(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
         EuclideanTestUtils.assertNegativeInfinity(set.getInf());
         EuclideanTestUtils.assertPositiveInfinity(set.getSup());
         EuclideanTestUtils.assertPositiveInfinity(set.getSize());
-        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_EPS);
 
         BSPTree<Vector1D> tree = set.getTree(true);
         Assert.assertEquals(Boolean.TRUE, tree.getAttribute());
@@ -82,7 +86,7 @@ public class IntervalsSetTest {
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(1, intervals.size());
-        assertInterval(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, intervals.get(0), TEST_TOLERANCE);
+        assertInterval(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, intervals.get(0), TEST_EPS);
 
         assertLocation(Region.Location.INSIDE, set, Double.NEGATIVE_INFINITY);
         assertLocation(Region.Location.INSIDE, set, 0.0);
@@ -92,19 +96,19 @@ public class IntervalsSetTest {
     @Test
     public void testInterval_openInterval_positive() {
         // act
-        IntervalsSet set = new IntervalsSet(9.0, Double.POSITIVE_INFINITY, TEST_TOLERANCE);
+        IntervalsSet set = new IntervalsSet(9.0, Double.POSITIVE_INFINITY, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
-        Assert.assertEquals(9.0, set.getInf(), TEST_TOLERANCE);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
+        Assert.assertEquals(9.0, set.getInf(), TEST_EPS);
         EuclideanTestUtils.assertPositiveInfinity(set.getSup());
         EuclideanTestUtils.assertPositiveInfinity(set.getSize());
-        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_EPS);
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(1, intervals.size());
-        assertInterval(9.0, Double.POSITIVE_INFINITY, intervals.get(0), TEST_TOLERANCE);
+        assertInterval(9.0, Double.POSITIVE_INFINITY, intervals.get(0), TEST_EPS);
 
         assertLocation(Region.Location.OUTSIDE, set, Double.NEGATIVE_INFINITY);
         assertLocation(Region.Location.OUTSIDE, set, 0.0);
@@ -117,19 +121,19 @@ public class IntervalsSetTest {
     @Test
     public void testInterval_openInterval_negative() {
         // act
-        IntervalsSet set = new IntervalsSet(Double.NEGATIVE_INFINITY, 9.0, TEST_TOLERANCE);
+        IntervalsSet set = new IntervalsSet(Double.NEGATIVE_INFINITY, 9.0, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
         EuclideanTestUtils.assertNegativeInfinity(set.getInf());
-        Assert.assertEquals(9.0, set.getSup(), TEST_TOLERANCE);
+        Assert.assertEquals(9.0, set.getSup(), TEST_EPS);
         EuclideanTestUtils.assertPositiveInfinity(set.getSize());
-        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_EPS);
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(1, intervals.size());
-        assertInterval(Double.NEGATIVE_INFINITY, 9.0, intervals.get(0), TEST_TOLERANCE);
+        assertInterval(Double.NEGATIVE_INFINITY, 9.0, intervals.get(0), TEST_EPS);
 
         assertLocation(Region.Location.INSIDE, set, Double.NEGATIVE_INFINITY);
         assertLocation(Region.Location.INSIDE, set, 0.0);
@@ -142,19 +146,19 @@ public class IntervalsSetTest {
     @Test
     public void testInterval_singleClosedInterval() {
         // act
-        IntervalsSet set = new IntervalsSet(-1.0, 9.0, TEST_TOLERANCE);
+        IntervalsSet set = new IntervalsSet(-1.0, 9.0, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
-        Assert.assertEquals(-1.0, set.getInf(), TEST_TOLERANCE);
-        Assert.assertEquals(9.0, set.getSup(), TEST_TOLERANCE);
-        Assert.assertEquals(10.0, set.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(4.0), set.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
+        Assert.assertEquals(-1.0, set.getInf(), TEST_EPS);
+        Assert.assertEquals(9.0, set.getSup(), TEST_EPS);
+        Assert.assertEquals(10.0, set.getSize(), TEST_EPS);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(4.0), set.getBarycenter(), TEST_EPS);
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(1, intervals.size());
-        assertInterval(-1.0, 9.0, intervals.get(0), TEST_TOLERANCE);
+        assertInterval(-1.0, 9.0, intervals.get(0), TEST_EPS);
 
         assertLocation(Region.Location.OUTSIDE, set, Double.NEGATIVE_INFINITY);
         assertLocation(Region.Location.OUTSIDE, set, -2.0);
@@ -168,19 +172,19 @@ public class IntervalsSetTest {
     @Test
     public void testInterval_singlePoint() {
         // act
-        IntervalsSet set = new IntervalsSet(1.0, 1.0, TEST_TOLERANCE);
+        IntervalsSet set = new IntervalsSet(1.0, 1.0, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
-        Assert.assertEquals(1.0, set.getInf(), TEST_TOLERANCE);
-        Assert.assertEquals(1.0, set.getSup(), TEST_TOLERANCE);
-        Assert.assertEquals(0.0, set.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(1.0), set.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
+        Assert.assertEquals(1.0, set.getInf(), TEST_EPS);
+        Assert.assertEquals(1.0, set.getSup(), TEST_EPS);
+        Assert.assertEquals(0.0, set.getSize(), TEST_EPS);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(1.0), set.getBarycenter(), TEST_EPS);
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(1, intervals.size());
-        assertInterval(1.0, 1.0, intervals.get(0), TEST_TOLERANCE);
+        assertInterval(1.0, 1.0, intervals.get(0), TEST_EPS);
 
         assertLocation(Region.Location.OUTSIDE, set, Double.NEGATIVE_INFINITY);
         assertLocation(Region.Location.OUTSIDE, set, 0.0);
@@ -195,15 +199,15 @@ public class IntervalsSetTest {
         List<SubHyperplane<Vector1D>> boundaries = new ArrayList<>();
 
         // act
-        IntervalsSet set = new IntervalsSet(boundaries, TEST_TOLERANCE);
+        IntervalsSet set = new IntervalsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
         EuclideanTestUtils.assertNegativeInfinity(set.getInf());
         EuclideanTestUtils.assertPositiveInfinity(set.getSup());
         EuclideanTestUtils.assertPositiveInfinity(set.getSize());
-        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_EPS);
 
         BSPTree<Vector1D> tree = set.getTree(true);
         Assert.assertEquals(Boolean.TRUE, tree.getAttribute());
@@ -213,7 +217,7 @@ public class IntervalsSetTest {
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(1, intervals.size());
-        assertInterval(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, intervals.get(0), TEST_TOLERANCE);
+        assertInterval(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, intervals.get(0), TEST_EPS);
 
         assertLocation(Region.Location.INSIDE, set, Double.NEGATIVE_INFINITY);
         assertLocation(Region.Location.INSIDE, set, 0.0);
@@ -227,19 +231,19 @@ public class IntervalsSetTest {
         boundaries.add(subOrientedPoint(9.0, false));
 
         // act
-        IntervalsSet set = new IntervalsSet(boundaries, TEST_TOLERANCE);
+        IntervalsSet set = new IntervalsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
-        Assert.assertEquals(9.0, set.getInf(), TEST_TOLERANCE);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
+        Assert.assertEquals(9.0, set.getInf(), TEST_EPS);
         EuclideanTestUtils.assertPositiveInfinity(set.getSup());
         EuclideanTestUtils.assertPositiveInfinity(set.getSize());
-        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_EPS);
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(1, intervals.size());
-        assertInterval(9.0, Double.POSITIVE_INFINITY, intervals.get(0), TEST_TOLERANCE);
+        assertInterval(9.0, Double.POSITIVE_INFINITY, intervals.get(0), TEST_EPS);
 
         assertLocation(Region.Location.OUTSIDE, set, Double.NEGATIVE_INFINITY);
         assertLocation(Region.Location.OUTSIDE, set, 0.0);
@@ -256,19 +260,19 @@ public class IntervalsSetTest {
         boundaries.add(subOrientedPoint(9.0, true));
 
         // act
-        IntervalsSet set = new IntervalsSet(boundaries, TEST_TOLERANCE);
+        IntervalsSet set = new IntervalsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
         EuclideanTestUtils.assertNegativeInfinity(set.getInf());
-        Assert.assertEquals(9.0, set.getSup(), TEST_TOLERANCE);
+        Assert.assertEquals(9.0, set.getSup(), TEST_EPS);
         EuclideanTestUtils.assertPositiveInfinity(set.getSize());
-        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_EPS);
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(1, intervals.size());
-        assertInterval(Double.NEGATIVE_INFINITY, 9.0, intervals.get(0), TEST_TOLERANCE);
+        assertInterval(Double.NEGATIVE_INFINITY, 9.0, intervals.get(0), TEST_EPS);
 
         assertLocation(Region.Location.INSIDE, set, Double.NEGATIVE_INFINITY);
         assertLocation(Region.Location.INSIDE, set, 0.0);
@@ -286,19 +290,19 @@ public class IntervalsSetTest {
         boundaries.add(subOrientedPoint(9.0, true));
 
         // act
-        IntervalsSet set = new IntervalsSet(boundaries, TEST_TOLERANCE);
+        IntervalsSet set = new IntervalsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
-        Assert.assertEquals(-1.0, set.getInf(), TEST_TOLERANCE);
-        Assert.assertEquals(9.0, set.getSup(), TEST_TOLERANCE);
-        Assert.assertEquals(10.0, set.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(4.0), set.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
+        Assert.assertEquals(-1.0, set.getInf(), TEST_EPS);
+        Assert.assertEquals(9.0, set.getSup(), TEST_EPS);
+        Assert.assertEquals(10.0, set.getSize(), TEST_EPS);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(4.0), set.getBarycenter(), TEST_EPS);
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(1, intervals.size());
-        assertInterval(-1.0, 9.0, intervals.get(0), TEST_TOLERANCE);
+        assertInterval(-1.0, 9.0, intervals.get(0), TEST_EPS);
 
         assertLocation(Region.Location.OUTSIDE, set, Double.NEGATIVE_INFINITY);
         assertLocation(Region.Location.OUTSIDE, set, -2.0);
@@ -319,20 +323,20 @@ public class IntervalsSetTest {
         boundaries.add(subOrientedPoint(9.0, true));
 
         // act
-        IntervalsSet set = new IntervalsSet(boundaries, TEST_TOLERANCE);
+        IntervalsSet set = new IntervalsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
-        Assert.assertEquals(-1.0, set.getInf(), TEST_TOLERANCE);
-        Assert.assertEquals(9.0, set.getSup(), TEST_TOLERANCE);
-        Assert.assertEquals(7.0, set.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(29.5 / 7.0), set.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
+        Assert.assertEquals(-1.0, set.getInf(), TEST_EPS);
+        Assert.assertEquals(9.0, set.getSup(), TEST_EPS);
+        Assert.assertEquals(7.0, set.getSize(), TEST_EPS);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(29.5 / 7.0), set.getBarycenter(), TEST_EPS);
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(2, intervals.size());
-        assertInterval(-1.0, 2.0, intervals.get(0), TEST_TOLERANCE);
-        assertInterval(5.0, 9.0, intervals.get(1), TEST_TOLERANCE);
+        assertInterval(-1.0, 2.0, intervals.get(0), TEST_EPS);
+        assertInterval(5.0, 9.0, intervals.get(1), TEST_EPS);
 
         assertLocation(Region.Location.OUTSIDE, set, Double.NEGATIVE_INFINITY);
         assertLocation(Region.Location.OUTSIDE, set, -2.0);
@@ -357,22 +361,22 @@ public class IntervalsSetTest {
         boundaries.add(subOrientedPoint(10.0, false));
 
         // act
-        IntervalsSet set = new IntervalsSet(boundaries, TEST_TOLERANCE);
+        IntervalsSet set = new IntervalsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
         EuclideanTestUtils.assertNegativeInfinity(set.getInf());
         EuclideanTestUtils.assertPositiveInfinity(set.getSup());
         EuclideanTestUtils.assertPositiveInfinity(set.getSize());
-        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(Double.NaN), set.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(Double.NaN), set.getBarycenter(), TEST_EPS);
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(4, intervals.size());
-        assertInterval(Double.NEGATIVE_INFINITY, -2.0, intervals.get(0), TEST_TOLERANCE);
-        assertInterval(-1.0, 2.0, intervals.get(1), TEST_TOLERANCE);
-        assertInterval(5.0, 9.0, intervals.get(2), TEST_TOLERANCE);
-        assertInterval(10.0, Double.POSITIVE_INFINITY, intervals.get(3), TEST_TOLERANCE);
+        assertInterval(Double.NEGATIVE_INFINITY, -2.0, intervals.get(0), TEST_EPS);
+        assertInterval(-1.0, 2.0, intervals.get(1), TEST_EPS);
+        assertInterval(5.0, 9.0, intervals.get(2), TEST_EPS);
+        assertInterval(10.0, Double.POSITIVE_INFINITY, intervals.get(3), TEST_EPS);
 
         assertLocation(Region.Location.INSIDE, set, Double.NEGATIVE_INFINITY);
         assertLocation(Region.Location.INSIDE, set, -3);
@@ -388,29 +392,30 @@ public class IntervalsSetTest {
     }
 
     @Test
-    public void testFromBoundaries_intervalEqualToTolerance_onlyFirstBoundaryUsed() {
+    public void testFromBoundaries_intervalEqualToEpsilon_onlyFirstBoundaryUsed() {
         // arrange
-        double tolerance = 1e-3;
+        double eps = 1e-3;
+        DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(eps);
         double first = 1.0;
-        double second = 1.0 + tolerance;
+        double second = 1.0 + eps;
         List<SubHyperplane<Vector1D>> boundaries = new ArrayList<>();
-        boundaries.add(subOrientedPoint(first, true, tolerance));
-        boundaries.add(subOrientedPoint(second, false, tolerance));
+        boundaries.add(subOrientedPoint(first, true, precision));
+        boundaries.add(subOrientedPoint(second, false, precision));
 
         // act
-        IntervalsSet set = new IntervalsSet(boundaries, tolerance);
+        IntervalsSet set = new IntervalsSet(boundaries, precision);
 
         // assert
-        Assert.assertEquals(tolerance, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertSame(precision, set.getPrecision());
         EuclideanTestUtils.assertNegativeInfinity(set.getInf());
-        Assert.assertEquals(first, set.getSup(), TEST_TOLERANCE);
+        Assert.assertEquals(first, set.getSup(), TEST_EPS);
         EuclideanTestUtils.assertPositiveInfinity(set.getSize());
-        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_EPS);
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(1, intervals.size());
-        assertInterval(Double.NEGATIVE_INFINITY, first, intervals.get(0), TEST_TOLERANCE);
+        assertInterval(Double.NEGATIVE_INFINITY, first, intervals.get(0), TEST_EPS);
 
         assertLocation(Region.Location.INSIDE, set, 0.0);
         assertLocation(Region.Location.BOUNDARY, set, 1.0);
@@ -420,27 +425,28 @@ public class IntervalsSetTest {
     @Test
     public void testFromBoundaries_intervalSmallerThanTolerance_onlyFirstBoundaryUsed() {
         // arrange
-        double tolerance = 1e-3;
+        double eps = 1e-3;
+        DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(eps);
         double first = 1.0;
         double second = 1.0 - 1e-4;
         List<SubHyperplane<Vector1D>> boundaries = new ArrayList<>();
-        boundaries.add(subOrientedPoint(first, false, tolerance));
-        boundaries.add(subOrientedPoint(second, true, tolerance));
+        boundaries.add(subOrientedPoint(first, false, precision));
+        boundaries.add(subOrientedPoint(second, true, precision));
 
         // act
-        IntervalsSet set = new IntervalsSet(boundaries, tolerance);
+        IntervalsSet set = new IntervalsSet(boundaries, precision);
 
         // assert
-        Assert.assertEquals(tolerance, set.getTolerance(), Precision.SAFE_MIN);
-        Assert.assertEquals(first, set.getInf(), TEST_TOLERANCE);
+        Assert.assertSame(precision, set.getPrecision());
+        Assert.assertEquals(first, set.getInf(), TEST_EPS);
         EuclideanTestUtils.assertPositiveInfinity(set.getSup());
         EuclideanTestUtils.assertPositiveInfinity(set.getSize());
-        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector1D.NaN, set.getBarycenter(), TEST_EPS);
 
         List<Interval> intervals = set.asList();
         Assert.assertEquals(1, intervals.size());
-        assertInterval(first, Double.POSITIVE_INFINITY, intervals.get(0), TEST_TOLERANCE);
+        assertInterval(first, Double.POSITIVE_INFINITY, intervals.get(0), TEST_EPS);
 
         assertLocation(Region.Location.OUTSIDE, set, 0.0);
         assertLocation(Region.Location.BOUNDARY, set, 1.0);
@@ -458,7 +464,7 @@ public class IntervalsSetTest {
         boundaries.add(subOrientedPoint(9.0, true));
         boundaries.add(subOrientedPoint(10.0, false));
 
-        IntervalsSet set = new IntervalsSet(boundaries, TEST_TOLERANCE);
+        IntervalsSet set = new IntervalsSet(boundaries, TEST_PRECISION);
 
         // act/assert
         assertProjection(Vector1D.of(-2), -1, set, Vector1D.of(-3));
@@ -490,7 +496,7 @@ public class IntervalsSetTest {
 
     @Test
     public void testInterval() {
-        IntervalsSet set = new IntervalsSet(2.3, 5.7, 1.0e-10);
+        IntervalsSet set = new IntervalsSet(2.3, 5.7, TEST_PRECISION);
         Assert.assertEquals(3.4, set.getSize(), 1.0e-10);
         Assert.assertEquals(4.0, set.getBarycenter().getX(), 1.0e-10);
         Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(Vector1D.of(2.3)));
@@ -504,7 +510,7 @@ public class IntervalsSetTest {
 
     @Test
     public void testInfinite() {
-        IntervalsSet set = new IntervalsSet(9.0, Double.POSITIVE_INFINITY, 1.0e-10);
+        IntervalsSet set = new IntervalsSet(9.0, Double.POSITIVE_INFINITY, TEST_PRECISION);
         Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(Vector1D.of(9.0)));
         Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(Vector1D.of(8.4)));
         for (double e = 1.0; e <= 6.0; e += 1.0) {
@@ -528,17 +534,17 @@ public class IntervalsSetTest {
 
         // act
         IntervalsSet set = (IntervalsSet)
-        factory.intersection(factory.union(factory.difference(new IntervalsSet(1.0, 6.0, TEST_TOLERANCE),
-                                                              new IntervalsSet(3.0, 5.0, TEST_TOLERANCE)),
-                                                              new IntervalsSet(9.0, Double.POSITIVE_INFINITY, TEST_TOLERANCE)),
-                                                              new IntervalsSet(Double.NEGATIVE_INFINITY, 11.0, TEST_TOLERANCE));
+        factory.intersection(factory.union(factory.difference(new IntervalsSet(1.0, 6.0, TEST_PRECISION),
+                                                              new IntervalsSet(3.0, 5.0, TEST_PRECISION)),
+                                                              new IntervalsSet(9.0, Double.POSITIVE_INFINITY, TEST_PRECISION)),
+                                                              new IntervalsSet(Double.NEGATIVE_INFINITY, 11.0, TEST_PRECISION));
 
         // arrange
-        Assert.assertEquals(1.0, set.getInf(), TEST_TOLERANCE);
-        Assert.assertEquals(11.0, set.getSup(), TEST_TOLERANCE);
+        Assert.assertEquals(1.0, set.getInf(), TEST_EPS);
+        Assert.assertEquals(11.0, set.getSup(), TEST_EPS);
 
-        Assert.assertEquals(5.0, set.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(5.9, set.getBarycenter().getX(), TEST_TOLERANCE);
+        Assert.assertEquals(5.0, set.getSize(), TEST_EPS);
+        Assert.assertEquals(5.9, set.getBarycenter().getX(), TEST_EPS);
 
         assertLocation(Region.Location.OUTSIDE, set, 0.0);
         assertLocation(Region.Location.OUTSIDE, set, 4.0);
@@ -552,9 +558,9 @@ public class IntervalsSetTest {
 
         List<Interval> list = set.asList();
         Assert.assertEquals(3, list.size());
-        assertInterval(1.0, 3.0, list.get(0), TEST_TOLERANCE);
-        assertInterval(5.0, 6.0, list.get(1), TEST_TOLERANCE);
-        assertInterval(9.0, 11.0, list.get(2), TEST_TOLERANCE);
+        assertInterval(1.0, 3.0, list.get(0), TEST_EPS);
+        assertInterval(5.0, 6.0, list.get(1), TEST_EPS);
+        assertInterval(9.0, 11.0, list.get(2), TEST_EPS);
     }
 
     private void assertLocation(Region.Location location, IntervalsSet set, double pt) {
@@ -570,17 +576,17 @@ public class IntervalsSetTest {
             IntervalsSet set, Vector1D toProject) {
         BoundaryProjection<Vector1D> proj = set.projectToBoundary(toProject);
 
-        EuclideanTestUtils.assertCoordinatesEqual(toProject, proj.getOriginal(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(expectedProjection, proj.getProjected(), TEST_TOLERANCE);
-        Assert.assertEquals(expectedOffset, proj.getOffset(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(toProject, proj.getOriginal(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(expectedProjection, proj.getProjected(), TEST_EPS);
+        Assert.assertEquals(expectedOffset, proj.getOffset(), TEST_EPS);
     }
 
     private SubOrientedPoint subOrientedPoint(double location, boolean direct) {
-        return subOrientedPoint(location, direct, TEST_TOLERANCE);
+        return subOrientedPoint(location, direct, TEST_PRECISION);
     }
 
-    private SubOrientedPoint subOrientedPoint(double location, boolean direct, double tolerance) {
+    private SubOrientedPoint subOrientedPoint(double location, boolean direct, DoublePrecisionContext precision) {
         // the remaining region isn't necessary for creating 1D boundaries so we can set it to null here
-        return new SubOrientedPoint(new OrientedPoint(Vector1D.of(location), direct, tolerance), null);
+        return new SubOrientedPoint(new OrientedPoint(Vector1D.of(location), direct, precision), null);
     }
 }
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/OrientedPointTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/OrientedPointTest.java
index 764ac26..1621c8e 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/OrientedPointTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/OrientedPointTest.java
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.geometry.euclidean.oned;
 
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
 import org.apache.commons.numbers.core.Precision;
 import org.junit.Assert;
@@ -23,36 +25,41 @@ import org.junit.Test;
 
 public class OrientedPointTest {
 
+    private static final double TEST_EPS = 1e-15;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
+
     @Test
     public void testConstructor() {
         // act
-        OrientedPoint pt = new OrientedPoint(Vector1D.of(2.0), true, 1e-5);
+        OrientedPoint pt = new OrientedPoint(Vector1D.of(2.0), true, TEST_PRECISION);
 
         // assert
+        Assert.assertSame(TEST_PRECISION, pt.getPrecision());
         Assert.assertEquals(2.0, pt.getLocation().getX(), Precision.EPSILON);
         Assert.assertTrue(pt.isDirect());
-        Assert.assertEquals(1e-5, pt.getTolerance(), Precision.EPSILON);
     }
 
     @Test
     public void testCopySelf() {
         // arrange
-        OrientedPoint orig = new OrientedPoint(Vector1D.of(2.0), true, 1e-5);
+        OrientedPoint orig = new OrientedPoint(Vector1D.of(2.0), true, TEST_PRECISION);
 
         // act
         OrientedPoint copy = orig.copySelf();
 
         // assert
         Assert.assertSame(orig, copy);
+        Assert.assertSame(TEST_PRECISION, copy.getPrecision());
         Assert.assertEquals(2.0, copy.getLocation().getX(), Precision.EPSILON);
         Assert.assertTrue(copy.isDirect());
-        Assert.assertEquals(1e-5, copy.getTolerance(), Precision.EPSILON);
     }
 
     @Test
     public void testGetOffset_direct_point() {
         // arrange
-        OrientedPoint pt = new OrientedPoint(Vector1D.of(-1.0), true, 1e-5);
+        OrientedPoint pt = new OrientedPoint(Vector1D.of(-1.0), true, TEST_PRECISION);
 
         // act/assert
         Assert.assertEquals(-99, pt.getOffset(Vector1D.of(-100)), Precision.EPSILON);
@@ -67,7 +74,7 @@ public class OrientedPointTest {
     @Test
     public void testGetOffset_notDirect_point() {
         // arrange
-        OrientedPoint pt = new OrientedPoint(Vector1D.of(-1.0), false, 1e-5);
+        OrientedPoint pt = new OrientedPoint(Vector1D.of(-1.0), false, TEST_PRECISION);
 
         // act/assert
         Assert.assertEquals(99, pt.getOffset(Vector1D.of(-100)), Precision.EPSILON);
@@ -82,7 +89,7 @@ public class OrientedPointTest {
     @Test
     public void testWholeHyperplane() {
         // arrange
-        OrientedPoint pt = new OrientedPoint(Vector1D.of(1.0), false, 1e-5);
+        OrientedPoint pt = new OrientedPoint(Vector1D.of(1.0), false, TEST_PRECISION);
 
         // act
         SubOrientedPoint subPt = pt.wholeHyperplane();
@@ -95,7 +102,7 @@ public class OrientedPointTest {
     @Test
     public void testWholeSpace() {
         // arrange
-        OrientedPoint pt = new OrientedPoint(Vector1D.of(1.0), false, 1e-5);
+        OrientedPoint pt = new OrientedPoint(Vector1D.of(1.0), false, TEST_PRECISION);
 
         // act
         IntervalsSet set = pt.wholeSpace();
@@ -108,10 +115,10 @@ public class OrientedPointTest {
     @Test
     public void testSameOrientationAs() {
         // arrange
-        OrientedPoint notDirect1 = new OrientedPoint(Vector1D.of(1.0), false, 1e-5);
-        OrientedPoint notDirect2 = new OrientedPoint(Vector1D.of(1.0), false, 1e-5);
-        OrientedPoint direct1 = new OrientedPoint(Vector1D.of(1.0), true, 1e-5);
-        OrientedPoint direct2 = new OrientedPoint(Vector1D.of(1.0), true, 1e-5);
+        OrientedPoint notDirect1 = new OrientedPoint(Vector1D.of(1.0), false, TEST_PRECISION);
+        OrientedPoint notDirect2 = new OrientedPoint(Vector1D.of(1.0), false, TEST_PRECISION);
+        OrientedPoint direct1 = new OrientedPoint(Vector1D.of(1.0), true, TEST_PRECISION);
+        OrientedPoint direct2 = new OrientedPoint(Vector1D.of(1.0), true, TEST_PRECISION);
 
         // act/assert
         Assert.assertTrue(notDirect1.sameOrientationAs(notDirect1));
@@ -129,7 +136,7 @@ public class OrientedPointTest {
     @Test
     public void testProject() {
         // arrange
-        OrientedPoint pt = new OrientedPoint(Vector1D.of(1.0), true, 1e-5);
+        OrientedPoint pt = new OrientedPoint(Vector1D.of(1.0), true, TEST_PRECISION);
 
         // act/assert
         Assert.assertEquals(1.0, pt.project(Vector1D.of(-1.0)).getX(), Precision.EPSILON);
@@ -141,7 +148,7 @@ public class OrientedPointTest {
     @Test
     public void testRevertSelf() {
         // arrange
-        OrientedPoint pt = new OrientedPoint(Vector1D.of(2.0), true, 1e-5);
+        OrientedPoint pt = new OrientedPoint(Vector1D.of(2.0), true, TEST_PRECISION);
 
         // act
         pt.revertSelf();
@@ -149,7 +156,7 @@ public class OrientedPointTest {
         // assert
         Assert.assertEquals(2.0, pt.getLocation().getX(), Precision.EPSILON);
         Assert.assertFalse(pt.isDirect());
-        Assert.assertEquals(1e-5, pt.getTolerance(), Precision.EPSILON);
+        Assert.assertSame(TEST_PRECISION, pt.getPrecision());
 
         Assert.assertEquals(1, pt.getOffset(Vector1D.of(1.0)), Precision.EPSILON);
         Assert.assertEquals(-1, pt.getOffset(Vector1D.of(3.0)), Precision.EPSILON);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/SubOrientedPointTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/SubOrientedPointTest.java
index 14d7286..c9dab33 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/SubOrientedPointTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/oned/SubOrientedPointTest.java
@@ -19,26 +19,32 @@ package org.apache.commons.geometry.euclidean.oned;
 import org.apache.commons.geometry.core.partitioning.Side;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane.SplitSubHyperplane;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class SubOrientedPointTest {
-    private static final double TEST_TOLERANCE = 1e-10;
+
+    private static final double TEST_EPS = 1e-15;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
 
     @Test
     public void testGetSize() {
         // arrange
-        OrientedPoint hyperplane = new OrientedPoint(Vector1D.of(1), true, TEST_TOLERANCE);
+        OrientedPoint hyperplane = new OrientedPoint(Vector1D.of(1), true, TEST_PRECISION);
         SubOrientedPoint pt = hyperplane.wholeHyperplane();
 
         // act/assert
-        Assert.assertEquals(0.0, pt.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, pt.getSize(), TEST_EPS);
     }
 
     @Test
     public void testIsEmpty() {
         // arrange
-        OrientedPoint hyperplane = new OrientedPoint(Vector1D.of(1), true, TEST_TOLERANCE);
+        OrientedPoint hyperplane = new OrientedPoint(Vector1D.of(1), true, TEST_PRECISION);
         SubOrientedPoint pt = hyperplane.wholeHyperplane();
 
         // act/assert
@@ -48,11 +54,11 @@ public class SubOrientedPointTest {
     @Test
     public void testBuildNew() {
         // arrange
-        OrientedPoint originalHyperplane = new OrientedPoint(Vector1D.of(1), true, TEST_TOLERANCE);
+        OrientedPoint originalHyperplane = new OrientedPoint(Vector1D.of(1), true, TEST_PRECISION);
         SubOrientedPoint pt = originalHyperplane.wholeHyperplane();
 
-        OrientedPoint hyperplane = new OrientedPoint(Vector1D.of(2), true, TEST_TOLERANCE);
-        IntervalsSet intervals = new IntervalsSet(2, 3, TEST_TOLERANCE);
+        OrientedPoint hyperplane = new OrientedPoint(Vector1D.of(2), true, TEST_PRECISION);
+        IntervalsSet intervals = new IntervalsSet(2, 3, TEST_PRECISION);
 
         // act
         SubHyperplane<Vector1D> result = pt.buildNew(hyperplane, intervals);
@@ -66,11 +72,11 @@ public class SubOrientedPointTest {
     @Test
     public void testSplit_resultOnMinusSide() {
         // arrange
-        OrientedPoint hyperplane = new OrientedPoint(Vector1D.of(1), true, TEST_TOLERANCE);
-        IntervalsSet interval = new IntervalsSet(TEST_TOLERANCE);
+        OrientedPoint hyperplane = new OrientedPoint(Vector1D.of(1), true, TEST_PRECISION);
+        IntervalsSet interval = new IntervalsSet(TEST_PRECISION);
         SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
 
-        OrientedPoint splitter = new OrientedPoint(Vector1D.of(2), true, TEST_TOLERANCE);
+        OrientedPoint splitter = new OrientedPoint(Vector1D.of(2), true, TEST_PRECISION);
 
         // act
         SplitSubHyperplane<Vector1D> split = pt.split(splitter);
@@ -82,7 +88,7 @@ public class SubOrientedPointTest {
         Assert.assertNotNull(minusSub);
 
         OrientedPoint minusHyper = (OrientedPoint) minusSub.getHyperplane();
-        Assert.assertEquals(1, minusHyper.getLocation().getX(), TEST_TOLERANCE);
+        Assert.assertEquals(1, minusHyper.getLocation().getX(), TEST_EPS);
 
         Assert.assertSame(interval, minusSub.getRemainingRegion());
 
@@ -92,11 +98,11 @@ public class SubOrientedPointTest {
     @Test
     public void testSplit_resultOnPlusSide() {
         // arrange
-        OrientedPoint hyperplane = new OrientedPoint(Vector1D.of(1), true, TEST_TOLERANCE);
-        IntervalsSet interval = new IntervalsSet(TEST_TOLERANCE);
+        OrientedPoint hyperplane = new OrientedPoint(Vector1D.of(1), true, TEST_PRECISION);
+        IntervalsSet interval = new IntervalsSet(TEST_PRECISION);
         SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
 
-        OrientedPoint splitter = new OrientedPoint(Vector1D.of(0), true, TEST_TOLERANCE);
+        OrientedPoint splitter = new OrientedPoint(Vector1D.of(0), true, TEST_PRECISION);
 
         // act
         SplitSubHyperplane<Vector1D> split = pt.split(splitter);
@@ -110,7 +116,7 @@ public class SubOrientedPointTest {
         Assert.assertNotNull(plusSub);
 
         OrientedPoint plusHyper = (OrientedPoint) plusSub.getHyperplane();
-        Assert.assertEquals(1, plusHyper.getLocation().getX(), TEST_TOLERANCE);
+        Assert.assertEquals(1, plusHyper.getLocation().getX(), TEST_EPS);
 
         Assert.assertSame(interval, plusSub.getRemainingRegion());
     }
@@ -118,11 +124,11 @@ public class SubOrientedPointTest {
     @Test
     public void testSplit_equivalentHyperplanes() {
         // arrange
-        OrientedPoint hyperplane = new OrientedPoint(Vector1D.of(1), true, TEST_TOLERANCE);
-        IntervalsSet interval = new IntervalsSet(TEST_TOLERANCE);
+        OrientedPoint hyperplane = new OrientedPoint(Vector1D.of(1), true, TEST_PRECISION);
+        IntervalsSet interval = new IntervalsSet(TEST_PRECISION);
         SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
 
-        OrientedPoint splitter = new OrientedPoint(Vector1D.of(1), true, TEST_TOLERANCE);
+        OrientedPoint splitter = new OrientedPoint(Vector1D.of(1), true, TEST_PRECISION);
 
         // act
         SplitSubHyperplane<Vector1D> split = pt.split(splitter);
@@ -137,23 +143,26 @@ public class SubOrientedPointTest {
     @Test
     public void testSplit_usesToleranceFromParentHyperplane() {
         // arrange
-        OrientedPoint hyperplane = new OrientedPoint(Vector1D.of(1), true, 0.1);
+        DoublePrecisionContext parentPrecision = new EpsilonDoublePrecisionContext(0.1);
+        DoublePrecisionContext otherPrecision = new EpsilonDoublePrecisionContext(1e-10);
+
+        OrientedPoint hyperplane = new OrientedPoint(Vector1D.of(1), true, parentPrecision);
         SubOrientedPoint pt = hyperplane.wholeHyperplane();
 
         // act/assert
-        SplitSubHyperplane<Vector1D> plusSplit = pt.split(new OrientedPoint(Vector1D.of(0.899), true, 1e-10));
+        SplitSubHyperplane<Vector1D> plusSplit = pt.split(new OrientedPoint(Vector1D.of(0.899), true, otherPrecision));
         Assert.assertNull(plusSplit.getMinus());
         Assert.assertNotNull(plusSplit.getPlus());
 
-        SplitSubHyperplane<Vector1D> lowWithinTolerance = pt.split(new OrientedPoint(Vector1D.of(0.901), true, 1e-10));
+        SplitSubHyperplane<Vector1D> lowWithinTolerance = pt.split(new OrientedPoint(Vector1D.of(0.901), true, otherPrecision));
         Assert.assertNull(lowWithinTolerance.getMinus());
         Assert.assertNull(lowWithinTolerance.getPlus());
 
-        SplitSubHyperplane<Vector1D> highWithinTolerance = pt.split(new OrientedPoint(Vector1D.of(1.09), true, 1e-10));
+        SplitSubHyperplane<Vector1D> highWithinTolerance = pt.split(new OrientedPoint(Vector1D.of(1.09), true, otherPrecision));
         Assert.assertNull(highWithinTolerance.getMinus());
         Assert.assertNull(highWithinTolerance.getPlus());
 
-        SplitSubHyperplane<Vector1D> minusSplit = pt.split(new OrientedPoint(Vector1D.of(1.101), true, 1e-10));
+        SplitSubHyperplane<Vector1D> minusSplit = pt.split(new OrientedPoint(Vector1D.of(1.101), true, otherPrecision));
         Assert.assertNotNull(minusSplit.getMinus());
         Assert.assertNull(minusSplit.getPlus());
     }
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/LineTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/LineTest.java
index 5779fbd..fe667e0 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/LineTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/LineTest.java
@@ -16,15 +16,22 @@
  */
 package org.apache.commons.geometry.euclidean.threed;
 
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class LineTest {
 
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
+
     @Test
     public void testContains() {
         Vector3D p1 = Vector3D.of(0, 0, 1);
-        Line l = new Line(p1, Vector3D.of(0, 0, 2), 1.0e-10);
+        Line l = new Line(p1, Vector3D.of(0, 0, 2), TEST_PRECISION);
         Assert.assertTrue(l.contains(p1));
         Assert.assertTrue(l.contains(Vector3D.linearCombination(1.0, p1, 0.3, l.getDirection())));
         Vector3D u = l.getDirection().orthogonal();
@@ -39,89 +46,89 @@ public class LineTest {
     public void testSimilar() {
         Vector3D p1  = Vector3D.of(1.2, 3.4, -5.8);
         Vector3D p2  = Vector3D.of(3.4, -5.8, 1.2);
-        Line     lA  = new Line(p1, p2, 1.0e-10);
-        Line     lB  = new Line(p2, p1, 1.0e-10);
+        Line     lA  = new Line(p1, p2, TEST_PRECISION);
+        Line     lB  = new Line(p2, p1, TEST_PRECISION);
         Assert.assertTrue(lA.isSimilarTo(lB));
-        Assert.assertTrue(! lA.isSimilarTo(new Line(p1, p1.add(lA.getDirection().orthogonal()), 1.0e-10)));
+        Assert.assertTrue(!lA.isSimilarTo(new Line(p1, p1.add(lA.getDirection().orthogonal()), TEST_PRECISION)));
     }
 
     @Test
     public void testPointDistance() {
-        Line l = new Line(Vector3D.of(0, 1, 1), Vector3D.of(0, 2, 2), 1.0e-10);
-        Assert.assertEquals(Math.sqrt(3.0 / 2.0), l.distance(Vector3D.of(1, 0, 1)), 1.0e-10);
-        Assert.assertEquals(0, l.distance(Vector3D.of(0, -4, -4)), 1.0e-10);
+        Line l = new Line(Vector3D.of(0, 1, 1), Vector3D.of(0, 2, 2), TEST_PRECISION);
+        Assert.assertEquals(Math.sqrt(3.0 / 2.0), l.distance(Vector3D.of(1, 0, 1)), TEST_EPS);
+        Assert.assertEquals(0, l.distance(Vector3D.of(0, -4, -4)), TEST_EPS);
     }
 
     @Test
     public void testLineDistance() {
-        Line l = new Line(Vector3D.of(0, 1, 1), Vector3D.of(0, 2, 2), 1.0e-10);
+        Line l = new Line(Vector3D.of(0, 1, 1), Vector3D.of(0, 2, 2), TEST_PRECISION);
         Assert.assertEquals(1.0,
-                            l.distance(new Line(Vector3D.of(1, 0, 1), Vector3D.of(1, 0, 2), 1.0e-10)),
+                            l.distance(new Line(Vector3D.of(1, 0, 1), Vector3D.of(1, 0, 2), TEST_PRECISION)),
                             1.0e-10);
         Assert.assertEquals(0.5,
-                            l.distance(new Line(Vector3D.of(-0.5, 0, 0), Vector3D.of(-0.5, -1, -1), 1.0e-10)),
+                            l.distance(new Line(Vector3D.of(-0.5, 0, 0), Vector3D.of(-0.5, -1, -1), TEST_PRECISION)),
                             1.0e-10);
         Assert.assertEquals(0.0,
                             l.distance(l),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.distance(new Line(Vector3D.of(0, -4, -4), Vector3D.of(0, -5, -5), 1.0e-10)),
+                            l.distance(new Line(Vector3D.of(0, -4, -4), Vector3D.of(0, -5, -5), TEST_PRECISION)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.distance(new Line(Vector3D.of(0, -4, -4), Vector3D.of(0, -3, -4), 1.0e-10)),
+                            l.distance(new Line(Vector3D.of(0, -4, -4), Vector3D.of(0, -3, -4), TEST_PRECISION)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.distance(new Line(Vector3D.of(0, -4, -4), Vector3D.of(1, -4, -4), 1.0e-10)),
+                            l.distance(new Line(Vector3D.of(0, -4, -4), Vector3D.of(1, -4, -4), TEST_PRECISION)),
                             1.0e-10);
         Assert.assertEquals(Math.sqrt(8),
-                            l.distance(new Line(Vector3D.of(0, -4, 0), Vector3D.of(1, -4, 0), 1.0e-10)),
+                            l.distance(new Line(Vector3D.of(0, -4, 0), Vector3D.of(1, -4, 0), TEST_PRECISION)),
                             1.0e-10);
     }
 
     @Test
     public void testClosest() {
-        Line l = new Line(Vector3D.of(0, 1, 1), Vector3D.of(0, 2, 2), 1.0e-10);
+        Line l = new Line(Vector3D.of(0, 1, 1), Vector3D.of(0, 2, 2), TEST_PRECISION);
         Assert.assertEquals(0.0,
-                            l.closestPoint(new Line(Vector3D.of(1, 0, 1), Vector3D.of(1, 0, 2), 1.0e-10)).distance(Vector3D.of(0, 0, 0)),
+                            l.closestPoint(new Line(Vector3D.of(1, 0, 1), Vector3D.of(1, 0, 2), TEST_PRECISION)).distance(Vector3D.of(0, 0, 0)),
                             1.0e-10);
         Assert.assertEquals(0.5,
-                            l.closestPoint(new Line(Vector3D.of(-0.5, 0, 0), Vector3D.of(-0.5, -1, -1), 1.0e-10)).distance(Vector3D.of(-0.5, 0, 0)),
+                            l.closestPoint(new Line(Vector3D.of(-0.5, 0, 0), Vector3D.of(-0.5, -1, -1), TEST_PRECISION)).distance(Vector3D.of(-0.5, 0, 0)),
                             1.0e-10);
         Assert.assertEquals(0.0,
                             l.closestPoint(l).distance(Vector3D.of(0, 0, 0)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.closestPoint(new Line(Vector3D.of(0, -4, -4), Vector3D.of(0, -5, -5), 1.0e-10)).distance(Vector3D.of(0, 0, 0)),
+                            l.closestPoint(new Line(Vector3D.of(0, -4, -4), Vector3D.of(0, -5, -5), TEST_PRECISION)).distance(Vector3D.of(0, 0, 0)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.closestPoint(new Line(Vector3D.of(0, -4, -4), Vector3D.of(0, -3, -4), 1.0e-10)).distance(Vector3D.of(0, -4, -4)),
+                            l.closestPoint(new Line(Vector3D.of(0, -4, -4), Vector3D.of(0, -3, -4), TEST_PRECISION)).distance(Vector3D.of(0, -4, -4)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.closestPoint(new Line(Vector3D.of(0, -4, -4), Vector3D.of(1, -4, -4), 1.0e-10)).distance(Vector3D.of(0, -4, -4)),
+                            l.closestPoint(new Line(Vector3D.of(0, -4, -4), Vector3D.of(1, -4, -4), TEST_PRECISION)).distance(Vector3D.of(0, -4, -4)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.closestPoint(new Line(Vector3D.of(0, -4, 0), Vector3D.of(1, -4, 0), 1.0e-10)).distance(Vector3D.of(0, -2, -2)),
+                            l.closestPoint(new Line(Vector3D.of(0, -4, 0), Vector3D.of(1, -4, 0), TEST_PRECISION)).distance(Vector3D.of(0, -2, -2)),
                             1.0e-10);
     }
 
     @Test
     public void testIntersection() {
-        Line l = new Line(Vector3D.of(0, 1, 1), Vector3D.of(0, 2, 2), 1.0e-10);
-        Assert.assertNull(l.intersection(new Line(Vector3D.of(1, 0, 1), Vector3D.of(1, 0, 2), 1.0e-10)));
-        Assert.assertNull(l.intersection(new Line(Vector3D.of(-0.5, 0, 0), Vector3D.of(-0.5, -1, -1), 1.0e-10)));
+        Line l = new Line(Vector3D.of(0, 1, 1), Vector3D.of(0, 2, 2), TEST_PRECISION);
+        Assert.assertNull(l.intersection(new Line(Vector3D.of(1, 0, 1), Vector3D.of(1, 0, 2), TEST_PRECISION)));
+        Assert.assertNull(l.intersection(new Line(Vector3D.of(-0.5, 0, 0), Vector3D.of(-0.5, -1, -1), TEST_PRECISION)));
         Assert.assertEquals(0.0,
                             l.intersection(l).distance(Vector3D.of(0, 0, 0)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.intersection(new Line(Vector3D.of(0, -4, -4), Vector3D.of(0, -5, -5), 1.0e-10)).distance(Vector3D.of(0, 0, 0)),
+                            l.intersection(new Line(Vector3D.of(0, -4, -4), Vector3D.of(0, -5, -5), TEST_PRECISION)).distance(Vector3D.of(0, 0, 0)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.intersection(new Line(Vector3D.of(0, -4, -4), Vector3D.of(0, -3, -4), 1.0e-10)).distance(Vector3D.of(0, -4, -4)),
+                            l.intersection(new Line(Vector3D.of(0, -4, -4), Vector3D.of(0, -3, -4), TEST_PRECISION)).distance(Vector3D.of(0, -4, -4)),
                             1.0e-10);
         Assert.assertEquals(0.0,
-                            l.intersection(new Line(Vector3D.of(0, -4, -4), Vector3D.of(1, -4, -4), 1.0e-10)).distance(Vector3D.of(0, -4, -4)),
+                            l.intersection(new Line(Vector3D.of(0, -4, -4), Vector3D.of(1, -4, -4), TEST_PRECISION)).distance(Vector3D.of(0, -4, -4)),
                             1.0e-10);
-        Assert.assertNull(l.intersection(new Line(Vector3D.of(0, -4, 0), Vector3D.of(1, -4, 0), 1.0e-10)));
+        Assert.assertNull(l.intersection(new Line(Vector3D.of(0, -4, 0), Vector3D.of(1, -4, 0), TEST_PRECISION)));
     }
 
     @Test
@@ -130,7 +137,7 @@ public class LineTest {
         // setup
         Line line = new Line(Vector3D.of(1653345.6696423641, 6170370.041579291, 90000),
                              Vector3D.of(1650757.5050732433, 6160710.879908984, 0.9),
-                             1.0e-10);
+                             TEST_PRECISION);
         Vector3D expected = line.getDirection().negate();
 
         // action
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/OBJWriter.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/OBJWriter.java
index b1bccca..4346306 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/OBJWriter.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/OBJWriter.java
@@ -31,6 +31,7 @@ import java.util.TreeMap;
 import org.apache.commons.geometry.core.partitioning.BSPTree;
 import org.apache.commons.geometry.core.partitioning.BSPTreeVisitor;
 import org.apache.commons.geometry.core.partitioning.BoundaryAttribute;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.twod.PolygonsSet;
 import org.apache.commons.geometry.euclidean.twod.Vector2D;
 
@@ -60,7 +61,7 @@ public class OBJWriter {
      */
     public static void write(File file, PolyhedronsSet poly) throws IOException {
         // get the vertices and faces
-        MeshBuilder meshBuilder = new MeshBuilder(poly.getTolerance());
+        MeshBuilder meshBuilder = new MeshBuilder(poly.getPrecision());
         poly.getTree(true).visit(meshBuilder);
 
         // write them to the file
@@ -114,46 +115,28 @@ public class OBJWriter {
      */
     private static class VertexComparator implements Comparator<Vector3D> {
 
-        /** Geometric tolerance value */
-        private double tolerance;
+        /** Precision context to deteremine floating-point equality */
+        private final DoublePrecisionContext precision;
 
         /** Creates a new instance with the given tolerance value.
          * @param tolerance
          */
-        public VertexComparator(double tolerance) {
-            this.tolerance = tolerance;
+        public VertexComparator(final DoublePrecisionContext precision) {
+            this.precision = precision;
         }
 
         /** {@inheritDoc} */
         @Override
         public int compare(Vector3D a, Vector3D b) {
-            int result = compareDoubles(a.getX(), b.getX());
+            int result = precision.compare(a.getX(), b.getX());
             if (result == 0) {
-                result = compareDoubles(a.getY(), b.getY());
+                result = precision.compare(a.getY(), b.getY());
                 if (result == 0) {
-                    result = compareDoubles(a.getZ(), b.getZ());
+                    result = precision.compare(a.getZ(), b.getZ());
                 }
             }
             return result;
         }
-
-        /** Helper method to compare two double values using the
-         * configured tolerance value. If the values are within
-         * tolerance of each other, then they are considered equal.
-         * @param a
-         * @param b
-         * @return
-         */
-        private int compareDoubles(double a, double b) {
-            double diff = a - b;
-            if (diff < -tolerance) {
-                return -1;
-            }
-            else if (diff > tolerance) {
-                return 1;
-            }
-            return 0;
-        }
     }
 
     /** Class for converting a 3D BSPTree into a list of vertices
@@ -161,8 +144,8 @@ public class OBJWriter {
      */
     private static class MeshBuilder implements BSPTreeVisitor<Vector3D> {
 
-        /** Geometric tolerance */
-        private final double tolerance;
+        /** Precision context to deteremine floating-point equality */
+        private final DoublePrecisionContext precision;
 
         /** Map of vertices to their index in the vertices list */
         private Map<Vector3D, Integer> vertexIndexMap;
@@ -179,9 +162,9 @@ public class OBJWriter {
         /** Creates a new instance with the given tolerance.
          * @param tolerance
          */
-        public MeshBuilder(double tolerance) {
-            this.tolerance = tolerance;
-            this.vertexIndexMap = new TreeMap<>(new VertexComparator(tolerance));
+        public MeshBuilder(final DoublePrecisionContext precision) {
+            this.precision = precision;
+            this.vertexIndexMap = new TreeMap<>(new VertexComparator(precision));
             this.vertices = new ArrayList<>();
             this.faces = new ArrayList<>();
         }
@@ -235,7 +218,7 @@ public class OBJWriter {
             Plane plane = (Plane) subplane.getHyperplane();
             PolygonsSet poly = (PolygonsSet) subplane.getRemainingRegion();
 
-            TriangleExtractor triExtractor = new TriangleExtractor(tolerance);
+            TriangleExtractor triExtractor = new TriangleExtractor(precision);
             poly.getTree(true).visit(triExtractor);
 
             Vector3D v1, v2, v3;
@@ -274,8 +257,8 @@ public class OBJWriter {
      */
     private static class TriangleExtractor implements BSPTreeVisitor<Vector2D> {
 
-        /** Geometric tolerance */
-        private double tolerance;
+        /** Precision context to deteremine floating-point equality */
+        private final DoublePrecisionContext precision;
 
         /** List of extracted triangles */
         private List<Vector2D[]> triangles = new ArrayList<>();
@@ -283,8 +266,8 @@ public class OBJWriter {
         /** Creates a new instance with the given geometric tolerance.
          * @param tolerance
          */
-        public TriangleExtractor(double tolerance) {
-            this.tolerance = tolerance;
+        public TriangleExtractor(final DoublePrecisionContext precision) {
+            this.precision = precision;
         }
 
         /** Returns the list of extracted triangles.
@@ -311,7 +294,7 @@ public class OBJWriter {
         public void visitLeafNode(BSPTree<Vector2D> node) {
             if ((Boolean) node.getAttribute()) {
                 PolygonsSet convexPoly = new PolygonsSet(node.pruneAroundConvexCell(Boolean.TRUE,
-                        Boolean.FALSE, null), tolerance);
+                        Boolean.FALSE, null), precision);
 
                 for (Vector2D[] loop : convexPoly.getVertices()) {
                     if (loop.length > 0 && loop[0] != null) { // skip unclosed loops
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PlaneTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PlaneTest.java
index b509024..f76471a 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PlaneTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PlaneTest.java
@@ -16,15 +16,22 @@
  */
 package org.apache.commons.geometry.euclidean.threed;
 
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class PlaneTest {
 
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
+
     @Test
     public void testContains() {
-        Plane p = new Plane(Vector3D.of(0, 0, 1), Vector3D.of(0, 0, 1), 1.0e-10);
+        Plane p = new Plane(Vector3D.of(0, 0, 1), Vector3D.of(0, 0, 1), TEST_PRECISION);
         Assert.assertTrue(p.contains(Vector3D.of(0, 0, 1)));
         Assert.assertTrue(p.contains(Vector3D.of(17, -32, 1)));
         Assert.assertTrue(! p.contains(Vector3D.of(17, -32, 1.001)));
@@ -33,20 +40,20 @@ public class PlaneTest {
     @Test
     public void testOffset() {
         Vector3D p1 = Vector3D.of(1, 1, 1);
-        Plane p = new Plane(p1, Vector3D.of(0.2, 0, 0), 1.0e-10);
-        Assert.assertEquals(-5.0, p.getOffset(Vector3D.of(-4, 0, 0)), 1.0e-10);
-        Assert.assertEquals(+5.0, p.getOffset(Vector3D.of(6, 10, -12)), 1.0e-10);
+        Plane p = new Plane(p1, Vector3D.of(0.2, 0, 0), TEST_PRECISION);
+        Assert.assertEquals(-5.0, p.getOffset(Vector3D.of(-4, 0, 0)), TEST_EPS);
+        Assert.assertEquals(+5.0, p.getOffset(Vector3D.of(6, 10, -12)), TEST_EPS);
         Assert.assertEquals(0.3,
                             p.getOffset(Vector3D.linearCombination(1.0, p1, 0.3, p.getNormal())),
-                            1.0e-10);
+                            TEST_EPS);
         Assert.assertEquals(-0.3,
                             p.getOffset(Vector3D.linearCombination(1.0, p1, -0.3, p.getNormal())),
-                            1.0e-10);
+                            TEST_EPS);
     }
 
     @Test
     public void testPoint() {
-        Plane p = new Plane(Vector3D.of(2, -3, 1), Vector3D.of(1, 4, 9), 1.0e-10);
+        Plane p = new Plane(Vector3D.of(2, -3, 1), Vector3D.of(1, 4, 9), TEST_PRECISION);
         Assert.assertTrue(p.contains(p.getOrigin()));
     }
 
@@ -55,7 +62,7 @@ public class PlaneTest {
         Vector3D p1 = Vector3D.of(1.2, 3.4, -5.8);
         Vector3D p2 = Vector3D.of(3.4, -5.8, 1.2);
         Vector3D p3 = Vector3D.of(-2.0, 4.3, 0.7);
-        Plane    p  = new Plane(p1, p2, p3, 1.0e-10);
+        Plane    p  = new Plane(p1, p2, p3, TEST_PRECISION);
         Assert.assertTrue(p.contains(p1));
         Assert.assertTrue(p.contains(p2));
         Assert.assertTrue(p.contains(p3));
@@ -66,7 +73,7 @@ public class PlaneTest {
         Vector3D p1 = Vector3D.of(1.2, 3.4, -5.8);
         Vector3D p2 = Vector3D.of(3.4, -5.8, 1.2);
         Vector3D p3 = Vector3D.of(-2.0, 4.3, 0.7);
-        Plane    p  = new Plane(p1, p2, p3, 1.0e-10);
+        Plane    p  = new Plane(p1, p2, p3, TEST_PRECISION);
         Vector3D oldNormal = p.getNormal();
 
         p = p.rotate(p2, QuaternionRotation.fromAxisAngle(p2.subtract(p1), 1.7));
@@ -91,7 +98,7 @@ public class PlaneTest {
         Vector3D p1 = Vector3D.of(1.2, 3.4, -5.8);
         Vector3D p2 = Vector3D.of(3.4, -5.8, 1.2);
         Vector3D p3 = Vector3D.of(-2.0, 4.3, 0.7);
-        Plane    p  = new Plane(p1, p2, p3, 1.0e-10);
+        Plane    p  = new Plane(p1, p2, p3, TEST_PRECISION);
 
         p = p.translate(Vector3D.linearCombination(2.0, p.getU(), -1.5, p.getV()));
         Assert.assertTrue(p.contains(p1));
@@ -112,22 +119,22 @@ public class PlaneTest {
 
     @Test
     public void testIntersection() {
-        Plane p = new Plane(Vector3D.of(1, 2, 3), Vector3D.of(-4, 1, -5), 1.0e-10);
-        Line  l = new Line(Vector3D.of(0.2, -3.5, 0.7), Vector3D.of(1.2, -2.5, -0.3), 1.0e-10);
+        Plane p = new Plane(Vector3D.of(1, 2, 3), Vector3D.of(-4, 1, -5), TEST_PRECISION);
+        Line  l = new Line(Vector3D.of(0.2, -3.5, 0.7), Vector3D.of(1.2, -2.5, -0.3), TEST_PRECISION);
         Vector3D point = p.intersection(l);
         Assert.assertTrue(p.contains(point));
         Assert.assertTrue(l.contains(point));
         Assert.assertNull(p.intersection(new Line(Vector3D.of(10, 10, 10),
                                                   Vector3D.of(10, 10, 10).add(p.getNormal().orthogonal()),
-                                                  1.0e-10)));
+                                                  TEST_PRECISION)));
     }
 
     @Test
     public void testIntersection2() {
         Vector3D p1  = Vector3D.of(1.2, 3.4, -5.8);
         Vector3D p2  = Vector3D.of(3.4, -5.8, 1.2);
-        Plane    pA  = new Plane(p1, p2, Vector3D.of(-2.0, 4.3, 0.7), 1.0e-10);
-        Plane    pB  = new Plane(p1, Vector3D.of(11.4, -3.8, 5.1), p2, 1.0e-10);
+        Plane    pA  = new Plane(p1, p2, Vector3D.of(-2.0, 4.3, 0.7), TEST_PRECISION);
+        Plane    pB  = new Plane(p1, Vector3D.of(11.4, -3.8, 5.1), p2, TEST_PRECISION);
         Line     l   = pA.intersection(pB);
         Assert.assertTrue(l.contains(p1));
         Assert.assertTrue(l.contains(p2));
@@ -137,13 +144,13 @@ public class PlaneTest {
     @Test
     public void testIntersection3() {
         Vector3D reference = Vector3D.of(1.2, 3.4, -5.8);
-        Plane p1 = new Plane(reference, Vector3D.of(1, 3, 3), 1.0e-10);
-        Plane p2 = new Plane(reference, Vector3D.of(-2, 4, 0), 1.0e-10);
-        Plane p3 = new Plane(reference, Vector3D.of(7, 0, -4), 1.0e-10);
+        Plane p1 = new Plane(reference, Vector3D.of(1, 3, 3), TEST_PRECISION);
+        Plane p2 = new Plane(reference, Vector3D.of(-2, 4, 0), TEST_PRECISION);
+        Plane p3 = new Plane(reference, Vector3D.of(7, 0, -4), TEST_PRECISION);
         Vector3D p = Plane.intersection(p1, p2, p3);
-        Assert.assertEquals(reference.getX(), p.getX(), 1.0e-10);
-        Assert.assertEquals(reference.getY(), p.getY(), 1.0e-10);
-        Assert.assertEquals(reference.getZ(), p.getZ(), 1.0e-10);
+        Assert.assertEquals(reference.getX(), p.getX(), TEST_EPS);
+        Assert.assertEquals(reference.getY(), p.getY(), TEST_EPS);
+        Assert.assertEquals(reference.getZ(), p.getZ(), TEST_EPS);
     }
 
     @Test
@@ -151,16 +158,16 @@ public class PlaneTest {
         Vector3D p1  = Vector3D.of(1.2, 3.4, -5.8);
         Vector3D p2  = Vector3D.of(3.4, -5.8, 1.2);
         Vector3D p3  = Vector3D.of(-2.0, 4.3, 0.7);
-        Plane    pA  = new Plane(p1, p2, p3, 1.0e-10);
-        Plane    pB  = new Plane(p1, Vector3D.of(11.4, -3.8, 5.1), p2, 1.0e-10);
+        Plane    pA  = new Plane(p1, p2, p3, TEST_PRECISION);
+        Plane    pB  = new Plane(p1, Vector3D.of(11.4, -3.8, 5.1), p2, TEST_PRECISION);
         Assert.assertTrue(! pA.isSimilarTo(pB));
         Assert.assertTrue(pA.isSimilarTo(pA));
-        Assert.assertTrue(pA.isSimilarTo(new Plane(p1, p3, p2, 1.0e-10)));
+        Assert.assertTrue(pA.isSimilarTo(new Plane(p1, p3, p2, TEST_PRECISION)));
         Vector3D shift = Vector3D.linearCombination(0.3, pA.getNormal());
         Assert.assertTrue(! pA.isSimilarTo(new Plane(p1.add(shift),
                                                      p3.add(shift),
                                                      p2.add(shift),
-                                                     1.0e-10)));
+                                                     TEST_PRECISION)));
     }
 
 }
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PolyhedronsSetTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PolyhedronsSetTest.java
index e4c1a3e..c2c528b 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PolyhedronsSetTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/PolyhedronsSetTest.java
@@ -31,12 +31,13 @@ import org.apache.commons.geometry.core.partitioning.BoundaryProjection;
 import org.apache.commons.geometry.core.partitioning.Region;
 import org.apache.commons.geometry.core.partitioning.RegionFactory;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
 import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
 import org.apache.commons.geometry.euclidean.twod.PolygonsSet;
 import org.apache.commons.geometry.euclidean.twod.SubLine;
 import org.apache.commons.geometry.euclidean.twod.Vector2D;
-import org.apache.commons.numbers.core.Precision;
 import org.apache.commons.rng.UniformRandomProvider;
 import org.apache.commons.rng.simple.RandomSource;
 import org.junit.Assert;
@@ -44,18 +45,21 @@ import org.junit.Test;
 
 public class PolyhedronsSetTest {
 
-    private static final double TEST_TOLERANCE = 1e-10;
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
 
     @Test
     public void testWholeSpace() {
         // act
-        PolyhedronsSet polySet = new PolyhedronsSet(TEST_TOLERANCE);
+        PolyhedronsSet polySet = new PolyhedronsSet(TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
+        Assert.assertSame(TEST_PRECISION, polySet.getPrecision());
         EuclideanTestUtils.assertPositiveInfinity(polySet.getSize());
-        Assert.assertEquals(0.0, polySet.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.NaN, polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, polySet.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.NaN, polySet.getBarycenter(), TEST_EPS);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertTrue(polySet.isFull());
 
@@ -70,13 +74,13 @@ public class PolyhedronsSetTest {
     @Test
     public void testEmptyRegion() {
         // act
-        PolyhedronsSet polySet = new PolyhedronsSet(new BSPTree<Vector3D>(Boolean.FALSE), TEST_TOLERANCE);
+        PolyhedronsSet polySet = new PolyhedronsSet(new BSPTree<Vector3D>(Boolean.FALSE), TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
-        Assert.assertEquals(0.0, polySet.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(0.0, polySet.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.NaN, polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertSame(TEST_PRECISION, polySet.getPrecision());
+        Assert.assertEquals(0.0, polySet.getSize(), TEST_EPS);
+        Assert.assertEquals(0.0, polySet.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.NaN, polySet.getBarycenter(), TEST_EPS);
         Assert.assertTrue(polySet.isEmpty());
         Assert.assertFalse(polySet.isFull());
 
@@ -92,17 +96,17 @@ public class PolyhedronsSetTest {
     public void testHalfSpace() {
         // arrange
         List<SubHyperplane<Vector3D>> boundaries = new ArrayList<>();
-        boundaries.add(new SubPlane(new Plane(Vector3D.ZERO, Vector3D.PLUS_Y, TEST_TOLERANCE),
-                new PolygonsSet(TEST_TOLERANCE)));
+        boundaries.add(new SubPlane(new Plane(Vector3D.ZERO, Vector3D.PLUS_Y, TEST_PRECISION),
+                new PolygonsSet(TEST_PRECISION)));
 
         // act
-        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
+        Assert.assertSame(TEST_PRECISION, polySet.getPrecision());
         EuclideanTestUtils.assertPositiveInfinity(polySet.getSize());
         EuclideanTestUtils.assertPositiveInfinity(polySet.getBoundarySize());
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.NaN, polySet.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.NaN, polySet.getBarycenter(), TEST_EPS);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertFalse(polySet.isFull());
 
@@ -118,17 +122,17 @@ public class PolyhedronsSetTest {
     @Test
     public void testInvertedRegion() {
         // arrange
-        List<SubHyperplane<Vector3D>> boundaries = createBoxBoundaries(Vector3D.ZERO, 1.0, TEST_TOLERANCE);
-        PolyhedronsSet box = new PolyhedronsSet(boundaries, TEST_TOLERANCE);;
+        List<SubHyperplane<Vector3D>> boundaries = createBoxBoundaries(Vector3D.ZERO, 1.0, TEST_EPS);
+        PolyhedronsSet box = new PolyhedronsSet(boundaries, TEST_PRECISION);
 
         // act
         PolyhedronsSet polySet = (PolyhedronsSet) new RegionFactory<Vector3D>().getComplement(box);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
+        Assert.assertSame(TEST_PRECISION, polySet.getPrecision());
         EuclideanTestUtils.assertPositiveInfinity(polySet.getSize());
-        Assert.assertEquals(6, polySet.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.NaN, polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(6, polySet.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.NaN, polySet.getBarycenter(), TEST_EPS);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertFalse(polySet.isFull());
 
@@ -147,13 +151,13 @@ public class PolyhedronsSetTest {
         List<SubHyperplane<Vector3D>> boundaries = new ArrayList<>();
 
         // act
-        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
+        Assert.assertSame(TEST_PRECISION, polySet.getPrecision());
         EuclideanTestUtils.assertPositiveInfinity(polySet.getSize());
-        Assert.assertEquals(0.0, polySet.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.NaN, polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, polySet.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.NaN, polySet.getBarycenter(), TEST_EPS);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertTrue(polySet.isFull());
     }
@@ -161,16 +165,16 @@ public class PolyhedronsSetTest {
     @Test
     public void testCreateFromBoundaries_unitBox() {
         // arrange
-        List<SubHyperplane<Vector3D>> boundaries = createBoxBoundaries(Vector3D.ZERO, 1.0, TEST_TOLERANCE);
+        List<SubHyperplane<Vector3D>> boundaries = createBoxBoundaries(Vector3D.ZERO, 1.0, TEST_EPS);
 
         // act
-        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
-        Assert.assertEquals(1.0, polySet.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(6.0, polySet.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.ZERO, polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertSame(TEST_PRECISION, polySet.getPrecision());
+        Assert.assertEquals(1.0, polySet.getSize(), TEST_EPS);
+        Assert.assertEquals(6.0, polySet.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.ZERO, polySet.getBarycenter(), TEST_EPS);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertFalse(polySet.isFull());
 
@@ -225,17 +229,17 @@ public class PolyhedronsSetTest {
     public void testCreateFromBoundaries_twoBoxes_disjoint() {
         // arrange
         List<SubHyperplane<Vector3D>> boundaries = new ArrayList<>();
-        boundaries.addAll(createBoxBoundaries(Vector3D.ZERO, 1.0, TEST_TOLERANCE));
-        boundaries.addAll(createBoxBoundaries(Vector3D.of(2, 0, 0), 1.0, TEST_TOLERANCE));
+        boundaries.addAll(createBoxBoundaries(Vector3D.ZERO, 1.0, TEST_EPS));
+        boundaries.addAll(createBoxBoundaries(Vector3D.of(2, 0, 0), 1.0, TEST_EPS));
 
         // act
-        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
-        Assert.assertEquals(2.0, polySet.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(12.0, polySet.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 0, 0), polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertSame(TEST_PRECISION, polySet.getPrecision());
+        Assert.assertEquals(2.0, polySet.getSize(), TEST_EPS);
+        Assert.assertEquals(12.0, polySet.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 0, 0), polySet.getBarycenter(), TEST_EPS);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertFalse(polySet.isFull());
 
@@ -253,17 +257,17 @@ public class PolyhedronsSetTest {
     public void testCreateFromBoundaries_twoBoxes_sharedSide() {
         // arrange
         List<SubHyperplane<Vector3D>> boundaries = new ArrayList<>();
-        boundaries.addAll(createBoxBoundaries(Vector3D.of(0, 0, 0), 1.0, TEST_TOLERANCE));
-        boundaries.addAll(createBoxBoundaries(Vector3D.of(1, 0, 0), 1.0, TEST_TOLERANCE));
+        boundaries.addAll(createBoxBoundaries(Vector3D.of(0, 0, 0), 1.0, TEST_EPS));
+        boundaries.addAll(createBoxBoundaries(Vector3D.of(1, 0, 0), 1.0, TEST_EPS));
 
         // act
-        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
-        Assert.assertEquals(2.0, polySet.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(10.0, polySet.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0.5, 0, 0), polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertSame(TEST_PRECISION, polySet.getPrecision());
+        Assert.assertEquals(2.0, polySet.getSize(), TEST_EPS);
+        Assert.assertEquals(10.0, polySet.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0.5, 0, 0), polySet.getBarycenter(), TEST_EPS);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertFalse(polySet.isFull());
 
@@ -279,19 +283,20 @@ public class PolyhedronsSetTest {
     @Test
     public void testCreateFromBoundaries_twoBoxes_separationLessThanTolerance() {
         // arrange
-        double tolerance = 1e-6;
+        double eps = 1e-6;
+        DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(eps);
         List<SubHyperplane<Vector3D>> boundaries = new ArrayList<>();
-        boundaries.addAll(createBoxBoundaries(Vector3D.of(0, 0, 0), 1.0, tolerance));
-        boundaries.addAll(createBoxBoundaries(Vector3D.of(1 + 1e-7, 0, 0), 1.0, tolerance));
+        boundaries.addAll(createBoxBoundaries(Vector3D.of(0, 0, 0), 1.0, eps));
+        boundaries.addAll(createBoxBoundaries(Vector3D.of(1 + 1e-7, 0, 0), 1.0, eps));
 
         // act
-        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, tolerance);
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, precision);
 
         // assert
-        Assert.assertEquals(tolerance, polySet.getTolerance(), Precision.EPSILON);
-        Assert.assertEquals(2.0, polySet.getSize(), tolerance);
-        Assert.assertEquals(10.0, polySet.getBoundarySize(), tolerance);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0.5 + 5e-8, 0, 0), polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertSame(precision, polySet.getPrecision());
+        Assert.assertEquals(2.0, polySet.getSize(), eps);
+        Assert.assertEquals(10.0, polySet.getBoundarySize(), eps);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0.5 + 5e-8, 0, 0), polySet.getBarycenter(), TEST_EPS);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertFalse(polySet.isFull());
 
@@ -308,17 +313,17 @@ public class PolyhedronsSetTest {
     public void testCreateFromBoundaries_twoBoxes_sharedEdge() {
         // arrange
         List<SubHyperplane<Vector3D>> boundaries = new ArrayList<>();
-        boundaries.addAll(createBoxBoundaries(Vector3D.of(0, 0, 0), 1.0, TEST_TOLERANCE));
-        boundaries.addAll(createBoxBoundaries(Vector3D.of(1, 1, 0), 1.0, TEST_TOLERANCE));
+        boundaries.addAll(createBoxBoundaries(Vector3D.of(0, 0, 0), 1.0, TEST_EPS));
+        boundaries.addAll(createBoxBoundaries(Vector3D.of(1, 1, 0), 1.0, TEST_EPS));
 
         // act
-        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
-        Assert.assertEquals(2.0, polySet.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(12.0, polySet.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0.5, 0.5, 0), polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertSame(TEST_PRECISION, polySet.getPrecision());
+        Assert.assertEquals(2.0, polySet.getSize(), TEST_EPS);
+        Assert.assertEquals(12.0, polySet.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0.5, 0.5, 0), polySet.getBarycenter(), TEST_EPS);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertFalse(polySet.isFull());
 
@@ -337,17 +342,17 @@ public class PolyhedronsSetTest {
     public void testCreateFromBoundaries_twoBoxes_sharedPoint() {
         // arrange
         List<SubHyperplane<Vector3D>> boundaries = new ArrayList<>();
-        boundaries.addAll(createBoxBoundaries(Vector3D.of(0, 0, 0), 1.0, TEST_TOLERANCE));
-        boundaries.addAll(createBoxBoundaries(Vector3D.of(1, 1, 1), 1.0, TEST_TOLERANCE));
+        boundaries.addAll(createBoxBoundaries(Vector3D.of(0, 0, 0), 1.0, TEST_EPS));
+        boundaries.addAll(createBoxBoundaries(Vector3D.of(1, 1, 1), 1.0, TEST_EPS));
 
         // act
-        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
-        Assert.assertEquals(2.0, polySet.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(12.0, polySet.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0.5, 0.5, 0.5), polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertSame(TEST_PRECISION, polySet.getPrecision());
+        Assert.assertEquals(2.0, polySet.getSize(), TEST_EPS);
+        Assert.assertEquals(12.0, polySet.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0.5, 0.5, 0.5), polySet.getBarycenter(), TEST_EPS);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertFalse(polySet.isFull());
 
@@ -365,12 +370,12 @@ public class PolyhedronsSetTest {
     @Test
     public void testCreateBox() {
         // act
-        PolyhedronsSet tree = new PolyhedronsSet(0, 1, 0, 1, 0, 1, TEST_TOLERANCE);
+        PolyhedronsSet tree = new PolyhedronsSet(0, 1, 0, 1, 0, 1, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(1.0, tree.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(6.0, tree.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0.5, 0.5, 0.5), tree.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(1.0, tree.getSize(), TEST_EPS);
+        Assert.assertEquals(6.0, tree.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0.5, 0.5, 0.5), tree.getBarycenter(), TEST_EPS);
 
         for (double x = -0.25; x < 1.25; x += 0.1) {
             boolean xOK = (x >= 0.0) && (x <= 1.0);
@@ -405,7 +410,7 @@ public class PolyhedronsSetTest {
     @Test
     public void testInvertedBox() {
         // arrange
-        PolyhedronsSet tree = new PolyhedronsSet(0, 1, 0, 1, 0, 1, 1.0e-10);
+        PolyhedronsSet tree = new PolyhedronsSet(0, 1, 0, 1, 0, 1, TEST_PRECISION);
 
         // act
         tree = (PolyhedronsSet) new RegionFactory<Vector3D>().getComplement(tree);
@@ -460,15 +465,15 @@ public class PolyhedronsSetTest {
         // act
         PolyhedronsSet tree =
             (PolyhedronsSet) new RegionFactory<Vector3D>().buildConvex(
-                new Plane(vertex3, vertex2, vertex1, TEST_TOLERANCE),
-                new Plane(vertex2, vertex3, vertex4, TEST_TOLERANCE),
-                new Plane(vertex4, vertex3, vertex1, TEST_TOLERANCE),
-                new Plane(vertex1, vertex2, vertex4, TEST_TOLERANCE));
+                new Plane(vertex3, vertex2, vertex1, TEST_PRECISION),
+                new Plane(vertex2, vertex3, vertex4, TEST_PRECISION),
+                new Plane(vertex4, vertex3, vertex1, TEST_PRECISION),
+                new Plane(vertex1, vertex2, vertex4, TEST_PRECISION));
 
         // assert
-        Assert.assertEquals(1.0 / 3.0, tree.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(2.0 * Math.sqrt(3.0), tree.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1.5, 2.5, 3.5), tree.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(1.0 / 3.0, tree.getSize(), TEST_EPS);
+        Assert.assertEquals(2.0 * Math.sqrt(3.0), tree.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1.5, 2.5, 3.5), tree.getBarycenter(), TEST_EPS);
 
         double third = 1.0 / 3.0;
         checkPoints(Region.Location.BOUNDARY, tree, new Vector3D[] {
@@ -499,7 +504,7 @@ public class PolyhedronsSetTest {
         // assert
         Assert.assertEquals(sphereVolume(radius), polySet.getSize(), approximationTolerance);
         Assert.assertEquals(sphereSurface(radius), polySet.getBoundarySize(), approximationTolerance);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 2, 3), polySet.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(1, 2, 3), polySet.getBarycenter(), TEST_EPS);
         Assert.assertFalse(polySet.isEmpty());
         Assert.assertFalse(polySet.isFull());
 
@@ -534,10 +539,10 @@ public class PolyhedronsSetTest {
         // act
         PolyhedronsSet tree =
             (PolyhedronsSet) new RegionFactory<Vector3D>().buildConvex(
-                new Plane(vertex3, vertex2, vertex1, TEST_TOLERANCE),
-                new Plane(vertex2, vertex3, vertex4, TEST_TOLERANCE),
-                new Plane(vertex4, vertex3, vertex1, TEST_TOLERANCE),
-                new Plane(vertex1, vertex2, vertex4, TEST_TOLERANCE));
+                new Plane(vertex3, vertex2, vertex1, TEST_PRECISION),
+                new Plane(vertex2, vertex3, vertex4, TEST_PRECISION),
+                new Plane(vertex4, vertex3, vertex1, TEST_PRECISION),
+                new Plane(vertex1, vertex2, vertex4, TEST_PRECISION));
 
         // assert
         Vector3D barycenter = tree.getBarycenter();
@@ -553,7 +558,7 @@ public class PolyhedronsSetTest {
                          1.0, r.apply(barycenter.subtract(c)));
         Assert.assertEquals(0.0,
                             newB.subtract(tree.getBarycenter()).norm(),
-                            TEST_TOLERANCE);
+                            TEST_EPS);
 
         final Vector3D[] expectedV = new Vector3D[] {
                 Vector3D.linearCombination(1.0, s,
@@ -604,7 +609,7 @@ public class PolyhedronsSetTest {
                     for (int k = 0; k < expectedV.length; ++k) {
                         d = Math.min(d, v.subtract(expectedV[k]).norm());
                     }
-                    Assert.assertEquals(0, d, TEST_TOLERANCE);
+                    Assert.assertEquals(0, d, TEST_EPS);
                 }
             }
 
@@ -623,12 +628,12 @@ public class PolyhedronsSetTest {
 
         // act
         PolyhedronsSet tree =
-            new PolyhedronsSet(x - l, x + l, y - w, y + w, z - w, z + w, TEST_TOLERANCE);
+            new PolyhedronsSet(x - l, x + l, y - w, y + w, z - w, z + w, TEST_PRECISION);
 
         // assert
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(x, y, z), tree.getBarycenter(), TEST_TOLERANCE);
-        Assert.assertEquals(8 * l * w * w, tree.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(8 * w * (2 * l + w), tree.getBoundarySize(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(x, y, z), tree.getBarycenter(), TEST_EPS);
+        Assert.assertEquals(8 * l * w * w, tree.getSize(), TEST_EPS);
+        Assert.assertEquals(8 * w * (2 * l + w), tree.getBoundarySize(), TEST_EPS);
     }
 
     @Test
@@ -640,20 +645,20 @@ public class PolyhedronsSetTest {
         double w = 0.1;
         double l = 1.0;
         PolyhedronsSet xBeam =
-            new PolyhedronsSet(x - l, x + l, y - w, y + w, z - w, z + w, TEST_TOLERANCE);
+            new PolyhedronsSet(x - l, x + l, y - w, y + w, z - w, z + w, TEST_PRECISION);
         PolyhedronsSet yBeam =
-            new PolyhedronsSet(x - w, x + w, y - l, y + l, z - w, z + w, TEST_TOLERANCE);
+            new PolyhedronsSet(x - w, x + w, y - l, y + l, z - w, z + w, TEST_PRECISION);
         PolyhedronsSet zBeam =
-            new PolyhedronsSet(x - w, x + w, y - w, y + w, z - l, z + l, TEST_TOLERANCE);
+            new PolyhedronsSet(x - w, x + w, y - w, y + w, z - l, z + l, TEST_PRECISION);
         RegionFactory<Vector3D> factory = new RegionFactory<>();
 
         // act
         PolyhedronsSet tree = (PolyhedronsSet) factory.union(xBeam, factory.union(yBeam, zBeam));
 
         // assert
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(x, y, z), tree.getBarycenter(), TEST_TOLERANCE);
-        Assert.assertEquals(8 * w * w * (3 * l - 2 * w), tree.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(24 * w * (2 * l - w), tree.getBoundarySize(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(x, y, z), tree.getBarycenter(), TEST_EPS);
+        Assert.assertEquals(8 * w * w * (3 * l - 2 * w), tree.getSize(), TEST_EPS);
+        Assert.assertEquals(24 * w * (2 * l - w), tree.getBoundarySize(), TEST_EPS);
     }
 
     // Issue MATH-780
@@ -686,7 +691,7 @@ public class PolyhedronsSetTest {
             Vector3D v_2 = Vector3D.of(coords[idxB], coords[idxB + 1], coords[idxB + 2]);
             Vector3D v_3 = Vector3D.of(coords[idxC], coords[idxC + 1], coords[idxC + 2]);
             Vector3D[] vertices = {v_1, v_2, v_3};
-            Plane polyPlane = new Plane(v_1, v_2, v_3, TEST_TOLERANCE);
+            Plane polyPlane = new Plane(v_1, v_2, v_3, TEST_PRECISION);
             ArrayList<SubHyperplane<Vector2D>> lines = new ArrayList<>();
 
             Vector2D[] projPts = new Vector2D[vertices.length];
@@ -696,16 +701,16 @@ public class PolyhedronsSetTest {
 
             SubLine lineInPlane = null;
             for (int ptIdx = 0; ptIdx < projPts.length; ptIdx++) {
-                lineInPlane = new SubLine(projPts[ptIdx], projPts[(ptIdx + 1) % projPts.length], TEST_TOLERANCE);
+                lineInPlane = new SubLine(projPts[ptIdx], projPts[(ptIdx + 1) % projPts.length], TEST_PRECISION);
                 lines.add(lineInPlane);
             }
-            Region<Vector2D> polyRegion = new PolygonsSet(lines, TEST_TOLERANCE);
+            Region<Vector2D> polyRegion = new PolygonsSet(lines, TEST_PRECISION);
             SubPlane polygon = new SubPlane(polyPlane, polyRegion);
             subHyperplaneList.add(polygon);
         }
 
         // act
-        PolyhedronsSet polyhedronsSet = new PolyhedronsSet(subHyperplaneList, TEST_TOLERANCE);
+        PolyhedronsSet polyhedronsSet = new PolyhedronsSet(subHyperplaneList, TEST_PRECISION);
 
         // assert
         Assert.assertEquals(8.0, polyhedronsSet.getSize(), 3.0e-6);
@@ -715,10 +720,10 @@ public class PolyhedronsSetTest {
     @Test
     public void testTooThinBox() {
         // act
-        PolyhedronsSet polyhedronsSet = new PolyhedronsSet(0.0, 0.0, 0.0, 1.0, 0.0, 1.0, TEST_TOLERANCE);
+        PolyhedronsSet polyhedronsSet = new PolyhedronsSet(0.0, 0.0, 0.0, 1.0, 0.0, 1.0, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(0.0, polyhedronsSet.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, polyhedronsSet.getSize(), TEST_EPS);
     }
 
     @Test
@@ -726,7 +731,7 @@ public class PolyhedronsSetTest {
         // the following is a wrong usage of the constructor.
         // as explained in the javadoc, the failure is NOT detected at construction
         // time but occurs later on
-        PolyhedronsSet ps = new PolyhedronsSet(new BSPTree<Vector3D>(), TEST_TOLERANCE);
+        PolyhedronsSet ps = new PolyhedronsSet(new BSPTree<Vector3D>(), TEST_PRECISION);
         Assert.assertNotNull(ps);
         try {
             ps.checkPoint(Vector3D.ZERO);
@@ -739,7 +744,8 @@ public class PolyhedronsSetTest {
     @Test
     public void testDumpParse() throws IOException, ParseException {
         // arrange
-        double tol=1e-8;
+        double eps = 1e-8;
+        DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(eps);
 
         Vector3D[] verts=new Vector3D[8];
         double xmin=-1,xmax=1;
@@ -768,18 +774,18 @@ public class PolyhedronsSetTest {
         faces[10]=new int[]{3,6,2}; // back (+y)
         faces[11]=new int[]{6,3,7}; // back (+y)
 
-        PolyhedronsSet polyset = new PolyhedronsSet(Arrays.asList(verts), Arrays.asList(faces), tol);
+        PolyhedronsSet polyset = new PolyhedronsSet(Arrays.asList(verts), Arrays.asList(faces), precision);
 
         // act
         String dump = EuclideanTestUtils.dump(polyset);
-        PolyhedronsSet parsed = EuclideanTestUtils.parsePolyhedronsSet(dump);
+        PolyhedronsSet parsed = EuclideanTestUtils.parsePolyhedronsSet(dump, precision);
 
         // assert
-        Assert.assertEquals(8.0, polyset.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(24.0, polyset.getBoundarySize(), TEST_TOLERANCE);
+        Assert.assertEquals(8.0, polyset.getSize(), TEST_EPS);
+        Assert.assertEquals(24.0, polyset.getBoundarySize(), TEST_EPS);
 
-        Assert.assertEquals(8.0, parsed.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(24.0, parsed.getBoundarySize(), TEST_TOLERANCE);
+        Assert.assertEquals(8.0, parsed.getSize(), TEST_EPS);
+        Assert.assertEquals(24.0, parsed.getBoundarySize(), TEST_EPS);
         Assert.assertTrue(new RegionFactory<Vector3D>().difference(polyset, parsed).isEmpty());
     }
 
@@ -788,9 +794,9 @@ public class PolyhedronsSetTest {
         InputStream stream = getClass().getResourceAsStream("pentomino-N.ply");
         PLYParser   parser = new PLYParser(stream);
         stream.close();
-        PolyhedronsSet polyhedron = new PolyhedronsSet(parser.getVertices(), parser.getFaces(), TEST_TOLERANCE);
-        Assert.assertEquals( 5.0, polyhedron.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(22.0, polyhedron.getBoundarySize(), TEST_TOLERANCE);
+        PolyhedronsSet polyhedron = new PolyhedronsSet(parser.getVertices(), parser.getFaces(), TEST_PRECISION);
+        Assert.assertEquals( 5.0, polyhedron.getSize(), TEST_EPS);
+        Assert.assertEquals(22.0, polyhedron.getBoundarySize(), TEST_EPS);
     }
 
     @Test
@@ -834,7 +840,7 @@ public class PolyhedronsSetTest {
     private void checkError(final List<Vector3D> vertices, final List<int[]> facets,
                             final String expected) {
         try {
-            new PolyhedronsSet(vertices, facets, TEST_TOLERANCE);
+            new PolyhedronsSet(vertices, facets, TEST_PRECISION);
             Assert.fail("an exception should have been thrown");
         } catch (IllegalArgumentException e) {
             String actual = e.getMessage();
@@ -846,17 +852,17 @@ public class PolyhedronsSetTest {
     @Test
     public void testFirstIntersection() {
         // arrange
-        List<SubHyperplane<Vector3D>> boundaries = createBoxBoundaries(Vector3D.ZERO, 2.0, TEST_TOLERANCE);
-        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
+        List<SubHyperplane<Vector3D>> boundaries = createBoxBoundaries(Vector3D.ZERO, 2.0, TEST_EPS);
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_PRECISION);
 
-        Line xPlus = new Line(Vector3D.ZERO, Vector3D.of(1, 0, 0), TEST_TOLERANCE);
-        Line xMinus = new Line(Vector3D.ZERO, Vector3D.of(-1, 0, 0), TEST_TOLERANCE);
+        Line xPlus = new Line(Vector3D.ZERO, Vector3D.of(1, 0, 0), TEST_PRECISION);
+        Line xMinus = new Line(Vector3D.ZERO, Vector3D.of(-1, 0, 0), TEST_PRECISION);
 
-        Line yPlus = new Line(Vector3D.ZERO, Vector3D.of(0, 1, 0), TEST_TOLERANCE);
-        Line yMinus = new Line(Vector3D.ZERO, Vector3D.of(0, -1, 0), TEST_TOLERANCE);
+        Line yPlus = new Line(Vector3D.ZERO, Vector3D.of(0, 1, 0), TEST_PRECISION);
+        Line yMinus = new Line(Vector3D.ZERO, Vector3D.of(0, -1, 0), TEST_PRECISION);
 
-        Line zPlus = new Line(Vector3D.ZERO, Vector3D.of(0, 0, 1), TEST_TOLERANCE);
-        Line zMinus = new Line(Vector3D.ZERO, Vector3D.of(0, 0, -1), TEST_TOLERANCE);
+        Line zPlus = new Line(Vector3D.ZERO, Vector3D.of(0, 0, 1), TEST_PRECISION);
+        Line zMinus = new Line(Vector3D.ZERO, Vector3D.of(0, 0, -1), TEST_PRECISION);
 
         // act/assert
         assertSubPlaneNormal(Vector3D.of(-1, 0, 0), polySet.firstIntersection(Vector3D.of(-1.1, 0, 0), xPlus));
@@ -898,32 +904,32 @@ public class PolyhedronsSetTest {
         Vector3D upperCorner = Vector3D.of(1, 1, 1);
         Vector3D center = lowerCorner.lerp(upperCorner, 0.5);
 
-        List<SubHyperplane<Vector3D>> boundaries = createBoxBoundaries(center, 1.0, TEST_TOLERANCE);
-        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
+        List<SubHyperplane<Vector3D>> boundaries = createBoxBoundaries(center, 1.0, TEST_EPS);
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_PRECISION);
 
-        Line upDiagonal = new Line(lowerCorner, upperCorner, TEST_TOLERANCE);
+        Line upDiagonal = new Line(lowerCorner, upperCorner, TEST_PRECISION);
         Line downDiagonal = upDiagonal.revert();
 
         // act/assert
         SubPlane upFromOutsideResult = (SubPlane) polySet.firstIntersection(Vector3D.of(-1, -1, -1), upDiagonal);
         Assert.assertNotNull(upFromOutsideResult);
         EuclideanTestUtils.assertCoordinatesEqual(lowerCorner,
-                ((Plane) upFromOutsideResult.getHyperplane()).intersection(upDiagonal), TEST_TOLERANCE);
+                ((Plane) upFromOutsideResult.getHyperplane()).intersection(upDiagonal), TEST_EPS);
 
         SubPlane upFromCenterResult = (SubPlane) polySet.firstIntersection(center, upDiagonal);
         Assert.assertNotNull(upFromCenterResult);
         EuclideanTestUtils.assertCoordinatesEqual(upperCorner,
-                ((Plane) upFromCenterResult.getHyperplane()).intersection(upDiagonal), TEST_TOLERANCE);
+                ((Plane) upFromCenterResult.getHyperplane()).intersection(upDiagonal), TEST_EPS);
 
         SubPlane downFromOutsideResult = (SubPlane) polySet.firstIntersection(Vector3D.of(2, 2, 2), downDiagonal);
         Assert.assertNotNull(downFromOutsideResult);
         EuclideanTestUtils.assertCoordinatesEqual(upperCorner,
-                ((Plane) downFromOutsideResult.getHyperplane()).intersection(downDiagonal), TEST_TOLERANCE);
+                ((Plane) downFromOutsideResult.getHyperplane()).intersection(downDiagonal), TEST_EPS);
 
         SubPlane downFromCenterResult = (SubPlane) polySet.firstIntersection(center, downDiagonal);
         Assert.assertNotNull(downFromCenterResult);
         EuclideanTestUtils.assertCoordinatesEqual(lowerCorner,
-                ((Plane) downFromCenterResult.getHyperplane()).intersection(downDiagonal), TEST_TOLERANCE);
+                ((Plane) downFromCenterResult.getHyperplane()).intersection(downDiagonal), TEST_EPS);
     }
 
 
@@ -932,7 +938,8 @@ public class PolyhedronsSetTest {
     @Test
     public void testFirstIntersection_onlyReturnsPointsInDirectionOfRay() throws IOException, ParseException {
         // arrange
-        PolyhedronsSet polyset = EuclideanTestUtils.parsePolyhedronsSet(loadTestData("issue-1211.bsp"));
+        DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-8);
+        PolyhedronsSet polyset = EuclideanTestUtils.parsePolyhedronsSet(loadTestData("issue-1211.bsp"), precision);
         UniformRandomProvider random = RandomSource.create(RandomSource.WELL_1024_A, 0xb97c9d1ade21e40al);
 
         // act/assert
@@ -942,7 +949,7 @@ public class PolyhedronsSetTest {
             Vector3D direction = Vector3D.of(2 * random.nextDouble() - 1,
                                               2 * random.nextDouble() - 1,
                                               2 * random.nextDouble() - 1).normalize();
-            Line line = new Line(origin, origin.add(direction), polyset.getTolerance());
+            Line line = new Line(origin, origin.add(direction), polyset.getPrecision());
             SubHyperplane<Vector3D> plane = polyset.firstIntersection(origin, line);
             if (plane != null) {
                 Vector3D intersectionPoint = ((Plane)plane.getHyperplane()).intersection(line);
@@ -958,7 +965,7 @@ public class PolyhedronsSetTest {
         double tolerance = 0.05;
         double size = 1.0;
         double radius = size * 0.5;
-        PolyhedronsSet box = new PolyhedronsSet(0, size, 0, size, 0, size, TEST_TOLERANCE);
+        PolyhedronsSet box = new PolyhedronsSet(0, size, 0, size, 0, size, TEST_PRECISION);
         PolyhedronsSet sphere = createSphere(Vector3D.of(size * 0.5, size * 0.5, size), radius, 8, 16);
 
         // act
@@ -1005,7 +1012,7 @@ public class PolyhedronsSetTest {
         // assert
         Assert.assertEquals(sphereVolume(radius), result.getSize(), tolerance);
         Assert.assertEquals(sphereSurface(radius), result.getBoundarySize(), tolerance);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.ZERO, result.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.ZERO, result.getBarycenter(), TEST_EPS);
         Assert.assertFalse(result.isEmpty());
         Assert.assertFalse(result.isFull());
 
@@ -1033,7 +1040,7 @@ public class PolyhedronsSetTest {
         double tolerance = 0.05;
         double size = 1.0;
         double radius = size * 0.5;
-        PolyhedronsSet box = new PolyhedronsSet(0, size, 0, size, 0, size, TEST_TOLERANCE);
+        PolyhedronsSet box = new PolyhedronsSet(0, size, 0, size, 0, size, TEST_PRECISION);
         PolyhedronsSet sphere = createSphere(Vector3D.of(size * 0.5, size * 0.5, size), radius, 8, 16);
 
         // act
@@ -1079,7 +1086,7 @@ public class PolyhedronsSetTest {
         // assert
         Assert.assertEquals(sphereVolume(radius), result.getSize(), tolerance);
         Assert.assertEquals(sphereSurface(radius), result.getBoundarySize(), tolerance);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.ZERO, result.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.ZERO, result.getBarycenter(), TEST_EPS);
         Assert.assertFalse(result.isEmpty());
         Assert.assertFalse(result.isFull());
 
@@ -1108,21 +1115,21 @@ public class PolyhedronsSetTest {
         PolyhedronsSet box1 = new PolyhedronsSet(
                 0, size,
                 0, size,
-                0, size, TEST_TOLERANCE);
+                0, size, TEST_PRECISION);
         PolyhedronsSet box2 = new PolyhedronsSet(
                 0.5, size + 0.5,
                 0.5, size + 0.5,
-                0.5, size + 0.5, TEST_TOLERANCE);
+                0.5, size + 0.5, TEST_PRECISION);
 
         // act
         PolyhedronsSet result = (PolyhedronsSet) new RegionFactory<Vector3D>().xor(box1, box2);
 
         // OBJWriter.write("xor_twoCubes.obj", result);
 
-        Assert.assertEquals((2 * cubeVolume(size)) - (2 * cubeVolume(size * 0.5)), result.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals((2 * cubeVolume(size)) - (2 * cubeVolume(size * 0.5)), result.getSize(), TEST_EPS);
 
         // assert
-        Assert.assertEquals(2 * cubeSurface(size), result.getBoundarySize(), TEST_TOLERANCE);
+        Assert.assertEquals(2 * cubeSurface(size), result.getBoundarySize(), TEST_EPS);
         Assert.assertFalse(result.isEmpty());
         Assert.assertFalse(result.isFull());
 
@@ -1150,7 +1157,7 @@ public class PolyhedronsSetTest {
         double tolerance = 0.05;
         double size = 1.0;
         double radius = size * 0.5;
-        PolyhedronsSet box = new PolyhedronsSet(0, size, 0, size, 0, size, TEST_TOLERANCE);
+        PolyhedronsSet box = new PolyhedronsSet(0, size, 0, size, 0, size, TEST_PRECISION);
         PolyhedronsSet sphere = createSphere(Vector3D.of(size * 0.5, size * 0.5, size), radius, 8, 16);
 
         // act
@@ -1195,9 +1202,9 @@ public class PolyhedronsSetTest {
         PolyhedronsSet result = (PolyhedronsSet) new RegionFactory<Vector3D>().xor(sphere, sphere.copySelf());
 
         // assert
-        Assert.assertEquals(0.0, result.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(0.0, result.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.NaN, result.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, result.getSize(), TEST_EPS);
+        Assert.assertEquals(0.0, result.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.NaN, result.getBarycenter(), TEST_EPS);
         Assert.assertTrue(result.isEmpty());
         Assert.assertFalse(result.isFull());
 
@@ -1223,7 +1230,7 @@ public class PolyhedronsSetTest {
         double tolerance = 0.05;
         double size = 1.0;
         double radius = size * 0.5;
-        PolyhedronsSet box = new PolyhedronsSet(0, size, 0, size, 0, size, TEST_TOLERANCE);
+        PolyhedronsSet box = new PolyhedronsSet(0, size, 0, size, 0, size, TEST_PRECISION);
         PolyhedronsSet sphere = createSphere(Vector3D.of(size * 0.5, size * 0.5, size), radius, 8, 16);
 
         // act
@@ -1266,9 +1273,9 @@ public class PolyhedronsSetTest {
         PolyhedronsSet result = (PolyhedronsSet) new RegionFactory<Vector3D>().difference(sphere, sphere.copySelf());
 
         // assert
-        Assert.assertEquals(0.0, result.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(0.0, result.getBoundarySize(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.NaN, result.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, result.getSize(), TEST_EPS);
+        Assert.assertEquals(0.0, result.getBoundarySize(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector3D.NaN, result.getBarycenter(), TEST_EPS);
         Assert.assertTrue(result.isEmpty());
         Assert.assertFalse(result.isFull());
 
@@ -1294,7 +1301,7 @@ public class PolyhedronsSetTest {
         double tolerance = 0.05;
         double size = 1.0;
         double radius = size * 0.5;
-        PolyhedronsSet box = new PolyhedronsSet(0, size, 0, size, 0, size, TEST_TOLERANCE);
+        PolyhedronsSet box = new PolyhedronsSet(0, size, 0, size, 0, size, TEST_PRECISION);
         PolyhedronsSet sphereToAdd = createSphere(Vector3D.of(size * 0.5, size * 0.5, size), radius, 8, 16);
         PolyhedronsSet sphereToRemove1 = createSphere(Vector3D.of(size * 0.5, 0, size * 0.5), radius, 8, 16);
         PolyhedronsSet sphereToRemove2 = createSphere(Vector3D.of(size * 0.5, 1, size * 0.5), radius, 8, 16);
@@ -1336,7 +1343,7 @@ public class PolyhedronsSetTest {
     @Test
     public void testProjectToBoundary() {
         // arrange
-        PolyhedronsSet polySet = new PolyhedronsSet(0, 1, 0, 1, 0, 1, TEST_TOLERANCE);
+        PolyhedronsSet polySet = new PolyhedronsSet(0, 1, 0, 1, 0, 1, TEST_PRECISION);
 
         // act/assert
         checkProjectToBoundary(polySet, Vector3D.of(0.4, 0.5, 0.5),
@@ -1350,7 +1357,7 @@ public class PolyhedronsSetTest {
     @Test
     public void testProjectToBoundary_invertedRegion() {
         // arrange
-        PolyhedronsSet polySet = new PolyhedronsSet(0, 1, 0, 1, 0, 1, TEST_TOLERANCE);
+        PolyhedronsSet polySet = new PolyhedronsSet(0, 1, 0, 1, 0, 1, TEST_PRECISION);
         polySet = (PolyhedronsSet) new RegionFactory<Vector3D>().getComplement(polySet);
 
         // act/assert
@@ -1366,9 +1373,9 @@ public class PolyhedronsSetTest {
             Vector3D expectedPoint, double expectedOffset) {
         BoundaryProjection<Vector3D> proj = poly.projectToBoundary(toProject);
 
-        EuclideanTestUtils.assertCoordinatesEqual(toProject, proj.getOriginal(), TEST_TOLERANCE);
-        EuclideanTestUtils.assertCoordinatesEqual(expectedPoint, proj.getProjected(), TEST_TOLERANCE);
-        Assert.assertEquals(expectedOffset, proj.getOffset(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(toProject, proj.getOriginal(), TEST_EPS);
+        EuclideanTestUtils.assertCoordinatesEqual(expectedPoint, proj.getProjected(), TEST_EPS);
+        Assert.assertEquals(expectedOffset, proj.getOffset(), TEST_EPS);
     }
 
     private String loadTestData(final String resourceName)
@@ -1388,17 +1395,18 @@ public class PolyhedronsSetTest {
         }
     }
 
-    private List<SubHyperplane<Vector3D>> createBoxBoundaries(Vector3D center, double size, double tolerance) {
+    private List<SubHyperplane<Vector3D>> createBoxBoundaries(Vector3D center, double size, double eps) {
         List<SubHyperplane<Vector3D>> boundaries = new ArrayList<>();
 
         double offset = size * 0.5;
+        DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(eps);
 
-        Plane xMinus = new Plane(center.add(Vector3D.of(-offset, 0, 0)), Vector3D.MINUS_X, tolerance);
-        Plane xPlus = new Plane(center.add(Vector3D.of(offset, 0, 0)), Vector3D.PLUS_X, tolerance);
-        Plane yPlus = new Plane(center.add(Vector3D.of(0, offset, 0)), Vector3D.PLUS_Y, tolerance);
-        Plane yMinus = new Plane(center.add(Vector3D.of(0, -offset, 0)), Vector3D.MINUS_Y, tolerance);
-        Plane zPlus = new Plane(center.add(Vector3D.of(0, 0, offset)), Vector3D.PLUS_Z, tolerance);
-        Plane zMinus = new Plane(center.add(Vector3D.of(0, 0, -offset)), Vector3D.MINUS_Z, tolerance);
+        Plane xMinus = new Plane(center.add(Vector3D.of(-offset, 0, 0)), Vector3D.MINUS_X, precision);
+        Plane xPlus = new Plane(center.add(Vector3D.of(offset, 0, 0)), Vector3D.PLUS_X, precision);
+        Plane yPlus = new Plane(center.add(Vector3D.of(0, offset, 0)), Vector3D.PLUS_Y, precision);
+        Plane yMinus = new Plane(center.add(Vector3D.of(0, -offset, 0)), Vector3D.MINUS_Y, precision);
+        Plane zPlus = new Plane(center.add(Vector3D.of(0, 0, offset)), Vector3D.PLUS_Z, precision);
+        Plane zMinus = new Plane(center.add(Vector3D.of(0, 0, -offset)), Vector3D.MINUS_Z, precision);
 
         // +x
         boundaries.add(createSubPlane(xPlus,
@@ -1451,7 +1459,7 @@ public class PolyhedronsSetTest {
             points2d[i] = plane.toSubSpace(points[i]);
         }
 
-        PolygonsSet polygon = new PolygonsSet(plane.getTolerance(), points2d);
+        PolygonsSet polygon = new PolygonsSet(plane.getPrecision(), points2d);
 
         return new SubPlane(plane, polygon);
     }
@@ -1463,8 +1471,8 @@ public class PolyhedronsSetTest {
         Vector3D topZ = Vector3D.of(center.getX(), center.getY(), center.getZ() + radius);
         Vector3D bottomZ = Vector3D.of(center.getX(), center.getY(), center.getZ() - radius);
 
-        planes.add(new Plane(topZ, Vector3D.PLUS_Z, TEST_TOLERANCE));
-        planes.add(new Plane(bottomZ, Vector3D.MINUS_Z, TEST_TOLERANCE));
+        planes.add(new Plane(topZ, Vector3D.PLUS_Z, TEST_PRECISION));
+        planes.add(new Plane(bottomZ, Vector3D.MINUS_Z, TEST_PRECISION));
 
         // add the side planes
         double vDelta = Math.PI / stacks;
@@ -1497,7 +1505,7 @@ public class PolyhedronsSetTest {
                 norm = Vector3D.of(x, y, stackHeight).normalize();
                 pt = center.add(norm.multiply(adjustedRadius));
 
-                planes.add(new Plane(pt, norm, TEST_TOLERANCE));
+                planes.add(new Plane(pt, norm, TEST_PRECISION));
             }
         }
 
@@ -1506,7 +1514,7 @@ public class PolyhedronsSetTest {
 
     private void assertSubPlaneNormal(Vector3D expectedNormal, SubHyperplane<Vector3D> sub) {
         Vector3D norm = ((Plane) sub.getHyperplane()).getNormal();
-        EuclideanTestUtils.assertCoordinatesEqual(expectedNormal, norm, TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(expectedNormal, norm, TEST_EPS);
     }
 
     private double cubeVolume(double size) {
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SubLineTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SubLineTest.java
index 7d3872e..38d2041 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SubLineTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SubLineTest.java
@@ -19,6 +19,8 @@ package org.apache.commons.geometry.euclidean.threed;
 import java.util.List;
 
 import org.apache.commons.geometry.core.partitioning.RegionFactory;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.oned.IntervalsSet;
 import org.apache.commons.geometry.euclidean.oned.Vector1D;
 import org.junit.Assert;
@@ -26,21 +28,26 @@ import org.junit.Test;
 
 public class SubLineTest {
 
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
+
     @Test
     public void testEndPoints() {
         Vector3D p1 = Vector3D.of(-1, -7, 2);
         Vector3D p2 = Vector3D.of(7, -1, 0);
-        Segment segment = new Segment(p1, p2, new Line(p1, p2, 1.0e-10));
+        Segment segment = new Segment(p1, p2, new Line(p1, p2, TEST_PRECISION));
         SubLine sub = new SubLine(segment);
         List<Segment> segments = sub.getSegments();
         Assert.assertEquals(1, segments.size());
-        Assert.assertEquals(0.0, Vector3D.of(-1, -7, 2).distance(segments.get(0).getStart()), 1.0e-10);
-        Assert.assertEquals(0.0, Vector3D.of( 7, -1, 0).distance(segments.get(0).getEnd()), 1.0e-10);
+        Assert.assertEquals(0.0, Vector3D.of(-1, -7, 2).distance(segments.get(0).getStart()), TEST_EPS);
+        Assert.assertEquals(0.0, Vector3D.of( 7, -1, 0).distance(segments.get(0).getEnd()), TEST_EPS);
     }
 
     @Test
     public void testNoEndPoints() {
-        SubLine wholeLine = new Line(Vector3D.of(-1, 7, 2), Vector3D.of(7, 1, 0), 1.0e-10).wholeLine();
+        SubLine wholeLine = new Line(Vector3D.of(-1, 7, 2), Vector3D.of(7, 1, 0), TEST_PRECISION).wholeLine();
         List<Segment> segments = wholeLine.getSegments();
         Assert.assertEquals(1, segments.size());
         Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getX()) &&
@@ -59,25 +66,25 @@ public class SubLineTest {
 
     @Test
     public void testNoSegments() {
-        SubLine empty = new SubLine(new Line(Vector3D.of(-1, -7, 2), Vector3D.of(7, -1, 0), 1.0e-10),
-                                    (IntervalsSet) new RegionFactory<Vector1D>().getComplement(new IntervalsSet(1.0e-10)));
+        SubLine empty = new SubLine(new Line(Vector3D.of(-1, -7, 2), Vector3D.of(7, -1, 0), TEST_PRECISION),
+                                    (IntervalsSet) new RegionFactory<Vector1D>().getComplement(new IntervalsSet(TEST_PRECISION)));
         List<Segment> segments = empty.getSegments();
         Assert.assertEquals(0, segments.size());
     }
 
     @Test
     public void testSeveralSegments() {
-        SubLine twoSubs = new SubLine(new Line(Vector3D.of(-1, -7, 2), Vector3D.of(7, -1, 0), 1.0e-10),
-                                      (IntervalsSet) new RegionFactory<Vector1D>().union(new IntervalsSet(1, 2, 1.0e-10),
-                                                                                            new IntervalsSet(3, 4, 1.0e-10)));
+        SubLine twoSubs = new SubLine(new Line(Vector3D.of(-1, -7, 2), Vector3D.of(7, -1, 0), TEST_PRECISION),
+                                      (IntervalsSet) new RegionFactory<Vector1D>().union(new IntervalsSet(1, 2, TEST_PRECISION),
+                                                                                            new IntervalsSet(3, 4, TEST_PRECISION)));
         List<Segment> segments = twoSubs.getSegments();
         Assert.assertEquals(2, segments.size());
     }
 
     @Test
     public void testHalfInfiniteNeg() {
-        SubLine empty = new SubLine(new Line(Vector3D.of(-1, -7, 2), Vector3D.of(7, -1, -2), 1.0e-10),
-                                    new IntervalsSet(Double.NEGATIVE_INFINITY, 0.0, 1.0e-10));
+        SubLine empty = new SubLine(new Line(Vector3D.of(-1, -7, 2), Vector3D.of(7, -1, -2), TEST_PRECISION),
+                                    new IntervalsSet(Double.NEGATIVE_INFINITY, 0.0, TEST_PRECISION));
         List<Segment> segments = empty.getSegments();
         Assert.assertEquals(1, segments.size());
         Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getX()) &&
@@ -86,13 +93,13 @@ public class SubLineTest {
                           segments.get(0).getStart().getY() < 0);
         Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getZ()) &&
                           segments.get(0).getStart().getZ() > 0);
-        Assert.assertEquals(0.0, Vector3D.of(3, -4, 0).distance(segments.get(0).getEnd()), 1.0e-10);
+        Assert.assertEquals(0.0, Vector3D.of(3, -4, 0).distance(segments.get(0).getEnd()), TEST_EPS);
     }
 
     @Test
     public void testHalfInfinitePos() {
-        SubLine empty = new SubLine(new Line(Vector3D.of(-1, -7, 2), Vector3D.of(7, -1, -2), 1.0e-10),
-                                    new IntervalsSet(0.0, Double.POSITIVE_INFINITY, 1.0e-10));
+        SubLine empty = new SubLine(new Line(Vector3D.of(-1, -7, 2), Vector3D.of(7, -1, -2), TEST_PRECISION),
+                                    new IntervalsSet(0.0, Double.POSITIVE_INFINITY, TEST_PRECISION));
         List<Segment> segments = empty.getSegments();
         Assert.assertEquals(1, segments.size());
         Assert.assertEquals(0.0, Vector3D.of(3, -4, 0).distance(segments.get(0).getStart()), 1.0e-10);
@@ -106,56 +113,56 @@ public class SubLineTest {
 
     @Test
     public void testIntersectionInsideInside() {
-        SubLine sub1 = new SubLine(Vector3D.of(1, 1, 1), Vector3D.of(3, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(Vector3D.of(2, 0, 0), Vector3D.of(2, 2, 2), 1.0e-10);
-        Assert.assertEquals(0.0, Vector3D.of(2, 1, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
-        Assert.assertEquals(0.0, Vector3D.of(2, 1, 1).distance(sub1.intersection(sub2, false)), 1.0e-12);
+        SubLine sub1 = new SubLine(Vector3D.of(1, 1, 1), Vector3D.of(3, 1, 1), TEST_PRECISION);
+        SubLine sub2 = new SubLine(Vector3D.of(2, 0, 0), Vector3D.of(2, 2, 2), TEST_PRECISION);
+        Assert.assertEquals(0.0, Vector3D.of(2, 1, 1).distance(sub1.intersection(sub2, true)), TEST_EPS);
+        Assert.assertEquals(0.0, Vector3D.of(2, 1, 1).distance(sub1.intersection(sub2, false)), TEST_EPS);
     }
 
     @Test
     public void testIntersectionInsideBoundary() {
-        SubLine sub1 = new SubLine(Vector3D.of(1, 1, 1), Vector3D.of(3, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(Vector3D.of(2, 0, 0), Vector3D.of(2, 1, 1), 1.0e-10);
-        Assert.assertEquals(0.0, Vector3D.of(2, 1, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
+        SubLine sub1 = new SubLine(Vector3D.of(1, 1, 1), Vector3D.of(3, 1, 1), TEST_PRECISION);
+        SubLine sub2 = new SubLine(Vector3D.of(2, 0, 0), Vector3D.of(2, 1, 1), TEST_PRECISION);
+        Assert.assertEquals(0.0, Vector3D.of(2, 1, 1).distance(sub1.intersection(sub2, true)), TEST_EPS);
         Assert.assertNull(sub1.intersection(sub2, false));
     }
 
     @Test
     public void testIntersectionInsideOutside() {
-        SubLine sub1 = new SubLine(Vector3D.of(1, 1, 1), Vector3D.of(3, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(Vector3D.of(2, 0, 0), Vector3D.of(2, 0.5, 0.5), 1.0e-10);
+        SubLine sub1 = new SubLine(Vector3D.of(1, 1, 1), Vector3D.of(3, 1, 1), TEST_PRECISION);
+        SubLine sub2 = new SubLine(Vector3D.of(2, 0, 0), Vector3D.of(2, 0.5, 0.5), TEST_PRECISION);
         Assert.assertNull(sub1.intersection(sub2, true));
         Assert.assertNull(sub1.intersection(sub2, false));
     }
 
     @Test
     public void testIntersectionBoundaryBoundary() {
-        SubLine sub1 = new SubLine(Vector3D.of(1, 1, 1), Vector3D.of(2, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(Vector3D.of(2, 0, 0), Vector3D.of(2, 1, 1), 1.0e-10);
-        Assert.assertEquals(0.0, Vector3D.of(2, 1, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
+        SubLine sub1 = new SubLine(Vector3D.of(1, 1, 1), Vector3D.of(2, 1, 1), TEST_PRECISION);
+        SubLine sub2 = new SubLine(Vector3D.of(2, 0, 0), Vector3D.of(2, 1, 1), TEST_PRECISION);
+        Assert.assertEquals(0.0, Vector3D.of(2, 1, 1).distance(sub1.intersection(sub2, true)),  TEST_EPS);
         Assert.assertNull(sub1.intersection(sub2, false));
     }
 
     @Test
     public void testIntersectionBoundaryOutside() {
-        SubLine sub1 = new SubLine(Vector3D.of(1, 1, 1), Vector3D.of(2, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(Vector3D.of(2, 0, 0), Vector3D.of(2, 0.5, 0.5), 1.0e-10);
+        SubLine sub1 = new SubLine(Vector3D.of(1, 1, 1), Vector3D.of(2, 1, 1), TEST_PRECISION);
+        SubLine sub2 = new SubLine(Vector3D.of(2, 0, 0), Vector3D.of(2, 0.5, 0.5), TEST_PRECISION);
         Assert.assertNull(sub1.intersection(sub2, true));
         Assert.assertNull(sub1.intersection(sub2, false));
     }
 
     @Test
     public void testIntersectionOutsideOutside() {
-        SubLine sub1 = new SubLine(Vector3D.of(1, 1, 1), Vector3D.of(1.5, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(Vector3D.of(2, 0, 0), Vector3D.of(2, 0.5, 0.5), 1.0e-10);
+        SubLine sub1 = new SubLine(Vector3D.of(1, 1, 1), Vector3D.of(1.5, 1, 1), TEST_PRECISION);
+        SubLine sub2 = new SubLine(Vector3D.of(2, 0, 0), Vector3D.of(2, 0.5, 0.5), TEST_PRECISION);
         Assert.assertNull(sub1.intersection(sub2, true));
         Assert.assertNull(sub1.intersection(sub2, false));
     }
 
     @Test
     public void testIntersectionNotIntersecting() {
-        SubLine sub1 = new SubLine(Vector3D.of(1, 1, 1), Vector3D.of(1.5, 1, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(Vector3D.of(2, 3, 0), Vector3D.of(2, 3, 0.5), 1.0e-10);
+        SubLine sub1 = new SubLine(Vector3D.of(1, 1, 1), Vector3D.of(1.5, 1, 1), TEST_PRECISION);
+        SubLine sub2 = new SubLine(Vector3D.of(2, 3, 0), Vector3D.of(2, 3, 0.5), TEST_PRECISION);
         Assert.assertNull(sub1.intersection(sub2, true));
         Assert.assertNull(sub1.intersection(sub2, false));
     }
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/rotation/AxisSequenceTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/rotation/AxisSequenceTest.java
index 4ef9e50..fc9ef7e 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/rotation/AxisSequenceTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/rotation/AxisSequenceTest.java
@@ -17,7 +17,6 @@
 package org.apache.commons.geometry.euclidean.threed.rotation;
 
 import org.apache.commons.geometry.euclidean.threed.Vector3D;
-import org.apache.commons.geometry.euclidean.threed.rotation.AxisSequence;
 import org.junit.Assert;
 import org.junit.Test;
 
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/LineTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/LineTest.java
index 70285b2..5a5db25 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/LineTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/LineTest.java
@@ -17,15 +17,22 @@
 package org.apache.commons.geometry.euclidean.twod;
 
 import org.apache.commons.geometry.core.partitioning.Transform;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.oned.Vector1D;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class LineTest {
 
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
+
     @Test
     public void testContains() {
-        Line l = new Line(Vector2D.of(0, 1), Vector2D.of(1, 2), 1.0e-10);
+        Line l = new Line(Vector2D.of(0, 1), Vector2D.of(1, 2), TEST_PRECISION);
         Assert.assertTrue(l.contains(Vector2D.of(0, 1)));
         Assert.assertTrue(l.contains(Vector2D.of(1, 2)));
         Assert.assertTrue(l.contains(Vector2D.of(7, 8)));
@@ -34,7 +41,7 @@ public class LineTest {
 
     @Test
     public void testAbscissa() {
-        Line l = new Line(Vector2D.of(2, 1), Vector2D.of(-2, -2), 1.0e-10);
+        Line l = new Line(Vector2D.of(2, 1), Vector2D.of(-2, -2), TEST_PRECISION);
         Assert.assertEquals(0.0,
                             (l.toSubSpace(Vector2D.of(-3,  4))).getX(),
                             1.0e-10);
@@ -51,21 +58,21 @@ public class LineTest {
 
     @Test
     public void testOffset() {
-        Line l = new Line(Vector2D.of(2, 1), Vector2D.of(-2, -2), 1.0e-10);
+        Line l = new Line(Vector2D.of(2, 1), Vector2D.of(-2, -2), TEST_PRECISION);
         Assert.assertEquals(-5.0, l.getOffset(Vector2D.of(5, -3)), 1.0e-10);
         Assert.assertEquals(+5.0, l.getOffset(Vector2D.of(-5, 2)), 1.0e-10);
     }
 
     @Test
     public void testDistance() {
-        Line l = new Line(Vector2D.of(2, 1), Vector2D.of(-2, -2), 1.0e-10);
+        Line l = new Line(Vector2D.of(2, 1), Vector2D.of(-2, -2), TEST_PRECISION);
         Assert.assertEquals(+5.0, l.distance(Vector2D.of(5, -3)), 1.0e-10);
         Assert.assertEquals(+5.0, l.distance(Vector2D.of(-5, 2)), 1.0e-10);
     }
 
     @Test
     public void testPointAt() {
-        Line l = new Line(Vector2D.of(2, 1), Vector2D.of(-2, -2), 1.0e-10);
+        Line l = new Line(Vector2D.of(2, 1), Vector2D.of(-2, -2), TEST_PRECISION);
         for (double a = -2.0; a < 2.0; a += 0.2) {
             Vector1D pA = Vector1D.of(a);
             Vector2D point = l.toSpace(pA);
@@ -81,34 +88,34 @@ public class LineTest {
 
     @Test
     public void testOriginOffset() {
-        Line l1 = new Line(Vector2D.of(0, 1), Vector2D.of(1, 2), 1.0e-10);
+        Line l1 = new Line(Vector2D.of(0, 1), Vector2D.of(1, 2), TEST_PRECISION);
         Assert.assertEquals(Math.sqrt(0.5), l1.getOriginOffset(), 1.0e-10);
-        Line l2 = new Line(Vector2D.of(1, 2), Vector2D.of(0, 1), 1.0e-10);
+        Line l2 = new Line(Vector2D.of(1, 2), Vector2D.of(0, 1), TEST_PRECISION);
         Assert.assertEquals(-Math.sqrt(0.5), l2.getOriginOffset(), 1.0e-10);
     }
 
     @Test
     public void testParallel() {
-        Line l1 = new Line(Vector2D.of(0, 1), Vector2D.of(1, 2), 1.0e-10);
-        Line l2 = new Line(Vector2D.of(2, 2), Vector2D.of(3, 3), 1.0e-10);
+        Line l1 = new Line(Vector2D.of(0, 1), Vector2D.of(1, 2), TEST_PRECISION);
+        Line l2 = new Line(Vector2D.of(2, 2), Vector2D.of(3, 3), TEST_PRECISION);
         Assert.assertTrue(l1.isParallelTo(l2));
-        Line l3 = new Line(Vector2D.of(1, 0), Vector2D.of(0.5, -0.5), 1.0e-10);
+        Line l3 = new Line(Vector2D.of(1, 0), Vector2D.of(0.5, -0.5), TEST_PRECISION);
         Assert.assertTrue(l1.isParallelTo(l3));
-        Line l4 = new Line(Vector2D.of(1, 0), Vector2D.of(0.5, -0.51), 1.0e-10);
+        Line l4 = new Line(Vector2D.of(1, 0), Vector2D.of(0.5, -0.51), TEST_PRECISION);
         Assert.assertTrue(! l1.isParallelTo(l4));
     }
 
     @Test
     public void testTransform() {
 
-        Line l1 = new Line(Vector2D.of(1.0 ,1.0), Vector2D.of(4.0 ,1.0), 1.0e-10);
+        Line l1 = new Line(Vector2D.of(1.0 ,1.0), Vector2D.of(4.0 ,1.0), TEST_PRECISION);
         Transform<Vector2D, Vector1D> t1 =
             Line.getTransform(0.0, 0.5, -1.0, 0.0, 1.0, 1.5);
         Assert.assertEquals(0.5 * Math.PI,
                             ((Line) t1.apply(l1)).getAngle(),
                             1.0e-10);
 
-        Line l2 = new Line(Vector2D.of(0.0, 0.0), Vector2D.of(1.0, 1.0), 1.0e-10);
+        Line l2 = new Line(Vector2D.of(0.0, 0.0), Vector2D.of(1.0, 1.0), TEST_PRECISION);
         Transform<Vector2D, Vector1D> t2 =
             Line.getTransform(0.0, 0.5, -1.0, 0.0, 1.0, 1.5);
         Assert.assertEquals(Math.atan2(1.0, -2.0),
@@ -119,8 +126,8 @@ public class LineTest {
 
     @Test
     public void testIntersection() {
-        Line    l1 = new Line(Vector2D.of( 0, 1), Vector2D.of(1, 2), 1.0e-10);
-        Line    l2 = new Line(Vector2D.of(-1, 2), Vector2D.of(2, 1), 1.0e-10);
+        Line    l1 = new Line(Vector2D.of( 0, 1), Vector2D.of(1, 2), TEST_PRECISION);
+        Line    l2 = new Line(Vector2D.of(-1, 2), Vector2D.of(2, 1), TEST_PRECISION);
         Vector2D p  = l1.intersection(l2);
         Assert.assertEquals(0.5, p.getX(), 1.0e-10);
         Assert.assertEquals(1.5, p.getY(), 1.0e-10);
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/NestedLoopsTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/NestedLoopsTest.java
index 9f9b742..05a0fb4 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/NestedLoopsTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/NestedLoopsTest.java
@@ -23,11 +23,18 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class NestedLoopsTest {
 
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
+
     @SuppressWarnings("unchecked")
     @Test
     public void testNestedLoops() throws Exception {
@@ -45,7 +52,7 @@ public class NestedLoopsTest {
                 origin
         };
 
-        NestedLoops nestedLoops = new NestedLoops(0.00000001);
+        NestedLoops nestedLoops = new NestedLoops(TEST_PRECISION);
         nestedLoops.add(vertices);
         nestedLoops.correctOrientation();
 
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/PolygonsSetTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/PolygonsSetTest.java
index 0ac2832..14f917b 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/PolygonsSetTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/PolygonsSetTest.java
@@ -28,6 +28,8 @@ import org.apache.commons.geometry.core.partitioning.Region;
 import org.apache.commons.geometry.core.partitioning.Region.Location;
 import org.apache.commons.geometry.core.partitioning.RegionFactory;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
 import org.apache.commons.geometry.euclidean.oned.Interval;
 import org.apache.commons.geometry.euclidean.oned.IntervalsSet;
@@ -38,21 +40,24 @@ import org.junit.Test;
 
 public class PolygonsSetTest {
 
-    private static final double TEST_TOLERANCE = 1e-10;
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
 
     @Test
     public void testFull() {
         // act
-        PolygonsSet poly = new PolygonsSet(TEST_TOLERANCE);
+        PolygonsSet poly = new PolygonsSet(TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, poly.getTolerance(), Precision.EPSILON);
+        Assert.assertSame(TEST_PRECISION, poly.getPrecision());
         EuclideanTestUtils.assertPositiveInfinity(poly.getSize());
-        Assert.assertEquals(0.0, poly.getBoundarySize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, poly.getBoundarySize(), TEST_EPS);
         Assert.assertEquals(0, poly.getVertices().length);
         Assert.assertFalse(poly.isEmpty());
         Assert.assertTrue(poly.isFull());
-        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, poly.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, poly.getBarycenter(), TEST_EPS);
 
         checkPoints(Region.Location.INSIDE, poly,
                 Vector2D.of(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY),
@@ -69,16 +74,16 @@ public class PolygonsSetTest {
     @Test
     public void testEmpty() {
         // act
-        PolygonsSet poly = (PolygonsSet) new RegionFactory<Vector2D>().getComplement(new PolygonsSet(TEST_TOLERANCE));
+        PolygonsSet poly = (PolygonsSet) new RegionFactory<Vector2D>().getComplement(new PolygonsSet(TEST_PRECISION));
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, poly.getTolerance(), Precision.EPSILON);
-        Assert.assertEquals(0.0, poly.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(0.0, poly.getBoundarySize(), TEST_TOLERANCE);
+        Assert.assertSame(TEST_PRECISION, poly.getPrecision());
+        Assert.assertEquals(0.0, poly.getSize(), TEST_EPS);
+        Assert.assertEquals(0.0, poly.getBoundarySize(), TEST_EPS);
         Assert.assertEquals(0, poly.getVertices().length);
         Assert.assertTrue(poly.isEmpty());
         Assert.assertFalse(poly.isFull());
-        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, poly.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, poly.getBarycenter(), TEST_EPS);
 
         checkPoints(Region.Location.OUTSIDE, poly,
                 Vector2D.of(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY),
@@ -96,21 +101,21 @@ public class PolygonsSetTest {
     @Test
     public void testInfiniteLines_single() {
         // arrange
-        Line line = new Line(Vector2D.of(0, 0), Vector2D.of(1, 1), TEST_TOLERANCE);
+        Line line = new Line(Vector2D.of(0, 0), Vector2D.of(1, 1), TEST_PRECISION);
 
         List<SubHyperplane<Vector2D>> boundaries = new ArrayList<SubHyperplane<Vector2D>>();
         boundaries.add(line.wholeHyperplane());
 
         // act
-        PolygonsSet poly = new PolygonsSet(boundaries, TEST_TOLERANCE);
+        PolygonsSet poly = new PolygonsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, poly.getTolerance(), Precision.EPSILON);
+        Assert.assertSame(TEST_PRECISION, poly.getPrecision());
         EuclideanTestUtils.assertPositiveInfinity(poly.getSize());
         EuclideanTestUtils.assertPositiveInfinity(poly.getBoundarySize());
         Assert.assertFalse(poly.isEmpty());
         Assert.assertFalse(poly.isFull());
-        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, poly.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, poly.getBarycenter(), TEST_EPS);
 
         checkVertexLoopsEquivalent(new Vector2D[][] {
             {
@@ -132,23 +137,23 @@ public class PolygonsSetTest {
     @Test
     public void testInfiniteLines_twoIntersecting() {
         // arrange
-        Line line1 = new Line(Vector2D.of(0, 0), Vector2D.of(1, 1), TEST_TOLERANCE);
-        Line line2 = new Line(Vector2D.of(1, -1), Vector2D.of(0, 0), TEST_TOLERANCE);
+        Line line1 = new Line(Vector2D.of(0, 0), Vector2D.of(1, 1), TEST_PRECISION);
+        Line line2 = new Line(Vector2D.of(1, -1), Vector2D.of(0, 0), TEST_PRECISION);
 
         List<SubHyperplane<Vector2D>> boundaries = new ArrayList<SubHyperplane<Vector2D>>();
         boundaries.add(line1.wholeHyperplane());
         boundaries.add(line2.wholeHyperplane());
 
         // act
-        PolygonsSet poly = new PolygonsSet(boundaries, TEST_TOLERANCE);
+        PolygonsSet poly = new PolygonsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, poly.getTolerance(), Precision.EPSILON);
+        Assert.assertSame(TEST_PRECISION, poly.getPrecision());
         EuclideanTestUtils.assertPositiveInfinity(poly.getSize());
         EuclideanTestUtils.assertPositiveInfinity(poly.getBoundarySize());
         Assert.assertFalse(poly.isEmpty());
         Assert.assertFalse(poly.isFull());
-        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, poly.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, poly.getBarycenter(), TEST_EPS);
 
         checkVertexLoopsEquivalent(new Vector2D[][] {
             {
@@ -170,23 +175,23 @@ public class PolygonsSetTest {
     @Test
     public void testInfiniteLines_twoParallel_facingIn() {
         // arrange
-        Line line1 = new Line(Vector2D.of(1, 1), Vector2D.of(0, 1), TEST_TOLERANCE);
-        Line line2 = new Line(Vector2D.of(0, -1), Vector2D.of(1, -1), TEST_TOLERANCE);
+        Line line1 = new Line(Vector2D.of(1, 1), Vector2D.of(0, 1), TEST_PRECISION);
+        Line line2 = new Line(Vector2D.of(0, -1), Vector2D.of(1, -1), TEST_PRECISION);
 
         List<SubHyperplane<Vector2D>> boundaries = new ArrayList<SubHyperplane<Vector2D>>();
         boundaries.add(line1.wholeHyperplane());
         boundaries.add(line2.wholeHyperplane());
 
         // act
-        PolygonsSet poly = new PolygonsSet(boundaries, TEST_TOLERANCE);
+        PolygonsSet poly = new PolygonsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, poly.getTolerance(), Precision.EPSILON);
+        Assert.assertSame(TEST_PRECISION, poly.getPrecision());
         EuclideanTestUtils.assertPositiveInfinity(poly.getSize());
         EuclideanTestUtils.assertPositiveInfinity(poly.getBoundarySize());
         Assert.assertFalse(poly.isEmpty());
         Assert.assertFalse(poly.isFull());
-        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, poly.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, poly.getBarycenter(), TEST_EPS);
 
         checkVertexLoopsEquivalent(new Vector2D[][] {
             {
@@ -216,23 +221,23 @@ public class PolygonsSetTest {
     @Test
     public void testInfiniteLines_twoParallel_facingOut() {
         // arrange
-        Line line1 = new Line(Vector2D.of(0, 1), Vector2D.of(1, 1), TEST_TOLERANCE);
-        Line line2 = new Line(Vector2D.of(1, -1), Vector2D.of(0, -1), TEST_TOLERANCE);
+        Line line1 = new Line(Vector2D.of(0, 1), Vector2D.of(1, 1), TEST_PRECISION);
+        Line line2 = new Line(Vector2D.of(1, -1), Vector2D.of(0, -1), TEST_PRECISION);
 
         List<SubHyperplane<Vector2D>> boundaries = new ArrayList<SubHyperplane<Vector2D>>();
         boundaries.add(line1.wholeHyperplane());
         boundaries.add(line2.wholeHyperplane());
 
         // act
-        PolygonsSet poly = new PolygonsSet(boundaries, TEST_TOLERANCE);
+        PolygonsSet poly = new PolygonsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, poly.getTolerance(), Precision.EPSILON);
+        Assert.assertSame(TEST_PRECISION, poly.getPrecision());
         EuclideanTestUtils.assertPositiveInfinity(poly.getSize());
         EuclideanTestUtils.assertPositiveInfinity(poly.getBoundarySize());
         Assert.assertFalse(poly.isEmpty());
         Assert.assertFalse(poly.isFull());
-        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, poly.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, poly.getBarycenter(), TEST_EPS);
 
         checkVertexLoopsEquivalent(new Vector2D[][] {
             {
@@ -262,8 +267,8 @@ public class PolygonsSetTest {
     @Test
     public void testMixedFiniteAndInfiniteLines_explicitInfiniteBoundaries() {
         // arrange
-        Line line1 = new Line(Vector2D.of(3, 3), Vector2D.of(0, 3), TEST_TOLERANCE);
-        Line line2 = new Line(Vector2D.of(0, -3), Vector2D.of(3, -3), TEST_TOLERANCE);
+        Line line1 = new Line(Vector2D.of(3, 3), Vector2D.of(0, 3), TEST_PRECISION);
+        Line line2 = new Line(Vector2D.of(0, -3), Vector2D.of(3, -3), TEST_PRECISION);
 
         List<SubHyperplane<Vector2D>> boundaries = new ArrayList<SubHyperplane<Vector2D>>();
         boundaries.add(line1.wholeHyperplane());
@@ -271,15 +276,15 @@ public class PolygonsSetTest {
         boundaries.add(buildSegment(Vector2D.of(0, 3), Vector2D.of(0, -3)));
 
         // act
-        PolygonsSet poly = new PolygonsSet(boundaries, TEST_TOLERANCE);
+        PolygonsSet poly = new PolygonsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, poly.getTolerance(), Precision.EPSILON);
+        Assert.assertSame(TEST_PRECISION, poly.getPrecision());
         EuclideanTestUtils.assertPositiveInfinity(poly.getSize());
         EuclideanTestUtils.assertPositiveInfinity(poly.getBoundarySize());
         Assert.assertFalse(poly.isEmpty());
         Assert.assertFalse(poly.isFull());
-        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, poly.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, poly.getBarycenter(), TEST_EPS);
 
         checkVertexLoopsEquivalent(new Vector2D[][] {
             {
@@ -313,23 +318,23 @@ public class PolygonsSetTest {
     @Test
     public void testMixedFiniteAndInfiniteLines_impliedInfiniteBoundaries() {
         // arrange
-        Line line = new Line(Vector2D.of(3, 0), Vector2D.of(3, 3), TEST_TOLERANCE);
+        Line line = new Line(Vector2D.of(3, 0), Vector2D.of(3, 3), TEST_PRECISION);
 
         List<SubHyperplane<Vector2D>> boundaries = new ArrayList<SubHyperplane<Vector2D>>();
         boundaries.add(buildSegment(Vector2D.of(0, 3), Vector2D.of(0, 0)));
         boundaries.add(buildSegment(Vector2D.of(0, 0), Vector2D.of(3, 0)));
-        boundaries.add(new SubLine(line, new IntervalsSet(0, Double.POSITIVE_INFINITY, TEST_TOLERANCE)));
+        boundaries.add(new SubLine(line, new IntervalsSet(0, Double.POSITIVE_INFINITY, TEST_PRECISION)));
 
         // act
-        PolygonsSet poly = new PolygonsSet(boundaries, TEST_TOLERANCE);
+        PolygonsSet poly = new PolygonsSet(boundaries, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(TEST_TOLERANCE, poly.getTolerance(), Precision.EPSILON);
+        Assert.assertSame(TEST_PRECISION, poly.getPrecision());
         EuclideanTestUtils.assertPositiveInfinity(poly.getSize());
         EuclideanTestUtils.assertPositiveInfinity(poly.getBoundarySize());
         Assert.assertFalse(poly.isEmpty());
         Assert.assertFalse(poly.isFull());
-        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, poly.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, poly.getBarycenter(), TEST_EPS);
 
         checkVertexLoopsEquivalent(new Vector2D[][] {
             {
@@ -362,14 +367,14 @@ public class PolygonsSetTest {
     @Test
     public void testBox() {
         // act
-        PolygonsSet box = new PolygonsSet(0, 2, -1, 1, TEST_TOLERANCE);
+        PolygonsSet box = new PolygonsSet(0, 2, -1, 1, TEST_PRECISION);
 
         // assert
-        Assert.assertEquals(4.0, box.getSize(), TEST_TOLERANCE);
-        Assert.assertEquals(8.0, box.getBoundarySize(), TEST_TOLERANCE);
+        Assert.assertEquals(4.0, box.getSize(), TEST_EPS);
+        Assert.assertEquals(8.0, box.getBoundarySize(), TEST_EPS);
         Assert.assertFalse(box.isEmpty());
         Assert.assertFalse(box.isFull());
-        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, 0), box.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, 0), box.getBarycenter(), TEST_EPS);
 
         checkVertexLoopsEquivalent(new Vector2D[][] {
             {
@@ -407,14 +412,14 @@ public class PolygonsSetTest {
         boundaries.add(buildSegment(Vector2D.of(2, -1), Vector2D.of(0, -1)));
 
         // act
-        PolygonsSet box = new PolygonsSet(boundaries, TEST_TOLERANCE);
+        PolygonsSet box = new PolygonsSet(boundaries, TEST_PRECISION);
 
         // assert
         EuclideanTestUtils.assertPositiveInfinity(box.getSize());
-        Assert.assertEquals(8.0, box.getBoundarySize(), TEST_TOLERANCE);
+        Assert.assertEquals(8.0, box.getBoundarySize(), TEST_EPS);
         Assert.assertFalse(box.isEmpty());
         Assert.assertFalse(box.isFull());
-        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, box.getBarycenter(), TEST_TOLERANCE);
+        EuclideanTestUtils.assertCoordinatesEqual(Vector2D.NaN, box.getBarycenter(), TEST_EPS);
 
         checkVertexLoopsEquivalent(new Vector2D[][] {
             {
@@ -510,7 +515,7 @@ public class PolygonsSetTest {
         // assert
         checkVertexLoopsEquivalent(vertices, set.getVertices());
 
-        Assert.assertEquals(1.1 + 0.95 * Math.sqrt(2.0), set.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(1.1 + 0.95 * Math.sqrt(2.0), set.getSize(), TEST_EPS);
     }
 
     @Test
@@ -567,29 +572,29 @@ public class PolygonsSetTest {
             Assert.assertTrue(projection.getOriginal() == v);
             Vector2D p = projection.getProjected();
             if (x < -0.5) {
-                Assert.assertEquals(0.0,      p.getX(), TEST_TOLERANCE);
-                Assert.assertEquals(0.0,      p.getY(), TEST_TOLERANCE);
-                Assert.assertEquals(+v.distance(Vector2D.ZERO), projection.getOffset(), TEST_TOLERANCE);
+                Assert.assertEquals(0.0,      p.getX(), TEST_EPS);
+                Assert.assertEquals(0.0,      p.getY(), TEST_EPS);
+                Assert.assertEquals(+v.distance(Vector2D.ZERO), projection.getOffset(), TEST_EPS);
             } else if (x < 0.5) {
-                Assert.assertEquals(0.0,      p.getX(), TEST_TOLERANCE);
-                Assert.assertEquals(v.getY(), p.getY(), TEST_TOLERANCE);
-                Assert.assertEquals(-v.getX(), projection.getOffset(), TEST_TOLERANCE);
+                Assert.assertEquals(0.0,      p.getX(), TEST_EPS);
+                Assert.assertEquals(v.getY(), p.getY(), TEST_EPS);
+                Assert.assertEquals(-v.getX(), projection.getOffset(), TEST_EPS);
             } else if (x < 1.25) {
-                Assert.assertEquals(1.0,      p.getX(), TEST_TOLERANCE);
-                Assert.assertEquals(v.getY(), p.getY(), TEST_TOLERANCE);
-                Assert.assertEquals(v.getX() - 1.0, projection.getOffset(), TEST_TOLERANCE);
+                Assert.assertEquals(1.0,      p.getX(), TEST_EPS);
+                Assert.assertEquals(v.getY(), p.getY(), TEST_EPS);
+                Assert.assertEquals(v.getX() - 1.0, projection.getOffset(), TEST_EPS);
             } else if (x < 2.0) {
-                Assert.assertEquals(v.getX(), p.getX(), TEST_TOLERANCE);
-                Assert.assertEquals(2.0,      p.getY(), TEST_TOLERANCE);
-                Assert.assertEquals(2.0 - v.getY(), projection.getOffset(), TEST_TOLERANCE);
+                Assert.assertEquals(v.getX(), p.getX(), TEST_EPS);
+                Assert.assertEquals(2.0,      p.getY(), TEST_EPS);
+                Assert.assertEquals(2.0 - v.getY(), projection.getOffset(), TEST_EPS);
             } else if (x < 3.0) {
-                Assert.assertEquals(v.getX(), p.getX(), TEST_TOLERANCE);
-                Assert.assertEquals(3.0,      p.getY(), TEST_TOLERANCE);
-                Assert.assertEquals(v.getY() - 3.0, projection.getOffset(), TEST_TOLERANCE);
+                Assert.assertEquals(v.getX(), p.getX(), TEST_EPS);
+                Assert.assertEquals(3.0,      p.getY(), TEST_EPS);
+                Assert.assertEquals(v.getY() - 3.0, projection.getOffset(), TEST_EPS);
             } else {
-                Assert.assertEquals(3.0,      p.getX(), TEST_TOLERANCE);
-                Assert.assertEquals(3.0,      p.getY(), TEST_TOLERANCE);
-                Assert.assertEquals(+v.distance(Vector2D.of(3, 3)), projection.getOffset(), TEST_TOLERANCE);
+                Assert.assertEquals(3.0,      p.getX(), TEST_EPS);
+                Assert.assertEquals(3.0,      p.getY(), TEST_EPS);
+                Assert.assertEquals(+v.distance(Vector2D.of(3, 3)), projection.getOffset(), TEST_EPS);
             }
         }
     }
@@ -709,36 +714,36 @@ public class PolygonsSetTest {
         PolygonsSet set = buildSet(vertices);
 
         // assert
-        Line l1 = new Line(Vector2D.of(-1.5, 0.0), Math.PI / 4, TEST_TOLERANCE);
+        Line l1 = new Line(Vector2D.of(-1.5, 0.0), Math.PI / 4, TEST_PRECISION);
         SubLine s1 = (SubLine) set.intersection(l1.wholeHyperplane());
         List<Interval> i1 = ((IntervalsSet) s1.getRemainingRegion()).asList();
         Assert.assertEquals(2, i1.size());
         Interval v10 = i1.get(0);
         Vector2D p10Lower = l1.toSpace(Vector1D.of(v10.getInf()));
-        Assert.assertEquals(0.0, p10Lower.getX(), TEST_TOLERANCE);
-        Assert.assertEquals(1.5, p10Lower.getY(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, p10Lower.getX(), TEST_EPS);
+        Assert.assertEquals(1.5, p10Lower.getY(), TEST_EPS);
         Vector2D p10Upper = l1.toSpace(Vector1D.of(v10.getSup()));
-        Assert.assertEquals(0.5, p10Upper.getX(), TEST_TOLERANCE);
-        Assert.assertEquals(2.0, p10Upper.getY(), TEST_TOLERANCE);
+        Assert.assertEquals(0.5, p10Upper.getX(), TEST_EPS);
+        Assert.assertEquals(2.0, p10Upper.getY(), TEST_EPS);
         Interval v11 = i1.get(1);
         Vector2D p11Lower = l1.toSpace(Vector1D.of(v11.getInf()));
-        Assert.assertEquals(1.0, p11Lower.getX(), TEST_TOLERANCE);
-        Assert.assertEquals(2.5, p11Lower.getY(), TEST_TOLERANCE);
+        Assert.assertEquals(1.0, p11Lower.getX(), TEST_EPS);
+        Assert.assertEquals(2.5, p11Lower.getY(), TEST_EPS);
         Vector2D p11Upper = l1.toSpace(Vector1D.of(v11.getSup()));
-        Assert.assertEquals(1.5, p11Upper.getX(), TEST_TOLERANCE);
-        Assert.assertEquals(3.0, p11Upper.getY(), TEST_TOLERANCE);
+        Assert.assertEquals(1.5, p11Upper.getX(), TEST_EPS);
+        Assert.assertEquals(3.0, p11Upper.getY(), TEST_EPS);
 
-        Line l2 = new Line(Vector2D.of(-1.0, 2.0), 0, TEST_TOLERANCE);
+        Line l2 = new Line(Vector2D.of(-1.0, 2.0), 0, TEST_PRECISION);
         SubLine s2 = (SubLine) set.intersection(l2.wholeHyperplane());
         List<Interval> i2 = ((IntervalsSet) s2.getRemainingRegion()).asList();
         Assert.assertEquals(1, i2.size());
         Interval v20 = i2.get(0);
         Vector2D p20Lower = l2.toSpace(Vector1D.of(v20.getInf()));
-        Assert.assertEquals(1.0, p20Lower.getX(), TEST_TOLERANCE);
-        Assert.assertEquals(2.0, p20Lower.getY(), TEST_TOLERANCE);
+        Assert.assertEquals(1.0, p20Lower.getX(), TEST_EPS);
+        Assert.assertEquals(2.0, p20Lower.getY(), TEST_EPS);
         Vector2D p20Upper = l2.toSpace(Vector1D.of(v20.getSup()));
-        Assert.assertEquals(3.0, p20Upper.getX(), TEST_TOLERANCE);
-        Assert.assertEquals(2.0, p20Upper.getY(), TEST_TOLERANCE);
+        Assert.assertEquals(3.0, p20Upper.getX(), TEST_EPS);
+        Assert.assertEquals(2.0, p20Upper.getY(), TEST_EPS);
     }
 
     @Test
@@ -1079,7 +1084,7 @@ public class PolygonsSetTest {
         PolygonsSet diff = (PolygonsSet) new RegionFactory<Vector2D>().difference(set1.copySelf(), set2.copySelf());
 
         // assert
-        Assert.assertEquals(0.0, diff.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, diff.getSize(), TEST_EPS);
         Assert.assertTrue(diff.isEmpty());
     }
 
@@ -1089,13 +1094,13 @@ public class PolygonsSetTest {
         double pi6   = Math.PI / 6.0;
         double sqrt3 = Math.sqrt(3.0);
         SubLine[] hyp = {
-            new Line(Vector2D.of(   0.0, 1.0),  5 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(Vector2D.of(-sqrt3, 1.0),  7 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(Vector2D.of(-sqrt3, 1.0),  9 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(Vector2D.of(-sqrt3, 0.0), 11 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(Vector2D.of(   0.0, 0.0), 13 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(Vector2D.of(   0.0, 1.0),  3 * pi6, TEST_TOLERANCE).wholeHyperplane(),
-            new Line(Vector2D.of(-5.0 * sqrt3 / 6.0, 0.0), 9 * pi6, TEST_TOLERANCE).wholeHyperplane()
+            new Line(Vector2D.of(   0.0, 1.0),  5 * pi6, TEST_PRECISION).wholeHyperplane(),
+            new Line(Vector2D.of(-sqrt3, 1.0),  7 * pi6, TEST_PRECISION).wholeHyperplane(),
+            new Line(Vector2D.of(-sqrt3, 1.0),  9 * pi6, TEST_PRECISION).wholeHyperplane(),
+            new Line(Vector2D.of(-sqrt3, 0.0), 11 * pi6, TEST_PRECISION).wholeHyperplane(),
+            new Line(Vector2D.of(   0.0, 0.0), 13 * pi6, TEST_PRECISION).wholeHyperplane(),
+            new Line(Vector2D.of(   0.0, 1.0),  3 * pi6, TEST_PRECISION).wholeHyperplane(),
+            new Line(Vector2D.of(-5.0 * sqrt3 / 6.0, 0.0), 9 * pi6, TEST_PRECISION).wholeHyperplane()
         };
         hyp[1] = (SubLine) hyp[1].split(hyp[0].getHyperplane()).getMinus();
         hyp[2] = (SubLine) hyp[2].split(hyp[1].getHyperplane()).getMinus();
@@ -1107,21 +1112,21 @@ public class PolygonsSetTest {
         for (int i = hyp.length - 1; i >= 0; --i) {
             tree = new BSPTree<>(hyp[i], new BSPTree<Vector2D>(Boolean.FALSE), tree, null);
         }
-        PolygonsSet set = new PolygonsSet(tree, TEST_TOLERANCE);
+        PolygonsSet set = new PolygonsSet(tree, TEST_PRECISION);
         SubLine splitter =
-            new Line(Vector2D.of(-2.0 * sqrt3 / 3.0, 0.0), 9 * pi6, TEST_TOLERANCE).wholeHyperplane();
+            new Line(Vector2D.of(-2.0 * sqrt3 / 3.0, 0.0), 9 * pi6, TEST_PRECISION).wholeHyperplane();
 
         // act
         PolygonsSet slice =
             new PolygonsSet(new BSPTree<>(splitter,
                                                      set.getTree(false).split(splitter).getPlus(),
                                                      new BSPTree<Vector2D>(Boolean.FALSE), null),
-                            TEST_TOLERANCE);
+                    TEST_PRECISION);
 
         // assert
         Assert.assertEquals(Region.Location.OUTSIDE,
                             slice.checkPoint(Vector2D.of(0.1, 0.5)));
-        Assert.assertEquals(11.0 / 3.0, slice.getBoundarySize(), TEST_TOLERANCE);
+        Assert.assertEquals(11.0 / 3.0, slice.getBoundarySize(), TEST_EPS);
     }
 
     @Test
@@ -1245,8 +1250,8 @@ public class PolygonsSetTest {
 
         // act
         PolygonsSet c =
-            (PolygonsSet) new RegionFactory<Vector2D>().union(new PolygonsSet(a9, TEST_TOLERANCE),
-                                                                 new PolygonsSet(b6, TEST_TOLERANCE));
+            (PolygonsSet) new RegionFactory<Vector2D>().union(new PolygonsSet(a9, TEST_PRECISION),
+                                                                 new PolygonsSet(b6, TEST_PRECISION));
 
         // assert
         checkPoints(Region.Location.INSIDE, c, new Vector2D[] {
@@ -1291,20 +1296,20 @@ public class PolygonsSetTest {
         // arrange
         Line[] l = {
             new Line(Vector2D.of(0.0, 0.625000007541172),
-                     Vector2D.of(1.0, 0.625000007541172), TEST_TOLERANCE),
+                     Vector2D.of(1.0, 0.625000007541172), TEST_PRECISION),
             new Line(Vector2D.of(-0.19204433621902645, 0.0),
-                     Vector2D.of(-0.19204433621902645, 1.0), TEST_TOLERANCE),
+                     Vector2D.of(-0.19204433621902645, 1.0), TEST_PRECISION),
             new Line(Vector2D.of(-0.40303524786887,  0.4248364535319128),
-                     Vector2D.of(-1.12851149797877, -0.2634107480798909), TEST_TOLERANCE),
+                     Vector2D.of(-1.12851149797877, -0.2634107480798909), TEST_PRECISION),
             new Line(Vector2D.of(0.0, 2.0),
-                     Vector2D.of(1.0, 2.0), TEST_TOLERANCE)
+                     Vector2D.of(1.0, 2.0), TEST_PRECISION)
         };
 
         BSPTree<Vector2D> node1 =
             new BSPTree<>(new SubLine(l[0],
                                                  new IntervalsSet(intersectionAbscissa(l[0], l[1]),
                                                                   intersectionAbscissa(l[0], l[2]),
-                                                                  TEST_TOLERANCE)),
+                                                                  TEST_PRECISION)),
                                      new BSPTree<Vector2D>(Boolean.TRUE),
                                      new BSPTree<Vector2D>(Boolean.FALSE),
                                      null);
@@ -1312,14 +1317,14 @@ public class PolygonsSetTest {
             new BSPTree<>(new SubLine(l[1],
                                                  new IntervalsSet(intersectionAbscissa(l[1], l[2]),
                                                                   intersectionAbscissa(l[1], l[3]),
-                                                                  TEST_TOLERANCE)),
+                                                                  TEST_PRECISION)),
                                      node1,
                                      new BSPTree<Vector2D>(Boolean.FALSE),
                                      null);
         BSPTree<Vector2D> node3 =
             new BSPTree<>(new SubLine(l[2],
                                                  new IntervalsSet(intersectionAbscissa(l[2], l[3]),
-                                                 Double.POSITIVE_INFINITY, TEST_TOLERANCE)),
+                                                 Double.POSITIVE_INFINITY, TEST_PRECISION)),
                                      node2,
                                      new BSPTree<Vector2D>(Boolean.FALSE),
                                      null);
@@ -1330,7 +1335,7 @@ public class PolygonsSetTest {
                                      null);
 
         // act
-        PolygonsSet set = new PolygonsSet(node4, TEST_TOLERANCE);
+        PolygonsSet set = new PolygonsSet(node4, TEST_PRECISION);
 
         // assert
         Assert.assertEquals(0, set.getVertices().length);
@@ -1339,7 +1344,7 @@ public class PolygonsSetTest {
     @Test
     public void testSqueezedHexa() {
         // act
-        PolygonsSet set = new PolygonsSet(TEST_TOLERANCE,
+        PolygonsSet set = new PolygonsSet(TEST_PRECISION,
                                           Vector2D.of(-6, -4), Vector2D.of(-8, -8), Vector2D.of(  8, -8),
                                           Vector2D.of( 6, -4), Vector2D.of(10,  4), Vector2D.of(-10,  4));
 
@@ -1362,7 +1367,7 @@ public class PolygonsSetTest {
         };
 
         // act
-        PolygonsSet set1 = new PolygonsSet(TEST_TOLERANCE, vertices1);
+        PolygonsSet set1 = new PolygonsSet(TEST_PRECISION, vertices1);
 
         // assert
         Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(Vector2D.of(90.12,  38.32)));
@@ -1444,7 +1449,7 @@ public class PolygonsSetTest {
                 Vector2D.of( 90.09081227075944,  38.37526295920463),
                 Vector2D.of( 90.09081378927135,  38.375193883266434)
         };
-        PolygonsSet set1 = new PolygonsSet(1.0e-8, vertices1);
+        PolygonsSet set1 = new PolygonsSet(TEST_PRECISION, vertices1);
         Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(Vector2D.of(90.0905,  38.3755)));
         Assert.assertEquals(Location.INSIDE,  set1.checkPoint(Vector2D.of(90.09084, 38.3755)));
         Assert.assertEquals(Location.OUTSIDE, set1.checkPoint(Vector2D.of(90.0913,  38.3755)));
@@ -1516,7 +1521,7 @@ public class PolygonsSetTest {
                 Vector2D.of( 90.16746107640665,  38.40902614307544),
                 Vector2D.of( 90.16122795307462,  38.39773101873203)
         };
-        PolygonsSet set2 = new PolygonsSet(1.0e-8, vertices2);
+        PolygonsSet set2 = new PolygonsSet(TEST_PRECISION, vertices2);
         PolygonsSet set  = (PolygonsSet) new
                 RegionFactory<Vector2D>().difference(set1.copySelf(),
                                                         set2.copySelf());
@@ -1530,8 +1535,8 @@ public class PolygonsSetTest {
     public void testTooThinBox() {
         // act/assert
         Assert.assertEquals(0.0,
-                            new PolygonsSet(0.0, 0.0, 0.0, 10.3206397147574, TEST_TOLERANCE).getSize(),
-                            TEST_TOLERANCE);
+                            new PolygonsSet(0.0, 0.0, 0.0, 10.3206397147574, TEST_PRECISION).getSize(),
+                            TEST_EPS);
     }
 
     @Test
@@ -1539,7 +1544,7 @@ public class PolygonsSetTest {
         // the following is a wrong usage of the constructor.
         // as explained in the javadoc, the failure is NOT detected at construction
         // time but occurs later on
-        PolygonsSet ps = new PolygonsSet(new BSPTree<Vector2D>(), TEST_TOLERANCE);
+        PolygonsSet ps = new PolygonsSet(new BSPTree<Vector2D>(), TEST_PRECISION);
         Assert.assertNotNull(ps);
         try {
             ps.getSize();
@@ -1552,13 +1557,13 @@ public class PolygonsSetTest {
     @Test
     public void testIssue1162() {
         // arrange
-        PolygonsSet p = new PolygonsSet(TEST_TOLERANCE,
+        PolygonsSet p = new PolygonsSet(TEST_PRECISION,
                                                 Vector2D.of(4.267199999996532, -11.928637756014894),
                                                 Vector2D.of(4.267200000026445, -14.12360595809307),
                                                 Vector2D.of(9.144000000273694, -14.12360595809307),
                                                 Vector2D.of(9.144000000233383, -11.928637756020067));
 
-        PolygonsSet w = new PolygonsSet(TEST_TOLERANCE,
+        PolygonsSet w = new PolygonsSet(TEST_PRECISION,
                                                 Vector2D.of(2.56735636510452512E-9, -11.933116461089332),
                                                 Vector2D.of(2.56735636510452512E-9, -12.393225665247766),
                                                 Vector2D.of(2.56735636510452512E-9, -27.785625665247778),
@@ -1581,20 +1586,21 @@ public class PolygonsSetTest {
         Vector2D pD = Vector2D.of(1.0 / 64.0, 1.0);
 
         // if tolerance is smaller than rectangle width, the rectangle is computed accurately
+        DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1.0 / 256);
         Hyperplane<Vector2D>[] h1 = new Line[] {
-            new Line(pA, pB, 1.0 / 256),
-            new Line(pB, pC, 1.0 / 256),
-            new Line(pC, pD, 1.0 / 256),
-            new Line(pD, pA, 1.0 / 256)
+            new Line(pA, pB, precision),
+            new Line(pB, pC, precision),
+            new Line(pC, pD, precision),
+            new Line(pD, pA, precision)
         };
 
         // act
         Region<Vector2D> accuratePolygon = factory.buildConvex(h1);
 
         // assert
-        Assert.assertEquals(1.0 / 64.0, accuratePolygon.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(1.0 / 64.0, accuratePolygon.getSize(), TEST_EPS);
         EuclideanTestUtils.assertPositiveInfinity(new RegionFactory<Vector2D>().getComplement(accuratePolygon).getSize());
-        Assert.assertEquals(2 * (1.0 + 1.0 / 64.0), accuratePolygon.getBoundarySize(), TEST_TOLERANCE);
+        Assert.assertEquals(2 * (1.0 + 1.0 / 64.0), accuratePolygon.getBoundarySize(), TEST_EPS);
     }
 
     @Test
@@ -1610,33 +1616,34 @@ public class PolygonsSetTest {
         Vector2D pC = Vector2D.of(1.0 / 64.0, 0.0);
         Vector2D pD = Vector2D.of(1.0 / 64.0, 1.0);
 
+        DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1.0 / 16);
+
         Hyperplane<Vector2D>[] h2 = new Line[] {
-                new Line(pA, pB, 1.0 / 16),
-                new Line(pB, pC, 1.0 / 16),
-                new Line(pC, pD, 1.0 / 16),
-                new Line(pD, pA, 1.0 / 16)
+                new Line(pA, pB, precision),
+                new Line(pB, pC, precision),
+                new Line(pC, pD, precision),
+                new Line(pD, pA, precision)
             };
 
         // act
         Region<Vector2D> degeneratedPolygon = factory.buildConvex(h2);
 
         // assert
-        Assert.assertEquals(0.0, degeneratedPolygon.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, degeneratedPolygon.getSize(), TEST_EPS);
         Assert.assertTrue(degeneratedPolygon.isEmpty());
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void testInconsistentHyperplanes() {
         // act
-        double tolerance = TEST_TOLERANCE;
-        new RegionFactory<Vector2D>().buildConvex(new Line(Vector2D.of(0, 0), Vector2D.of(0, 1), tolerance),
-                                                     new Line(Vector2D.of(1, 1), Vector2D.of(1, 0), tolerance));
+        new RegionFactory<Vector2D>().buildConvex(new Line(Vector2D.of(0, 0), Vector2D.of(0, 1), TEST_PRECISION),
+                                                     new Line(Vector2D.of(1, 1), Vector2D.of(1, 0), TEST_PRECISION));
     }
 
     @Test
     public void testBoundarySimplification() {
         // a simple square will result in a 4 cuts and 5 leafs tree
-        PolygonsSet square = new PolygonsSet(TEST_TOLERANCE,
+        PolygonsSet square = new PolygonsSet(TEST_PRECISION,
                                              Vector2D.of(0, 0),
                                              Vector2D.of(1, 0),
                                              Vector2D.of(1, 1),
@@ -1651,9 +1658,9 @@ public class PolygonsSetTest {
 
         // splitting the square in two halves increases the BSP tree
         // with 3 more cuts and 3 more leaf nodes
-        SubLine cut = new Line(Vector2D.of(0.5, 0.5), 0.0, square.getTolerance()).wholeHyperplane();
+        SubLine cut = new Line(Vector2D.of(0.5, 0.5), 0.0, square.getPrecision()).wholeHyperplane();
         PolygonsSet splitSquare = new PolygonsSet(square.getTree(false).split(cut),
-                                                  square.getTolerance());
+                                                  square.getPrecision());
         Counter splitSquareCount = new Counter();
         splitSquareCount.count(splitSquare);
         Assert.assertEquals(squareCount.getInternalNodes() + 3, splitSquareCount.getInternalNodes());
@@ -1709,11 +1716,11 @@ public class PolygonsSetTest {
                 edges.add(buildSegment(vertices[i][j], vertices[i][(j + 1) % l]));
             }
         }
-        return new PolygonsSet(edges, TEST_TOLERANCE);
+        return new PolygonsSet(edges, TEST_PRECISION);
     }
 
     private SubHyperplane<Vector2D> buildLine(Vector2D start, Vector2D end) {
-        return new Line(start, end, TEST_TOLERANCE).wholeHyperplane();
+        return new Line(start, end, TEST_PRECISION).wholeHyperplane();
     }
 
     private double intersectionAbscissa(Line l0, Line l1) {
@@ -1723,17 +1730,17 @@ public class PolygonsSetTest {
 
     private SubHyperplane<Vector2D> buildHalfLine(Vector2D start, Vector2D end,
                                                      boolean startIsVirtual) {
-        Line   line  = new Line(start, end, TEST_TOLERANCE);
+        Line   line  = new Line(start, end, TEST_PRECISION);
         double lower = startIsVirtual ? Double.NEGATIVE_INFINITY : (line.toSubSpace(start)).getX();
         double upper = startIsVirtual ? (line.toSubSpace(end)).getX() : Double.POSITIVE_INFINITY;
-        return new SubLine(line, new IntervalsSet(lower, upper, TEST_TOLERANCE));
+        return new SubLine(line, new IntervalsSet(lower, upper, TEST_PRECISION));
     }
 
     private SubHyperplane<Vector2D> buildSegment(Vector2D start, Vector2D end) {
-        Line   line  = new Line(start, end, TEST_TOLERANCE);
+        Line   line  = new Line(start, end, TEST_PRECISION);
         double lower = (line.toSubSpace(start)).getX();
         double upper = (line.toSubSpace(end)).getX();
-        return new SubLine(line, new IntervalsSet(lower, upper, TEST_TOLERANCE));
+        return new SubLine(line, new IntervalsSet(lower, upper, TEST_PRECISION));
     }
 
     private void checkPoints(Region.Location expected, PolygonsSet poly, Vector2D ... points) {
@@ -1754,7 +1761,7 @@ public class PolygonsSetTest {
         for (Vector2D[] expectedLoop : expectedLoops) {
             boolean foundMatch = false;
             for (Vector2D[] actualLoop : actualLoops) {
-                if (vertexLoopsEquivalent(expectedLoop, actualLoop, TEST_TOLERANCE)) {
+                if (vertexLoopsEquivalent(expectedLoop, actualLoop, TEST_EPS)) {
                     foundMatch = true;
                     break;
                 }
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SegmentTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SegmentTest.java
index c41aa50..cd94cfe 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SegmentTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SegmentTest.java
@@ -16,27 +16,34 @@
  */
 package org.apache.commons.geometry.euclidean.twod;
 
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class SegmentTest {
 
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
+
     @Test
     public void testDistance() {
         Vector2D start = Vector2D.of(2, 2);
         Vector2D end = Vector2D.of(-2, -2);
-        Segment segment = new Segment(start, end, new Line(start, end, 1.0e-10));
+        Segment segment = new Segment(start, end, new Line(start, end, TEST_PRECISION));
 
         // distance to center of segment
-        Assert.assertEquals(Math.sqrt(2), segment.distance(Vector2D.of(1, -1)), 1.0e-10);
+        Assert.assertEquals(Math.sqrt(2), segment.distance(Vector2D.of(1, -1)), TEST_EPS);
 
         // distance a point on segment
-        Assert.assertEquals(Math.sin(Math.PI / 4.0), segment.distance(Vector2D.of(0, -1)), 1.0e-10);
+        Assert.assertEquals(Math.sin(Math.PI / 4.0), segment.distance(Vector2D.of(0, -1)), TEST_EPS);
 
         // distance to end point
-        Assert.assertEquals(Math.sqrt(8), segment.distance(Vector2D.of(0, 4)), 1.0e-10);
+        Assert.assertEquals(Math.sqrt(8), segment.distance(Vector2D.of(0, 4)), TEST_EPS);
 
         // distance to start point
-        Assert.assertEquals(Math.sqrt(8), segment.distance(Vector2D.of(0, -4)), 1.0e-10);
+        Assert.assertEquals(Math.sqrt(8), segment.distance(Vector2D.of(0, -4)), TEST_EPS);
     }
 }
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SubLineTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SubLineTest.java
index 7943659..6ef6638 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SubLineTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/SubLineTest.java
@@ -19,6 +19,8 @@ package org.apache.commons.geometry.euclidean.twod;
 import java.util.List;
 
 import org.apache.commons.geometry.core.partitioning.RegionFactory;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.oned.IntervalsSet;
 import org.apache.commons.geometry.euclidean.oned.Vector1D;
 import org.junit.Assert;
@@ -26,21 +28,26 @@ import org.junit.Test;
 
 public class SubLineTest {
 
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
+
     @Test
     public void testEndPoints() {
         Vector2D p1 = Vector2D.of(-1, -7);
         Vector2D p2 = Vector2D.of(7, -1);
-        Segment segment = new Segment(p1, p2, new Line(p1, p2, 1.0e-10));
+        Segment segment = new Segment(p1, p2, new Line(p1, p2, TEST_PRECISION));
         SubLine sub = new SubLine(segment);
         List<Segment> segments = sub.getSegments();
         Assert.assertEquals(1, segments.size());
-        Assert.assertEquals(0.0, Vector2D.of(-1, -7).distance(segments.get(0).getStart()), 1.0e-10);
-        Assert.assertEquals(0.0, Vector2D.of( 7, -1).distance(segments.get(0).getEnd()), 1.0e-10);
+        Assert.assertEquals(0.0, Vector2D.of(-1, -7).distance(segments.get(0).getStart()), TEST_EPS);
+        Assert.assertEquals(0.0, Vector2D.of( 7, -1).distance(segments.get(0).getEnd()), TEST_EPS);
     }
 
     @Test
     public void testNoEndPoints() {
-        SubLine wholeLine = new Line(Vector2D.of(-1, 7), Vector2D.of(7, 1), 1.0e-10).wholeHyperplane();
+        SubLine wholeLine = new Line(Vector2D.of(-1, 7), Vector2D.of(7, 1), TEST_PRECISION).wholeHyperplane();
         List<Segment> segments = wholeLine.getSegments();
         Assert.assertEquals(1, segments.size());
         Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getX()) &&
@@ -55,41 +62,41 @@ public class SubLineTest {
 
     @Test
     public void testNoSegments() {
-        SubLine empty = new SubLine(new Line(Vector2D.of(-1, -7), Vector2D.of(7, -1), 1.0e-10),
-                                    new RegionFactory<Vector1D>().getComplement(new IntervalsSet(1.0e-10)));
+        SubLine empty = new SubLine(new Line(Vector2D.of(-1, -7), Vector2D.of(7, -1), TEST_PRECISION),
+                                    new RegionFactory<Vector1D>().getComplement(new IntervalsSet(TEST_PRECISION)));
         List<Segment> segments = empty.getSegments();
         Assert.assertEquals(0, segments.size());
     }
 
     @Test
     public void testSeveralSegments() {
-        SubLine twoSubs = new SubLine(new Line(Vector2D.of(-1, -7), Vector2D.of(7, -1), 1.0e-10),
-                                    new RegionFactory<Vector1D>().union(new IntervalsSet(1, 2, 1.0e-10),
-                                                                           new IntervalsSet(3, 4, 1.0e-10)));
+        SubLine twoSubs = new SubLine(new Line(Vector2D.of(-1, -7), Vector2D.of(7, -1), TEST_PRECISION),
+                                    new RegionFactory<Vector1D>().union(new IntervalsSet(1, 2, TEST_PRECISION),
+                                                                           new IntervalsSet(3, 4, TEST_PRECISION)));
         List<Segment> segments = twoSubs.getSegments();
         Assert.assertEquals(2, segments.size());
     }
 
     @Test
     public void testHalfInfiniteNeg() {
-        SubLine empty = new SubLine(new Line(Vector2D.of(-1, -7), Vector2D.of(7, -1), 1.0e-10),
-                                    new IntervalsSet(Double.NEGATIVE_INFINITY, 0.0, 1.0e-10));
+        SubLine empty = new SubLine(new Line(Vector2D.of(-1, -7), Vector2D.of(7, -1), TEST_PRECISION),
+                                    new IntervalsSet(Double.NEGATIVE_INFINITY, 0.0, TEST_PRECISION));
         List<Segment> segments = empty.getSegments();
         Assert.assertEquals(1, segments.size());
         Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getX()) &&
                           segments.get(0).getStart().getX() < 0);
         Assert.assertTrue(Double.isInfinite(segments.get(0).getStart().getY()) &&
                           segments.get(0).getStart().getY() < 0);
-        Assert.assertEquals(0.0, Vector2D.of(3, -4).distance(segments.get(0).getEnd()), 1.0e-10);
+        Assert.assertEquals(0.0, Vector2D.of(3, -4).distance(segments.get(0).getEnd()), TEST_EPS);
     }
 
     @Test
     public void testHalfInfinitePos() {
-        SubLine empty = new SubLine(new Line(Vector2D.of(-1, -7), Vector2D.of(7, -1), 1.0e-10),
-                                    new IntervalsSet(0.0, Double.POSITIVE_INFINITY, 1.0e-10));
+        SubLine empty = new SubLine(new Line(Vector2D.of(-1, -7), Vector2D.of(7, -1), TEST_PRECISION),
+                                    new IntervalsSet(0.0, Double.POSITIVE_INFINITY, TEST_PRECISION));
         List<Segment> segments = empty.getSegments();
         Assert.assertEquals(1, segments.size());
-        Assert.assertEquals(0.0, Vector2D.of(3, -4).distance(segments.get(0).getStart()), 1.0e-10);
+        Assert.assertEquals(0.0, Vector2D.of(3, -4).distance(segments.get(0).getStart()), TEST_EPS);
         Assert.assertTrue(Double.isInfinite(segments.get(0).getEnd().getX()) &&
                           segments.get(0).getEnd().getX() > 0);
         Assert.assertTrue(Double.isInfinite(segments.get(0).getEnd().getY()) &&
@@ -98,56 +105,56 @@ public class SubLineTest {
 
     @Test
     public void testIntersectionInsideInside() {
-        SubLine sub1 = new SubLine(Vector2D.of(1, 1), Vector2D.of(3, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(Vector2D.of(2, 0), Vector2D.of(2, 2), 1.0e-10);
-        Assert.assertEquals(0.0, Vector2D.of(2, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
-        Assert.assertEquals(0.0, Vector2D.of(2, 1).distance(sub1.intersection(sub2, false)), 1.0e-12);
+        SubLine sub1 = new SubLine(Vector2D.of(1, 1), Vector2D.of(3, 1), TEST_PRECISION);
+        SubLine sub2 = new SubLine(Vector2D.of(2, 0), Vector2D.of(2, 2), TEST_PRECISION);
+        Assert.assertEquals(0.0, Vector2D.of(2, 1).distance(sub1.intersection(sub2, true)), TEST_EPS);
+        Assert.assertEquals(0.0, Vector2D.of(2, 1).distance(sub1.intersection(sub2, false)), TEST_EPS);
     }
 
     @Test
     public void testIntersectionInsideBoundary() {
-        SubLine sub1 = new SubLine(Vector2D.of(1, 1), Vector2D.of(3, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(Vector2D.of(2, 0), Vector2D.of(2, 1), 1.0e-10);
-        Assert.assertEquals(0.0, Vector2D.of(2, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
+        SubLine sub1 = new SubLine(Vector2D.of(1, 1), Vector2D.of(3, 1), TEST_PRECISION);
+        SubLine sub2 = new SubLine(Vector2D.of(2, 0), Vector2D.of(2, 1), TEST_PRECISION);
+        Assert.assertEquals(0.0, Vector2D.of(2, 1).distance(sub1.intersection(sub2, true)), TEST_EPS);
         Assert.assertNull(sub1.intersection(sub2, false));
     }
 
     @Test
     public void testIntersectionInsideOutside() {
-        SubLine sub1 = new SubLine(Vector2D.of(1, 1), Vector2D.of(3, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(Vector2D.of(2, 0), Vector2D.of(2, 0.5), 1.0e-10);
+        SubLine sub1 = new SubLine(Vector2D.of(1, 1), Vector2D.of(3, 1), TEST_PRECISION);
+        SubLine sub2 = new SubLine(Vector2D.of(2, 0), Vector2D.of(2, 0.5), TEST_PRECISION);
         Assert.assertNull(sub1.intersection(sub2, true));
         Assert.assertNull(sub1.intersection(sub2, false));
     }
 
     @Test
     public void testIntersectionBoundaryBoundary() {
-        SubLine sub1 = new SubLine(Vector2D.of(1, 1), Vector2D.of(2, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(Vector2D.of(2, 0), Vector2D.of(2, 1), 1.0e-10);
-        Assert.assertEquals(0.0, Vector2D.of(2, 1).distance(sub1.intersection(sub2, true)),  1.0e-12);
+        SubLine sub1 = new SubLine(Vector2D.of(1, 1), Vector2D.of(2, 1), TEST_PRECISION);
+        SubLine sub2 = new SubLine(Vector2D.of(2, 0), Vector2D.of(2, 1), TEST_PRECISION);
+        Assert.assertEquals(0.0, Vector2D.of(2, 1).distance(sub1.intersection(sub2, true)), TEST_EPS);
         Assert.assertNull(sub1.intersection(sub2, false));
     }
 
     @Test
     public void testIntersectionBoundaryOutside() {
-        SubLine sub1 = new SubLine(Vector2D.of(1, 1), Vector2D.of(2, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(Vector2D.of(2, 0), Vector2D.of(2, 0.5), 1.0e-10);
+        SubLine sub1 = new SubLine(Vector2D.of(1, 1), Vector2D.of(2, 1), TEST_PRECISION);
+        SubLine sub2 = new SubLine(Vector2D.of(2, 0), Vector2D.of(2, 0.5), TEST_PRECISION);
         Assert.assertNull(sub1.intersection(sub2, true));
         Assert.assertNull(sub1.intersection(sub2, false));
     }
 
     @Test
     public void testIntersectionOutsideOutside() {
-        SubLine sub1 = new SubLine(Vector2D.of(1, 1), Vector2D.of(1.5, 1), 1.0e-10);
-        SubLine sub2 = new SubLine(Vector2D.of(2, 0), Vector2D.of(2, 0.5), 1.0e-10);
+        SubLine sub1 = new SubLine(Vector2D.of(1, 1), Vector2D.of(1.5, 1), TEST_PRECISION);
+        SubLine sub2 = new SubLine(Vector2D.of(2, 0), Vector2D.of(2, 0.5), TEST_PRECISION);
         Assert.assertNull(sub1.intersection(sub2, true));
         Assert.assertNull(sub1.intersection(sub2, false));
     }
 
     @Test
     public void testIntersectionParallel() {
-        final SubLine sub1 = new SubLine(Vector2D.of(0, 1), Vector2D.of(0, 2), 1.0e-10);
-        final SubLine sub2 = new SubLine(Vector2D.of(66, 3), Vector2D.of(66, 4), 1.0e-10);
+        final SubLine sub1 = new SubLine(Vector2D.of(0, 1), Vector2D.of(0, 2), TEST_PRECISION);
+        final SubLine sub2 = new SubLine(Vector2D.of(66, 3), Vector2D.of(66, 4), TEST_PRECISION);
         Assert.assertNull(sub1.intersection(sub2, true));
         Assert.assertNull(sub1.intersection(sub2, false));
     }
diff --git a/commons-geometry-euclidean/src/test/resources/org/apache/commons/geometry/euclidean/threed/issue-1211.bsp b/commons-geometry-euclidean/src/test/resources/org/apache/commons/geometry/euclidean/threed/issue-1211.bsp
index 23c2cdb..2803ac6 100644
--- a/commons-geometry-euclidean/src/test/resources/org/apache/commons/geometry/euclidean/threed/issue-1211.bsp
+++ b/commons-geometry-euclidean/src/test/resources/org/apache/commons/geometry/euclidean/threed/issue-1211.bsp
@@ -1,11 +1,10 @@
 PolyhedronsSet
-tolerance  1.0e-8
- plus  internal -1.0  0.0  0.0 -1.0  0.0  0.0  1.0e-8
-   minus internal  0.0  1.0  0.0  0.0  1.0  0.0  1.0e-8
-     minus internal  0.0  0.0  1.0  0.0  0.0  1.0  1.0e-8
-       minus internal  0.0  0.0 -1.0  0.0  0.0 -1.0  1.0e-8
-         minus internal  0.0 -1.0  0.0  0.0 -1.0  0.0  1.0e-8
-           minus internal  1.0  0.0  0.0  1.0  0.0  0.0  1.0e-8
+ plus  internal -1.0  0.0  0.0 -1.0  0.0  0.0
+   minus internal  0.0  1.0  0.0  0.0  1.0  0.0
+     minus internal  0.0  0.0  1.0  0.0  0.0  1.0
+       minus internal  0.0  0.0 -1.0  0.0  0.0 -1.0
+         minus internal  0.0 -1.0  0.0  0.0 -1.0  0.0
+           minus internal  1.0  0.0  0.0  1.0  0.0  0.0
              minus leaf true
              plus  leaf false
            plus  leaf false
diff --git a/commons-geometry-hull/src/main/java/org/apache/commons/geometry/euclidean/twod/hull/AbstractConvexHullGenerator2D.java b/commons-geometry-hull/src/main/java/org/apache/commons/geometry/euclidean/twod/hull/AbstractConvexHullGenerator2D.java
index a304935..3ec1621 100644
--- a/commons-geometry-hull/src/main/java/org/apache/commons/geometry/euclidean/twod/hull/AbstractConvexHullGenerator2D.java
+++ b/commons-geometry-hull/src/main/java/org/apache/commons/geometry/euclidean/twod/hull/AbstractConvexHullGenerator2D.java
@@ -18,6 +18,8 @@ package org.apache.commons.geometry.euclidean.twod.hull;
 
 import java.util.Collection;
 
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.twod.Vector2D;
 
 /**
@@ -25,11 +27,11 @@ import org.apache.commons.geometry.euclidean.twod.Vector2D;
  */
 abstract class AbstractConvexHullGenerator2D implements ConvexHullGenerator2D {
 
-    /** Default value for tolerance. */
-    private static final double DEFAULT_TOLERANCE = 1e-10;
+    /** Default epsilon vlaue. */
+    private static final double DEFAULT_EPSILON = 1e-10;
 
-    /** Tolerance below which points are considered identical. */
-    private final double tolerance;
+    /** Precision context used to compare floating point numbers. */
+    private final DoublePrecisionContext precision;
 
     /**
      * Indicates if collinear points on the hull shall be present in the output.
@@ -40,13 +42,13 @@ abstract class AbstractConvexHullGenerator2D implements ConvexHullGenerator2D {
     /**
      * Simple constructor.
      * <p>
-     * The default tolerance (1e-10) will be used to determine identical points.
+     * The default epsilon (1e-10) will be used to determine identical points.
      *
      * @param includeCollinearPoints indicates if collinear points on the hull shall be
      * added as hull vertices
      */
     protected AbstractConvexHullGenerator2D(final boolean includeCollinearPoints) {
-        this(includeCollinearPoints, DEFAULT_TOLERANCE);
+        this(includeCollinearPoints, new EpsilonDoublePrecisionContext(DEFAULT_EPSILON));
     }
 
     /**
@@ -54,19 +56,18 @@ abstract class AbstractConvexHullGenerator2D implements ConvexHullGenerator2D {
      *
      * @param includeCollinearPoints indicates if collinear points on the hull shall be
      * added as hull vertices
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point numbers
      */
-    protected AbstractConvexHullGenerator2D(final boolean includeCollinearPoints, final double tolerance) {
+    protected AbstractConvexHullGenerator2D(final boolean includeCollinearPoints, final DoublePrecisionContext precision) {
         this.includeCollinearPoints = includeCollinearPoints;
-        this.tolerance = tolerance;
+        this.precision = precision;
     }
 
-    /**
-     * Get the tolerance below which points are considered identical.
-     * @return the tolerance below which points are considered identical
+    /** Get the object used to determine floating point equality for this region.
+     * @return the floating point precision context for the instance
      */
-    public double getTolerance() {
-        return tolerance;
+    public DoublePrecisionContext getPrecision() {
+        return precision;
     }
 
     /**
@@ -91,7 +92,7 @@ abstract class AbstractConvexHullGenerator2D implements ConvexHullGenerator2D {
 
         try {
             return new ConvexHull2D(hullVertices.toArray(new Vector2D[hullVertices.size()]),
-                                    tolerance);
+                                    precision);
         } catch (IllegalArgumentException e) {
             // the hull vertices may not form a convex hull if the tolerance value is to large
             throw new IllegalStateException("Convex hull algorithm failed to generate solution", e);
diff --git a/commons-geometry-hull/src/main/java/org/apache/commons/geometry/euclidean/twod/hull/ConvexHull2D.java b/commons-geometry-hull/src/main/java/org/apache/commons/geometry/euclidean/twod/hull/ConvexHull2D.java
index cd990b8..2aee11d 100644
--- a/commons-geometry-hull/src/main/java/org/apache/commons/geometry/euclidean/twod/hull/ConvexHull2D.java
+++ b/commons-geometry-hull/src/main/java/org/apache/commons/geometry/euclidean/twod/hull/ConvexHull2D.java
@@ -20,13 +20,12 @@ import java.io.Serializable;
 
 import org.apache.commons.geometry.core.partitioning.Region;
 import org.apache.commons.geometry.core.partitioning.RegionFactory;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.twod.Line;
-import org.apache.commons.geometry.euclidean.twod.Vector2D;
 import org.apache.commons.geometry.euclidean.twod.Segment;
 import org.apache.commons.geometry.euclidean.twod.Vector2D;
 import org.apache.commons.geometry.hull.ConvexHull;
 import org.apache.commons.numbers.arrays.LinearCombination;
-import org.apache.commons.numbers.core.Precision;
 
 /**
  * This class represents a convex hull in an two-dimensional Euclidean space.
@@ -39,8 +38,8 @@ public class ConvexHull2D implements ConvexHull<Vector2D>, Serializable {
     /** Vertices of the hull. */
     private final Vector2D[] vertices;
 
-    /** Tolerance threshold used during creation of the hull vertices. */
-    private final double tolerance;
+    /** Precision context used to compare floating point numbers. */
+    private final DoublePrecisionContext precision;
 
     /**
      * Line segments of the hull.
@@ -51,14 +50,13 @@ public class ConvexHull2D implements ConvexHull<Vector2D>, Serializable {
     /**
      * Simple constructor.
      * @param vertices the vertices of the convex hull, must be ordered
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point numbers
      * @throws IllegalArgumentException if the vertices do not form a convex hull
      */
-    public ConvexHull2D(final Vector2D[] vertices, final double tolerance)
+    public ConvexHull2D(final Vector2D[] vertices, final DoublePrecisionContext precision)
         throws IllegalArgumentException {
 
-        // assign tolerance as it will be used by the isConvex method
-        this.tolerance = tolerance;
+        this.precision = precision;
 
         if (!isConvex(vertices)) {
             throw new IllegalArgumentException("Vertices do not form a convex hull in CCW winding");
@@ -87,7 +85,7 @@ public class ConvexHull2D implements ConvexHull<Vector2D>, Serializable {
             final Vector2D d2 = p3.subtract(p2);
 
             final double crossProduct = LinearCombination.value(d1.getX(), d2.getY(), -d1.getY(), d2.getX());
-            final int cmp = Precision.compareTo(crossProduct, 0.0, tolerance);
+            final int cmp = precision.compare(crossProduct, 0.0);
             // in case of collinear points the cross product will be zero
             if (cmp != 0.0) {
                 if (sign != 0.0 && cmp != sign) {
@@ -129,7 +127,7 @@ public class ConvexHull2D implements ConvexHull<Vector2D>, Serializable {
                 this.lineSegments = new Segment[1];
                 final Vector2D p1 = vertices[0];
                 final Vector2D p2 = vertices[1];
-                this.lineSegments[0] = new Segment(p1, p2, new Line(p1, p2, tolerance));
+                this.lineSegments[0] = new Segment(p1, p2, new Line(p1, p2, precision));
             } else {
                 this.lineSegments = new Segment[size];
                 Vector2D firstPoint = null;
@@ -141,12 +139,12 @@ public class ConvexHull2D implements ConvexHull<Vector2D>, Serializable {
                         lastPoint = point;
                     } else {
                         this.lineSegments[index++] =
-                                new Segment(lastPoint, point, new Line(lastPoint, point, tolerance));
+                                new Segment(lastPoint, point, new Line(lastPoint, point, precision));
                         lastPoint = point;
                     }
                 }
                 this.lineSegments[index] =
-                        new Segment(lastPoint, firstPoint, new Line(lastPoint, firstPoint, tolerance));
+                        new Segment(lastPoint, firstPoint, new Line(lastPoint, firstPoint, precision));
             }
         }
         return lineSegments;
diff --git a/commons-geometry-hull/src/main/java/org/apache/commons/geometry/euclidean/twod/hull/MonotoneChain.java b/commons-geometry-hull/src/main/java/org/apache/commons/geometry/euclidean/twod/hull/MonotoneChain.java
index f383787..043b79f 100644
--- a/commons-geometry-hull/src/main/java/org/apache/commons/geometry/euclidean/twod/hull/MonotoneChain.java
+++ b/commons-geometry-hull/src/main/java/org/apache/commons/geometry/euclidean/twod/hull/MonotoneChain.java
@@ -22,9 +22,9 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.twod.Line;
 import org.apache.commons.geometry.euclidean.twod.Vector2D;
-import org.apache.commons.numbers.core.Precision;
 
 /**
  * Implements Andrew's monotone chain method to generate the convex hull of a finite set of
@@ -65,10 +65,10 @@ public class MonotoneChain extends AbstractConvexHullGenerator2D {
     /**
      * Create a new MonotoneChain instance.
      * @param includeCollinearPoints whether collinear points shall be added as hull vertices
-     * @param tolerance tolerance below which points are considered identical
+     * @param precision precision context used to compare floating point numbers
      */
-    public MonotoneChain(final boolean includeCollinearPoints, final double tolerance) {
-        super(includeCollinearPoints, tolerance);
+    public MonotoneChain(final boolean includeCollinearPoints, final DoublePrecisionContext precision) {
+        super(includeCollinearPoints, precision);
     }
 
     /** {@inheritDoc} */
@@ -82,12 +82,12 @@ public class MonotoneChain extends AbstractConvexHullGenerator2D {
             /** {@inheritDoc} */
             @Override
             public int compare(final Vector2D o1, final Vector2D o2) {
-                final double tolerance = getTolerance();
+                final DoublePrecisionContext precision = getPrecision();
                 // need to take the tolerance value into account, otherwise collinear points
                 // will not be handled correctly when building the upper/lower hull
-                final int diff = Precision.compareTo(o1.getX(), o2.getX(), tolerance);
+                final int diff = precision.compare(o1.getX(), o2.getX());
                 if (diff == 0) {
-                    return Precision.compareTo(o1.getY(), o2.getY(), tolerance);
+                    return precision.compare(o1.getY(), o2.getY());
                 } else {
                     return diff;
                 }
@@ -132,12 +132,12 @@ public class MonotoneChain extends AbstractConvexHullGenerator2D {
      * @param hull the partial hull
      */
     private void updateHull(final Vector2D point, final List<Vector2D> hull) {
-        final double tolerance = getTolerance();
+        final DoublePrecisionContext precision = getPrecision();
 
         if (hull.size() == 1) {
             // ensure that we do not add an identical point
             final Vector2D p1 = hull.get(0);
-            if (p1.distance(point) < tolerance) {
+            if (precision.isZero(p1.distance(point))) {
                 return;
             }
         }
@@ -147,12 +147,12 @@ public class MonotoneChain extends AbstractConvexHullGenerator2D {
             final Vector2D p1 = hull.get(size - 2);
             final Vector2D p2 = hull.get(size - 1);
 
-            final double offset = new Line(p1, p2, tolerance).getOffset(point);
-            if (Math.abs(offset) < tolerance) {
+            final double offset = new Line(p1, p2, precision).getOffset(point);
+            if (precision.isZero(offset)) {
                 // the point is collinear to the line (p1, p2)
 
                 final double distanceToCurrent = p1.distance(point);
-                if (distanceToCurrent < tolerance || p2.distance(point) < tolerance) {
+                if (precision.isZero(distanceToCurrent) || precision.isZero(p2.distance(point))) {
                     // the point is assumed to be identical to either p1 or p2
                     return;
                 }
diff --git a/commons-geometry-hull/src/test/java/org/apache/commons/geometry/euclidean/twod/hull/AklToussaintHeuristicTest.java b/commons-geometry-hull/src/test/java/org/apache/commons/geometry/euclidean/twod/hull/AklToussaintHeuristicTest.java
index 34a5dae..c81177f 100644
--- a/commons-geometry-hull/src/test/java/org/apache/commons/geometry/euclidean/twod/hull/AklToussaintHeuristicTest.java
+++ b/commons-geometry-hull/src/test/java/org/apache/commons/geometry/euclidean/twod/hull/AklToussaintHeuristicTest.java
@@ -19,9 +19,6 @@ package org.apache.commons.geometry.euclidean.twod.hull;
 import java.util.Collection;
 
 import org.apache.commons.geometry.euclidean.twod.Vector2D;
-import org.apache.commons.geometry.euclidean.twod.hull.AklToussaintHeuristic;
-import org.apache.commons.geometry.euclidean.twod.hull.ConvexHullGenerator2D;
-import org.apache.commons.geometry.euclidean.twod.hull.MonotoneChain;
 
 /**
  * Test class for AklToussaintHeuristic.
diff --git a/commons-geometry-hull/src/test/java/org/apache/commons/geometry/euclidean/twod/hull/MonotoneChainTest.java b/commons-geometry-hull/src/test/java/org/apache/commons/geometry/euclidean/twod/hull/MonotoneChainTest.java
index 4ea3c6e..2a24af4 100644
--- a/commons-geometry-hull/src/test/java/org/apache/commons/geometry/euclidean/twod/hull/MonotoneChainTest.java
+++ b/commons-geometry-hull/src/test/java/org/apache/commons/geometry/euclidean/twod/hull/MonotoneChainTest.java
@@ -19,6 +19,7 @@ package org.apache.commons.geometry.euclidean.twod.hull;
 import java.util.ArrayList;
 import java.util.Collection;
 
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.twod.Vector2D;
 import org.junit.Test;
 
@@ -48,7 +49,7 @@ public class MonotoneChainTest extends ConvexHullGenerator2DAbstractTest {
         points.add(Vector2D.of(40, 1));
 
         @SuppressWarnings("unused")
-        final ConvexHull2D hull = new MonotoneChain(true, 2).generate(points);
+        final ConvexHull2D hull = new MonotoneChain(true, new EpsilonDoublePrecisionContext(2)).generate(points);
     }
 
 }
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/Arc.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/Arc.java
index 804f37d..ba2b34d 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/Arc.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/Arc.java
@@ -16,9 +16,10 @@
  */
 package org.apache.commons.geometry.spherical.oned;
 
-import org.apache.commons.numbers.angle.PlaneAngleRadians;
 import org.apache.commons.geometry.core.Geometry;
 import org.apache.commons.geometry.core.partitioning.Region.Location;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.numbers.angle.PlaneAngleRadians;
 import org.apache.commons.numbers.core.Precision;
 
 
@@ -36,8 +37,8 @@ public class Arc {
     /** Middle point of the arc. */
     private final double middle;
 
-    /** Tolerance below which angles are considered identical. */
-    private final double tolerance;
+    /** Precision context used to determine floating point equality. */
+    private final DoublePrecisionContext precision;
 
     /** Simple constructor.
      * <p>
@@ -52,12 +53,12 @@ public class Arc {
      * </p>
      * @param lower lower angular bound of the arc
      * @param upper upper angular bound of the arc
-     * @param tolerance tolerance below which angles are considered identical
+     * @param precision precision context used to compare floating point values
      * @exception IllegalArgumentException if lower is greater than upper
      */
-    public Arc(final double lower, final double upper, final double tolerance)
+    public Arc(final double lower, final double upper, final DoublePrecisionContext precision)
         throws IllegalArgumentException {
-        this.tolerance = tolerance;
+        this.precision = precision;
         if (Precision.equals(lower, upper, 0) || (upper - lower) >= Geometry.TWO_PI) {
             // the arc must cover the whole circle
             this.lower  = 0;
@@ -102,11 +103,11 @@ public class Arc {
         return middle;
     }
 
-    /** Get the tolerance below which angles are considered identical.
-     * @return tolerance below which angles are considered identical
+    /** Get the object used to determine floating point equality for this region.
+     * @return the floating point precision context for the instance
      */
-    public double getTolerance() {
-        return tolerance;
+    public DoublePrecisionContext getPrecision() {
+        return precision;
     }
 
     /** Check a point with respect to the arc.
@@ -116,12 +117,16 @@ public class Arc {
      */
     public Location checkPoint(final double point) {
         final double normalizedPoint = PlaneAngleRadians.normalize(point, middle);
-        if (normalizedPoint < lower - tolerance || normalizedPoint > upper + tolerance) {
+
+        final int lowerCmp = precision.compare(normalizedPoint, lower);
+        final int upperCmp = precision.compare(normalizedPoint, upper);
+
+        if (lowerCmp < 0 || upperCmp > 0) {
             return Location.OUTSIDE;
-        } else if (normalizedPoint > lower + tolerance && normalizedPoint < upper - tolerance) {
+        } else if (lowerCmp > 0 && upperCmp < 0) {
             return Location.INSIDE;
         } else {
-            return (getSize() >= Geometry.TWO_PI - tolerance) ? Location.INSIDE : Location.BOUNDARY;
+            return (precision.compare(getSize(), Geometry.TWO_PI) >= 0) ? Location.INSIDE : Location.BOUNDARY;
         }
     }
 
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java
index 3334aea..01866f4 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/ArcsSet.java
@@ -29,6 +29,7 @@ import org.apache.commons.geometry.core.partitioning.BSPTree;
 import org.apache.commons.geometry.core.partitioning.BoundaryProjection;
 import org.apache.commons.geometry.core.partitioning.Side;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.numbers.angle.PlaneAngleRadians;
 import org.apache.commons.numbers.core.Precision;
 
@@ -44,10 +45,10 @@ import org.apache.commons.numbers.core.Precision;
 public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterable<double[]> {
 
     /** Build an arcs set representing the whole circle.
-     * @param tolerance tolerance below which close sub-arcs are merged together
+     * @param precision precision context used to compare floating point values
      */
-    public ArcsSet(final double tolerance) {
-        super(tolerance);
+    public ArcsSet(final DoublePrecisionContext precision) {
+        super(precision);
     }
 
     /** Build an arcs set corresponding to a single arc.
@@ -60,11 +61,11 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
      * </p>
      * @param lower lower bound of the arc
      * @param upper upper bound of the arc
-     * @param tolerance tolerance below which close sub-arcs are merged together
+     * @param precision precision context used to compare floating point values
      * @exception IllegalArgumentException if lower is greater than upper
      */
-    public ArcsSet(final double lower, final double upper, final double tolerance) {
-        super(buildTree(lower, upper, tolerance), tolerance);
+    public ArcsSet(final double lower, final double upper, final DoublePrecisionContext precision) {
+        super(buildTree(lower, upper, precision), precision);
     }
 
     /** Build an arcs set from an inside/outside BSP tree.
@@ -75,12 +76,12 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
      * recommended to use the predefined constants
      * {@code Boolean.TRUE} and {@code Boolean.FALSE}</p>
      * @param tree inside/outside BSP tree representing the arcs set
-     * @param tolerance tolerance below which close sub-arcs are merged together
+     * @param precision precision context used to compare floating point values
      * @exception IllegalArgumentException if the tree leaf nodes are not
      * consistent across the \( 0, 2 \pi \) crossing
      */
-    public ArcsSet(final BSPTree<S1Point> tree, final double tolerance) {
-        super(tree, tolerance);
+    public ArcsSet(final BSPTree<S1Point> tree, final DoublePrecisionContext precision) {
+        super(tree, precision);
         check2PiConsistency();
     }
 
@@ -102,24 +103,24 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
      * <p>If the boundary is empty, the region will represent the whole
      * space.</p>
      * @param boundary collection of boundary elements
-     * @param tolerance tolerance below which close sub-arcs are merged together
+     * @param precision precision context used to compare floating point values
      * @exception IllegalArgumentException if the tree leaf nodes are not
      * consistent across the \( 0, 2 \pi \) crossing
      */
-    public ArcsSet(final Collection<SubHyperplane<S1Point>> boundary, final double tolerance) {
-        super(boundary, tolerance);
+    public ArcsSet(final Collection<SubHyperplane<S1Point>> boundary, final DoublePrecisionContext precision) {
+        super(boundary, precision);
         check2PiConsistency();
     }
 
     /** Build an inside/outside tree representing a single arc.
      * @param lower lower angular bound of the arc
      * @param upper upper angular bound of the arc
-     * @param tolerance tolerance below which close sub-arcs are merged together
+     * @param precision precision context used to compare floating point values
      * @return the built tree
      * @exception IllegalArgumentException if lower is greater than upper
      */
     private static BSPTree<S1Point> buildTree(final double lower, final double upper,
-                                               final double tolerance) {
+                                               final DoublePrecisionContext precision) {
 
         if (Precision.equals(lower, upper, 0) || (upper - lower) >= Geometry.TWO_PI) {
             // the tree must cover the whole circle
@@ -132,12 +133,12 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
         final double normalizedLower = PlaneAngleRadians.normalizeBetweenZeroAndTwoPi(lower);
         final double normalizedUpper = normalizedLower + (upper - lower);
         final SubHyperplane<S1Point> lowerCut =
-                new LimitAngle(S1Point.of(normalizedLower), false, tolerance).wholeHyperplane();
+                new LimitAngle(S1Point.of(normalizedLower), false, precision).wholeHyperplane();
 
         if (normalizedUpper <= Geometry.TWO_PI) {
             // simple arc starting after 0 and ending before 2 \pi
             final SubHyperplane<S1Point> upperCut =
-                    new LimitAngle(S1Point.of(normalizedUpper), true, tolerance).wholeHyperplane();
+                    new LimitAngle(S1Point.of(normalizedUpper), true, precision).wholeHyperplane();
             return new BSPTree<>(lowerCut,
                                          new BSPTree<S1Point>(Boolean.FALSE),
                                          new BSPTree<>(upperCut,
@@ -148,7 +149,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
         } else {
             // arc wrapping around 2 \pi
             final SubHyperplane<S1Point> upperCut =
-                    new LimitAngle(S1Point.of(normalizedUpper - Geometry.TWO_PI), true, tolerance).wholeHyperplane();
+                    new LimitAngle(S1Point.of(normalizedUpper - Geometry.TWO_PI), true, precision).wholeHyperplane();
             return new BSPTree<>(lowerCut,
                                          new BSPTree<>(upperCut,
                                                                new BSPTree<S1Point>(Boolean.FALSE),
@@ -435,7 +436,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
     /** {@inheritDoc} */
     @Override
     public ArcsSet buildNew(final BSPTree<S1Point> tree) {
-        return new ArcsSet(tree, getTolerance());
+        return new ArcsSet(tree, getPrecision());
     }
 
     /** {@inheritDoc} */
@@ -555,7 +556,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
     public List<Arc> asList() {
         final List<Arc> list = new ArrayList<>();
         for (final double[] a : this) {
-            list.add(new Arc(a[0], a[1], getTolerance()));
+            list.add(new Arc(a[0], a[1], getPrecision()));
         }
         return list;
     }
@@ -784,8 +785,8 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
      */
     private void addArcLimit(final BSPTree<S1Point> tree, final double alpha, final boolean isStart) {
 
-        final LimitAngle limit = new LimitAngle(S1Point.of(alpha), !isStart, getTolerance());
-        final BSPTree<S1Point> node = tree.getCell(limit.getLocation(), getTolerance());
+        final LimitAngle limit = new LimitAngle(S1Point.of(alpha), !isStart, getPrecision());
+        final BSPTree<S1Point> node = tree.getCell(limit.getLocation(), getPrecision());
         if (node.getCut() != null) {
             // this should never happen
             throw new GeometryInternalError();
@@ -817,7 +818,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
                 final int    j  = (i + 1) % limits.size();
                 final double lA = limits.get(i);
                 final double lB = PlaneAngleRadians.normalize(limits.get(j), lA);
-                if (Math.abs(lB - lA) <= getTolerance()) {
+                if (getPrecision().areEqual(lB, lA)) {
                     // the two limits are too close to each other, we remove both of them
                     if (j > 0) {
                         // regular case, the two entries are consecutive ones
@@ -833,7 +834,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
                             // the ends were the only limits, is it a full circle or an empty circle?
                             if (lEnd - lStart > Geometry.PI) {
                                 // it was full circle
-                                return new ArcsSet(new BSPTree<S1Point>(Boolean.TRUE), getTolerance());
+                                return new ArcsSet(new BSPTree<S1Point>(Boolean.TRUE), getPrecision());
                             } else {
                                 // it was an empty circle
                                 return null;
@@ -860,7 +861,7 @@ public class ArcsSet extends AbstractRegion<S1Point, S1Point> implements Iterabl
                 return null;
             }
 
-            return new ArcsSet(tree, getTolerance());
+            return new ArcsSet(tree, getPrecision());
 
         }
     }
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/LimitAngle.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/LimitAngle.java
index 605a649..554c483 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/LimitAngle.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/oned/LimitAngle.java
@@ -17,6 +17,7 @@
 package org.apache.commons.geometry.spherical.oned;
 
 import org.apache.commons.geometry.core.partitioning.Hyperplane;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 
 /** This class represents a 1D oriented hyperplane on the circle.
  * <p>An hyperplane on the 1-sphere is an angle with an orientation.</p>
@@ -30,19 +31,19 @@ public class LimitAngle implements Hyperplane<S1Point> {
     /** Orientation. */
     private final boolean direct;
 
-    /** Tolerance below which angles are considered identical. */
-    private final double tolerance;
+    /** Precision context used to compare floating point numbers. */
+    private final DoublePrecisionContext precision;
 
     /** Simple constructor.
      * @param location location of the hyperplane
      * @param direct if true, the plus side of the hyperplane is towards
      * angles greater than {@code location}
-     * @param tolerance tolerance below which angles are considered identical
+     * @param precision precision context used to compare floating point values
      */
-    public LimitAngle(final S1Point location, final boolean direct, final double tolerance) {
+    public LimitAngle(final S1Point location, final boolean direct, final DoublePrecisionContext precision) {
         this.location  = location;
         this.direct    = direct;
-        this.tolerance = tolerance;
+        this.precision = precision;
     }
 
     /** Copy the instance.
@@ -76,7 +77,7 @@ public class LimitAngle implements Hyperplane<S1Point> {
      * @return a new limit angle, with orientation opposite to the instance orientation
      */
     public LimitAngle getReverse() {
-        return new LimitAngle(location, !direct, tolerance);
+        return new LimitAngle(location, !direct, precision);
     }
 
     /** Build a region covering the whole hyperplane.
@@ -101,7 +102,7 @@ public class LimitAngle implements Hyperplane<S1Point> {
      */
     @Override
     public ArcsSet wholeSpace() {
-        return new ArcsSet(tolerance);
+        return new ArcsSet(precision);
     }
 
     /** {@inheritDoc} */
@@ -125,8 +126,8 @@ public class LimitAngle implements Hyperplane<S1Point> {
 
     /** {@inheritDoc} */
     @Override
-    public double getTolerance() {
-        return tolerance;
+    public DoublePrecisionContext getPrecision() {
+        return precision;
     }
 
 }
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Circle.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Circle.java
index 9d3c932..dd3dda7 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Circle.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Circle.java
@@ -20,6 +20,7 @@ import org.apache.commons.geometry.core.partitioning.Embedding;
 import org.apache.commons.geometry.core.partitioning.Hyperplane;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
 import org.apache.commons.geometry.core.partitioning.Transform;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.threed.Vector3D;
 import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
 import org.apache.commons.geometry.spherical.oned.Arc;
@@ -48,28 +49,28 @@ public class Circle implements Hyperplane<S2Point>, Embedding<S2Point, S1Point>
     /** Second axis in the equator plane, in quadrature with respect to x. */
     private Vector3D y;
 
-    /** Tolerance below which close sub-arcs are merged together. */
-    private final double tolerance;
+    /** Precision context used to determine floating point equality. */
+    private final DoublePrecisionContext precision;
 
     /** Build a great circle from its pole.
      * <p>The circle is oriented in the trigonometric direction around pole.</p>
      * @param pole circle pole
-     * @param tolerance tolerance below which close sub-arcs are merged together
+     * @param precision precision context used to compare floating point values
      */
-    public Circle(final Vector3D pole, final double tolerance) {
+    public Circle(final Vector3D pole, final DoublePrecisionContext precision) {
         reset(pole);
-        this.tolerance = tolerance;
+        this.precision = precision;
     }
 
     /** Build a great circle from two non-aligned points.
      * <p>The circle is oriented from first to second point using the path smaller than \( \pi \).</p>
      * @param first first point contained in the great circle
      * @param second second point contained in the great circle
-     * @param tolerance tolerance below which close sub-arcs are merged together
+     * @param precision precision context used to compare floating point values
      */
-    public Circle(final S2Point first, final S2Point second, final double tolerance) {
+    public Circle(final S2Point first, final S2Point second, final DoublePrecisionContext precision) {
         reset(first.getVector().cross(second.getVector()));
-        this.tolerance = tolerance;
+        this.precision = precision;
     }
 
     /** Build a circle from its internal components.
@@ -77,14 +78,14 @@ public class Circle implements Hyperplane<S2Point>, Embedding<S2Point, S1Point>
      * @param pole circle pole
      * @param x first axis in the equator plane
      * @param y second axis in the equator plane
-     * @param tolerance tolerance below which close sub-arcs are merged together
+     * @param precision precision context used to compare floating point values
      */
     private Circle(final Vector3D pole, final Vector3D x, final Vector3D y,
-                   final double tolerance) {
+            final DoublePrecisionContext precision) {
         this.pole      = pole;
         this.x         = x;
         this.y         = y;
-        this.tolerance = tolerance;
+        this.precision = precision;
     }
 
     /** Copy constructor.
@@ -93,7 +94,7 @@ public class Circle implements Hyperplane<S2Point>, Embedding<S2Point, S1Point>
      * @param circle circle to copy
      */
     public Circle(final Circle circle) {
-        this(circle.pole, circle.x, circle.y, circle.tolerance);
+        this(circle.pole, circle.x, circle.y, circle.precision);
     }
 
     /** {@inheritDoc} */
@@ -126,7 +127,7 @@ public class Circle implements Hyperplane<S2Point>, Embedding<S2Point, S1Point>
      * @return a new circle, with orientation opposite to the instance orientation
      */
     public Circle getReverse() {
-        return new Circle(pole.negate(), x, y.negate(), tolerance);
+        return new Circle(pole.negate(), x, y.negate(), precision);
     }
 
     /** {@inheritDoc} */
@@ -135,10 +136,12 @@ public class Circle implements Hyperplane<S2Point>, Embedding<S2Point, S1Point>
         return toSpace(toSubSpace(point));
     }
 
-    /** {@inheritDoc} */
+    /** Get the object used to determine floating point equality for this region.
+     * @return the floating point precision context for the instance
+     */
     @Override
-    public double getTolerance() {
-        return tolerance;
+    public DoublePrecisionContext getPrecision() {
+        return precision;
     }
 
     /** {@inheritDoc}
@@ -232,13 +235,13 @@ public class Circle implements Hyperplane<S2Point>, Embedding<S2Point, S1Point>
     public Arc getInsideArc(final Circle other) {
         final double alpha  = getPhase(other.pole);
         final double halfPi = 0.5 * Math.PI;
-        return new Arc(alpha - halfPi, alpha + halfPi, tolerance);
+        return new Arc(alpha - halfPi, alpha + halfPi, precision);
     }
 
     /** {@inheritDoc} */
     @Override
     public SubCircle wholeHyperplane() {
-        return new SubCircle(this, new ArcsSet(tolerance));
+        return new SubCircle(this, new ArcsSet(precision));
     }
 
     /** Build a region covering the whole space.
@@ -247,7 +250,7 @@ public class Circle implements Hyperplane<S2Point>, Embedding<S2Point, S1Point>
      */
     @Override
     public SphericalPolygonsSet wholeSpace() {
-        return new SphericalPolygonsSet(tolerance);
+        return new SphericalPolygonsSet(precision);
     }
 
     /** {@inheritDoc}
@@ -316,7 +319,7 @@ public class Circle implements Hyperplane<S2Point>, Embedding<S2Point, S1Point>
             return new Circle(rotation.apply(circle.pole),
                               rotation.apply(circle.x),
                               rotation.apply(circle.y),
-                              circle.tolerance);
+                              circle.precision);
         }
 
         /** {@inheritDoc} */
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Edge.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Edge.java
index 27b0137..e662c41 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Edge.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/Edge.java
@@ -19,6 +19,7 @@ package org.apache.commons.geometry.spherical.twod;
 import java.util.List;
 
 import org.apache.commons.geometry.core.Geometry;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.threed.Vector3D;
 import org.apache.commons.geometry.spherical.oned.Arc;
 import org.apache.commons.numbers.angle.PlaneAngleRadians;
@@ -132,9 +133,9 @@ public class Edge {
         final double unwrappedEnd     = arcRelativeEnd - Geometry.TWO_PI;
 
         // build the sub-edges
-        final double tolerance = circle.getTolerance();
+        final DoublePrecisionContext precision = circle.getPrecision();
         Vertex previousVertex = start;
-        if (unwrappedEnd >= length - tolerance) {
+        if (precision.compare(unwrappedEnd, length) >= 0) {
 
             // the edge is entirely contained inside the circle
             // we don't split anything
@@ -153,7 +154,7 @@ public class Edge {
                 alreadyManagedLength = unwrappedEnd;
             }
 
-            if (arcRelativeStart >= length - tolerance) {
+            if (precision.compare(arcRelativeStart, length) >= 0) {
                 // the edge ends while still outside of the circle
                 if (unwrappedEnd >= 0) {
                     previousVertex = addSubEdge(previousVertex, end,
@@ -170,7 +171,7 @@ public class Edge {
                                             arcRelativeStart - alreadyManagedLength, outsideList, splitCircle);
                 alreadyManagedLength = arcRelativeStart;
 
-                if (arcRelativeEnd >= length - tolerance) {
+                if (precision.compare(arcRelativeEnd, length) >= 0) {
                     // the edge ends while still inside of the circle
                     previousVertex = addSubEdge(previousVertex, end,
                                                 length - alreadyManagedLength, insideList, splitCircle);
@@ -205,7 +206,7 @@ public class Edge {
     private Vertex addSubEdge(final Vertex subStart, final Vertex subEnd, final double subLength,
                               final List<Edge> list, final Circle splitCircle) {
 
-        if (subLength <= circle.getTolerance()) {
+        if (circle.getPrecision().isZero(subLength)) {
             // the edge is too short, we ignore it
             return subStart;
         }
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/EdgesBuilder.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/EdgesBuilder.java
index 08b2df6..99c8814 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/EdgesBuilder.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/EdgesBuilder.java
@@ -24,6 +24,7 @@ import java.util.Map;
 import org.apache.commons.geometry.core.partitioning.BSPTree;
 import org.apache.commons.geometry.core.partitioning.BSPTreeVisitor;
 import org.apache.commons.geometry.core.partitioning.BoundaryAttribute;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.threed.Vector3D;
 import org.apache.commons.geometry.spherical.oned.Arc;
 import org.apache.commons.geometry.spherical.oned.ArcsSet;
@@ -36,8 +37,8 @@ class EdgesBuilder implements BSPTreeVisitor<S2Point> {
     /** Root of the tree. */
     private final BSPTree<S2Point> root;
 
-    /** Tolerance below which points are consider to be identical. */
-    private final double tolerance;
+    /** Precision context used to determine floating point equality. */
+    private final DoublePrecisionContext precision;
 
     /** Built edges and their associated nodes. */
     private final Map<Edge, BSPTree<S2Point>> edgeToNode;
@@ -47,11 +48,11 @@ class EdgesBuilder implements BSPTreeVisitor<S2Point> {
 
     /** Simple constructor.
      * @param root tree root
-     * @param tolerance below which points are consider to be identical
+     * @param precision precision context used to compare floating point values
      */
-    EdgesBuilder(final BSPTree<S2Point> root, final double tolerance) {
+    EdgesBuilder(final BSPTree<S2Point> root, final DoublePrecisionContext precision) {
         this.root            = root;
-        this.tolerance       = tolerance;
+        this.precision       = precision;
         this.edgeToNode      = new IdentityHashMap<>();
         this.nodeToEdgesList = new IdentityHashMap<>();
     }
@@ -117,10 +118,10 @@ class EdgesBuilder implements BSPTreeVisitor<S2Point> {
 
         // get the candidate nodes
         final S2Point point = previous.getEnd().getLocation();
-        final List<BSPTree<S2Point>> candidates = root.getCloseCuts(point, tolerance);
+        final List<BSPTree<S2Point>> candidates = root.getCloseCuts(point, precision.getMaxZero());
 
         // the following edge we are looking for must start from one of the candidates nodes
-        double closest = tolerance;
+        double closest = precision.getMaxZero();
         Edge following = null;
         for (final BSPTree<S2Point> node : candidates) {
             for (final Edge edge : nodeToEdgesList.get(node)) {
@@ -137,7 +138,7 @@ class EdgesBuilder implements BSPTreeVisitor<S2Point> {
 
         if (following == null) {
             final Vector3D previousStart = previous.getStart().getLocation().getVector();
-            if (point.getVector().angle(previousStart) <= tolerance) {
+            if (precision.isZero(point.getVector().angle(previousStart))) {
                 // the edge connects back to itself
                 return previous;
             }
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/PropertiesComputer.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/PropertiesComputer.java
index 0bd4dca..4793547 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/PropertiesComputer.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/PropertiesComputer.java
@@ -23,14 +23,15 @@ import org.apache.commons.geometry.core.Geometry;
 import org.apache.commons.geometry.core.internal.GeometryInternalError;
 import org.apache.commons.geometry.core.partitioning.BSPTree;
 import org.apache.commons.geometry.core.partitioning.BSPTreeVisitor;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.threed.Vector3D;
 
 /** Visitor computing geometrical properties.
  */
 class PropertiesComputer implements BSPTreeVisitor<S2Point> {
 
-    /** Tolerance below which points are consider to be identical. */
-    private final double tolerance;
+    /** Precision context used to determine floating point equality. */
+    private final DoublePrecisionContext precision;
 
     /** Summed area. */
     private double summedArea;
@@ -42,10 +43,10 @@ class PropertiesComputer implements BSPTreeVisitor<S2Point> {
     private final List<Vector3D> convexCellsInsidePoints;
 
     /** Simple constructor.
-     * @param tolerance below which points are consider to be identical
+     * @param precision precision context used to compare floating point values
      */
-    PropertiesComputer(final double tolerance) {
-        this.tolerance              = tolerance;
+    PropertiesComputer(final DoublePrecisionContext precision) {
+        this.precision              = precision;
         this.summedArea             = 0;
         this.summedBarycenter       = Vector3D.ZERO;
         this.convexCellsInsidePoints = new ArrayList<>();
@@ -73,7 +74,7 @@ class PropertiesComputer implements BSPTreeVisitor<S2Point> {
                     new SphericalPolygonsSet(node.pruneAroundConvexCell(Boolean.TRUE,
                                                                         Boolean.FALSE,
                                                                         null),
-                                             tolerance);
+                            precision);
 
             // extract the start of the single loop boundary of the convex cell
             final List<Vertex> boundary = convex.getBoundaryLoops();
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSet.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSet.java
index 647e448..ee7c29a 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSet.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSet.java
@@ -28,6 +28,7 @@ import org.apache.commons.geometry.core.partitioning.BSPTree;
 import org.apache.commons.geometry.core.partitioning.BoundaryProjection;
 import org.apache.commons.geometry.core.partitioning.RegionFactory;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.enclosing.EnclosingBall;
 import org.apache.commons.geometry.enclosing.WelzlEncloser;
 import org.apache.commons.geometry.euclidean.threed.Vector3D;
@@ -43,22 +44,22 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
     private List<Vertex> loops;
 
     /** Build a polygons set representing the whole real 2-sphere.
-     * @param tolerance below which points are consider to be identical
+     * @param precision precision context used to compare floating point values
      */
-    public SphericalPolygonsSet(final double tolerance) {
-        super(tolerance);
+    public SphericalPolygonsSet(final DoublePrecisionContext precision) {
+        super(precision);
     }
 
     /** Build a polygons set representing a hemisphere.
      * @param pole pole of the hemisphere (the pole is in the inside half)
-     * @param tolerance below which points are consider to be identical
+     * @param precision precision context used to compare floating point values
      */
-    public SphericalPolygonsSet(final Vector3D pole, final double tolerance) {
-        super(new BSPTree<>(new Circle(pole, tolerance).wholeHyperplane(),
+    public SphericalPolygonsSet(final Vector3D pole, final DoublePrecisionContext precision) {
+        super(new BSPTree<>(new Circle(pole, precision).wholeHyperplane(),
                                     new BSPTree<S2Point>(Boolean.FALSE),
                                     new BSPTree<S2Point>(Boolean.TRUE),
                                     null),
-              tolerance);
+              precision);
     }
 
     /** Build a polygons set representing a regular polygon.
@@ -66,12 +67,12 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
      * @param meridian point defining the reference meridian for first polygon vertex
      * @param outsideRadius distance of the vertices to the center
      * @param n number of sides of the polygon
-     * @param tolerance below which points are consider to be identical
+     * @param precision precision context used to compare floating point values
      */
     public SphericalPolygonsSet(final Vector3D center, final Vector3D meridian,
                                 final double outsideRadius, final int n,
-                                final double tolerance) {
-        this(tolerance, createRegularPolygonVertices(center, meridian, outsideRadius, n));
+                                final DoublePrecisionContext precision) {
+        this(precision, createRegularPolygonVertices(center, meridian, outsideRadius, n));
     }
 
     /** Build a polygons set from a BSP tree.
@@ -82,10 +83,10 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
      * recommended to use the predefined constants
      * {@code Boolean.TRUE} and {@code Boolean.FALSE}</p>
      * @param tree inside/outside BSP tree representing the region
-     * @param tolerance below which points are consider to be identical
+     * @param precision precision context used to compare floating point values
      */
-    public SphericalPolygonsSet(final BSPTree<S2Point> tree, final double tolerance) {
-        super(tree, tolerance);
+    public SphericalPolygonsSet(final BSPTree<S2Point> tree, final DoublePrecisionContext precision) {
+        super(tree, precision);
     }
 
     /** Build a polygons set from a Boundary REPresentation (B-rep).
@@ -107,10 +108,10 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
      * space.</p>
      * @param boundary collection of boundary elements, as a
      * collection of {@link SubHyperplane SubHyperplane} objects
-     * @param tolerance below which points are consider to be identical
+     * @param precision precision context used to compare floating point values
      */
-    public SphericalPolygonsSet(final Collection<SubHyperplane<S2Point>> boundary, final double tolerance) {
-        super(boundary, tolerance);
+    public SphericalPolygonsSet(final Collection<SubHyperplane<S2Point>> boundary, final DoublePrecisionContext precision) {
+        super(boundary, precision);
     }
 
     /** Build a polygon from a simple list of vertices.
@@ -121,8 +122,8 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
      * <p>This constructor does not handle polygons with a boundary
      * forming several disconnected paths (such as polygons with holes).</p>
      * <p>For cases where this simple constructor applies, it is expected to
-     * be numerically more robust than the {@link #SphericalPolygonsSet(Collection,
-     * double) general constructor} using {@link SubHyperplane subhyperplanes}.</p>
+     * be numerically more robust than the {@link #SphericalPolygonsSet(Collection, DoublePrecisionContext)
+     * general constructor} using {@link SubHyperplane subhyperplanes}.</p>
      * <p>If the list is empty, the region will represent the whole
      * space.</p>
      * <p>
@@ -139,12 +140,11 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
      * most accurate detail needed is a good value for the {@code hyperplaneThickness}
      * parameter.
      * </p>
-     * @param hyperplaneThickness tolerance below which points are considered to
-     * belong to the hyperplane (which is therefore more a slab)
+     * @param precision precision context used to compare floating point values
      * @param vertices vertices of the simple loop boundary
      */
-    public SphericalPolygonsSet(final double hyperplaneThickness, final S2Point ... vertices) {
-        super(verticesToTree(hyperplaneThickness, vertices), hyperplaneThickness);
+    public SphericalPolygonsSet(final DoublePrecisionContext precision, final S2Point ... vertices) {
+        super(verticesToTree(precision, vertices), precision);
     }
 
     /** Build the vertices representing a regular polygon.
@@ -182,12 +182,11 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
      * <p>For cases where this simple constructor applies, it is expected to
      * be numerically more robust than the {@link #PolygonsSet(Collection) general
      * constructor} using {@link SubHyperplane subhyperplanes}.</p>
-     * @param hyperplaneThickness tolerance below which points are consider to
-     * belong to the hyperplane (which is therefore more a slab)
+     * @param precision precision context used to compare floating point values
      * @param vertices vertices of the simple loop boundary
      * @return the BSP tree of the input vertices
      */
-    private static BSPTree<S2Point> verticesToTree(final double hyperplaneThickness,
+    private static BSPTree<S2Point> verticesToTree(final DoublePrecisionContext precision,
                                                     final S2Point ... vertices) {
 
         final int n = vertices.length;
@@ -216,7 +215,7 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
             // with the current one
             Circle circle = start.sharedCircleWith(end);
             if (circle == null) {
-                circle = new Circle(start.getLocation(), end.getLocation(), hyperplaneThickness);
+                circle = new Circle(start.getLocation(), end.getLocation(), precision);
             }
 
             // create the edge and store it
@@ -228,7 +227,7 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
             // check if another vertex also happens to be on this circle
             for (final Vertex vertex : vArray) {
                 if (vertex != start && vertex != end &&
-                    Math.abs(circle.getOffset(vertex.getLocation())) <= hyperplaneThickness) {
+                    precision.isZero(circle.getOffset(vertex.getLocation()))) {
                     vertex.bindWith(circle);
                 }
             }
@@ -237,21 +236,20 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
 
         // build the tree top-down
         final BSPTree<S2Point> tree = new BSPTree<>();
-        insertEdges(hyperplaneThickness, tree, edges);
+        insertEdges(precision, tree, edges);
 
         return tree;
 
     }
 
     /** Recursively build a tree by inserting cut sub-hyperplanes.
-     * @param hyperplaneThickness tolerance below which points are considered to
-     * belong to the hyperplane (which is therefore more a slab)
+     * @param precision precision context used to compare floating point values
      * @param node current tree node (it is a leaf node at the beginning
      * of the call)
      * @param edges list of edges to insert in the cell defined by this node
      * (excluding edges not belonging to the cell defined by this node)
      */
-    private static void insertEdges(final double hyperplaneThickness,
+    private static void insertEdges(final DoublePrecisionContext precision,
                                     final BSPTree<S2Point> node,
                                     final List<Edge> edges) {
 
@@ -289,12 +287,12 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
 
         // recurse through lower levels
         if (!outsideList.isEmpty()) {
-            insertEdges(hyperplaneThickness, node.getPlus(), outsideList);
+            insertEdges(precision, node.getPlus(), outsideList);
         } else {
             node.getPlus().setAttribute(Boolean.FALSE);
         }
         if (!insideList.isEmpty()) {
-            insertEdges(hyperplaneThickness, node.getMinus(),  insideList);
+            insertEdges(precision, node.getMinus(),  insideList);
         } else {
             node.getMinus().setAttribute(Boolean.TRUE);
         }
@@ -304,7 +302,7 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
     /** {@inheritDoc} */
     @Override
     public SphericalPolygonsSet buildNew(final BSPTree<S2Point> tree) {
-        return new SphericalPolygonsSet(tree, getTolerance());
+        return new SphericalPolygonsSet(tree, getPrecision());
     }
 
     /** {@inheritDoc}
@@ -332,7 +330,7 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
         } else {
 
             // the instance has a boundary
-            final PropertiesComputer pc = new PropertiesComputer(getTolerance());
+            final PropertiesComputer pc = new PropertiesComputer(getPrecision());
             tree.visit(pc);
             setSize(pc.getArea());
             setBarycenter(pc.getBarycenter());
@@ -373,7 +371,7 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
 
                 // sort the arcs according to their start point
                 final BSPTree<S2Point> root = getTree(true);
-                final EdgesBuilder visitor = new EdgesBuilder(root, getTolerance());
+                final EdgesBuilder visitor = new EdgesBuilder(root, getPrecision());
                 root.visit(visitor);
                 final List<Edge> edges = visitor.getEdges();
 
@@ -412,8 +410,6 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
 
     }
 
-    // TODO: Revisit the vector/point conversions here.
-
     /** Get a spherical cap enclosing the polygon.
      * <p>
      * This method is intended as a first test to quickly identify points
@@ -502,14 +498,14 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
         // find the smallest enclosing 3D sphere
         final SphereGenerator generator = new SphereGenerator();
         final WelzlEncloser<Vector3D> encloser =
-                new WelzlEncloser<>(getTolerance(), generator);
+                new WelzlEncloser<>(getPrecision(), generator);
         EnclosingBall<Vector3D> enclosing3D = encloser.enclose(points);
         final Vector3D[] support3D = enclosing3D.getSupport();
 
         // convert to 3D sphere to spherical cap
         final double r = enclosing3D.getRadius();
         final double h = enclosing3D.getCenter().norm();
-        if (h < getTolerance()) {
+        if (getPrecision().isZero(h)) {
             // the 3D sphere is centered on the unit sphere and covers it
             // fall back to a crude approximation, based only on outside convex cells
             EnclosingBall<S2Point> enclosingS2 =
@@ -543,7 +539,7 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
      * @return list of points known to be strictly in all inside convex cells
      */
     private List<Vector3D> getInsidePoints() {
-        final PropertiesComputer pc = new PropertiesComputer(getTolerance());
+        final PropertiesComputer pc = new PropertiesComputer(getPrecision());
         getTree(true).visit(pc);
         return pc.getConvexCellsInsidePoints();
     }
@@ -554,7 +550,7 @@ public class SphericalPolygonsSet extends AbstractRegion<S2Point, S1Point> {
     private List<Vector3D> getOutsidePoints() {
         final SphericalPolygonsSet complement =
                 (SphericalPolygonsSet) new RegionFactory<S2Point>().getComplement(this);
-        final PropertiesComputer pc = new PropertiesComputer(getTolerance());
+        final PropertiesComputer pc = new PropertiesComputer(getPrecision());
         complement.getTree(true).visit(pc);
         return pc.getConvexCellsInsidePoints();
     }
diff --git a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/SubCircle.java b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/SubCircle.java
index 30349ca..58bdd27 100644
--- a/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/SubCircle.java
+++ b/commons-geometry-spherical/src/main/java/org/apache/commons/geometry/spherical/twod/SubCircle.java
@@ -19,6 +19,7 @@ package org.apache.commons.geometry.spherical.twod;
 import org.apache.commons.geometry.core.partitioning.AbstractSubHyperplane;
 import org.apache.commons.geometry.core.partitioning.Hyperplane;
 import org.apache.commons.geometry.core.partitioning.Region;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
 import org.apache.commons.geometry.spherical.oned.Arc;
 import org.apache.commons.geometry.spherical.oned.ArcsSet;
 import org.apache.commons.geometry.spherical.oned.S1Point;
@@ -50,8 +51,9 @@ public class SubCircle extends AbstractSubHyperplane<S2Point, S1Point> {
         final Circle thisCircle   = (Circle) getHyperplane();
         final Circle otherCircle  = (Circle) hyperplane;
         final double angle = thisCircle.getPole().angle(otherCircle.getPole());
+        final DoublePrecisionContext precision = thisCircle.getPrecision();
 
-        if (angle < thisCircle.getTolerance() || angle > Math.PI - thisCircle.getTolerance()) {
+        if (precision.isZero(angle) || precision.compare(angle, Math.PI) >= 0) {
             // the two circles are aligned or opposite
             return new SplitSubHyperplane<>(null, null);
         } else {
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalTestUtils.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalTestUtils.java
index 6baa3b1..dcb2571 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalTestUtils.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/SphericalTestUtils.java
@@ -39,14 +39,14 @@ public class SphericalTestUtils {
      * @return string representation of the region
      */
     public static String dump(final ArcsSet arcsSet) {
-        final TreeDumper<S1Point> visitor = new TreeDumper<S1Point>("ArcsSet", arcsSet.getTolerance()) {
+        final TreeDumper<S1Point> visitor = new TreeDumper<S1Point>("ArcsSet") {
 
             /** {@inheritDoc} */
             @Override
             protected void formatHyperplane(final Hyperplane<S1Point> hyperplane) {
                 final LimitAngle h = (LimitAngle) hyperplane;
-                getFormatter().format("%22.15e %b %22.15e",
-                                      h.getLocation().getAzimuth(), h.isDirect(), h.getTolerance());
+                getFormatter().format("%22.15e %b %s",
+                                      h.getLocation().getAzimuth(), h.isDirect(), h.getPrecision().toString());
             }
 
         };
@@ -59,15 +59,15 @@ public class SphericalTestUtils {
      * @return string representation of the region
      */
     public static String dump(final SphericalPolygonsSet sphericalPolygonsSet) {
-        final TreeDumper<S2Point> visitor = new TreeDumper<S2Point>("SphericalPolygonsSet", sphericalPolygonsSet.getTolerance()) {
+        final TreeDumper<S2Point> visitor = new TreeDumper<S2Point>("SphericalPolygonsSet") {
 
             /** {@inheritDoc} */
             @Override
             protected void formatHyperplane(final Hyperplane<S2Point> hyperplane) {
                 final Circle h = (Circle) hyperplane;
-                getFormatter().format("%22.15e %22.15e %22.15e %22.15e",
+                getFormatter().format("%22.15e %22.15e %22.15e %s",
                                       h.getPole().getX(), h.getPole().getY(), h.getPole().getZ(),
-                                      h.getTolerance());
+                                      h.getPrecision().toString());
             }
 
         };
@@ -88,12 +88,12 @@ public class SphericalTestUtils {
             /** {@inheritDoc} */
             @Override
             protected LimitAngle parseHyperplane()
-                throws IOException, ParseException {
-                return new LimitAngle(S1Point.of(getNumber()), getBoolean(), getNumber());
+                throws ParseException {
+                return new LimitAngle(S1Point.of(getNumber()), getBoolean(), getPrecision());
             }
 
         };
-        return new ArcsSet(builder.getTree(), builder.getTolerance());
+        return new ArcsSet(builder.getTree(), builder.getPrecision());
     }
 
     /** Parse a string representation of a {@link SphericalPolygonsSet}.
@@ -109,12 +109,12 @@ public class SphericalTestUtils {
             /** {@inheritDoc} */
             @Override
             public Circle parseHyperplane()
-                throws IOException, ParseException {
-                return new Circle(Vector3D.of(getNumber(), getNumber(), getNumber()), getNumber());
+                throws ParseException {
+                return new Circle(Vector3D.of(getNumber(), getNumber(), getNumber()), getPrecision());
             }
 
         };
-        return new SphericalPolygonsSet(builder.getTree(), builder.getTolerance());
+        return new SphericalPolygonsSet(builder.getTree(), builder.getPrecision());
     }
 
 }
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcTest.java
index aad3335..358eac3 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcTest.java
@@ -18,52 +18,59 @@ package org.apache.commons.geometry.spherical.oned;
 
 import org.apache.commons.geometry.core.Geometry;
 import org.apache.commons.geometry.core.partitioning.Region;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.numbers.core.Precision;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class ArcTest {
 
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
+
     @Test
     public void testArc() {
-        Arc arc = new Arc(2.3, 5.7, 1.0e-10);
-        Assert.assertEquals(3.4, arc.getSize(), 1.0e-10);
-        Assert.assertEquals(4.0, arc.getBarycenter(), 1.0e-10);
+        Arc arc = new Arc(2.3, 5.7, TEST_PRECISION);
+        Assert.assertEquals(3.4, arc.getSize(), TEST_EPS);
+        Assert.assertEquals(4.0, arc.getBarycenter(), TEST_EPS);
         Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(2.3));
         Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(5.7));
         Assert.assertEquals(Region.Location.OUTSIDE,  arc.checkPoint(1.2));
         Assert.assertEquals(Region.Location.OUTSIDE,  arc.checkPoint(8.5));
         Assert.assertEquals(Region.Location.INSIDE,   arc.checkPoint(8.7));
         Assert.assertEquals(Region.Location.INSIDE,   arc.checkPoint(3.0));
-        Assert.assertEquals(2.3, arc.getInf(), 1.0e-10);
-        Assert.assertEquals(5.7, arc.getSup(), 1.0e-10);
-        Assert.assertEquals(4.0, arc.getBarycenter(), 1.0e-10);
-        Assert.assertEquals(3.4, arc.getSize(), 1.0e-10);
+        Assert.assertEquals(2.3, arc.getInf(), TEST_EPS);
+        Assert.assertEquals(5.7, arc.getSup(), TEST_EPS);
+        Assert.assertEquals(4.0, arc.getBarycenter(), TEST_EPS);
+        Assert.assertEquals(3.4, arc.getSize(), TEST_EPS);
     }
 
     @Test(expected=IllegalArgumentException.class)
     public void testWrongInterval() {
-        new Arc(1.2, 0.0, 1.0e-10);
+        new Arc(1.2, 0.0, TEST_PRECISION);
     }
 
     @Test
     public void testTolerance() {
-        Assert.assertEquals(Region.Location.OUTSIDE,  new Arc(2.3, 5.7, 1.0).checkPoint(1.2));
-        Assert.assertEquals(Region.Location.BOUNDARY, new Arc(2.3, 5.7, 1.2).checkPoint(1.2));
-        Assert.assertEquals(Region.Location.OUTSIDE,  new Arc(2.3, 5.7, 0.7).checkPoint(6.5));
-        Assert.assertEquals(Region.Location.BOUNDARY, new Arc(2.3, 5.7, 0.9).checkPoint(6.5));
-        Assert.assertEquals(Region.Location.INSIDE,   new Arc(2.3, 5.7, 0.6).checkPoint(3.0));
-        Assert.assertEquals(Region.Location.BOUNDARY, new Arc(2.3, 5.7, 0.8).checkPoint(3.0));
+        Assert.assertEquals(Region.Location.OUTSIDE,  new Arc(2.3, 5.7, createPrecision(1.0)).checkPoint(1.2));
+        Assert.assertEquals(Region.Location.BOUNDARY, new Arc(2.3, 5.7, createPrecision(1.2)).checkPoint(1.2));
+        Assert.assertEquals(Region.Location.OUTSIDE,  new Arc(2.3, 5.7, createPrecision(0.7)).checkPoint(6.5));
+        Assert.assertEquals(Region.Location.BOUNDARY, new Arc(2.3, 5.7, createPrecision(0.9)).checkPoint(6.5));
+        Assert.assertEquals(Region.Location.INSIDE,   new Arc(2.3, 5.7, createPrecision(0.6)).checkPoint(3.0));
+        Assert.assertEquals(Region.Location.BOUNDARY, new Arc(2.3, 5.7, createPrecision(0.8)).checkPoint(3.0));
     }
 
     @Test
     public void testFullCircle() {
-        Arc arc = new Arc(9.0, 9.0, 1.0e-10);
+        Arc arc = new Arc(9.0, 9.0, TEST_PRECISION);
         // no boundaries on a full circle
         Assert.assertEquals(Region.Location.INSIDE, arc.checkPoint(9.0));
-        Assert.assertEquals(.0, arc.getInf(), 1.0e-10);
-        Assert.assertEquals(Geometry.TWO_PI, arc.getSup(), 1.0e-10);
-        Assert.assertEquals(2.0 * Math.PI, arc.getSize(), 1.0e-10);
+        Assert.assertEquals(.0, arc.getInf(), TEST_EPS);
+        Assert.assertEquals(Geometry.TWO_PI, arc.getSup(), TEST_EPS);
+        Assert.assertEquals(2.0 * Math.PI, arc.getSize(), TEST_EPS);
         for (double alpha = -20.0; alpha <= 20.0; alpha += 0.1) {
             Assert.assertEquals(Region.Location.INSIDE, arc.checkPoint(alpha));
         }
@@ -71,9 +78,16 @@ public class ArcTest {
 
     @Test
     public void testSmall() {
-        Arc arc = new Arc(1.0, Math.nextAfter(1.0, Double.POSITIVE_INFINITY), Precision.EPSILON);
+        Arc arc = new Arc(1.0, Math.nextAfter(1.0, Double.POSITIVE_INFINITY), createPrecision(Precision.EPSILON));
         Assert.assertEquals(2 * Precision.EPSILON, arc.getSize(), Precision.SAFE_MIN);
         Assert.assertEquals(1.0, arc.getBarycenter(), Precision.EPSILON);
     }
 
+    /** Create a {@link DoublePrecisionContext} with the given epsilon value.
+     * @param eps epsilon value
+     * @return new precision context
+     */
+    private static DoublePrecisionContext createPrecision(final double eps) {
+        return new EpsilonDoublePrecisionContext(eps);
+    }
 }
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcsSetTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcsSetTest.java
index 8d8c600..1171665 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcsSetTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/ArcsSetTest.java
@@ -28,17 +28,24 @@ import org.apache.commons.geometry.core.partitioning.Region.Location;
 import org.apache.commons.geometry.core.partitioning.RegionFactory;
 import org.apache.commons.geometry.core.partitioning.Side;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.numbers.core.Precision;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class ArcsSetTest {
 
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
+
     @Test
     public void testArc() {
-        ArcsSet set = new ArcsSet(2.3, 5.7, 1.0e-10);
-        Assert.assertEquals(3.4, set.getSize(), 1.0e-10);
-        Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
+        ArcsSet set = new ArcsSet(2.3, 5.7, TEST_PRECISION);
+        Assert.assertEquals(3.4, set.getSize(), TEST_EPS);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
         Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(2.3)));
         Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(5.7)));
         Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(S1Point.of(1.2)));
@@ -46,15 +53,15 @@ public class ArcsSetTest {
         Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(S1Point.of(8.7)));
         Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(S1Point.of(3.0)));
         Assert.assertEquals(1, set.asList().size());
-        Assert.assertEquals(2.3, set.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.7, set.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(2.3, set.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(5.7, set.asList().get(0).getSup(), TEST_EPS);
     }
 
     @Test
     public void testWrapAround2PiArc() {
-        ArcsSet set = new ArcsSet(5.7 - Geometry.TWO_PI, 2.3, 1.0e-10);
-        Assert.assertEquals(Geometry.TWO_PI - 3.4, set.getSize(), 1.0e-10);
-        Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
+        ArcsSet set = new ArcsSet(5.7 - Geometry.TWO_PI, 2.3, TEST_PRECISION);
+        Assert.assertEquals(Geometry.TWO_PI - 3.4, set.getSize(), TEST_EPS);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
         Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(2.3)));
         Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(S1Point.of(5.7)));
         Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(S1Point.of(1.2)));
@@ -62,14 +69,14 @@ public class ArcsSetTest {
         Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(S1Point.of(8.7)));
         Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(S1Point.of(3.0)));
         Assert.assertEquals(1, set.asList().size());
-        Assert.assertEquals(5.7, set.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(2.3 + Geometry.TWO_PI, set.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(5.7, set.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(2.3 + Geometry.TWO_PI, set.asList().get(0).getSup(), TEST_EPS);
     }
 
     @Test
     public void testSplitOver2Pi() {
-        ArcsSet set = new ArcsSet(1.0e-10);
-        Arc     arc = new Arc(1.5 * Math.PI, 2.5 * Math.PI, 1.0e-10);
+        ArcsSet set = new ArcsSet(TEST_PRECISION);
+        Arc     arc = new Arc(1.5 * Math.PI, 2.5 * Math.PI, TEST_PRECISION);
         ArcsSet.Split split = set.split(arc);
         for (double alpha = 0.0; alpha <= Geometry.TWO_PI; alpha += 0.01) {
             S1Point p = S1Point.of(alpha);
@@ -85,8 +92,8 @@ public class ArcsSetTest {
 
     @Test
     public void testSplitAtEnd() {
-        ArcsSet set = new ArcsSet(1.0e-10);
-        Arc     arc = new Arc(Math.PI, Geometry.TWO_PI, 1.0e-10);
+        ArcsSet set = new ArcsSet(TEST_PRECISION);
+        Arc     arc = new Arc(Math.PI, Geometry.TWO_PI, TEST_PRECISION);
         ArcsSet.Split split = set.split(arc);
         for (double alpha = 0.01; alpha < Geometry.TWO_PI; alpha += 0.01) {
             S1Point p = S1Point.of(alpha);
@@ -111,82 +118,82 @@ public class ArcsSetTest {
 
     @Test(expected=IllegalArgumentException.class)
     public void testWrongInterval() {
-        new ArcsSet(1.2, 0.0, 1.0e-10);
+        new ArcsSet(1.2, 0.0, TEST_PRECISION);
     }
 
     @Test
     public void testFullEqualEndPoints() {
-        ArcsSet set = new ArcsSet(1.0, 1.0, 1.0e-10);
-        Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
+        ArcsSet set = new ArcsSet(1.0, 1.0, TEST_PRECISION);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
         Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(9.0)));
         for (double alpha = -20.0; alpha <= 20.0; alpha += 0.1) {
             Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(alpha)));
         }
         Assert.assertEquals(1, set.asList().size());
-        Assert.assertEquals(0.0, set.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(2 * Math.PI, set.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(2 * Math.PI, set.getSize(), 1.0e-10);
+        Assert.assertEquals(0.0, set.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(2 * Math.PI, set.asList().get(0).getSup(), TEST_EPS);
+        Assert.assertEquals(2 * Math.PI, set.getSize(), TEST_EPS);
     }
 
     @Test
     public void testFullCircle() {
-        ArcsSet set = new ArcsSet(1.0e-10);
-        Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
+        ArcsSet set = new ArcsSet(TEST_PRECISION);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
         Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(9.0)));
         for (double alpha = -20.0; alpha <= 20.0; alpha += 0.1) {
             Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(S1Point.of(alpha)));
         }
         Assert.assertEquals(1, set.asList().size());
-        Assert.assertEquals(0.0, set.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(2 * Math.PI, set.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(2 * Math.PI, set.getSize(), 1.0e-10);
+        Assert.assertEquals(0.0, set.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(2 * Math.PI, set.asList().get(0).getSup(), TEST_EPS);
+        Assert.assertEquals(2 * Math.PI, set.getSize(), TEST_EPS);
     }
 
     @Test
     public void testEmpty() {
-        ArcsSet empty = (ArcsSet) new RegionFactory<S1Point>().getComplement(new ArcsSet(1.0e-10));
-        Assert.assertEquals(1.0e-10, empty.getTolerance(), 1.0e-20);
-        Assert.assertEquals(0.0, empty.getSize(), 1.0e-10);
+        ArcsSet empty = (ArcsSet) new RegionFactory<S1Point>().getComplement(new ArcsSet(TEST_PRECISION));
+        Assert.assertSame(TEST_PRECISION, empty.getPrecision());
+        Assert.assertEquals(0.0, empty.getSize(), TEST_EPS);
         Assert.assertTrue(empty.asList().isEmpty());
     }
 
     @Test
     public void testTiny() {
-        ArcsSet tiny = new ArcsSet(0.0, Precision.SAFE_MIN / 2, 1.0e-10);
-        Assert.assertEquals(1.0e-10, tiny.getTolerance(), 1.0e-20);
-        Assert.assertEquals(Precision.SAFE_MIN / 2, tiny.getSize(), 1.0e-10);
+        ArcsSet tiny = new ArcsSet(0.0, Precision.SAFE_MIN / 2, TEST_PRECISION);
+        Assert.assertSame(TEST_PRECISION, tiny.getPrecision());
+        Assert.assertEquals(Precision.SAFE_MIN / 2, tiny.getSize(), TEST_EPS);
         Assert.assertEquals(1, tiny.asList().size());
-        Assert.assertEquals(0.0, tiny.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(Precision.SAFE_MIN / 2, tiny.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(0.0, tiny.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(Precision.SAFE_MIN / 2, tiny.asList().get(0).getSup(), TEST_EPS);
     }
 
     @Test
     public void testSpecialConstruction() {
         List<SubHyperplane<S1Point>> boundary = new ArrayList<>();
-        boundary.add(new LimitAngle(S1Point.of(0.0), false, 1.0e-10).wholeHyperplane());
-        boundary.add(new LimitAngle(S1Point.of(Geometry.TWO_PI - 1.0e-11), true, 1.0e-10).wholeHyperplane());
-        ArcsSet set = new ArcsSet(boundary, 1.0e-10);
-        Assert.assertEquals(Geometry.TWO_PI, set.getSize(), 1.0e-10);
-        Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
+        boundary.add(new LimitAngle(S1Point.of(0.0), false, TEST_PRECISION).wholeHyperplane());
+        boundary.add(new LimitAngle(S1Point.of(Geometry.TWO_PI - 1.0e-11), true, TEST_PRECISION).wholeHyperplane());
+        ArcsSet set = new ArcsSet(boundary, TEST_PRECISION);
+        Assert.assertEquals(Geometry.TWO_PI, set.getSize(), TEST_EPS);
+        Assert.assertSame(TEST_PRECISION, set.getPrecision());
         Assert.assertEquals(1, set.asList().size());
-        Assert.assertEquals(0.0, set.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(Geometry.TWO_PI, set.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(0.0, set.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(Geometry.TWO_PI, set.asList().get(0).getSup(), TEST_EPS);
     }
 
     @Test
     public void testDifference() {
 
-        ArcsSet a   = new ArcsSet(1.0, 6.0, 1.0e-10);
+        ArcsSet a   = new ArcsSet(1.0, 6.0, TEST_PRECISION);
         List<Arc> aList = a.asList();
         Assert.assertEquals(1,   aList.size());
-        Assert.assertEquals(1.0, aList.get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, aList.get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(1.0, aList.get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(6.0, aList.get(0).getSup(), TEST_EPS);
 
-        ArcsSet b   = new ArcsSet(3.0, 5.0, 1.0e-10);
+        ArcsSet b   = new ArcsSet(3.0, 5.0, TEST_PRECISION);
         List<Arc> bList = b.asList();
         Assert.assertEquals(1,   bList.size());
-        Assert.assertEquals(3.0, bList.get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, bList.get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(3.0, bList.get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(5.0, bList.get(0).getSup(), TEST_EPS);
 
         ArcsSet aMb = (ArcsSet) new RegionFactory<S1Point>().difference(a, b);
         for (int k = -2; k < 3; ++k) {
@@ -208,10 +215,10 @@ public class ArcsSetTest {
 
         List<Arc> aMbList = aMb.asList();
         Assert.assertEquals(2,   aMbList.size());
-        Assert.assertEquals(1.0, aMbList.get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(3.0, aMbList.get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(5.0, aMbList.get(1).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, aMbList.get(1).getSup(), 1.0e-10);
+        Assert.assertEquals(1.0, aMbList.get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(3.0, aMbList.get(0).getSup(), TEST_EPS);
+        Assert.assertEquals(5.0, aMbList.get(1).getInf(), TEST_EPS);
+        Assert.assertEquals(6.0, aMbList.get(1).getSup(), TEST_EPS);
 
 
     }
@@ -219,20 +226,20 @@ public class ArcsSetTest {
     @Test
     public void testIntersection() {
 
-        ArcsSet a   = (ArcsSet) new RegionFactory<S1Point>().union(new ArcsSet(1.0, 3.0, 1.0e-10),
-                                                                    new ArcsSet(5.0, 6.0, 1.0e-10));
+        ArcsSet a   = (ArcsSet) new RegionFactory<S1Point>().union(new ArcsSet(1.0, 3.0, TEST_PRECISION),
+                                                                    new ArcsSet(5.0, 6.0, TEST_PRECISION));
         List<Arc> aList = a.asList();
         Assert.assertEquals(2,   aList.size());
-        Assert.assertEquals(1.0, aList.get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(3.0, aList.get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(5.0, aList.get(1).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, aList.get(1).getSup(), 1.0e-10);
+        Assert.assertEquals(1.0, aList.get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(3.0, aList.get(0).getSup(), TEST_EPS);
+        Assert.assertEquals(5.0, aList.get(1).getInf(), TEST_EPS);
+        Assert.assertEquals(6.0, aList.get(1).getSup(), TEST_EPS);
 
-        ArcsSet b   = new ArcsSet(0.0, 5.5, 1.0e-10);
+        ArcsSet b   = new ArcsSet(0.0, 5.5, TEST_PRECISION);
         List<Arc> bList = b.asList();
         Assert.assertEquals(1,   bList.size());
-        Assert.assertEquals(0.0, bList.get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.5, bList.get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(0.0, bList.get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(5.5, bList.get(0).getSup(), TEST_EPS);
 
         ArcsSet aMb = (ArcsSet) new RegionFactory<S1Point>().intersection(a, b);
         for (int k = -2; k < 3; ++k) {
@@ -253,10 +260,10 @@ public class ArcsSetTest {
 
         List<Arc> aMbList = aMb.asList();
         Assert.assertEquals(2,   aMbList.size());
-        Assert.assertEquals(1.0, aMbList.get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(3.0, aMbList.get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(5.0, aMbList.get(1).getInf(), 1.0e-10);
-        Assert.assertEquals(5.5, aMbList.get(1).getSup(), 1.0e-10);
+        Assert.assertEquals(1.0, aMbList.get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(3.0, aMbList.get(0).getSup(), TEST_EPS);
+        Assert.assertEquals(5.0, aMbList.get(1).getInf(), TEST_EPS);
+        Assert.assertEquals(5.5, aMbList.get(1).getSup(), TEST_EPS);
 
 
     }
@@ -265,11 +272,11 @@ public class ArcsSetTest {
     public void testMultiple() {
         RegionFactory<S1Point> factory = new RegionFactory<>();
         ArcsSet set = (ArcsSet)
-        factory.intersection(factory.union(factory.difference(new ArcsSet(1.0, 6.0, 1.0e-10),
-                                                              new ArcsSet(3.0, 5.0, 1.0e-10)),
-                                                              new ArcsSet(0.5, 2.0, 1.0e-10)),
-                                                              new ArcsSet(0.0, 5.5, 1.0e-10));
-        Assert.assertEquals(3.0, set.getSize(), 1.0e-10);
+        factory.intersection(factory.union(factory.difference(new ArcsSet(1.0, 6.0, TEST_PRECISION),
+                                                              new ArcsSet(3.0, 5.0, TEST_PRECISION)),
+                                                              new ArcsSet(0.5, 2.0, TEST_PRECISION)),
+                                                              new ArcsSet(0.0, 5.5, TEST_PRECISION));
+        Assert.assertEquals(3.0, set.getSize(), TEST_EPS);
         Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(S1Point.of(0.0)));
         Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(S1Point.of(4.0)));
         Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(S1Point.of(6.0)));
@@ -282,23 +289,23 @@ public class ArcsSetTest {
 
         List<Arc> list = set.asList();
         Assert.assertEquals(2, list.size());
-        Assert.assertEquals( 0.5, list.get(0).getInf(), 1.0e-10);
-        Assert.assertEquals( 3.0, list.get(0).getSup(), 1.0e-10);
-        Assert.assertEquals( 5.0, list.get(1).getInf(), 1.0e-10);
-        Assert.assertEquals( 5.5, list.get(1).getSup(), 1.0e-10);
+        Assert.assertEquals( 0.5, list.get(0).getInf(), TEST_EPS);
+        Assert.assertEquals( 3.0, list.get(0).getSup(), TEST_EPS);
+        Assert.assertEquals( 5.0, list.get(1).getInf(), TEST_EPS);
+        Assert.assertEquals( 5.5, list.get(1).getSup(), TEST_EPS);
 
     }
 
     @Test
     public void testSinglePoint() {
-        ArcsSet set = new ArcsSet(1.0, Math.nextAfter(1.0, Double.POSITIVE_INFINITY), 1.0e-10);
+        ArcsSet set = new ArcsSet(1.0, Math.nextAfter(1.0, Double.POSITIVE_INFINITY), TEST_PRECISION);
         Assert.assertEquals(2 * Precision.EPSILON, set.getSize(), Precision.SAFE_MIN);
     }
 
     @Test
     public void testIteration() {
-        ArcsSet set = (ArcsSet) new RegionFactory<S1Point>().difference(new ArcsSet(1.0, 6.0, 1.0e-10),
-                                                                         new ArcsSet(3.0, 5.0, 1.0e-10));
+        ArcsSet set = (ArcsSet) new RegionFactory<S1Point>().difference(new ArcsSet(1.0, 6.0, TEST_PRECISION),
+                                                                         new ArcsSet(3.0, 5.0, TEST_PRECISION));
         Iterator<double[]> iterator = set.iterator();
         try {
             iterator.remove();
@@ -310,14 +317,14 @@ public class ArcsSetTest {
         Assert.assertTrue(iterator.hasNext());
         double[] a0 = iterator.next();
         Assert.assertEquals(2, a0.length);
-        Assert.assertEquals(1.0, a0[0], 1.0e-10);
-        Assert.assertEquals(3.0, a0[1], 1.0e-10);
+        Assert.assertEquals(1.0, a0[0], TEST_EPS);
+        Assert.assertEquals(3.0, a0[1], TEST_EPS);
 
         Assert.assertTrue(iterator.hasNext());
         double[] a1 = iterator.next();
         Assert.assertEquals(2, a1.length);
-        Assert.assertEquals(5.0, a1[0], 1.0e-10);
-        Assert.assertEquals(6.0, a1[1], 1.0e-10);
+        Assert.assertEquals(5.0, a1[0], TEST_EPS);
+        Assert.assertEquals(6.0, a1[1], TEST_EPS);
 
         Assert.assertFalse(iterator.hasNext());
         try {
@@ -331,14 +338,14 @@ public class ArcsSetTest {
 
     @Test
     public void testEmptyTree() {
-        Assert.assertEquals(Geometry.TWO_PI, new ArcsSet(new BSPTree<S1Point>(Boolean.TRUE), 1.0e-10).getSize(), 1.0e-10);
+        Assert.assertEquals(Geometry.TWO_PI, new ArcsSet(new BSPTree<S1Point>(Boolean.TRUE), TEST_PRECISION).getSize(), TEST_EPS);
     }
 
     @Test
     public void testShiftedAngles() {
         for (int k = -2; k < 3; ++k) {
-            SubLimitAngle l1  = new LimitAngle(S1Point.of(1.0 + k * Geometry.TWO_PI), false, 1.0e-10).wholeHyperplane();
-            SubLimitAngle l2  = new LimitAngle(S1Point.of(1.5 + k * Geometry.TWO_PI), true,  1.0e-10).wholeHyperplane();
+            SubLimitAngle l1  = new LimitAngle(S1Point.of(1.0 + k * Geometry.TWO_PI), false, TEST_PRECISION).wholeHyperplane();
+            SubLimitAngle l2  = new LimitAngle(S1Point.of(1.5 + k * Geometry.TWO_PI), true,  TEST_PRECISION).wholeHyperplane();
             ArcsSet set = new ArcsSet(new BSPTree<>(l1,
                                                             new BSPTree<S1Point>(Boolean.FALSE),
                                                             new BSPTree<>(l2,
@@ -346,7 +353,7 @@ public class ArcsSetTest {
                                                                                   new BSPTree<S1Point>(Boolean.TRUE),
                                                                                   null),
                                                             null),
-                                      1.0e-10);
+                    TEST_PRECISION);
             for (double alpha = 1.0e-6; alpha < Geometry.TWO_PI; alpha += 0.001) {
                 if (alpha < 1 || alpha > 1.5) {
                     Assert.assertEquals(Location.OUTSIDE, set.checkPoint(S1Point.of(alpha)));
@@ -360,9 +367,9 @@ public class ArcsSetTest {
 
     @Test(expected=IllegalArgumentException.class)
     public void testInconsistentState() {
-        SubLimitAngle l1 = new LimitAngle(S1Point.of(1.0), false, 1.0e-10).wholeHyperplane();
-        SubLimitAngle l2 = new LimitAngle(S1Point.of(2.0), true,  1.0e-10).wholeHyperplane();
-        SubLimitAngle l3 = new LimitAngle(S1Point.of(3.0), false, 1.0e-10).wholeHyperplane();
+        SubLimitAngle l1 = new LimitAngle(S1Point.of(1.0), false, TEST_PRECISION).wholeHyperplane();
+        SubLimitAngle l2 = new LimitAngle(S1Point.of(2.0), true,  TEST_PRECISION).wholeHyperplane();
+        SubLimitAngle l3 = new LimitAngle(S1Point.of(3.0), false, TEST_PRECISION).wholeHyperplane();
         new ArcsSet(new BSPTree<>(l1,
                                           new BSPTree<S1Point>(Boolean.FALSE),
                                           new BSPTree<>(l2,
@@ -373,119 +380,119 @@ public class ArcsSetTest {
                                                                 new BSPTree<S1Point>(Boolean.TRUE),
                                                                 null),
                                           null),
-                                          1.0e-10);
+                TEST_PRECISION);
     }
 
     @Test
     public void testSide() {
-        ArcsSet set = (ArcsSet) new RegionFactory<S1Point>().difference(new ArcsSet(1.0, 6.0, 1.0e-10),
-                                                                         new ArcsSet(3.0, 5.0, 1.0e-10));
+        ArcsSet set = (ArcsSet) new RegionFactory<S1Point>().difference(new ArcsSet(1.0, 6.0, TEST_PRECISION),
+                                                                         new ArcsSet(3.0, 5.0, TEST_PRECISION));
         for (int k = -2; k < 3; ++k) {
             Assert.assertEquals(Side.MINUS, set.split(new Arc(0.5 + k * Geometry.TWO_PI,
                                                               6.1 + k * Geometry.TWO_PI,
-                                                              set.getTolerance())).getSide());
+                                                              set.getPrecision())).getSide());
             Assert.assertEquals(Side.PLUS,  set.split(new Arc(0.5 + k * Geometry.TWO_PI,
                                                               0.8 + k * Geometry.TWO_PI,
-                                                              set.getTolerance())).getSide());
+                                                              set.getPrecision())).getSide());
             Assert.assertEquals(Side.PLUS,  set.split(new Arc(6.2 + k * Geometry.TWO_PI,
                                                               6.3 + k * Geometry.TWO_PI,
-                                                              set.getTolerance())).getSide());
+                                                              set.getPrecision())).getSide());
             Assert.assertEquals(Side.PLUS,  set.split(new Arc(3.5 + k * Geometry.TWO_PI,
                                                               4.5 + k * Geometry.TWO_PI,
-                                                              set.getTolerance())).getSide());
+                                                              set.getPrecision())).getSide());
             Assert.assertEquals(Side.BOTH,  set.split(new Arc(2.9 + k * Geometry.TWO_PI,
                                                               4.5 + k * Geometry.TWO_PI,
-                                                              set.getTolerance())).getSide());
+                                                              set.getPrecision())).getSide());
             Assert.assertEquals(Side.BOTH,  set.split(new Arc(0.5 + k * Geometry.TWO_PI,
                                                               1.2 + k * Geometry.TWO_PI,
-                                                              set.getTolerance())).getSide());
+                                                              set.getPrecision())).getSide());
             Assert.assertEquals(Side.BOTH,  set.split(new Arc(0.5 + k * Geometry.TWO_PI,
                                                               5.9 + k * Geometry.TWO_PI,
-                                                              set.getTolerance())).getSide());
+                                                              set.getPrecision())).getSide());
         }
     }
 
     @Test
     public void testSideEmbedded() {
 
-        ArcsSet s35 = new ArcsSet(3.0, 5.0, 1.0e-10);
-        ArcsSet s16 = new ArcsSet(1.0, 6.0, 1.0e-10);
+        ArcsSet s35 = new ArcsSet(3.0, 5.0, TEST_PRECISION);
+        ArcsSet s16 = new ArcsSet(1.0, 6.0, TEST_PRECISION);
 
-        Assert.assertEquals(Side.BOTH,  s16.split(new Arc(3.0, 5.0, 1.0e-10)).getSide());
-        Assert.assertEquals(Side.BOTH,  s16.split(new Arc(5.0, 3.0 + Geometry.TWO_PI, 1.0e-10)).getSide());
-        Assert.assertEquals(Side.MINUS, s35.split(new Arc(1.0, 6.0, 1.0e-10)).getSide());
-        Assert.assertEquals(Side.PLUS,  s35.split(new Arc(6.0, 1.0 + Geometry.TWO_PI, 1.0e-10)).getSide());
+        Assert.assertEquals(Side.BOTH,  s16.split(new Arc(3.0, 5.0, TEST_PRECISION)).getSide());
+        Assert.assertEquals(Side.BOTH,  s16.split(new Arc(5.0, 3.0 + Geometry.TWO_PI, TEST_PRECISION)).getSide());
+        Assert.assertEquals(Side.MINUS, s35.split(new Arc(1.0, 6.0, TEST_PRECISION)).getSide());
+        Assert.assertEquals(Side.PLUS,  s35.split(new Arc(6.0, 1.0 + Geometry.TWO_PI, TEST_PRECISION)).getSide());
 
     }
 
     @Test
     public void testSideOverlapping() {
-        ArcsSet s35 = new ArcsSet(3.0, 5.0, 1.0e-10);
-        ArcsSet s46 = new ArcsSet(4.0, 6.0, 1.0e-10);
+        ArcsSet s35 = new ArcsSet(3.0, 5.0, TEST_PRECISION);
+        ArcsSet s46 = new ArcsSet(4.0, 6.0, TEST_PRECISION);
 
-        Assert.assertEquals(Side.BOTH,  s46.split(new Arc(3.0, 5.0, 1.0e-10)).getSide());
-        Assert.assertEquals(Side.BOTH,  s46.split(new Arc(5.0, 3.0 + Geometry.TWO_PI, 1.0e-10)).getSide());
-        Assert.assertEquals(Side.BOTH, s35.split(new Arc(4.0, 6.0, 1.0e-10)).getSide());
-        Assert.assertEquals(Side.BOTH,  s35.split(new Arc(6.0, 4.0 + Geometry.TWO_PI, 1.0e-10)).getSide());
+        Assert.assertEquals(Side.BOTH,  s46.split(new Arc(3.0, 5.0, TEST_PRECISION)).getSide());
+        Assert.assertEquals(Side.BOTH,  s46.split(new Arc(5.0, 3.0 + Geometry.TWO_PI, TEST_PRECISION)).getSide());
+        Assert.assertEquals(Side.BOTH, s35.split(new Arc(4.0, 6.0, TEST_PRECISION)).getSide());
+        Assert.assertEquals(Side.BOTH,  s35.split(new Arc(6.0, 4.0 + Geometry.TWO_PI, TEST_PRECISION)).getSide());
     }
 
     @Test
     public void testSideHyper() {
-        ArcsSet sub = (ArcsSet) new RegionFactory<S1Point>().getComplement(new ArcsSet(1.0e-10));
+        ArcsSet sub = (ArcsSet) new RegionFactory<S1Point>().getComplement(new ArcsSet(TEST_PRECISION));
         Assert.assertTrue(sub.isEmpty());
-        Assert.assertEquals(Side.HYPER,  sub.split(new Arc(2.0, 3.0, 1.0e-10)).getSide());
+        Assert.assertEquals(Side.HYPER,  sub.split(new Arc(2.0, 3.0, TEST_PRECISION)).getSide());
     }
 
     @Test
     public void testSplitEmbedded() {
 
-        ArcsSet s35 = new ArcsSet(3.0, 5.0, 1.0e-10);
-        ArcsSet s16 = new ArcsSet(1.0, 6.0, 1.0e-10);
+        ArcsSet s35 = new ArcsSet(3.0, 5.0, TEST_PRECISION);
+        ArcsSet s16 = new ArcsSet(1.0, 6.0, TEST_PRECISION);
 
-        ArcsSet.Split split1 = s16.split(new Arc(3.0, 5.0, 1.0e-10));
+        ArcsSet.Split split1 = s16.split(new Arc(3.0, 5.0, TEST_PRECISION));
         ArcsSet split1Plus  = split1.getPlus();
         ArcsSet split1Minus = split1.getMinus();
-        Assert.assertEquals(3.0, split1Plus.getSize(), 1.0e-10);
+        Assert.assertEquals(3.0, split1Plus.getSize(), TEST_EPS);
         Assert.assertEquals(2,   split1Plus.asList().size());
-        Assert.assertEquals(1.0, split1Plus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(3.0, split1Plus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(5.0, split1Plus.asList().get(1).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, split1Plus.asList().get(1).getSup(), 1.0e-10);
-        Assert.assertEquals(2.0, split1Minus.getSize(), 1.0e-10);
+        Assert.assertEquals(1.0, split1Plus.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(3.0, split1Plus.asList().get(0).getSup(), TEST_EPS);
+        Assert.assertEquals(5.0, split1Plus.asList().get(1).getInf(), TEST_EPS);
+        Assert.assertEquals(6.0, split1Plus.asList().get(1).getSup(), TEST_EPS);
+        Assert.assertEquals(2.0, split1Minus.getSize(), TEST_EPS);
         Assert.assertEquals(1,   split1Minus.asList().size());
-        Assert.assertEquals(3.0, split1Minus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, split1Minus.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(3.0, split1Minus.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(5.0, split1Minus.asList().get(0).getSup(), TEST_EPS);
 
-        ArcsSet.Split split2 = s16.split(new Arc(5.0, 3.0 + Geometry.TWO_PI, 1.0e-10));
+        ArcsSet.Split split2 = s16.split(new Arc(5.0, 3.0 + Geometry.TWO_PI, TEST_PRECISION));
         ArcsSet split2Plus  = split2.getPlus();
         ArcsSet split2Minus = split2.getMinus();
-        Assert.assertEquals(2.0, split2Plus.getSize(), 1.0e-10);
+        Assert.assertEquals(2.0, split2Plus.getSize(), TEST_EPS);
         Assert.assertEquals(1,   split2Plus.asList().size());
-        Assert.assertEquals(3.0, split2Plus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, split2Plus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(3.0, split2Minus.getSize(), 1.0e-10);
+        Assert.assertEquals(3.0, split2Plus.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(5.0, split2Plus.asList().get(0).getSup(), TEST_EPS);
+        Assert.assertEquals(3.0, split2Minus.getSize(), TEST_EPS);
         Assert.assertEquals(2,   split2Minus.asList().size());
-        Assert.assertEquals(1.0, split2Minus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(3.0, split2Minus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(5.0, split2Minus.asList().get(1).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, split2Minus.asList().get(1).getSup(), 1.0e-10);
+        Assert.assertEquals(1.0, split2Minus.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(3.0, split2Minus.asList().get(0).getSup(), TEST_EPS);
+        Assert.assertEquals(5.0, split2Minus.asList().get(1).getInf(), TEST_EPS);
+        Assert.assertEquals(6.0, split2Minus.asList().get(1).getSup(), TEST_EPS);
 
-        ArcsSet.Split split3 = s35.split(new Arc(1.0, 6.0, 1.0e-10));
+        ArcsSet.Split split3 = s35.split(new Arc(1.0, 6.0, TEST_PRECISION));
         ArcsSet split3Plus  = split3.getPlus();
         ArcsSet split3Minus = split3.getMinus();
         Assert.assertNull(split3Plus);
-        Assert.assertEquals(2.0, split3Minus.getSize(), 1.0e-10);
+        Assert.assertEquals(2.0, split3Minus.getSize(), TEST_EPS);
         Assert.assertEquals(1,   split3Minus.asList().size());
-        Assert.assertEquals(3.0, split3Minus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, split3Minus.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(3.0, split3Minus.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(5.0, split3Minus.asList().get(0).getSup(), TEST_EPS);
 
-        ArcsSet.Split split4 = s35.split(new Arc(6.0, 1.0 + Geometry.TWO_PI, 1.0e-10));
+        ArcsSet.Split split4 = s35.split(new Arc(6.0, 1.0 + Geometry.TWO_PI, TEST_PRECISION));
         ArcsSet split4Plus  = split4.getPlus();
         ArcsSet split4Minus = split4.getMinus();
-        Assert.assertEquals(2.0, split4Plus.getSize(), 1.0e-10);
+        Assert.assertEquals(2.0, split4Plus.getSize(), TEST_EPS);
         Assert.assertEquals(1,   split4Plus.asList().size());
-        Assert.assertEquals(3.0, split4Plus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, split4Plus.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(3.0, split4Plus.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(5.0, split4Plus.asList().get(0).getSup(), TEST_EPS);
         Assert.assertNull(split4Minus);
 
     }
@@ -493,83 +500,84 @@ public class ArcsSetTest {
     @Test
     public void testSplitOverlapping() {
 
-        ArcsSet s35 = new ArcsSet(3.0, 5.0, 1.0e-10);
-        ArcsSet s46 = new ArcsSet(4.0, 6.0, 1.0e-10);
+        ArcsSet s35 = new ArcsSet(3.0, 5.0, TEST_PRECISION);
+        ArcsSet s46 = new ArcsSet(4.0, 6.0, TEST_PRECISION);
 
-        ArcsSet.Split split1 = s46.split(new Arc(3.0, 5.0, 1.0e-10));
+        ArcsSet.Split split1 = s46.split(new Arc(3.0, 5.0, TEST_PRECISION));
         ArcsSet split1Plus  = split1.getPlus();
         ArcsSet split1Minus = split1.getMinus();
-        Assert.assertEquals(1.0, split1Plus.getSize(), 1.0e-10);
+        Assert.assertEquals(1.0, split1Plus.getSize(), TEST_EPS);
         Assert.assertEquals(1,   split1Plus.asList().size());
-        Assert.assertEquals(5.0, split1Plus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, split1Plus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(1.0, split1Minus.getSize(), 1.0e-10);
+        Assert.assertEquals(5.0, split1Plus.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(6.0, split1Plus.asList().get(0).getSup(), TEST_EPS);
+        Assert.assertEquals(1.0, split1Minus.getSize(), TEST_EPS);
         Assert.assertEquals(1,   split1Minus.asList().size());
-        Assert.assertEquals(4.0, split1Minus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, split1Minus.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(4.0, split1Minus.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(5.0, split1Minus.asList().get(0).getSup(), TEST_EPS);
 
-        ArcsSet.Split split2 = s46.split(new Arc(5.0, 3.0 + Geometry.TWO_PI, 1.0e-10));
+        ArcsSet.Split split2 = s46.split(new Arc(5.0, 3.0 + Geometry.TWO_PI, TEST_PRECISION));
         ArcsSet split2Plus  = split2.getPlus();
         ArcsSet split2Minus = split2.getMinus();
-        Assert.assertEquals(1.0, split2Plus.getSize(), 1.0e-10);
+        Assert.assertEquals(1.0, split2Plus.getSize(), TEST_EPS);
         Assert.assertEquals(1,   split2Plus.asList().size());
-        Assert.assertEquals(4.0, split2Plus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, split2Plus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(1.0, split2Minus.getSize(), 1.0e-10);
+        Assert.assertEquals(4.0, split2Plus.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(5.0, split2Plus.asList().get(0).getSup(), TEST_EPS);
+        Assert.assertEquals(1.0, split2Minus.getSize(), TEST_EPS);
         Assert.assertEquals(1,   split2Minus.asList().size());
-        Assert.assertEquals(5.0, split2Minus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, split2Minus.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(5.0, split2Minus.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(6.0, split2Minus.asList().get(0).getSup(), TEST_EPS);
 
-        ArcsSet.Split split3 = s35.split(new Arc(4.0, 6.0, 1.0e-10));
+        ArcsSet.Split split3 = s35.split(new Arc(4.0, 6.0, TEST_PRECISION));
         ArcsSet split3Plus  = split3.getPlus();
         ArcsSet split3Minus = split3.getMinus();
-        Assert.assertEquals(1.0, split3Plus.getSize(), 1.0e-10);
+        Assert.assertEquals(1.0, split3Plus.getSize(), TEST_EPS);
         Assert.assertEquals(1,   split3Plus.asList().size());
-        Assert.assertEquals(3.0, split3Plus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(4.0, split3Plus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(1.0, split3Minus.getSize(), 1.0e-10);
+        Assert.assertEquals(3.0, split3Plus.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(4.0, split3Plus.asList().get(0).getSup(), TEST_EPS);
+        Assert.assertEquals(1.0, split3Minus.getSize(), TEST_EPS);
         Assert.assertEquals(1,   split3Minus.asList().size());
-        Assert.assertEquals(4.0, split3Minus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, split3Minus.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(4.0, split3Minus.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(5.0, split3Minus.asList().get(0).getSup(), TEST_EPS);
 
-        ArcsSet.Split split4 = s35.split(new Arc(6.0, 4.0 + Geometry.TWO_PI, 1.0e-10));
+        ArcsSet.Split split4 = s35.split(new Arc(6.0, 4.0 + Geometry.TWO_PI, TEST_PRECISION));
         ArcsSet split4Plus  = split4.getPlus();
         ArcsSet split4Minus = split4.getMinus();
-        Assert.assertEquals(1.0, split4Plus.getSize(), 1.0e-10);
+        Assert.assertEquals(1.0, split4Plus.getSize(), TEST_EPS);
         Assert.assertEquals(1,   split4Plus.asList().size());
-        Assert.assertEquals(4.0, split4Plus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(5.0, split4Plus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(1.0, split4Minus.getSize(), 1.0e-10);
+        Assert.assertEquals(4.0, split4Plus.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(5.0, split4Plus.asList().get(0).getSup(), TEST_EPS);
+        Assert.assertEquals(1.0, split4Minus.getSize(), TEST_EPS);
         Assert.assertEquals(1,   split4Minus.asList().size());
-        Assert.assertEquals(3.0, split4Minus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(4.0, split4Minus.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(3.0, split4Minus.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(4.0, split4Minus.asList().get(0).getSup(), TEST_EPS);
 
     }
 
     @Test
     public void testFarSplit() {
-        ArcsSet set = new ArcsSet(Math.PI, 2.5 * Math.PI, 1.0e-10);
-        ArcsSet.Split split = set.split(new Arc(0.5 * Math.PI, 1.5 * Math.PI, 1.0e-10));
+        ArcsSet set = new ArcsSet(Math.PI, 2.5 * Math.PI, TEST_PRECISION);
+        ArcsSet.Split split = set.split(new Arc(0.5 * Math.PI, 1.5 * Math.PI, TEST_PRECISION));
         ArcsSet splitPlus  = split.getPlus();
         ArcsSet splitMinus = split.getMinus();
         Assert.assertEquals(1,   splitMinus.asList().size());
-        Assert.assertEquals(1.0 * Math.PI, splitMinus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(1.5 * Math.PI, splitMinus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(0.5 * Math.PI, splitMinus.getSize(), 1.0e-10);
+        Assert.assertEquals(1.0 * Math.PI, splitMinus.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(1.5 * Math.PI, splitMinus.asList().get(0).getSup(), TEST_EPS);
+        Assert.assertEquals(0.5 * Math.PI, splitMinus.getSize(), TEST_EPS);
         Assert.assertEquals(1,   splitPlus.asList().size());
-        Assert.assertEquals(1.5 * Math.PI, splitPlus.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(2.5 * Math.PI, splitPlus.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(1.0 * Math.PI, splitPlus.getSize(), 1.0e-10);
+        Assert.assertEquals(1.5 * Math.PI, splitPlus.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(2.5 * Math.PI, splitPlus.asList().get(0).getSup(), TEST_EPS);
+        Assert.assertEquals(1.0 * Math.PI, splitPlus.getSize(), TEST_EPS);
 
     }
 
     @Test
     public void testSplitWithinEpsilon() {
-        double epsilon = 1.0e-10;
+        double epsilon = TEST_EPS;
+        DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(epsilon);
         double a = 6.25;
         double b = a - 0.5 * epsilon;
-        ArcsSet set = new ArcsSet(a - 1, a, epsilon);
-        Arc arc = new Arc(b, b + Math.PI, epsilon);
+        ArcsSet set = new ArcsSet(a - 1, a, precision);
+        Arc arc = new Arc(b, b + Math.PI, precision);
         ArcsSet.Split split = set.split(arc);
         Assert.assertEquals(set.getSize(), split.getPlus().getSize(),  epsilon);
         Assert.assertNull(split.getMinus());
@@ -578,9 +586,10 @@ public class ArcsSetTest {
     @Test
     public void testSideSplitConsistency() {
         double  epsilon = 1.0e-6;
+        DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(epsilon);
         double  a       = 4.725;
-        ArcsSet set     = new ArcsSet(a, a + 0.5, epsilon);
-        Arc     arc     = new Arc(a + 0.5 * epsilon, a + 1, epsilon);
+        ArcsSet set     = new ArcsSet(a, a + 0.5, precision);
+        Arc     arc     = new Arc(a + 0.5 * epsilon, a + 1, precision);
         ArcsSet.Split split = set.split(arc);
         Assert.assertNotNull(split.getMinus());
         Assert.assertNull(split.getPlus());
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/LimitAngleTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/LimitAngleTest.java
index 629f2b6..eb29564 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/LimitAngleTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/oned/LimitAngleTest.java
@@ -17,21 +17,28 @@
 package org.apache.commons.geometry.spherical.oned;
 
 import org.apache.commons.geometry.core.Geometry;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class LimitAngleTest {
 
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
+
     @Test
     public void testReversedLimit() {
         for (int k = -2; k < 3; ++k) {
-            LimitAngle l  = new LimitAngle(S1Point.of(1.0 + k * Geometry.TWO_PI), false, 1.0e-10);
-            Assert.assertEquals(l.getLocation().getAzimuth(), l.getReverse().getLocation().getAzimuth(), 1.0e-10);
-            Assert.assertEquals(l.getTolerance(), l.getReverse().getTolerance(), 1.0e-10);
+            LimitAngle l  = new LimitAngle(S1Point.of(1.0 + k * Geometry.TWO_PI), false, TEST_PRECISION);
+            Assert.assertEquals(l.getLocation().getAzimuth(), l.getReverse().getLocation().getAzimuth(), TEST_EPS);
+            Assert.assertSame(l.getPrecision(), l.getReverse().getPrecision());
             Assert.assertTrue(l.sameOrientationAs(l));
             Assert.assertFalse(l.sameOrientationAs(l.getReverse()));
-            Assert.assertEquals(Geometry.TWO_PI, l.wholeSpace().getSize(), 1.0e-10);
-            Assert.assertEquals(Geometry.TWO_PI, l.getReverse().wholeSpace().getSize(), 1.0e-10);
+            Assert.assertEquals(Geometry.TWO_PI, l.wholeSpace().getSize(), TEST_EPS);
+            Assert.assertEquals(Geometry.TWO_PI, l.getReverse().wholeSpace().getSize(), TEST_EPS);
         }
     }
 
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/CircleTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/CircleTest.java
index de3de2b..186692b 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/CircleTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/CircleTest.java
@@ -18,6 +18,8 @@ package org.apache.commons.geometry.spherical.twod;
 
 import org.apache.commons.geometry.core.Geometry;
 import org.apache.commons.geometry.core.partitioning.Transform;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.threed.Vector3D;
 import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
 import org.apache.commons.geometry.spherical.oned.Arc;
@@ -33,11 +35,16 @@ import org.junit.Test;
 
 public class CircleTest {
 
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
+
     @Test
     public void testEquator() {
-        Circle circle = new Circle(Vector3D.of(0, 0, 1000), 1.0e-10).copySelf();
+        Circle circle = new Circle(Vector3D.of(0, 0, 1000), TEST_PRECISION).copySelf();
         Assert.assertEquals(Vector3D.PLUS_Z, circle.getPole());
-        Assert.assertEquals(1.0e-10, circle.getTolerance(), 1.0e-20);
+        Assert.assertEquals(TEST_PRECISION, circle.getPrecision());
         circle.revertSelf();
         Assert.assertEquals(Vector3D.MINUS_Z, circle.getPole());
         Assert.assertEquals(Vector3D.PLUS_Z, circle.getReverse().getPole());
@@ -46,33 +53,33 @@ public class CircleTest {
 
     @Test
     public void testXY() {
-        Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), 1.0e-10);
-        Assert.assertEquals(0.0, circle.getPointAt(0).distance(circle.getXAxis()), 1.0e-10);
-        Assert.assertEquals(0.0, circle.getPointAt(0.5 * Math.PI).distance(circle.getYAxis()), 1.0e-10);
-        Assert.assertEquals(0.5 * Math.PI, circle.getXAxis().angle(circle.getYAxis()), 1.0e-10);
-        Assert.assertEquals(0.5 * Math.PI, circle.getXAxis().angle(circle.getPole()), 1.0e-10);
-        Assert.assertEquals(0.5 * Math.PI, circle.getPole().angle(circle.getYAxis()), 1.0e-10);
+        Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), TEST_PRECISION);
+        Assert.assertEquals(0.0, circle.getPointAt(0).distance(circle.getXAxis()), TEST_EPS);
+        Assert.assertEquals(0.0, circle.getPointAt(0.5 * Math.PI).distance(circle.getYAxis()), TEST_EPS);
+        Assert.assertEquals(0.5 * Math.PI, circle.getXAxis().angle(circle.getYAxis()), TEST_EPS);
+        Assert.assertEquals(0.5 * Math.PI, circle.getXAxis().angle(circle.getPole()), TEST_EPS);
+        Assert.assertEquals(0.5 * Math.PI, circle.getPole().angle(circle.getYAxis()), TEST_EPS);
         Assert.assertEquals(0.0,
                             circle.getPole().distance(circle.getXAxis().cross(circle.getYAxis())),
-                            1.0e-10);
+                            TEST_EPS);
     }
 
     @Test
     public void testReverse() {
-        Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), 1.0e-10);
+        Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), TEST_PRECISION);
         Circle reversed = circle.getReverse();
-        Assert.assertEquals(0.0, reversed.getPointAt(0).distance(reversed.getXAxis()), 1.0e-10);
-        Assert.assertEquals(0.0, reversed.getPointAt(0.5 * Math.PI).distance(reversed.getYAxis()), 1.0e-10);
-        Assert.assertEquals(0.5 * Math.PI, reversed.getXAxis().angle(reversed.getYAxis()), 1.0e-10);
-        Assert.assertEquals(0.5 * Math.PI, reversed.getXAxis().angle(reversed.getPole()), 1.0e-10);
-        Assert.assertEquals(0.5 * Math.PI, reversed.getPole().angle(reversed.getYAxis()), 1.0e-10);
+        Assert.assertEquals(0.0, reversed.getPointAt(0).distance(reversed.getXAxis()), TEST_EPS);
+        Assert.assertEquals(0.0, reversed.getPointAt(0.5 * Math.PI).distance(reversed.getYAxis()), TEST_EPS);
+        Assert.assertEquals(0.5 * Math.PI, reversed.getXAxis().angle(reversed.getYAxis()), TEST_EPS);
+        Assert.assertEquals(0.5 * Math.PI, reversed.getXAxis().angle(reversed.getPole()), TEST_EPS);
+        Assert.assertEquals(0.5 * Math.PI, reversed.getPole().angle(reversed.getYAxis()), TEST_EPS);
         Assert.assertEquals(0.0,
                             reversed.getPole().distance(reversed.getXAxis().cross(reversed.getYAxis())),
-                            1.0e-10);
+                            TEST_EPS);
 
-        Assert.assertEquals(0, circle.getXAxis().angle(reversed.getXAxis()), 1.0e-10);
-        Assert.assertEquals(Math.PI, circle.getYAxis().angle(reversed.getYAxis()), 1.0e-10);
-        Assert.assertEquals(Math.PI, circle.getPole().angle(reversed.getPole()), 1.0e-10);
+        Assert.assertEquals(0, circle.getXAxis().angle(reversed.getXAxis()), TEST_EPS);
+        Assert.assertEquals(Math.PI, circle.getYAxis().angle(reversed.getYAxis()), TEST_EPS);
+        Assert.assertEquals(Math.PI, circle.getPole().angle(reversed.getPole()), TEST_EPS);
 
         Assert.assertTrue(circle.sameOrientationAs(circle));
         Assert.assertFalse(circle.sameOrientationAs(reversed));
@@ -80,49 +87,49 @@ public class CircleTest {
 
     @Test
     public void testPhase() {
-        Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), 1.0e-10);
+        Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), TEST_PRECISION);
         Vector3D p = Vector3D.of(1, 2, -4);
         Vector3D samePhase = circle.getPointAt(circle.getPhase(p));
         Assert.assertEquals(0.0,
                             circle.getPole().cross(p).angle(
                                            circle.getPole().cross(samePhase)),
-                            1.0e-10);
-        Assert.assertEquals(0.5 * Math.PI, circle.getPole().angle(samePhase), 1.0e-10);
-        Assert.assertEquals(circle.getPhase(p), circle.getPhase(samePhase), 1.0e-10);
-        Assert.assertEquals(0.0, circle.getPhase(circle.getXAxis()), 1.0e-10);
-        Assert.assertEquals(0.5 * Math.PI, circle.getPhase(circle.getYAxis()), 1.0e-10);
+                            TEST_EPS);
+        Assert.assertEquals(0.5 * Math.PI, circle.getPole().angle(samePhase), TEST_EPS);
+        Assert.assertEquals(circle.getPhase(p), circle.getPhase(samePhase), TEST_EPS);
+        Assert.assertEquals(0.0, circle.getPhase(circle.getXAxis()), TEST_EPS);
+        Assert.assertEquals(0.5 * Math.PI, circle.getPhase(circle.getYAxis()), TEST_EPS);
     }
 
     @Test
     public void testSubSpace() {
-        Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), 1.0e-10);
-        Assert.assertEquals(0.0, circle.toSubSpace(S2Point.ofVector(circle.getXAxis())).getAzimuth(), 1.0e-10);
-        Assert.assertEquals(0.5 * Math.PI, circle.toSubSpace(S2Point.ofVector(circle.getYAxis())).getAzimuth(), 1.0e-10);
+        Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), TEST_PRECISION);
+        Assert.assertEquals(0.0, circle.toSubSpace(S2Point.ofVector(circle.getXAxis())).getAzimuth(), TEST_EPS);
+        Assert.assertEquals(0.5 * Math.PI, circle.toSubSpace(S2Point.ofVector(circle.getYAxis())).getAzimuth(), TEST_EPS);
         Vector3D p = Vector3D.of(1, 2, -4);
-        Assert.assertEquals(circle.getPhase(p), circle.toSubSpace(S2Point.ofVector(p)).getAzimuth(), 1.0e-10);
+        Assert.assertEquals(circle.getPhase(p), circle.toSubSpace(S2Point.ofVector(p)).getAzimuth(), TEST_EPS);
     }
 
     @Test
     public void testSpace() {
-        Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), 1.0e-10);
+        Circle circle = new Circle(S2Point.of(1.2, 2.5), S2Point.of(-4.3, 0), TEST_PRECISION);
         for (double alpha = 0; alpha < Geometry.TWO_PI; alpha += 0.1) {
             Vector3D p = Vector3D.linearCombination(Math.cos(alpha), circle.getXAxis(),
                                       Math.sin(alpha), circle.getYAxis());
             Vector3D q = circle.toSpace(S1Point.of(alpha)).getVector();
-            Assert.assertEquals(0.0, p.distance(q), 1.0e-10);
-            Assert.assertEquals(0.5 * Math.PI, circle.getPole().angle(q), 1.0e-10);
+            Assert.assertEquals(0.0, p.distance(q), TEST_EPS);
+            Assert.assertEquals(0.5 * Math.PI, circle.getPole().angle(q), TEST_EPS);
         }
     }
 
     @Test
     public void testOffset() {
-        Circle circle = new Circle(Vector3D.PLUS_Z, 1.0e-10);
-        Assert.assertEquals(0.0,                circle.getOffset(S2Point.ofVector(Vector3D.PLUS_X)),  1.0e-10);
-        Assert.assertEquals(0.0,                circle.getOffset(S2Point.ofVector(Vector3D.MINUS_X)), 1.0e-10);
-        Assert.assertEquals(0.0,                circle.getOffset(S2Point.ofVector(Vector3D.PLUS_Y)),  1.0e-10);
-        Assert.assertEquals(0.0,                circle.getOffset(S2Point.ofVector(Vector3D.MINUS_Y)), 1.0e-10);
-        Assert.assertEquals(-0.5 * Math.PI, circle.getOffset(S2Point.ofVector(Vector3D.PLUS_Z)),  1.0e-10);
-        Assert.assertEquals(0.5 * Math.PI, circle.getOffset(S2Point.ofVector(Vector3D.MINUS_Z)), 1.0e-10);
+        Circle circle = new Circle(Vector3D.PLUS_Z, TEST_PRECISION);
+        Assert.assertEquals(0.0,                circle.getOffset(S2Point.ofVector(Vector3D.PLUS_X)),  TEST_EPS);
+        Assert.assertEquals(0.0,                circle.getOffset(S2Point.ofVector(Vector3D.MINUS_X)), TEST_EPS);
+        Assert.assertEquals(0.0,                circle.getOffset(S2Point.ofVector(Vector3D.PLUS_Y)),  TEST_EPS);
+        Assert.assertEquals(0.0,                circle.getOffset(S2Point.ofVector(Vector3D.MINUS_Y)), TEST_EPS);
+        Assert.assertEquals(-0.5 * Math.PI, circle.getOffset(S2Point.ofVector(Vector3D.PLUS_Z)),  TEST_EPS);
+        Assert.assertEquals(0.5 * Math.PI, circle.getOffset(S2Point.ofVector(Vector3D.MINUS_Z)), TEST_EPS);
 
     }
 
@@ -131,8 +138,8 @@ public class CircleTest {
         UnitSphereSampler sphRandom = new UnitSphereSampler(3, RandomSource.create(RandomSource.WELL_1024_A,
                                                                                    0xbfd34e92231bbcfel));
         for (int i = 0; i < 100; ++i) {
-            Circle c1 = new Circle(Vector3D.of(sphRandom.nextVector()), 1.0e-10);
-            Circle c2 = new Circle(Vector3D.of(sphRandom.nextVector()), 1.0e-10);
+            Circle c1 = new Circle(Vector3D.of(sphRandom.nextVector()), TEST_PRECISION);
+            Circle c2 = new Circle(Vector3D.of(sphRandom.nextVector()), TEST_PRECISION);
             checkArcIsInside(c1, c2);
             checkArcIsInside(c2, c1);
         }
@@ -140,7 +147,7 @@ public class CircleTest {
 
     private void checkArcIsInside(final Circle arcCircle, final Circle otherCircle) {
         Arc arc = arcCircle.getInsideArc(otherCircle);
-        Assert.assertEquals(Math.PI, arc.getSize(), 1.0e-10);
+        Assert.assertEquals(Math.PI, arc.getSize(), TEST_EPS);
         for (double alpha = arc.getInf(); alpha < arc.getSup(); alpha += 0.1) {
             Assert.assertTrue(otherCircle.getOffset(arcCircle.getPointAt(alpha)) <= 2.0e-15);
         }
@@ -162,21 +169,21 @@ public class CircleTest {
 
             S2Point  p = S2Point.ofVector(Vector3D.of(sphRandom.nextVector()));
             S2Point tp = t.apply(p);
-            Assert.assertEquals(0.0, r.apply(p.getVector()).distance(tp.getVector()), 1.0e-10);
+            Assert.assertEquals(0.0, r.apply(p.getVector()).distance(tp.getVector()), TEST_EPS);
 
-            Circle  c = new Circle(Vector3D.of(sphRandom.nextVector()), 1.0e-10);
+            Circle  c = new Circle(Vector3D.of(sphRandom.nextVector()), TEST_PRECISION);
             Circle tc = (Circle) t.apply(c);
-            Assert.assertEquals(0.0, r.apply(c.getPole()).distance(tc.getPole()),   1.0e-10);
-            Assert.assertEquals(0.0, r.apply(c.getXAxis()).distance(tc.getXAxis()), 1.0e-10);
-            Assert.assertEquals(0.0, r.apply(c.getYAxis()).distance(tc.getYAxis()), 1.0e-10);
-            Assert.assertEquals(c.getTolerance(), ((Circle) t.apply(c)).getTolerance(), 1.0e-10);
+            Assert.assertEquals(0.0, r.apply(c.getPole()).distance(tc.getPole()),   TEST_EPS);
+            Assert.assertEquals(0.0, r.apply(c.getXAxis()).distance(tc.getXAxis()), TEST_EPS);
+            Assert.assertEquals(0.0, r.apply(c.getYAxis()).distance(tc.getYAxis()), TEST_EPS);
+            Assert.assertSame(c.getPrecision(), ((Circle) t.apply(c)).getPrecision());
 
             SubLimitAngle  sub = new LimitAngle(S1Point.of(Geometry.TWO_PI * random.nextDouble()),
-                                                random.nextBoolean(), 1.0e-10).wholeHyperplane();
+                                                random.nextBoolean(), TEST_PRECISION).wholeHyperplane();
             Vector3D psub = c.getPointAt(((LimitAngle) sub.getHyperplane()).getLocation().getAzimuth());
             SubLimitAngle tsub = (SubLimitAngle) t.apply(sub, c, tc);
             Vector3D ptsub = tc.getPointAt(((LimitAngle) tsub.getHyperplane()).getLocation().getAzimuth());
-            Assert.assertEquals(0.0, r.apply(psub).distance(ptsub), 1.0e-10);
+            Assert.assertEquals(0.0, r.apply(psub).distance(ptsub), TEST_EPS);
 
         }
     }
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSetTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSetTest.java
index 21cd3b0..dcd72e6 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSetTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SphericalPolygonsSetTest.java
@@ -23,6 +23,8 @@ import org.apache.commons.geometry.core.Geometry;
 import org.apache.commons.geometry.core.partitioning.Region.Location;
 import org.apache.commons.geometry.core.partitioning.RegionFactory;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.enclosing.EnclosingBall;
 import org.apache.commons.geometry.euclidean.threed.Vector3D;
 import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
@@ -35,9 +37,14 @@ import org.junit.Test;
 
 public class SphericalPolygonsSetTest {
 
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
+
     @Test
     public void testFullSphere() {
-        SphericalPolygonsSet full = new SphericalPolygonsSet(1.0e-10);
+        SphericalPolygonsSet full = new SphericalPolygonsSet(TEST_PRECISION);
         UnitSphereSampler random =
                 new UnitSphereSampler(3, RandomSource.create(RandomSource.WELL_1024_A,
                                                              0x852fd2a0ed8d2f6dl));
@@ -45,8 +52,8 @@ public class SphericalPolygonsSetTest {
             Vector3D v = Vector3D.of(random.nextVector());
             Assert.assertEquals(Location.INSIDE, full.checkPoint(S2Point.ofVector(v)));
         }
-        Assert.assertEquals(4 * Math.PI, new SphericalPolygonsSet(0.01, new S2Point[0]).getSize(), 1.0e-10);
-        Assert.assertEquals(0, new SphericalPolygonsSet(0.01, new S2Point[0]).getBoundarySize(), 1.0e-10);
+        Assert.assertEquals(4 * Math.PI, new SphericalPolygonsSet(createPrecision(0.01), new S2Point[0]).getSize(), TEST_EPS);
+        Assert.assertEquals(0, new SphericalPolygonsSet(createPrecision(0.01), new S2Point[0]).getBoundarySize(), TEST_EPS);
         Assert.assertEquals(0, full.getBoundaryLoops().size());
         Assert.assertTrue(full.getEnclosingCap().getRadius() > 0);
         Assert.assertTrue(Double.isInfinite(full.getEnclosingCap().getRadius()));
@@ -55,7 +62,7 @@ public class SphericalPolygonsSetTest {
     @Test
     public void testEmpty() {
         SphericalPolygonsSet empty =
-            (SphericalPolygonsSet) new RegionFactory<S2Point>().getComplement(new SphericalPolygonsSet(1.0e-10));
+            (SphericalPolygonsSet) new RegionFactory<S2Point>().getComplement(new SphericalPolygonsSet(TEST_PRECISION));
         UnitSphereSampler random =
                 new UnitSphereSampler(3, RandomSource.create(RandomSource.WELL_1024_A,
                                                              0x76d9205d6167b6ddl));
@@ -63,8 +70,8 @@ public class SphericalPolygonsSetTest {
             Vector3D v = Vector3D.of(random.nextVector());
             Assert.assertEquals(Location.OUTSIDE, empty.checkPoint(S2Point.ofVector(v)));
         }
-        Assert.assertEquals(0, empty.getSize(), 1.0e-10);
-        Assert.assertEquals(0, empty.getBoundarySize(), 1.0e-10);
+        Assert.assertEquals(0, empty.getSize(), TEST_EPS);
+        Assert.assertEquals(0, empty.getBoundarySize(), TEST_EPS);
         Assert.assertEquals(0, empty.getBoundaryLoops().size());
         Assert.assertTrue(empty.getEnclosingCap().getRadius() < 0);
         Assert.assertTrue(Double.isInfinite(empty.getEnclosingCap().getRadius()));
@@ -74,7 +81,7 @@ public class SphericalPolygonsSetTest {
     public void testSouthHemisphere() {
         double tol = 0.01;
         double sinTol = Math.sin(tol);
-        SphericalPolygonsSet south = new SphericalPolygonsSet(Vector3D.MINUS_Z, tol);
+        SphericalPolygonsSet south = new SphericalPolygonsSet(Vector3D.MINUS_Z, createPrecision(tol));
         UnitSphereSampler random =
                 new UnitSphereSampler(3, RandomSource.create(RandomSource.WELL_1024_A,
                                                              0x6b9d4a6ad90d7b0bl));
@@ -91,13 +98,13 @@ public class SphericalPolygonsSetTest {
         Assert.assertEquals(1, south.getBoundaryLoops().size());
 
         EnclosingBall<S2Point> southCap = south.getEnclosingCap();
-        Assert.assertEquals(0.0, S2Point.MINUS_K.distance(southCap.getCenter()), 1.0e-10);
-        Assert.assertEquals(0.5 * Math.PI, southCap.getRadius(), 1.0e-10);
+        Assert.assertEquals(0.0, S2Point.MINUS_K.distance(southCap.getCenter()), TEST_EPS);
+        Assert.assertEquals(0.5 * Math.PI, southCap.getRadius(), TEST_EPS);
 
         EnclosingBall<S2Point> northCap =
                 ((SphericalPolygonsSet) new RegionFactory<S2Point>().getComplement(south)).getEnclosingCap();
-        Assert.assertEquals(0.0, S2Point.PLUS_K.distance(northCap.getCenter()), 1.0e-10);
-        Assert.assertEquals(0.5 * Math.PI, northCap.getRadius(), 1.0e-10);
+        Assert.assertEquals(0.0, S2Point.PLUS_K.distance(northCap.getCenter()), TEST_EPS);
+        Assert.assertEquals(0.5 * Math.PI, northCap.getRadius(), TEST_EPS);
 
     }
 
@@ -105,10 +112,11 @@ public class SphericalPolygonsSetTest {
     public void testPositiveOctantByIntersection() {
         double tol = 0.01;
         double sinTol = Math.sin(tol);
+        DoublePrecisionContext precision = createPrecision(tol);
         RegionFactory<S2Point> factory = new RegionFactory<>();
-        SphericalPolygonsSet plusX = new SphericalPolygonsSet(Vector3D.PLUS_X, tol);
-        SphericalPolygonsSet plusY = new SphericalPolygonsSet(Vector3D.PLUS_Y, tol);
-        SphericalPolygonsSet plusZ = new SphericalPolygonsSet(Vector3D.PLUS_Z, tol);
+        SphericalPolygonsSet plusX = new SphericalPolygonsSet(Vector3D.PLUS_X, precision);
+        SphericalPolygonsSet plusY = new SphericalPolygonsSet(Vector3D.PLUS_Y, precision);
+        SphericalPolygonsSet plusZ = new SphericalPolygonsSet(Vector3D.PLUS_Z, precision);
         SphericalPolygonsSet octant =
                 (SphericalPolygonsSet) factory.intersection(factory.intersection(plusX, plusY), plusZ);
         UnitSphereSampler random =
@@ -139,13 +147,13 @@ public class SphericalPolygonsSetTest {
             ++count;
             Edge e = v.getIncoming();
             Assert.assertTrue(v == e.getStart().getOutgoing().getEnd());
-            xPFound = xPFound || e.getCircle().getPole().distance(Vector3D.PLUS_X) < 1.0e-10;
-            yPFound = yPFound || e.getCircle().getPole().distance(Vector3D.PLUS_Y) < 1.0e-10;
-            zPFound = zPFound || e.getCircle().getPole().distance(Vector3D.PLUS_Z) < 1.0e-10;
-            Assert.assertEquals(0.5 * Math.PI, e.getLength(), 1.0e-10);
-            xVFound = xVFound || v.getLocation().getVector().distance(Vector3D.PLUS_X) < 1.0e-10;
-            yVFound = yVFound || v.getLocation().getVector().distance(Vector3D.PLUS_Y) < 1.0e-10;
-            zVFound = zVFound || v.getLocation().getVector().distance(Vector3D.PLUS_Z) < 1.0e-10;
+            xPFound = xPFound || e.getCircle().getPole().distance(Vector3D.PLUS_X) < TEST_EPS;
+            yPFound = yPFound || e.getCircle().getPole().distance(Vector3D.PLUS_Y) < TEST_EPS;
+            zPFound = zPFound || e.getCircle().getPole().distance(Vector3D.PLUS_Z) < TEST_EPS;
+            Assert.assertEquals(0.5 * Math.PI, e.getLength(), TEST_EPS);
+            xVFound = xVFound || v.getLocation().getVector().distance(Vector3D.PLUS_X) < TEST_EPS;
+            yVFound = yVFound || v.getLocation().getVector().distance(Vector3D.PLUS_Y) < TEST_EPS;
+            zVFound = zVFound || v.getLocation().getVector().distance(Vector3D.PLUS_Z) < TEST_EPS;
         }
         Assert.assertTrue(xPFound);
         Assert.assertTrue(yPFound);
@@ -157,17 +165,17 @@ public class SphericalPolygonsSetTest {
 
         Assert.assertEquals(0.0,
                             octant.getBarycenter().distance(S2Point.ofVector(Vector3D.of(1, 1, 1))),
-                            1.0e-10);
-        Assert.assertEquals(0.5 * Math.PI, octant.getSize(), 1.0e-10);
+                            TEST_EPS);
+        Assert.assertEquals(0.5 * Math.PI, octant.getSize(), TEST_EPS);
 
         EnclosingBall<S2Point> cap = octant.getEnclosingCap();
-        Assert.assertEquals(0.0, octant.getBarycenter().distance(cap.getCenter()), 1.0e-10);
-        Assert.assertEquals(Math.acos(1.0 / Math.sqrt(3)), cap.getRadius(), 1.0e-10);
+        Assert.assertEquals(0.0, octant.getBarycenter().distance(cap.getCenter()), TEST_EPS);
+        Assert.assertEquals(Math.acos(1.0 / Math.sqrt(3)), cap.getRadius(), TEST_EPS);
 
         EnclosingBall<S2Point> reversedCap =
                 ((SphericalPolygonsSet) factory.getComplement(octant)).getEnclosingCap();
-        Assert.assertEquals(0, reversedCap.getCenter().distance(S2Point.ofVector(Vector3D.of(-1, -1, -1))), 1.0e-10);
-        Assert.assertEquals(Math.PI - Math.asin(1.0 / Math.sqrt(3)), reversedCap.getRadius(), 1.0e-10);
+        Assert.assertEquals(0, reversedCap.getCenter().distance(S2Point.ofVector(Vector3D.of(-1, -1, -1))), TEST_EPS);
+        Assert.assertEquals(Math.PI - Math.asin(1.0 / Math.sqrt(3)), reversedCap.getRadius(), TEST_EPS);
 
     }
 
@@ -175,7 +183,7 @@ public class SphericalPolygonsSetTest {
     public void testPositiveOctantByVertices() {
         double tol = 0.01;
         double sinTol = Math.sin(tol);
-        SphericalPolygonsSet octant = new SphericalPolygonsSet(tol, S2Point.PLUS_I, S2Point.PLUS_J, S2Point.PLUS_K);
+        SphericalPolygonsSet octant = new SphericalPolygonsSet(createPrecision(tol), S2Point.PLUS_I, S2Point.PLUS_J, S2Point.PLUS_K);
         UnitSphereSampler random =
                 new UnitSphereSampler(3, RandomSource.create(RandomSource.WELL_1024_A,
                                                              0xb8fc5acc91044308l));
@@ -195,10 +203,11 @@ public class SphericalPolygonsSetTest {
     public void testNonConvex() {
         double tol = 0.01;
         double sinTol = Math.sin(tol);
+        DoublePrecisionContext precision = createPrecision(tol);
         RegionFactory<S2Point> factory = new RegionFactory<>();
-        SphericalPolygonsSet plusX = new SphericalPolygonsSet(Vector3D.PLUS_X, tol);
-        SphericalPolygonsSet plusY = new SphericalPolygonsSet(Vector3D.PLUS_Y, tol);
-        SphericalPolygonsSet plusZ = new SphericalPolygonsSet(Vector3D.PLUS_Z, tol);
+        SphericalPolygonsSet plusX = new SphericalPolygonsSet(Vector3D.PLUS_X, precision);
+        SphericalPolygonsSet plusY = new SphericalPolygonsSet(Vector3D.PLUS_Y, precision);
+        SphericalPolygonsSet plusZ = new SphericalPolygonsSet(Vector3D.PLUS_Z, precision);
         SphericalPolygonsSet threeOctants =
                 (SphericalPolygonsSet) factory.difference(plusZ, factory.intersection(plusX, plusY));
 
@@ -233,20 +242,20 @@ public class SphericalPolygonsSetTest {
             ++count;
             Edge e = v.getIncoming();
             Assert.assertTrue(v == e.getStart().getOutgoing().getEnd());
-            if (e.getCircle().getPole().distance(Vector3D.MINUS_X) < 1.0e-10) {
+            if (e.getCircle().getPole().distance(Vector3D.MINUS_X) < TEST_EPS) {
                 xPFound = true;
                 sumPoleX += e.getLength();
-            } else if (e.getCircle().getPole().distance(Vector3D.MINUS_Y) < 1.0e-10) {
+            } else if (e.getCircle().getPole().distance(Vector3D.MINUS_Y) < TEST_EPS) {
                 yPFound = true;
                 sumPoleY += e.getLength();
             } else {
-                Assert.assertEquals(0.0, e.getCircle().getPole().distance(Vector3D.PLUS_Z), 1.0e-10);
+                Assert.assertEquals(0.0, e.getCircle().getPole().distance(Vector3D.PLUS_Z), TEST_EPS);
                 zPFound = true;
                 sumPoleZ += e.getLength();
             }
-            xVFound = xVFound || v.getLocation().getVector().distance(Vector3D.PLUS_X) < 1.0e-10;
-            yVFound = yVFound || v.getLocation().getVector().distance(Vector3D.PLUS_Y) < 1.0e-10;
-            zVFound = zVFound || v.getLocation().getVector().distance(Vector3D.PLUS_Z) < 1.0e-10;
+            xVFound = xVFound || v.getLocation().getVector().distance(Vector3D.PLUS_X) < TEST_EPS;
+            yVFound = yVFound || v.getLocation().getVector().distance(Vector3D.PLUS_Y) < TEST_EPS;
+            zVFound = zVFound || v.getLocation().getVector().distance(Vector3D.PLUS_Z) < TEST_EPS;
         }
         Assert.assertTrue(xPFound);
         Assert.assertTrue(yPFound);
@@ -254,25 +263,26 @@ public class SphericalPolygonsSetTest {
         Assert.assertTrue(xVFound);
         Assert.assertTrue(yVFound);
         Assert.assertTrue(zVFound);
-        Assert.assertEquals(0.5 * Math.PI, sumPoleX, 1.0e-10);
-        Assert.assertEquals(0.5 * Math.PI, sumPoleY, 1.0e-10);
-        Assert.assertEquals(1.5 * Math.PI, sumPoleZ, 1.0e-10);
+        Assert.assertEquals(0.5 * Math.PI, sumPoleX, TEST_EPS);
+        Assert.assertEquals(0.5 * Math.PI, sumPoleY, TEST_EPS);
+        Assert.assertEquals(1.5 * Math.PI, sumPoleZ, TEST_EPS);
 
-        Assert.assertEquals(1.5 * Math.PI, threeOctants.getSize(), 1.0e-10);
+        Assert.assertEquals(1.5 * Math.PI, threeOctants.getSize(), TEST_EPS);
 
     }
 
     @Test
     public void testModeratlyComplexShape() {
         double tol = 0.01;
+        DoublePrecisionContext precision = createPrecision(tol);
         List<SubHyperplane<S2Point>> boundary = new ArrayList<>();
-        boundary.add(create(Vector3D.MINUS_Y, Vector3D.PLUS_X,  Vector3D.PLUS_Z,  tol, 0.0, 0.5 * Math.PI));
-        boundary.add(create(Vector3D.MINUS_X, Vector3D.PLUS_Z,  Vector3D.PLUS_Y,  tol, 0.0, 0.5 * Math.PI));
-        boundary.add(create(Vector3D.PLUS_Z,  Vector3D.PLUS_Y,  Vector3D.MINUS_X, tol, 0.0, 0.5 * Math.PI));
-        boundary.add(create(Vector3D.MINUS_Y, Vector3D.MINUS_X, Vector3D.MINUS_Z, tol, 0.0, 0.5 * Math.PI));
-        boundary.add(create(Vector3D.MINUS_X, Vector3D.MINUS_Z, Vector3D.MINUS_Y, tol, 0.0, 0.5 * Math.PI));
-        boundary.add(create(Vector3D.PLUS_Z,  Vector3D.MINUS_Y, Vector3D.PLUS_X,  tol, 0.0, 0.5 * Math.PI));
-        SphericalPolygonsSet polygon = new SphericalPolygonsSet(boundary, tol);
+        boundary.add(create(Vector3D.MINUS_Y, Vector3D.PLUS_X,  Vector3D.PLUS_Z,  precision, 0.0, 0.5 * Math.PI));
+        boundary.add(create(Vector3D.MINUS_X, Vector3D.PLUS_Z,  Vector3D.PLUS_Y,  precision, 0.0, 0.5 * Math.PI));
+        boundary.add(create(Vector3D.PLUS_Z,  Vector3D.PLUS_Y,  Vector3D.MINUS_X, precision, 0.0, 0.5 * Math.PI));
+        boundary.add(create(Vector3D.MINUS_Y, Vector3D.MINUS_X, Vector3D.MINUS_Z, precision, 0.0, 0.5 * Math.PI));
+        boundary.add(create(Vector3D.MINUS_X, Vector3D.MINUS_Z, Vector3D.MINUS_Y, precision, 0.0, 0.5 * Math.PI));
+        boundary.add(create(Vector3D.PLUS_Z,  Vector3D.MINUS_Y, Vector3D.PLUS_X,  precision, 0.0, 0.5 * Math.PI));
+        SphericalPolygonsSet polygon = new SphericalPolygonsSet(boundary, precision);
 
         Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(S2Point.ofVector(Vector3D.of( 1,  1,  1).normalize())));
         Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(S2Point.ofVector(Vector3D.of(-1,  1,  1).normalize())));
@@ -283,8 +293,8 @@ public class SphericalPolygonsSetTest {
         Assert.assertEquals(Location.INSIDE,  polygon.checkPoint(S2Point.ofVector(Vector3D.of(-1, -1, -1).normalize())));
         Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(S2Point.ofVector(Vector3D.of( 1, -1, -1).normalize())));
 
-        Assert.assertEquals(Geometry.TWO_PI, polygon.getSize(), 1.0e-10);
-        Assert.assertEquals(3 * Math.PI, polygon.getBoundarySize(), 1.0e-10);
+        Assert.assertEquals(Geometry.TWO_PI, polygon.getSize(), TEST_EPS);
+        Assert.assertEquals(3 * Math.PI, polygon.getBoundarySize(), TEST_EPS);
 
         List<Vertex> loops = polygon.getBoundaryLoops();
         Assert.assertEquals(1, loops.size());
@@ -300,13 +310,13 @@ public class SphericalPolygonsSetTest {
             ++count;
             Edge e = v.getIncoming();
             Assert.assertTrue(v == e.getStart().getOutgoing().getEnd());
-            pXFound = pXFound || v.getLocation().getVector().distance(Vector3D.PLUS_X)  < 1.0e-10;
-            mXFound = mXFound || v.getLocation().getVector().distance(Vector3D.MINUS_X) < 1.0e-10;
-            pYFound = pYFound || v.getLocation().getVector().distance(Vector3D.PLUS_Y)  < 1.0e-10;
-            mYFound = mYFound || v.getLocation().getVector().distance(Vector3D.MINUS_Y) < 1.0e-10;
-            pZFound = pZFound || v.getLocation().getVector().distance(Vector3D.PLUS_Z)  < 1.0e-10;
-            mZFound = mZFound || v.getLocation().getVector().distance(Vector3D.MINUS_Z) < 1.0e-10;
-            Assert.assertEquals(0.5 * Math.PI, e.getLength(), 1.0e-10);
+            pXFound = pXFound || v.getLocation().getVector().distance(Vector3D.PLUS_X)  < TEST_EPS;
+            mXFound = mXFound || v.getLocation().getVector().distance(Vector3D.MINUS_X) < TEST_EPS;
+            pYFound = pYFound || v.getLocation().getVector().distance(Vector3D.PLUS_Y)  < TEST_EPS;
+            mYFound = mYFound || v.getLocation().getVector().distance(Vector3D.MINUS_Y) < TEST_EPS;
+            pZFound = pZFound || v.getLocation().getVector().distance(Vector3D.PLUS_Z)  < TEST_EPS;
+            mZFound = mZFound || v.getLocation().getVector().distance(Vector3D.MINUS_Z) < TEST_EPS;
+            Assert.assertEquals(0.5 * Math.PI, e.getLength(), TEST_EPS);
         }
         Assert.assertTrue(pXFound);
         Assert.assertTrue(mXFound);
@@ -322,19 +332,20 @@ public class SphericalPolygonsSetTest {
     public void testSeveralParts() {
         double tol = 0.01;
         double sinTol = Math.sin(tol);
+        DoublePrecisionContext precision = createPrecision(tol);
         List<SubHyperplane<S2Point>> boundary = new ArrayList<>();
 
         // first part: +X, +Y, +Z octant
-        boundary.add(create(Vector3D.PLUS_Y,  Vector3D.PLUS_Z,  Vector3D.PLUS_X,  tol, 0.0, 0.5 * Math.PI));
-        boundary.add(create(Vector3D.PLUS_Z,  Vector3D.PLUS_X,  Vector3D.PLUS_Y,  tol, 0.0, 0.5 * Math.PI));
-        boundary.add(create(Vector3D.PLUS_X,  Vector3D.PLUS_Y,  Vector3D.PLUS_Z,  tol, 0.0, 0.5 * Math.PI));
+        boundary.add(create(Vector3D.PLUS_Y,  Vector3D.PLUS_Z,  Vector3D.PLUS_X,  precision, 0.0, 0.5 * Math.PI));
+        boundary.add(create(Vector3D.PLUS_Z,  Vector3D.PLUS_X,  Vector3D.PLUS_Y,  precision, 0.0, 0.5 * Math.PI));
+        boundary.add(create(Vector3D.PLUS_X,  Vector3D.PLUS_Y,  Vector3D.PLUS_Z,  precision, 0.0, 0.5 * Math.PI));
 
         // first part: -X, -Y, -Z octant
-        boundary.add(create(Vector3D.MINUS_Y, Vector3D.MINUS_X, Vector3D.MINUS_Z, tol, 0.0, 0.5 * Math.PI));
-        boundary.add(create(Vector3D.MINUS_X, Vector3D.MINUS_Z, Vector3D.MINUS_Y, tol, 0.0, 0.5 * Math.PI));
-        boundary.add(create(Vector3D.MINUS_Z, Vector3D.MINUS_Y, Vector3D.MINUS_X,  tol, 0.0, 0.5 * Math.PI));
+        boundary.add(create(Vector3D.MINUS_Y, Vector3D.MINUS_X, Vector3D.MINUS_Z, precision, 0.0, 0.5 * Math.PI));
+        boundary.add(create(Vector3D.MINUS_X, Vector3D.MINUS_Z, Vector3D.MINUS_Y, precision, 0.0, 0.5 * Math.PI));
+        boundary.add(create(Vector3D.MINUS_Z, Vector3D.MINUS_Y, Vector3D.MINUS_X,  precision, 0.0, 0.5 * Math.PI));
 
-        SphericalPolygonsSet polygon = new SphericalPolygonsSet(boundary, tol);
+        SphericalPolygonsSet polygon = new SphericalPolygonsSet(boundary, precision);
 
         UnitSphereSampler random =
                 new UnitSphereSampler(3, RandomSource.create(RandomSource.WELL_1024_A,
@@ -354,8 +365,8 @@ public class SphericalPolygonsSetTest {
             }
         }
 
-        Assert.assertEquals(Math.PI, polygon.getSize(), 1.0e-10);
-        Assert.assertEquals(3 * Math.PI, polygon.getBoundarySize(), 1.0e-10);
+        Assert.assertEquals(Math.PI, polygon.getSize(), TEST_EPS);
+        Assert.assertEquals(3 * Math.PI, polygon.getBoundarySize(), TEST_EPS);
 
         // there should be two separate boundary loops
         Assert.assertEquals(2, polygon.getBoundaryLoops().size());
@@ -366,9 +377,10 @@ public class SphericalPolygonsSetTest {
     public void testPartWithHole() {
         double tol = 0.01;
         double alpha = 0.7;
+        DoublePrecisionContext precision = createPrecision(tol);
         S2Point center = S2Point.ofVector(Vector3D.of(1, 1, 1));
-        SphericalPolygonsSet hexa = new SphericalPolygonsSet(center.getVector(), Vector3D.PLUS_Z, alpha, 6, tol);
-        SphericalPolygonsSet hole  = new SphericalPolygonsSet(tol,
+        SphericalPolygonsSet hexa = new SphericalPolygonsSet(center.getVector(), Vector3D.PLUS_Z, alpha, 6, precision);
+        SphericalPolygonsSet hole  = new SphericalPolygonsSet(precision,
                                                               S2Point.of(Math.PI / 6, Math.PI / 3),
                                                               S2Point.of(Math.PI / 3, Math.PI / 3),
                                                               S2Point.of(Math.PI / 4, Math.PI / 6));
@@ -387,23 +399,24 @@ public class SphericalPolygonsSetTest {
         // there should be two separate boundary loops
         Assert.assertEquals(2, hexaWithHole.getBoundaryLoops().size());
 
-        Assert.assertEquals(hexa.getBoundarySize() + hole.getBoundarySize(), hexaWithHole.getBoundarySize(), 1.0e-10);
-        Assert.assertEquals(hexa.getSize() - hole.getSize(), hexaWithHole.getSize(), 1.0e-10);
+        Assert.assertEquals(hexa.getBoundarySize() + hole.getBoundarySize(), hexaWithHole.getBoundarySize(), TEST_EPS);
+        Assert.assertEquals(hexa.getSize() - hole.getSize(), hexaWithHole.getSize(), TEST_EPS);
 
     }
 
     @Test
     public void testConcentricSubParts() {
         double tol = 0.001;
+        DoublePrecisionContext precision = createPrecision(tol);
         Vector3D center = Vector3D.of(1, 1, 1);
-        SphericalPolygonsSet hexaOut   = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.9,  6, tol);
-        SphericalPolygonsSet hexaIn    = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.8,  6, tol);
-        SphericalPolygonsSet pentaOut  = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.7,  5, tol);
-        SphericalPolygonsSet pentaIn   = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.6,  5, tol);
-        SphericalPolygonsSet quadriOut = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.5,  4, tol);
-        SphericalPolygonsSet quadriIn  = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.4,  4, tol);
-        SphericalPolygonsSet triOut    = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.25, 3, tol);
-        SphericalPolygonsSet triIn     = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.15, 3, tol);
+        SphericalPolygonsSet hexaOut   = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.9,  6, precision);
+        SphericalPolygonsSet hexaIn    = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.8,  6, precision);
+        SphericalPolygonsSet pentaOut  = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.7,  5, precision);
+        SphericalPolygonsSet pentaIn   = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.6,  5, precision);
+        SphericalPolygonsSet quadriOut = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.5,  4, precision);
+        SphericalPolygonsSet quadriIn  = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.4,  4, precision);
+        SphericalPolygonsSet triOut    = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.25, 3, precision);
+        SphericalPolygonsSet triIn     = new SphericalPolygonsSet(center, Vector3D.PLUS_Z, 0.15, 3, precision);
 
         RegionFactory<S2Point> factory = new RegionFactory<>();
         SphericalPolygonsSet hexa   = (SphericalPolygonsSet) factory.difference(hexaOut,   hexaIn);
@@ -420,12 +433,12 @@ public class SphericalPolygonsSetTest {
                             pentaOut.getBoundarySize()  + pentaIn.getBoundarySize()  +
                             quadriOut.getBoundarySize() + quadriIn.getBoundarySize() +
                             triOut.getBoundarySize()    + triIn.getBoundarySize(),
-                            concentric.getBoundarySize(), 1.0e-10);
+                            concentric.getBoundarySize(), TEST_EPS);
         Assert.assertEquals(hexaOut.getSize()   - hexaIn.getSize()   +
                             pentaOut.getSize()  - pentaIn.getSize()  +
                             quadriOut.getSize() - quadriIn.getSize() +
                             triOut.getSize()    - triIn.getSize(),
-                            concentric.getSize(), 1.0e-10);
+                            concentric.getSize(), TEST_EPS);
 
         // we expect lots of sign changes as we traverse all concentric rings
         double phi = S2Point.ofVector(center).getPolar();
@@ -485,9 +498,9 @@ public class SphericalPolygonsSetTest {
 
         S2Point supportPointA = s2Point(48.68416, -4.59234);
         S2Point supportPointB = s2Point(41.38000,  9.22975);
-        Assert.assertEquals(enclosing.getRadius(), supportPointA.distance(enclosing.getCenter()), 1.0e-10);
-        Assert.assertEquals(enclosing.getRadius(), supportPointB.distance(enclosing.getCenter()), 1.0e-10);
-        Assert.assertEquals(0.5 * supportPointA.distance(supportPointB), enclosing.getRadius(), 1.0e-10);
+        Assert.assertEquals(enclosing.getRadius(), supportPointA.distance(enclosing.getCenter()), TEST_EPS);
+        Assert.assertEquals(enclosing.getRadius(), supportPointB.distance(enclosing.getCenter()), TEST_EPS);
+        Assert.assertEquals(0.5 * supportPointA.distance(supportPointB), enclosing.getRadius(), TEST_EPS);
         Assert.assertEquals(2, enclosing.getSupportSize());
 
         EnclosingBall<S2Point> continentalInscribed =
@@ -523,14 +536,14 @@ public class SphericalPolygonsSetTest {
     }
 
     private SubCircle create(Vector3D pole, Vector3D x, Vector3D y,
-                             double tolerance, double ... limits) {
+                             DoublePrecisionContext precision, double ... limits) {
         RegionFactory<S1Point> factory = new RegionFactory<>();
-        Circle circle = new Circle(pole, tolerance);
+        Circle circle = new Circle(pole, precision);
         Circle phased =
                 (Circle) Circle.getTransform(QuaternionRotation.createBasisRotation(circle.getXAxis(), circle.getYAxis(), x, y)).apply(circle);
-        ArcsSet set = (ArcsSet) factory.getComplement(new ArcsSet(tolerance));
+        ArcsSet set = (ArcsSet) factory.getComplement(new ArcsSet(precision));
         for (int i = 0; i < limits.length; i += 2) {
-            set = (ArcsSet) factory.union(set, new ArcsSet(limits[i], limits[i + 1], tolerance));
+            set = (ArcsSet) factory.union(set, new ArcsSet(limits[i], limits[i + 1], precision));
         }
         return new SubCircle(phased, set);
     }
@@ -540,11 +553,18 @@ public class SphericalPolygonsSetTest {
         for (int i = 0; i < points.length; ++i) {
             vertices[i] = s2Point(points[i][0], points[i][1]);
         }
-        return new SphericalPolygonsSet(1.0e-10, vertices);
+        return new SphericalPolygonsSet(TEST_PRECISION, vertices);
     }
 
     private S2Point s2Point(double latitude, double longitude) {
         return S2Point.of(Math.toRadians(longitude), Math.toRadians(90.0 - latitude));
     }
 
+    /** Create a {@link DoublePrecisionContext} with the given epsilon value.
+     * @param eps epsilon value
+     * @return new precision context
+     */
+    private static DoublePrecisionContext createPrecision(final double eps) {
+        return new EpsilonDoublePrecisionContext(eps);
+    }
 }
diff --git a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SubCircleTest.java b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SubCircleTest.java
index 95c8ad9..58e2015 100644
--- a/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SubCircleTest.java
+++ b/commons-geometry-spherical/src/test/java/org/apache/commons/geometry/spherical/twod/SubCircleTest.java
@@ -20,6 +20,8 @@ import org.apache.commons.geometry.core.Geometry;
 import org.apache.commons.geometry.core.partitioning.RegionFactory;
 import org.apache.commons.geometry.core.partitioning.Side;
 import org.apache.commons.geometry.core.partitioning.SubHyperplane.SplitSubHyperplane;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
 import org.apache.commons.geometry.euclidean.threed.Vector3D;
 import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
 import org.apache.commons.geometry.spherical.oned.ArcsSet;
@@ -29,11 +31,16 @@ import org.junit.Test;
 
 public class SubCircleTest {
 
+    private static final double TEST_EPS = 1e-10;
+
+    private static final DoublePrecisionContext TEST_PRECISION =
+            new EpsilonDoublePrecisionContext(TEST_EPS);
+
     @Test
     public void testFullCircle() {
-        Circle circle = new Circle(Vector3D.PLUS_Z, 1.0e-10);
+        Circle circle = new Circle(Vector3D.PLUS_Z, TEST_PRECISION);
         SubCircle set = circle.wholeHyperplane();
-        Assert.assertEquals(Geometry.TWO_PI, set.getSize(), 1.0e-10);
+        Assert.assertEquals(Geometry.TWO_PI, set.getSize(), TEST_EPS);
         Assert.assertTrue(circle == set.getHyperplane());
         Assert.assertTrue(circle != set.copySelf().getHyperplane());
     }
@@ -41,21 +48,21 @@ public class SubCircleTest {
     @Test
     public void testSide() {
 
-        Circle xzPlane = new Circle(Vector3D.PLUS_Y, 1.0e-10);
+        Circle xzPlane = new Circle(Vector3D.PLUS_Y, TEST_PRECISION);
 
-        SubCircle sc1 = create(Vector3D.PLUS_Z, Vector3D.PLUS_X, Vector3D.PLUS_Y, 1.0e-10, 1.0, 3.0, 5.0, 6.0);
+        SubCircle sc1 = create(Vector3D.PLUS_Z, Vector3D.PLUS_X, Vector3D.PLUS_Y, TEST_PRECISION, 1.0, 3.0, 5.0, 6.0);
         Assert.assertEquals(Side.BOTH, sc1.split(xzPlane).getSide());
 
-        SubCircle sc2 = create(Vector3D.PLUS_Z, Vector3D.PLUS_X, Vector3D.PLUS_Y, 1.0e-10, 1.0, 3.0);
+        SubCircle sc2 = create(Vector3D.PLUS_Z, Vector3D.PLUS_X, Vector3D.PLUS_Y, TEST_PRECISION, 1.0, 3.0);
         Assert.assertEquals(Side.MINUS, sc2.split(xzPlane).getSide());
 
-        SubCircle sc3 = create(Vector3D.PLUS_Z, Vector3D.PLUS_X, Vector3D.PLUS_Y, 1.0e-10, 5.0, 6.0);
+        SubCircle sc3 = create(Vector3D.PLUS_Z, Vector3D.PLUS_X, Vector3D.PLUS_Y, TEST_PRECISION, 5.0, 6.0);
         Assert.assertEquals(Side.PLUS, sc3.split(xzPlane).getSide());
 
-        SubCircle sc4 = create(Vector3D.PLUS_Y, Vector3D.PLUS_Z, Vector3D.PLUS_X, 1.0e-10, 5.0, 6.0);
+        SubCircle sc4 = create(Vector3D.PLUS_Y, Vector3D.PLUS_Z, Vector3D.PLUS_X, TEST_PRECISION, 5.0, 6.0);
         Assert.assertEquals(Side.HYPER, sc4.split(xzPlane).getSide());
 
-        SubCircle sc5 = create(Vector3D.MINUS_Y, Vector3D.PLUS_X, Vector3D.PLUS_Z, 1.0e-10, 5.0, 6.0);
+        SubCircle sc5 = create(Vector3D.MINUS_Y, Vector3D.PLUS_X, Vector3D.PLUS_Z, TEST_PRECISION, 5.0, 6.0);
         Assert.assertEquals(Side.HYPER, sc5.split(xzPlane).getSide());
 
     }
@@ -63,42 +70,42 @@ public class SubCircleTest {
     @Test
     public void testSPlit() {
 
-        Circle xzPlane = new Circle(Vector3D.PLUS_Y, 1.0e-10);
+        Circle xzPlane = new Circle(Vector3D.PLUS_Y, TEST_PRECISION);
 
-        SubCircle sc1 = create(Vector3D.PLUS_Z, Vector3D.PLUS_X, Vector3D.PLUS_Y, 1.0e-10, 1.0, 3.0, 5.0, 6.0);
+        SubCircle sc1 = create(Vector3D.PLUS_Z, Vector3D.PLUS_X, Vector3D.PLUS_Y, TEST_PRECISION, 1.0, 3.0, 5.0, 6.0);
         SplitSubHyperplane<S2Point> split1 = sc1.split(xzPlane);
         ArcsSet plus1  = (ArcsSet) ((SubCircle) split1.getPlus()).getRemainingRegion();
         ArcsSet minus1 = (ArcsSet) ((SubCircle) split1.getMinus()).getRemainingRegion();
         Assert.assertEquals(1, plus1.asList().size());
-        Assert.assertEquals(5.0, plus1.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, plus1.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(5.0, plus1.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(6.0, plus1.asList().get(0).getSup(), TEST_EPS);
         Assert.assertEquals(1, minus1.asList().size());
-        Assert.assertEquals(1.0, minus1.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(3.0, minus1.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(1.0, minus1.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(3.0, minus1.asList().get(0).getSup(), TEST_EPS);
 
-        SubCircle sc2 = create(Vector3D.PLUS_Z, Vector3D.PLUS_X, Vector3D.PLUS_Y, 1.0e-10, 1.0, 3.0);
+        SubCircle sc2 = create(Vector3D.PLUS_Z, Vector3D.PLUS_X, Vector3D.PLUS_Y, TEST_PRECISION, 1.0, 3.0);
         SplitSubHyperplane<S2Point> split2 = sc2.split(xzPlane);
         Assert.assertNull(split2.getPlus());
         ArcsSet minus2 = (ArcsSet) ((SubCircle) split2.getMinus()).getRemainingRegion();
         Assert.assertEquals(1, minus2.asList().size());
-        Assert.assertEquals(1.0, minus2.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(3.0, minus2.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(1.0, minus2.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(3.0, minus2.asList().get(0).getSup(), TEST_EPS);
 
-        SubCircle sc3 = create(Vector3D.PLUS_Z, Vector3D.PLUS_X, Vector3D.PLUS_Y, 1.0e-10, 5.0, 6.0);
+        SubCircle sc3 = create(Vector3D.PLUS_Z, Vector3D.PLUS_X, Vector3D.PLUS_Y, TEST_PRECISION, 5.0, 6.0);
         SplitSubHyperplane<S2Point> split3 = sc3.split(xzPlane);
         ArcsSet plus3  = (ArcsSet) ((SubCircle) split3.getPlus()).getRemainingRegion();
         Assert.assertEquals(1, plus3.asList().size());
-        Assert.assertEquals(5.0, plus3.asList().get(0).getInf(), 1.0e-10);
-        Assert.assertEquals(6.0, plus3.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(5.0, plus3.asList().get(0).getInf(), TEST_EPS);
+        Assert.assertEquals(6.0, plus3.asList().get(0).getSup(), TEST_EPS);
         Assert.assertNull(split3.getMinus());
 
-        SubCircle sc4 = create(Vector3D.PLUS_Y, Vector3D.PLUS_Z, Vector3D.PLUS_X, 1.0e-10, 5.0, 6.0);
+        SubCircle sc4 = create(Vector3D.PLUS_Y, Vector3D.PLUS_Z, Vector3D.PLUS_X, TEST_PRECISION, 5.0, 6.0);
         SplitSubHyperplane<S2Point> split4 = sc4.split(xzPlane);
         Assert.assertEquals(Side.HYPER, sc4.split(xzPlane).getSide());
         Assert.assertNull(split4.getPlus());
         Assert.assertNull(split4.getMinus());
 
-        SubCircle sc5 = create(Vector3D.MINUS_Y, Vector3D.PLUS_X, Vector3D.PLUS_Z, 1.0e-10, 5.0, 6.0);
+        SubCircle sc5 = create(Vector3D.MINUS_Y, Vector3D.PLUS_X, Vector3D.PLUS_Z, TEST_PRECISION, 5.0, 6.0);
         SplitSubHyperplane<S2Point> split5 = sc5.split(xzPlane);
         Assert.assertEquals(Side.HYPER, sc5.split(xzPlane).getSide());
         Assert.assertNull(split5.getPlus());
@@ -110,11 +117,12 @@ public class SubCircleTest {
     public void testSideSplitConsistency() {
 
         double tolerance = 1.0e-6;
+        DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(tolerance);
         Circle hyperplane = new Circle(Vector3D.of(9.738804529764676E-5, -0.6772824575010357, -0.7357230887208355),
-                                       tolerance);
+                precision);
         SubCircle sub = new SubCircle(new Circle(Vector3D.of(2.1793884139073498E-4, 0.9790647032675541, -0.20354915700704285),
-                                                 tolerance),
-                                      new ArcsSet(4.7121441684170700, 4.7125386635004760, tolerance));
+                precision),
+                                      new ArcsSet(4.7121441684170700, 4.7125386635004760, precision));
         SplitSubHyperplane<S2Point> split = sub.split(hyperplane);
         Assert.assertNotNull(split.getMinus());
         Assert.assertNull(split.getPlus());
@@ -123,14 +131,14 @@ public class SubCircleTest {
     }
 
     private SubCircle create(Vector3D pole, Vector3D x, Vector3D y,
-                             double tolerance, double ... limits) {
+                             DoublePrecisionContext precision, double ... limits) {
         RegionFactory<S1Point> factory = new RegionFactory<>();
-        Circle circle = new Circle(pole, tolerance);
+        Circle circle = new Circle(pole, precision);
         Circle phased =
                 (Circle) Circle.getTransform(QuaternionRotation.createBasisRotation(circle.getXAxis(), circle.getYAxis(), x, y)).apply(circle);
-        ArcsSet set = (ArcsSet) factory.getComplement(new ArcsSet(tolerance));
+        ArcsSet set = (ArcsSet) factory.getComplement(new ArcsSet(precision));
         for (int i = 0; i < limits.length; i += 2) {
-            set = (ArcsSet) factory.union(set, new ArcsSet(limits[i], limits[i + 1], tolerance));
+            set = (ArcsSet) factory.union(set, new ArcsSet(limits[i], limits[i + 1], precision));
         }
         return new SubCircle(phased, set);
     }


Mime
View raw message