You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by er...@apache.org on 2019/02/05 12:15:36 UTC

[commons-geometry] branch master updated (45b1fe0 -> 935d18a)

This is an automated email from the ASF dual-hosted git repository.

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


    from 45b1fe0  GEOMETRY-40: Fix template file (web site).
     new 6e83c6a  GEOMETRY-11: replacing double tolerance values with DoublePrecisionContext class
     new 706ce0d  Trailing spaces.
     new 935d18a  Merge branch 'GEOMETRY-11__matt'

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 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     |   5 +-
 .../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, 2311 insertions(+), 1546 deletions(-)
 create mode 100644 commons-geometry-core/src/main/java/org/apache/commons/geometry/core/precision/DoublePrecisionContext.java
 create mode 100644 commons-geometry-core/src/main/java/org/apache/commons/geometry/core/precision/EpsilonDoublePrecisionContext.java
 copy {commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod => commons-geometry-core/src/main/java/org/apache/commons/geometry/core/precision}/package-info.java (87%)
 create mode 100644 commons-geometry-core/src/test/java/org/apache/commons/geometry/core/precision/DoublePrecisionContextTest.java
 create mode 100644 commons-geometry-core/src/test/java/org/apache/commons/geometry/core/precision/EpsilonDoublePrecisionContextTest.java


[commons-geometry] 02/03: Trailing spaces.

Posted by er...@apache.org.
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 706ce0d38dc4a3365cd2bb036fccd9ac532b185f
Author: Gilles Sadowski <gi...@harfang.homelinux.org>
AuthorDate: Tue Feb 5 12:42:46 2019 +0100

    Trailing spaces.
---
 commons-geometry-core/pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/commons-geometry-core/pom.xml b/commons-geometry-core/pom.xml
index 82fd82c..6ecf798 100644
--- a/commons-geometry-core/pom.xml
+++ b/commons-geometry-core/pom.xml
@@ -42,7 +42,7 @@
     <!-- Workaround to avoid duplicating config files. -->
     <geometry.parent.dir>${basedir}/..</geometry.parent.dir>
   </properties>
-  
+
   <dependencies>
     <dependency>
       <groupId>org.apache.commons</groupId>


[commons-geometry] 03/03: Merge branch 'GEOMETRY-11__matt'

Posted by er...@apache.org.
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 935d18a52947dbadfe7aa638740a55e3b6d4d090
Merge: 45b1fe0 706ce0d
Author: Gilles Sadowski <gi...@harfang.homelinux.org>
AuthorDate: Tue Feb 5 12:44:00 2019 +0100

    Merge branch 'GEOMETRY-11__matt'
    
    Closes #22.

 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(-)


[commons-geometry] 01/03: GEOMETRY-11: replacing double tolerance values with DoublePrecisionContext class

Posted by er...@apache.org.
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 <ma...@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);
     }