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 2018/01/26 12:04:07 UTC

[1/7] [math] Merge branch 'bug-MATH-1436-PolygonsSet' into dev-4.0

Repository: commons-math
Updated Branches:
  refs/heads/master 3ea45970d -> 54fa0a855


Merge branch 'bug-MATH-1436-PolygonsSet' into dev-4.0


Project: http://git-wip-us.apache.org/repos/asf/commons-math/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-math/commit/cb4ad072
Tree: http://git-wip-us.apache.org/repos/asf/commons-math/tree/cb4ad072
Diff: http://git-wip-us.apache.org/repos/asf/commons-math/diff/cb4ad072

Branch: refs/heads/master
Commit: cb4ad072e0d357d4fe4f0f27a0ed4df0ecdb0f4c
Parents: 3b7deb9 b657c91
Author: darkma773r <ma...@hotmail.com>
Authored: Sun Dec 24 14:34:19 2017 -0500
Committer: darkma773r <ma...@hotmail.com>
Committed: Sun Dec 24 14:34:19 2017 -0500

----------------------------------------------------------------------
 .../geometry/euclidean/twod/PolygonsSet.java    | 67 ++++++++++++--------
 .../euclidean/twod/PolygonsSetTest.java         | 60 ++++++++++++++++++
 2 files changed, 99 insertions(+), 28 deletions(-)
----------------------------------------------------------------------



[6/7] [math] No tabs allowed.

Posted by er...@apache.org.
No tabs allowed.


Project: http://git-wip-us.apache.org/repos/asf/commons-math/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-math/commit/ed98d264
Tree: http://git-wip-us.apache.org/repos/asf/commons-math/tree/ed98d264
Diff: http://git-wip-us.apache.org/repos/asf/commons-math/diff/ed98d264

Branch: refs/heads/master
Commit: ed98d264cff306f7326db096cddf65cb26ff5498
Parents: 24d3dd8
Author: Gilles <er...@apache.org>
Authored: Fri Jan 26 12:41:34 2018 +0100
Committer: Gilles <er...@apache.org>
Committed: Fri Jan 26 12:41:34 2018 +0100

----------------------------------------------------------------------
 .../euclidean/oned/SubOrientedPointTest.java    | 84 ++++++++++----------
 1 file changed, 42 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-math/blob/ed98d264/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/SubOrientedPointTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/SubOrientedPointTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/SubOrientedPointTest.java
index 2843cac..7b8561a 100644
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/SubOrientedPointTest.java
+++ b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/SubOrientedPointTest.java
@@ -65,73 +65,73 @@ public class SubOrientedPointTest {
 
     @Test
     public void testSplit_resultOnMinusSide() {
-    	// arrange
-    	OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
-    	IntervalsSet interval = new IntervalsSet(TEST_TOLERANCE);
-    	SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
+        // arrange
+        OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
+        IntervalsSet interval = new IntervalsSet(TEST_TOLERANCE);
+        SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
 
-    	OrientedPoint splitter = new OrientedPoint(new Cartesian1D(2), true, TEST_TOLERANCE);
+        OrientedPoint splitter = new OrientedPoint(new Cartesian1D(2), true, TEST_TOLERANCE);
 
-    	// act
-    	SplitSubHyperplane<Euclidean1D> split = pt.split(splitter);
+        // act
+        SplitSubHyperplane<Euclidean1D> split = pt.split(splitter);
 
-    	// assert
-    	Assert.assertEquals(Side.MINUS, split.getSide());
+        // assert
+        Assert.assertEquals(Side.MINUS, split.getSide());
 
-    	SubOrientedPoint minusSub = ((SubOrientedPoint) split.getMinus());
-    	Assert.assertNotNull(minusSub);
+        SubOrientedPoint minusSub = ((SubOrientedPoint) split.getMinus());
+        Assert.assertNotNull(minusSub);
 
-    	OrientedPoint minusHyper = (OrientedPoint) minusSub.getHyperplane();
-    	Assert.assertEquals(1, minusHyper.getLocation().getX(), TEST_TOLERANCE);
+        OrientedPoint minusHyper = (OrientedPoint) minusSub.getHyperplane();
+        Assert.assertEquals(1, minusHyper.getLocation().getX(), TEST_TOLERANCE);
 
-    	Assert.assertSame(interval, minusSub.getRemainingRegion());
+        Assert.assertSame(interval, minusSub.getRemainingRegion());
 
-    	Assert.assertNull(split.getPlus());
+        Assert.assertNull(split.getPlus());
     }
 
     @Test
     public void testSplit_resultOnPlusSide() {
-    	// arrange
-    	OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
-    	IntervalsSet interval = new IntervalsSet(TEST_TOLERANCE);
-    	SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
+        // arrange
+        OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
+        IntervalsSet interval = new IntervalsSet(TEST_TOLERANCE);
+        SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
 
-    	OrientedPoint splitter = new OrientedPoint(new Cartesian1D(0), true, TEST_TOLERANCE);
+        OrientedPoint splitter = new OrientedPoint(new Cartesian1D(0), true, TEST_TOLERANCE);
 
-    	// act
-    	SplitSubHyperplane<Euclidean1D> split = pt.split(splitter);
+        // act
+        SplitSubHyperplane<Euclidean1D> split = pt.split(splitter);
 
-    	// assert
-    	Assert.assertEquals(Side.PLUS, split.getSide());
+        // assert
+        Assert.assertEquals(Side.PLUS, split.getSide());
 
-    	Assert.assertNull(split.getMinus());
+        Assert.assertNull(split.getMinus());
 
-    	SubOrientedPoint plusSub = ((SubOrientedPoint) split.getPlus());
-    	Assert.assertNotNull(plusSub);
+        SubOrientedPoint plusSub = ((SubOrientedPoint) split.getPlus());
+        Assert.assertNotNull(plusSub);
 
-    	OrientedPoint plusHyper = (OrientedPoint) plusSub.getHyperplane();
-    	Assert.assertEquals(1, plusHyper.getLocation().getX(), TEST_TOLERANCE);
+        OrientedPoint plusHyper = (OrientedPoint) plusSub.getHyperplane();
+        Assert.assertEquals(1, plusHyper.getLocation().getX(), TEST_TOLERANCE);
 
-    	Assert.assertSame(interval, plusSub.getRemainingRegion());
+        Assert.assertSame(interval, plusSub.getRemainingRegion());
     }
 
     @Test
     public void testSplit_equivalentHyperplanes() {
-    	// arrange
-    	OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
-    	IntervalsSet interval = new IntervalsSet(TEST_TOLERANCE);
-    	SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
+        // arrange
+        OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
+        IntervalsSet interval = new IntervalsSet(TEST_TOLERANCE);
+        SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
 
-    	OrientedPoint splitter = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
+        OrientedPoint splitter = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
 
-    	// act
-    	SplitSubHyperplane<Euclidean1D> split = pt.split(splitter);
+        // act
+        SplitSubHyperplane<Euclidean1D> split = pt.split(splitter);
 
-    	// assert
-    	Assert.assertEquals(Side.HYPER, split.getSide());
+        // assert
+        Assert.assertEquals(Side.HYPER, split.getSide());
 
-    	Assert.assertNull(split.getMinus());
-    	Assert.assertNull(split.getPlus());
+        Assert.assertNull(split.getMinus());
+        Assert.assertNull(split.getPlus());
     }
 
     @Test
@@ -157,4 +157,4 @@ public class SubOrientedPointTest {
         Assert.assertNotNull(minusSplit.getMinus());
         Assert.assertNull(minusSplit.getPlus());
     }
-}
\ No newline at end of file
+}


[7/7] [math] Merge branch 'task_MATH-1437'

Posted by er...@apache.org.
Merge branch 'task_MATH-1437'

Closes #77


Project: http://git-wip-us.apache.org/repos/asf/commons-math/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-math/commit/54fa0a85
Tree: http://git-wip-us.apache.org/repos/asf/commons-math/tree/54fa0a85
Diff: http://git-wip-us.apache.org/repos/asf/commons-math/diff/54fa0a85

Branch: refs/heads/master
Commit: 54fa0a855e549ae2a9f8445d71cbd01e8377e353
Parents: 3ea4597 ed98d26
Author: Gilles <er...@apache.org>
Authored: Fri Jan 26 13:01:13 2018 +0100
Committer: Gilles <er...@apache.org>
Committed: Fri Jan 26 13:01:13 2018 +0100

----------------------------------------------------------------------
 .../euclidean/threed/PolyhedronsSet.java        |    2 +-
 .../math4/geometry/GeometryTestUtils.java       |  324 +++++
 .../euclidean/oned/Cartesian1DTest.java         |  366 ++++--
 .../geometry/euclidean/oned/IntervalTest.java   |  158 ++-
 .../euclidean/oned/IntervalsSetTest.java        |  543 +++++++-
 .../euclidean/oned/OrientedPointTest.java       |  188 +++
 .../euclidean/oned/SubOrientedPointTest.java    |   28 +-
 .../geometry/euclidean/threed/OBJWriter.java    |  337 +++++
 .../euclidean/threed/PolyhedronsSetTest.java    | 1238 +++++++++++++++---
 9 files changed, 2846 insertions(+), 338 deletions(-)
----------------------------------------------------------------------



[4/7] [math] MATH-1437: adding additional unit tests and test utilities for o.a.c.m.geometry.euclidean.twod and o.a.c.m.geometry.euclidean.threed

Posted by er...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-math/blob/24d3dd8b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/SubOrientedPointTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/SubOrientedPointTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/SubOrientedPointTest.java
index 6888d51..2843cac 100644
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/SubOrientedPointTest.java
+++ b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/SubOrientedPointTest.java
@@ -16,8 +16,6 @@
  */
 package org.apache.commons.math4.geometry.euclidean.oned;
 
-import java.util.List;
-
 import org.apache.commons.math4.geometry.partitioning.Side;
 import org.apache.commons.math4.geometry.partitioning.SubHyperplane;
 import org.apache.commons.math4.geometry.partitioning.SubHyperplane.SplitSubHyperplane;
@@ -31,7 +29,7 @@ public class SubOrientedPointTest {
     public void testGetSize() {
         // arrange
         OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
-        SubOrientedPoint pt = (SubOrientedPoint) hyperplane.wholeHyperplane();
+        SubOrientedPoint pt = hyperplane.wholeHyperplane();
 
         // act/assert
         Assert.assertEquals(0.0, pt.getSize(), TEST_TOLERANCE);
@@ -41,7 +39,7 @@ public class SubOrientedPointTest {
     public void testIsEmpty() {
         // arrange
         OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
-        SubOrientedPoint pt = (SubOrientedPoint) hyperplane.wholeHyperplane();
+        SubOrientedPoint pt = hyperplane.wholeHyperplane();
 
         // act/assert
         Assert.assertFalse(pt.isEmpty());
@@ -51,7 +49,7 @@ public class SubOrientedPointTest {
     public void testBuildNew() {
         // arrange
         OrientedPoint originalHyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
-        SubOrientedPoint pt = (SubOrientedPoint) originalHyperplane.wholeHyperplane();
+        SubOrientedPoint pt = originalHyperplane.wholeHyperplane();
 
         OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(2), true, TEST_TOLERANCE);
         IntervalsSet intervals = new IntervalsSet(2, 3, TEST_TOLERANCE);
@@ -67,86 +65,80 @@ public class SubOrientedPointTest {
 
     @Test
     public void testSplit_resultOnMinusSide() {
-        // arrange
-        OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
-        IntervalsSet interval = new IntervalsSet(4, 5, TEST_TOLERANCE);
-        SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
+    	// arrange
+    	OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
+    	IntervalsSet interval = new IntervalsSet(TEST_TOLERANCE);
+    	SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
 
-        OrientedPoint splitter = new OrientedPoint(new Cartesian1D(2), true, TEST_TOLERANCE);
+    	OrientedPoint splitter = new OrientedPoint(new Cartesian1D(2), true, TEST_TOLERANCE);
 
-        // act
-        SplitSubHyperplane<Euclidean1D> split = pt.split(splitter);
+    	// act
+    	SplitSubHyperplane<Euclidean1D> split = pt.split(splitter);
 
-        // assert
-        Assert.assertEquals(Side.MINUS, split.getSide());
+    	// assert
+    	Assert.assertEquals(Side.MINUS, split.getSide());
 
-        SubOrientedPoint minusSub = ((SubOrientedPoint) split.getMinus());
-        Assert.assertNotNull(minusSub);
+    	SubOrientedPoint minusSub = ((SubOrientedPoint) split.getMinus());
+    	Assert.assertNotNull(minusSub);
 
-        OrientedPoint minusHyper = (OrientedPoint) minusSub.getHyperplane();
-        Assert.assertEquals(1, minusHyper.getLocation().getX(), TEST_TOLERANCE);
+    	OrientedPoint minusHyper = (OrientedPoint) minusSub.getHyperplane();
+    	Assert.assertEquals(1, minusHyper.getLocation().getX(), TEST_TOLERANCE);
 
-        List<Interval> minusIntervals = ((IntervalsSet) minusSub.getRemainingRegion()).asList();
-        Assert.assertEquals(1, minusIntervals.size());
-        Assert.assertEquals(4, minusIntervals.get(0).getInf(), TEST_TOLERANCE);
-        Assert.assertEquals(5, minusIntervals.get(0).getSup(), TEST_TOLERANCE);
+    	Assert.assertSame(interval, minusSub.getRemainingRegion());
 
-        Assert.assertNull(split.getPlus());
+    	Assert.assertNull(split.getPlus());
     }
 
     @Test
     public void testSplit_resultOnPlusSide() {
-        // arrange
-        OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
-        IntervalsSet interval = new IntervalsSet(4, 5, TEST_TOLERANCE);
-        SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
+    	// arrange
+    	OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
+    	IntervalsSet interval = new IntervalsSet(TEST_TOLERANCE);
+    	SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
 
-        OrientedPoint splitter = new OrientedPoint(new Cartesian1D(0), true, TEST_TOLERANCE);
+    	OrientedPoint splitter = new OrientedPoint(new Cartesian1D(0), true, TEST_TOLERANCE);
 
-        // act
-        SplitSubHyperplane<Euclidean1D> split = pt.split(splitter);
+    	// act
+    	SplitSubHyperplane<Euclidean1D> split = pt.split(splitter);
 
-        // assert
-        Assert.assertEquals(Side.PLUS, split.getSide());
+    	// assert
+    	Assert.assertEquals(Side.PLUS, split.getSide());
 
-        Assert.assertNull(split.getMinus());
+    	Assert.assertNull(split.getMinus());
 
-        SubOrientedPoint plusSub = ((SubOrientedPoint) split.getPlus());
-        Assert.assertNotNull(plusSub);
+    	SubOrientedPoint plusSub = ((SubOrientedPoint) split.getPlus());
+    	Assert.assertNotNull(plusSub);
 
-        OrientedPoint plusHyper = (OrientedPoint) plusSub.getHyperplane();
-        Assert.assertEquals(1, plusHyper.getLocation().getX(), TEST_TOLERANCE);
+    	OrientedPoint plusHyper = (OrientedPoint) plusSub.getHyperplane();
+    	Assert.assertEquals(1, plusHyper.getLocation().getX(), TEST_TOLERANCE);
 
-        List<Interval> plusIntervals = ((IntervalsSet) plusSub.getRemainingRegion()).asList();
-        Assert.assertEquals(1, plusIntervals.size());
-        Assert.assertEquals(4, plusIntervals.get(0).getInf(), TEST_TOLERANCE);
-        Assert.assertEquals(5, plusIntervals.get(0).getSup(), TEST_TOLERANCE);
+    	Assert.assertSame(interval, plusSub.getRemainingRegion());
     }
 
     @Test
     public void testSplit_equivalentHyperplanes() {
-        // arrange
-        OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
-        IntervalsSet interval = new IntervalsSet(4, 5, TEST_TOLERANCE);
-        SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
+    	// arrange
+    	OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
+    	IntervalsSet interval = new IntervalsSet(TEST_TOLERANCE);
+    	SubOrientedPoint pt = new SubOrientedPoint(hyperplane, interval);
 
-        OrientedPoint splitter = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
+    	OrientedPoint splitter = new OrientedPoint(new Cartesian1D(1), true, TEST_TOLERANCE);
 
-        // act
-        SplitSubHyperplane<Euclidean1D> split = pt.split(splitter);
+    	// act
+    	SplitSubHyperplane<Euclidean1D> split = pt.split(splitter);
 
-        // assert
-        Assert.assertEquals(Side.HYPER, split.getSide());
+    	// assert
+    	Assert.assertEquals(Side.HYPER, split.getSide());
 
-        Assert.assertNull(split.getMinus());
-        Assert.assertNull(split.getPlus());
+    	Assert.assertNull(split.getMinus());
+    	Assert.assertNull(split.getPlus());
     }
 
     @Test
     public void testSplit_usesToleranceFromParentHyperplane() {
         // arrange
         OrientedPoint hyperplane = new OrientedPoint(new Cartesian1D(1), true, 0.1);
-        SubOrientedPoint pt = (SubOrientedPoint) hyperplane.wholeHyperplane();
+        SubOrientedPoint pt = hyperplane.wholeHyperplane();
 
         // act/assert
         SplitSubHyperplane<Euclidean1D> plusSplit = pt.split(new OrientedPoint(new Cartesian1D(0.899), true, 1e-10));

http://git-wip-us.apache.org/repos/asf/commons-math/blob/24d3dd8b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/OBJWriter.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/OBJWriter.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/OBJWriter.java
new file mode 100644
index 0000000..4d13f0b
--- /dev/null
+++ b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/OBJWriter.java
@@ -0,0 +1,337 @@
+/*
+ * 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.math4.geometry.euclidean.threed;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.file.Files;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
+import org.apache.commons.math4.geometry.euclidean.twod.Euclidean2D;
+import org.apache.commons.math4.geometry.euclidean.twod.PolygonsSet;
+import org.apache.commons.math4.geometry.partitioning.BSPTree;
+import org.apache.commons.math4.geometry.partitioning.BSPTreeVisitor;
+import org.apache.commons.math4.geometry.partitioning.BoundaryAttribute;
+
+/** This class creates simple OBJ files from {@link PolyhedronsSet} instances.
+ * The output files can be opened in a 3D viewer for visual debugging of 3D
+ * regions. This class is only intended for use in testing.
+ *
+ * @see https://en.wikipedia.org/wiki/Wavefront_.obj_file
+ * @since 4.0
+ */
+public class OBJWriter {
+
+    /** Writes an OBJ file representing the given {@link PolyhedronsSet}. Only
+     * finite boundaries are written. Infinite boundaries are ignored.
+     * @param file The path of the file to write
+     * @param poly The input PolyhedronsSet
+     * @throws IOException
+     */
+    public static void write(String file, PolyhedronsSet poly) throws IOException {
+        write(new File(file), poly);
+    }
+
+    /** Writes an OBJ file representing the given {@link PolyhedronsSet}. Only
+     * finite boundaries are written. Infinite boundaries are ignored.
+     * @param file The file to write
+     * @param poly The input PolyhedronsSet
+     * @throws IOException
+     */
+    public static void write(File file, PolyhedronsSet poly) throws IOException {
+        // get the vertices and faces
+        MeshBuilder meshBuilder = new MeshBuilder(poly.getTolerance());
+        poly.getTree(true).visit(meshBuilder);
+
+        // write them to the file
+        try (Writer writer = Files.newBufferedWriter(file.toPath())) {
+            writer.write("# Generated by " + OBJWriter.class.getName() + " on " + new Date() + "\n");
+            writeVertices(writer, meshBuilder.getVertices());
+            writeFaces(writer, meshBuilder.getFaces());
+        }
+    }
+
+    /** Writes the given list of vertices to the file in the OBJ format.
+     * @param writer
+     * @param vertices
+     * @throws IOException
+     */
+    private static void writeVertices(Writer writer, List<Cartesian3D> vertices) throws IOException {
+        DecimalFormat df = new DecimalFormat("0.######");
+
+        for (Cartesian3D v : vertices) {
+            writer.write("v ");
+            writer.write(df.format(v.getX()));
+            writer.write(" ");
+            writer.write(df.format(v.getY()));
+            writer.write(" ");
+            writer.write(df.format(v.getZ()));
+            writer.write("\n");
+        }
+    }
+
+    /** Writes the given list of face vertex indices to the file in the OBJ format. The indices
+     * are expected to be 0-based and are converted to the 1-based format used by OBJ.
+     * @param writer
+     * @param faces
+     * @throws IOException
+     */
+    private static void writeFaces(Writer writer, List<int[]> faces) throws IOException {
+        for (int[] face : faces) {
+            writer.write("f ");
+            for (int idx : face) {
+                writer.write(String.valueOf(idx + 1)); // obj indices are 1-based
+                writer.write(" ");
+            }
+            writer.write("\n");
+        }
+    }
+
+    /** Class used to impose a strict sorting on 3D vertices.
+     * If all of the components of two vertices are within tolerance of each
+     * other, then the vertices are considered equal. This helps to avoid
+     * writing duplicate vertices in the OBJ output.
+     */
+    private static class VertexComparator implements Comparator<Cartesian3D> {
+
+        /** Geometric tolerance value */
+        private double tolerance;
+
+        /** Creates a new instance with the given tolerance value.
+         * @param tolerance
+         */
+        public VertexComparator(double tolerance) {
+            this.tolerance = tolerance;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public int compare(Cartesian3D a, Cartesian3D b) {
+            int result = compareDoubles(a.getX(), b.getX());
+            if (result == 0) {
+                result = compareDoubles(a.getY(), b.getY());
+                if (result == 0) {
+                    result = compareDoubles(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
+     * and face vertex indices.
+     */
+    private static class MeshBuilder implements BSPTreeVisitor<Euclidean3D> {
+
+        /** Geometric tolerance */
+        private final double tolerance;
+
+        /** Map of vertices to their index in the vertices list */
+        private Map<Cartesian3D, Integer> vertexIndexMap;
+
+        /** List of unique vertices in the BSPTree boundary */
+        private List<Cartesian3D> vertices;
+
+        /**
+         * List of face vertex indices. Each face will have 3 indices. Indices
+         * are 0-based.
+         * */
+        private List<int[]> faces;
+
+        /** Creates a new instance with the given tolerance.
+         * @param tolerance
+         */
+        public MeshBuilder(double tolerance) {
+            this.tolerance = tolerance;
+            this.vertexIndexMap = new TreeMap<>(new VertexComparator(tolerance));
+            this.vertices = new ArrayList<>();
+            this.faces = new ArrayList<>();
+        }
+
+        /** Returns the list of unique vertices found in the BSPTree.
+         * @return
+         */
+        public List<Cartesian3D> getVertices() {
+            return vertices;
+        }
+
+        /** Returns the list of 0-based face vertex indices for the BSPTree. Each face is
+         * a triangle with 3 indices.
+         * @return
+         */
+        public List<int[]> getFaces() {
+            return faces;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public Order visitOrder(BSPTree<Euclidean3D> node) {
+            return Order.SUB_MINUS_PLUS;
+        }
+
+        /** {@inheritDoc} */
+        @SuppressWarnings("unchecked")
+        @Override
+        public void visitInternalNode(BSPTree<Euclidean3D> node) {
+            BoundaryAttribute<Euclidean3D> attr = (BoundaryAttribute<Euclidean3D>) node.getAttribute();
+
+            if (attr.getPlusOutside() != null) {
+                addBoundary((SubPlane) attr.getPlusOutside());
+            }
+            else if (attr.getPlusInside() != null) {
+                addBoundary((SubPlane) attr.getPlusInside());
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitLeafNode(BSPTree<Euclidean3D> node) {
+            // do nothing
+        }
+
+        /** Adds the region boundary defined by the given {@link SubPlane}
+         * to the mesh.
+         * @param subplane
+         */
+        private void addBoundary(SubPlane subplane) {
+            Plane plane = (Plane) subplane.getHyperplane();
+            PolygonsSet poly = (PolygonsSet) subplane.getRemainingRegion();
+
+            TriangleExtractor triExtractor = new TriangleExtractor(tolerance);
+            poly.getTree(true).visit(triExtractor);
+
+            Cartesian3D v1, v2, v3;
+            for (Cartesian2D[] tri : triExtractor.getTriangles()) {
+                v1 = plane.toSpace(tri[0]);
+                v2 = plane.toSpace(tri[1]);
+                v3 = plane.toSpace(tri[2]);
+
+                faces.add(new int[] {
+                        getVertexIndex(v1),
+                        getVertexIndex(v2),
+                        getVertexIndex(v3)
+                });
+            }
+        }
+
+        /** Returns the 0-based index of the given vertex in the <code>vertices</code>
+         * list. If the vertex has not been encountered before, it is added
+         * to the list.
+         * @param vertex
+         * @return
+         */
+        private int getVertexIndex(Cartesian3D vertex) {
+            Integer idx = vertexIndexMap.get(vertex);
+            if (idx == null) {
+                idx = vertices.size();
+
+                vertices.add(vertex);
+                vertexIndexMap.put(vertex, idx);
+            }
+            return idx.intValue();
+        }
+    }
+
+    /** Visitor for extracting a collection of triangles from a 2D BSPTree.
+     */
+    private static class TriangleExtractor implements BSPTreeVisitor<Euclidean2D> {
+
+        /** Geometric tolerance */
+        private double tolerance;
+
+        /** List of extracted triangles */
+        private List<Cartesian2D[]> triangles = new ArrayList<>();
+
+        /** Creates a new instance with the given geometric tolerance.
+         * @param tolerance
+         */
+        public TriangleExtractor(double tolerance) {
+            this.tolerance = tolerance;
+        }
+
+        /** Returns the list of extracted triangles.
+         * @return
+         */
+        public List<Cartesian2D[]> getTriangles() {
+            return triangles;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public Order visitOrder(BSPTree<Euclidean2D> node) {
+            return Order.SUB_MINUS_PLUS;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitInternalNode(BSPTree<Euclidean2D> node) {
+            // do nothing
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitLeafNode(BSPTree<Euclidean2D> node) {
+            if ((Boolean) node.getAttribute()) {
+                PolygonsSet convexPoly = new PolygonsSet(node.pruneAroundConvexCell(Boolean.TRUE,
+                        Boolean.FALSE, null), tolerance);
+
+                for (Cartesian2D[] loop : convexPoly.getVertices()) {
+                    if (loop.length > 0 && loop[0] != null) { // skip unclosed loops
+                        addTriangles(loop);
+                    }
+                }
+            }
+        }
+
+        /** Splits the 2D convex area defined by the given vertices into
+         * triangles and adds them to the internal list.
+         * @param vertices
+         */
+        private void addTriangles(Cartesian2D[] vertices) {
+            // use a triangle fan to add the convex region
+            for (int i=2; i<vertices.length; ++i) {
+                triangles.add(new Cartesian2D[] { vertices[0], vertices[i-1], vertices[i] });
+            }
+        }
+    }
+}


[5/7] [math] MATH-1437: adding additional unit tests and test utilities for o.a.c.m.geometry.euclidean.twod and o.a.c.m.geometry.euclidean.threed

Posted by er...@apache.org.
MATH-1437: adding additional unit tests and test utilities for o.a.c.m.geometry.euclidean.twod and o.a.c.m.geometry.euclidean.threed


Project: http://git-wip-us.apache.org/repos/asf/commons-math/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-math/commit/24d3dd8b
Tree: http://git-wip-us.apache.org/repos/asf/commons-math/tree/24d3dd8b
Diff: http://git-wip-us.apache.org/repos/asf/commons-math/diff/24d3dd8b

Branch: refs/heads/master
Commit: 24d3dd8ba7032bc4590b82a99ff37713fb3cc5bb
Parents: 1b99b45
Author: darkma773r <ma...@hotmail.com>
Authored: Thu Jan 25 22:41:43 2018 -0500
Committer: darkma773r <ma...@hotmail.com>
Committed: Thu Jan 25 22:41:43 2018 -0500

----------------------------------------------------------------------
 .../euclidean/threed/PolyhedronsSet.java        |    2 +-
 .../math4/geometry/GeometryTestUtils.java       |  324 +++++
 .../euclidean/oned/Cartesian1DTest.java         |  366 ++++--
 .../geometry/euclidean/oned/IntervalTest.java   |  158 ++-
 .../euclidean/oned/IntervalsSetTest.java        |  543 +++++++-
 .../euclidean/oned/OrientedPointTest.java       |  188 +++
 .../euclidean/oned/SubOrientedPointTest.java    |   98 +-
 .../geometry/euclidean/threed/OBJWriter.java    |  337 +++++
 .../euclidean/threed/PolyhedronsSetTest.java    | 1238 +++++++++++++++---
 9 files changed, 2881 insertions(+), 373 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-math/blob/24d3dd8b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/PolyhedronsSet.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/PolyhedronsSet.java b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/PolyhedronsSet.java
index ab27283..cfd9f7c 100644
--- a/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/PolyhedronsSet.java
+++ b/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/PolyhedronsSet.java
@@ -512,7 +512,7 @@ public class PolyhedronsSet extends AbstractRegion<Euclidean3D, Euclidean2D> {
         final Plane                plane = (Plane) cut.getHyperplane();
 
         // establish search order
-        final double offset = plane.getOffset((Point<Euclidean3D>) point);
+        final double offset = plane.getOffset(point);
         final boolean in    = FastMath.abs(offset) < getTolerance();
         final BSPTree<Euclidean3D> near;
         final BSPTree<Euclidean3D> far;

http://git-wip-us.apache.org/repos/asf/commons-math/blob/24d3dd8b/src/test/java/org/apache/commons/math4/geometry/GeometryTestUtils.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/math4/geometry/GeometryTestUtils.java b/src/test/java/org/apache/commons/math4/geometry/GeometryTestUtils.java
new file mode 100644
index 0000000..74f2beb
--- /dev/null
+++ b/src/test/java/org/apache/commons/math4/geometry/GeometryTestUtils.java
@@ -0,0 +1,324 @@
+/*
+ * 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.math4.geometry;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.math3.util.FastMath;
+import org.apache.commons.math4.geometry.euclidean.oned.Cartesian1D;
+import org.apache.commons.math4.geometry.euclidean.oned.Euclidean1D;
+import org.apache.commons.math4.geometry.euclidean.oned.IntervalsSet;
+import org.apache.commons.math4.geometry.euclidean.oned.OrientedPoint;
+import org.apache.commons.math4.geometry.euclidean.oned.SubOrientedPoint;
+import org.apache.commons.math4.geometry.euclidean.oned.Vector1D;
+import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
+import org.apache.commons.math4.geometry.euclidean.threed.Euclidean3D;
+import org.apache.commons.math4.geometry.euclidean.threed.Plane;
+import org.apache.commons.math4.geometry.euclidean.threed.SubPlane;
+import org.apache.commons.math4.geometry.euclidean.threed.Vector3D;
+import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
+import org.apache.commons.math4.geometry.euclidean.twod.Euclidean2D;
+import org.apache.commons.math4.geometry.euclidean.twod.Line;
+import org.apache.commons.math4.geometry.euclidean.twod.PolygonsSet;
+import org.apache.commons.math4.geometry.euclidean.twod.SubLine;
+import org.apache.commons.math4.geometry.euclidean.twod.Vector2D;
+import org.apache.commons.math4.geometry.partitioning.BSPTree;
+import org.apache.commons.math4.geometry.partitioning.BSPTreeVisitor;
+import org.junit.Assert;
+
+/** Class containing various geometry-related test utilities.
+ * @since 4.0
+ */
+public class GeometryTestUtils {
+
+    /** Asserts that corresponding values in the given vectors are equal, using the specified
+     * tolerance value.
+     * @param expected
+     * @param actual
+     * @param tolerance
+     */
+    public static void assertVectorEquals(Vector1D expected, Vector1D actual, double tolerance) {
+        String msg = "Expected vector to equal " + expected + " but was " + actual + ";";
+        Assert.assertEquals(msg, expected.getX(), actual.getX(), tolerance);
+    }
+
+    /** Asserts that corresponding values in the given vectors are equal, using the specified
+     * tolerance value.
+     * @param expected
+     * @param actual
+     * @param tolerance
+     */
+    public static void assertVectorEquals(Vector2D expected, Vector2D actual, double tolerance) {
+        String msg = "Expected vector to equal " + expected + " but was " + actual + ";";
+        Assert.assertEquals(msg, expected.getX(), actual.getX(), tolerance);
+        Assert.assertEquals(msg, expected.getY(), actual.getY(), tolerance);
+    }
+
+    /** Asserts that corresponding values in the given vectors are equal, using the specified
+     * tolerance value.
+     * @param expected
+     * @param actual
+     * @param tolerance
+     */
+    public static void assertVectorEquals(Vector3D expected, Vector3D actual, double tolerance) {
+        String msg = "Expected vector to equal " + expected + " but was " + actual + ";";
+        Assert.assertEquals(msg, expected.getX(), actual.getX(), tolerance);
+        Assert.assertEquals(msg, expected.getY(), actual.getY(), tolerance);
+        Assert.assertEquals(msg, expected.getZ(), actual.getZ(), tolerance);
+    }
+
+    /** Prints a string representation of the given 1D {@link BSPTree} to
+     * the console. This is intended for quick debugging of small trees.
+     * @param tree
+     */
+    public static void printTree1D(BSPTree<Euclidean1D> tree) {
+        TreePrinter1D printer = new TreePrinter1D();
+        System.out.println(printer.writeAsString(tree));
+    }
+
+    /** Prints a string representation of the given 2D {@link BSPTree} to
+     * the console. This is intended for quick debugging of small trees.
+     * @param tree
+     */
+    public static void printTree2D(BSPTree<Euclidean2D> tree) {
+        TreePrinter2D printer = new TreePrinter2D();
+        System.out.println(printer.writeAsString(tree));
+    }
+
+    /** Prints a string representation of the given 3D {@link BSPTree} to
+     * the console. This is intended for quick debugging of small trees.
+     * @param tree
+     */
+    public static void printTree3D(BSPTree<Euclidean3D> tree) {
+        TreePrinter3D printer = new TreePrinter3D();
+        System.out.println(printer.writeAsString(tree));
+    }
+
+    /**
+     * Base for classes that create string representations of {@link BSPTree}s.
+     * @param <S>
+     */
+    public static abstract class TreePrinter<S extends Space> implements BSPTreeVisitor<S> {
+
+        /** Indent per tree level */
+        protected static final String INDENT = "    ";
+
+        /** Current depth in the tree */
+        protected int depth;
+
+        /** Contains the string output */
+        protected StringBuilder output = new StringBuilder();
+
+        /** Returns a string representation of the given {@link BSPTree}.
+         * @param tree
+         * @return
+         */
+        public String writeAsString(BSPTree<S> tree) {
+            output.delete(0, output.length());
+
+            tree.visit(this);
+
+            return output.toString();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public Order visitOrder(BSPTree<S> node) {
+            return Order.SUB_MINUS_PLUS;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitInternalNode(BSPTree<S> node) {
+            writeLinePrefix(node);
+            writeInternalNode(node);
+
+            write("\n");
+
+            ++depth;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitLeafNode(BSPTree<S> node) {
+            writeLinePrefix(node);
+            writeLeafNode(node);
+
+            write("\n");
+
+            BSPTree<S> cur = node;
+            while (cur.getParent() != null && cur.getParent().getPlus() == cur) {
+                --depth;
+                cur = cur.getParent();
+            }
+        }
+
+        /** Writes the prefix for the current line in the output. This includes
+         * the line indent, the plus/minus node indicator, and a string identifier
+         * for the node itself.
+         * @param node
+         */
+        protected void writeLinePrefix(BSPTree<S> node) {
+            for (int i=0; i<depth; ++i) {
+                write(INDENT);
+            }
+
+            if (node.getParent() != null) {
+                if (node.getParent().getMinus() == node) {
+                    write("[-] ");
+                }
+                else {
+                    write("[+] ");
+                }
+            }
+
+            write(node.getClass().getSimpleName() + "@" + System.identityHashCode(node) + " | ");
+        }
+
+        /** Adds the given string to the output.
+         * @param str
+         */
+        protected void write(String str) {
+            output.append(str);
+        }
+
+        /** Method for subclasses to provide their own string representation
+         * of the given internal node.
+         */
+        protected abstract void writeInternalNode(BSPTree<S> node);
+
+        /** Writes a leaf node. The default implementation here simply writes
+         * the node attribute as a string.
+         * @param node
+         */
+        protected void writeLeafNode(BSPTree<S> node) {
+            write(String.valueOf(node.getAttribute()));
+        }
+    }
+
+    /** Class for creating string representations of 1D {@link BSPTree}s.
+     */
+    public static class TreePrinter1D extends TreePrinter<Euclidean1D> {
+
+        /** {@inheritDoc} */
+        @Override
+        protected void writeInternalNode(BSPTree<Euclidean1D> node) {
+            SubOrientedPoint cut = (SubOrientedPoint) node.getCut();
+
+            OrientedPoint hyper = (OrientedPoint) cut.getHyperplane();
+            write("cut = { hyperplane: ");
+            if (hyper.isDirect()) {
+                write("[" + hyper.getLocation().getX() + ", inf)");
+            }
+            else {
+                write("(-inf, " + hyper.getLocation().getX() + "]");
+            }
+
+            IntervalsSet remainingRegion = (IntervalsSet) cut.getRemainingRegion();
+            if (remainingRegion != null) {
+                write(", remainingRegion: [");
+
+                boolean isFirst = true;
+                for (double[] interval : remainingRegion) {
+                    if (isFirst) {
+                        isFirst = false;
+                    }
+                    else {
+                        write(", ");
+                    }
+                    write(Arrays.toString(interval));
+                }
+
+                write("]");
+            }
+
+            write("}");
+        }
+    }
+
+    /** Class for creating string representations of 2D {@link BSPTree}s.
+     */
+    public static class TreePrinter2D extends TreePrinter<Euclidean2D> {
+
+        /** {@inheritDoc} */
+        @Override
+        protected void writeInternalNode(BSPTree<Euclidean2D> node) {
+            SubLine cut = (SubLine) node.getCut();
+            Line line = (Line) cut.getHyperplane();
+            IntervalsSet remainingRegion = (IntervalsSet) cut.getRemainingRegion();
+
+            write("cut = { angle: " + FastMath.toDegrees(line.getAngle()) + ", origin: " + line.toSpace(Cartesian1D.ZERO) + "}");
+            write(", remainingRegion: [");
+
+            boolean isFirst = true;
+            for (double[] interval : remainingRegion) {
+                if (isFirst) {
+                    isFirst = false;
+                }
+                else {
+                    write(", ");
+                }
+                write(Arrays.toString(interval));
+            }
+
+            write("]");
+        }
+    }
+
+    /** Class for creating string representations of 3D {@link BSPTree}s.
+     */
+    public static class TreePrinter3D extends TreePrinter<Euclidean3D> {
+
+        /** {@inheritDoc} */
+        @Override
+        protected void writeInternalNode(BSPTree<Euclidean3D> node) {
+            SubPlane cut = (SubPlane) node.getCut();
+            Plane plane = (Plane) cut.getHyperplane();
+            PolygonsSet polygon = (PolygonsSet) cut.getRemainingRegion();
+
+            write("cut = { normal: " + plane.getNormal() + ", origin: " + plane.getOrigin() + "}");
+            write(", remainingRegion = [");
+
+            boolean isFirst = true;
+            for (Cartesian2D[] loop : polygon.getVertices()) {
+                // convert to 3-space for easier debugging
+                List<Cartesian3D> loop3 = new ArrayList<>();
+                for (Cartesian2D vertex : loop) {
+                    if (vertex != null) {
+                        loop3.add(plane.toSpace(vertex));
+                    }
+                    else {
+                        loop3.add(null);
+                    }
+                }
+
+                if (isFirst) {
+                    isFirst = false;
+                }
+                else {
+                    write(", ");
+                }
+
+                write(loop3.toString());
+            }
+
+            write("]");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-math/blob/24d3dd8b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/Cartesian1DTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/Cartesian1DTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/Cartesian1DTest.java
index a01c9ef..ebac525 100644
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/Cartesian1DTest.java
+++ b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/Cartesian1DTest.java
@@ -22,198 +22,366 @@ import java.text.DecimalFormatSymbols;
 import java.text.NumberFormat;
 import java.util.Locale;
 
-import org.apache.commons.math4.exception.DimensionMismatchException;
 import org.apache.commons.math4.exception.MathArithmeticException;
+import org.apache.commons.math4.geometry.Point;
 import org.apache.commons.math4.geometry.Space;
+import org.apache.commons.math4.geometry.Vector;
 import org.apache.commons.math4.util.FastMath;
 import org.apache.commons.numbers.core.Precision;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class Cartesian1DTest {
+
+    private static final double TEST_TOLERANCE = 1e-15;
+
+    @Test
+    public void testConstants() {
+        // act/assert
+        checkVector(Cartesian1D.ZERO, 0.0);
+        checkVector(Cartesian1D.ONE, 1.0);
+        checkVector(Cartesian1D.NaN, Double.NaN);
+        checkVector(Cartesian1D.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
+        checkVector(Cartesian1D.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testConstructor_simple() {
+        // act/assert
+        checkVector(new Cartesian1D(2), 2);
+        checkVector(new Cartesian1D(-2), -2);
+        checkVector(new Cartesian1D(FastMath.PI), FastMath.PI);
+    }
+
+    @Test
+    public void testConstructor_multiplicative() {
+        // act/assert
+        checkVector(new Cartesian1D(2, new Cartesian1D(3)), 6);
+        checkVector(new Cartesian1D(-2, new Cartesian1D(3)), -6);
+    }
+
+    @Test
+    public void testConstructor_linear2() {
+        // act/assert
+        checkVector(new Cartesian1D(
+                2, new Cartesian1D(3),
+                5, new Cartesian1D(7)), 41);
+        checkVector(new Cartesian1D(
+                2, new Cartesian1D(3),
+                -5, new Cartesian1D(7)),-29);
+    }
+
+    @Test
+    public void testConstructor_linear3() {
+        // act/assert
+        checkVector(new Cartesian1D(
+                2, new Cartesian1D(3),
+                5, new Cartesian1D(7),
+                11, new Cartesian1D(13)), 184);
+        checkVector(new Cartesian1D(
+                2, new Cartesian1D(3),
+                5, new Cartesian1D(7),
+                -11, new Cartesian1D(13)), -102);
+    }
+
     @Test
-    public void testConstructors() throws DimensionMismatchException {
-        checkVector(new Cartesian1D(3, new Cartesian1D(FastMath.PI / 3)),
-                    FastMath.PI);
-        checkVector(new Cartesian1D(2, Cartesian1D.ONE, -3, new Cartesian1D(2)),
-                    -4);
-        checkVector(new Cartesian1D(2, Cartesian1D.ONE,
-                                 5, new Cartesian1D(2),
-                                 -3, new Cartesian1D(3)),
-                    3);
-        checkVector(new Cartesian1D(2, Cartesian1D.ONE,
-                                 5, new Cartesian1D(2),
-                                 5, new Cartesian1D(-2),
-                                 -3, new Cartesian1D(-3)),
-                    11);
+    public void testConstructor_linear4() {
+        // act/assert
+        checkVector(new Cartesian1D(
+                2, new Cartesian1D(3),
+                5, new Cartesian1D(7),
+                11, new Cartesian1D(13),
+                17, new Cartesian1D(19)), 507);
+        checkVector(new Cartesian1D(
+                2, new Cartesian1D(3),
+                5, new Cartesian1D(7),
+                11, new Cartesian1D(13),
+                -17, new Cartesian1D(19)), -139);
     }
 
     @Test
     public void testSpace() {
+        // act
         Space space = new Cartesian1D(1).getSpace();
+
+        // assert
         Assert.assertEquals(1, space.getDimension());
     }
 
     @Test
     public void testZero() {
-        Assert.assertEquals(0, new Cartesian1D(1).getZero().getNorm(), 1.0e-15);
+        // act
+        Cartesian1D zero = new Cartesian1D(1).getZero();
+
+        // assert
+        Assert.assertEquals(0, zero.getX(), TEST_TOLERANCE);
     }
 
     @Test
-    public void testEquals() {
-        Cartesian1D u1 = new Cartesian1D(1);
-        Cartesian1D u2 = new Cartesian1D(1);
-        Assert.assertTrue(u1.equals(u1));
-        Assert.assertTrue(u1.equals(u2));
-        Assert.assertFalse(u1.equals(new Cartesian1D(1 + 10 * Precision.EPSILON)));
-        Assert.assertTrue(new Cartesian1D(Double.NaN).equals(new Cartesian1D(Double.NaN)));
+    public void testNorm1() {
+        // act/assert
+        Assert.assertEquals(0.0, Cartesian1D.ZERO.getNorm1(), TEST_TOLERANCE);
+        Assert.assertEquals(6.0, new Cartesian1D(6).getNorm1(), TEST_TOLERANCE);
+        Assert.assertEquals(6.0, new Cartesian1D(-6).getNorm1(), TEST_TOLERANCE);
     }
 
     @Test
-    public void testHash() {
-        Assert.assertEquals(new Cartesian1D(Double.NaN).hashCode(), new Cartesian1D(Double.NaN).hashCode());
-        Cartesian1D u = new Cartesian1D(1);
-        Cartesian1D v = new Cartesian1D(1 + 10 * Precision.EPSILON);
-        Assert.assertTrue(u.hashCode() != v.hashCode());
+    public void testNorm() {
+        // act/assert
+        Assert.assertEquals(0.0, Cartesian1D.ZERO.getNorm(), TEST_TOLERANCE);
+        Assert.assertEquals(3.0, new Cartesian1D(3).getNorm(), TEST_TOLERANCE);
+        Assert.assertEquals(3.0, new Cartesian1D(-3).getNorm(), TEST_TOLERANCE);
     }
 
     @Test
-    public void testInfinite() {
-        Assert.assertTrue(new Cartesian1D(Double.NEGATIVE_INFINITY).isInfinite());
-        Assert.assertTrue(new Cartesian1D(Double.POSITIVE_INFINITY).isInfinite());
-        Assert.assertFalse(new Cartesian1D(1).isInfinite());
-        Assert.assertFalse(new Cartesian1D(Double.NaN).isInfinite());
+    public void testNormSq() {
+        // act/assert
+        Assert.assertEquals(0.0, new Cartesian1D(0).getNormSq(), TEST_TOLERANCE);
+        Assert.assertEquals(9.0, new Cartesian1D(3).getNormSq(), TEST_TOLERANCE);
+        Assert.assertEquals(9.0, new Cartesian1D(-3).getNormSq(), TEST_TOLERANCE);
     }
 
     @Test
-    public void testNaN() {
-        Assert.assertTrue(new Cartesian1D(Double.NaN).isNaN());
-        Assert.assertFalse(new Cartesian1D(1).isNaN());
-        Assert.assertFalse(new Cartesian1D(Double.NEGATIVE_INFINITY).isNaN());
+    public void testNormInf() {
+        // act/assert
+        Assert.assertEquals(0.0, Cartesian1D.ZERO.getNormInf(), TEST_TOLERANCE);
+        Assert.assertEquals(3.0, new Cartesian1D(3).getNormInf(), TEST_TOLERANCE);
+        Assert.assertEquals(3.0, new Cartesian1D(-3).getNormInf(), TEST_TOLERANCE);
     }
 
     @Test
-    public void testToString() {
-        Assert.assertEquals("{3}", new Cartesian1D(3).toString());
-        NumberFormat format = new DecimalFormat("0.000", new DecimalFormatSymbols(Locale.US));
-        Assert.assertEquals("{3.000}", new Cartesian1D(3).toString(format));
+    public void testAdd() {
+        // arrange
+        Cartesian1D v1 = new Cartesian1D(1);
+        Cartesian1D v2 = new Cartesian1D(-3);
+
+        // act/assert
+        v1 = v1.add(v2);
+        checkVector(v1, -2);
+
+        checkVector(v2.add(v1), -5);
+        checkVector(v2.add(3, v1), -9);
     }
 
     @Test
-    public void testCoordinates() {
-        Cartesian1D v = new Cartesian1D(1);
-        Assert.assertTrue(FastMath.abs(v.getX() - 1) < 1.0e-12);
+    public void testSubtract() {
+        // arrange
+        Cartesian1D v1 = new Cartesian1D(1);
+        Cartesian1D v2 = new Cartesian1D(-3);
+
+        // act/assert
+        v1 = v1.subtract(v2);
+        checkVector(v1, 4);
+
+        checkVector(v2.subtract(v1), -7);
+        checkVector(v2.subtract(3, v1), -15);
     }
 
     @Test
-    public void testNorm1() {
-        Assert.assertEquals(0.0, Cartesian1D.ZERO.getNorm1(), 0);
-        Assert.assertEquals(6.0, new Cartesian1D(6).getNorm1(), 0);
+    public void testNormalize() {
+        // act/assert
+        checkVector(new Cartesian1D(1).normalize(), 1);
+        checkVector(new Cartesian1D(-1).normalize(), -1);
+        checkVector(new Cartesian1D(5).normalize(), 1);
+        checkVector(new Cartesian1D(-5).normalize(), -1);
+    }
+
+    @Test(expected = MathArithmeticException.class)
+    public void testNormalize_zeroNorm() {
+        // act
+        Cartesian1D.ZERO.normalize();
     }
 
     @Test
-    public void testNorm() {
-        Assert.assertEquals(0.0, Cartesian1D.ZERO.getNorm(), 0);
-        Assert.assertEquals(3.0, new Cartesian1D(-3).getNorm(), 1.0e-12);
+    public void testNegate() {
+        // act/assert
+        checkVector(new Cartesian1D(0.1).negate(), -0.1);
+        checkVector(new Cartesian1D(-0.1).negate(), 0.1);
     }
 
     @Test
-    public void testNormSq() {
-        Assert.assertEquals(0.0, new Cartesian1D(0).getNormSq(), 0);
-        Assert.assertEquals(9.0, new Cartesian1D(-3).getNormSq(), 1.0e-12);
+    public void testScalarMultiply() {
+        // act/assert
+        checkVector(new Cartesian1D(1).scalarMultiply(3), 3);
+        checkVector(new Cartesian1D(1).scalarMultiply(-3), -3);
+
+        checkVector(new Cartesian1D(1.5).scalarMultiply(7), 10.5);
+        checkVector(new Cartesian1D(-1.5).scalarMultiply(7), -10.5);
     }
 
     @Test
-    public void testNormInf() {
-        Assert.assertEquals(0.0, Cartesian1D.ZERO.getNormInf(), 0);
-        Assert.assertEquals(3.0, new Cartesian1D(-3).getNormInf(), 0);
+    public void testNaN() {
+        // act/assert
+        Assert.assertTrue(new Cartesian1D(Double.NaN).isNaN());
+        Assert.assertFalse(new Cartesian1D(1).isNaN());
+        Assert.assertFalse(new Cartesian1D(Double.NEGATIVE_INFINITY).isNaN());
+    }
+
+    @Test
+    public void testInfinite() {
+        // act/assert
+        Assert.assertTrue(new Cartesian1D(Double.NEGATIVE_INFINITY).isInfinite());
+        Assert.assertTrue(new Cartesian1D(Double.POSITIVE_INFINITY).isInfinite());
+        Assert.assertFalse(new Cartesian1D(1).isInfinite());
+        Assert.assertFalse(new Cartesian1D(Double.NaN).isInfinite());
     }
 
     @Test
     public void testDistance1() {
+        // arrange
         Cartesian1D v1 = new Cartesian1D(1);
         Cartesian1D v2 = new Cartesian1D(-4);
-        Assert.assertEquals(0.0, new Cartesian1D(-1).distance1(new Cartesian1D(-1)), 0);
-        Assert.assertEquals(5.0, v1.distance1(v2), 1.0e-12);
-        Assert.assertEquals(v1.subtract(v2).getNorm1(), v1.distance1(v2), 1.0e-12);
+
+        // act/assert
+        Assert.assertEquals(0.0, v1.distance1(v1), TEST_TOLERANCE);
+
+        Assert.assertEquals(5.0, v1.distance1(v2), TEST_TOLERANCE);
+        Assert.assertEquals(v1.subtract(v2).getNorm1(), v1.distance1(v2), TEST_TOLERANCE);
+
+        Assert.assertEquals(0.0, new Cartesian1D(-1).distance1(new Cartesian1D(-1)), TEST_TOLERANCE);
     }
 
     @Test
     public void testDistance() {
+        // arrange
         Cartesian1D v1 = new Cartesian1D(1);
         Cartesian1D v2 = new Cartesian1D(-4);
-        Assert.assertEquals(0.0, Cartesian1D.distance(new Cartesian1D(-1), new Cartesian1D(-1)), 0);
-        Assert.assertEquals(5.0, Cartesian1D.distance(v1, v2), 1.0e-12);
-        Assert.assertEquals(v1.subtract(v2).getNorm(), Cartesian1D.distance(v1, v2), 1.0e-12);
+
+        // act/assert
+        Assert.assertEquals(0.0, v1.distance(v1), TEST_TOLERANCE);
+
+        Assert.assertEquals(5.0, v1.distance(v2), TEST_TOLERANCE);
+        Assert.assertEquals(5.0, v1.distance((Point<Euclidean1D>) v2), TEST_TOLERANCE);
+        Assert.assertEquals(5.0, v1.distance((Vector<Euclidean1D>) v2), TEST_TOLERANCE);
+        Assert.assertEquals(v1.subtract(v2).getNorm(), v1.distance(v2), TEST_TOLERANCE);
+
+        Assert.assertEquals(0.0, new Cartesian1D(-1).distance(new Cartesian1D(-1)), TEST_TOLERANCE);
     }
 
     @Test
-    public void testDistanceSq() {
+    public void testDistance_static() {
+        // arrange
         Cartesian1D v1 = new Cartesian1D(1);
         Cartesian1D v2 = new Cartesian1D(-4);
-        Assert.assertEquals(0.0, Cartesian1D.distanceSq(new Cartesian1D(-1), new Cartesian1D(-1)), 0);
-        Assert.assertEquals(25.0, Cartesian1D.distanceSq(v1, v2), 1.0e-12);
-        Assert.assertEquals(Cartesian1D.distance(v1, v2) * Cartesian1D.distance(v1, v2),
-                            Cartesian1D.distanceSq(v1, v2), 1.0e-12);
-  }
+
+        // act/assert
+        Assert.assertEquals(0.0, Cartesian1D.distance(v1, v1), TEST_TOLERANCE);
+
+        Assert.assertEquals(5.0, Cartesian1D.distance(v1, v2), TEST_TOLERANCE);
+        Assert.assertEquals(v1.subtract(v2).getNorm(), Cartesian1D.distance(v1, v2), TEST_TOLERANCE);
+
+        Assert.assertEquals(0.0, Cartesian1D.distance(new Cartesian1D(-1), new Cartesian1D(-1)), TEST_TOLERANCE);
+    }
 
     @Test
     public void testDistanceInf() {
+        // arrange
         Cartesian1D v1 = new Cartesian1D(1);
         Cartesian1D v2 = new Cartesian1D(-4);
-        Assert.assertEquals(0.0, Cartesian1D.distanceInf(new Cartesian1D(-1), new Cartesian1D(-1)), 0);
-        Assert.assertEquals(5.0, Cartesian1D.distanceInf(v1, v2), 1.0e-12);
-        Assert.assertEquals(v1.subtract(v2).getNormInf(), Cartesian1D.distanceInf(v1, v2), 1.0e-12);
+
+        // act/assert
+        Assert.assertEquals(0.0, new Cartesian1D(-1).distanceInf(new Cartesian1D(-1)), TEST_TOLERANCE);
+        Assert.assertEquals(5.0, v1.distanceInf(v2), TEST_TOLERANCE);
+
+        Assert.assertEquals(v1.subtract(v2).getNormInf(), v1.distanceInf(v2), TEST_TOLERANCE);
     }
 
     @Test
-    public void testSubtract() {
+    public void testDistanceInf_static() {
+        // arrange
         Cartesian1D v1 = new Cartesian1D(1);
-        Cartesian1D v2 = new Cartesian1D(-3);
-        v1 = v1.subtract(v2);
-        checkVector(v1, 4);
+        Cartesian1D v2 = new Cartesian1D(-4);
 
-        checkVector(v2.subtract(v1), -7);
-        checkVector(v2.subtract(3, v1), -15);
+        // act/assert
+        Assert.assertEquals(0.0, Cartesian1D.distanceInf(new Cartesian1D(-1), new Cartesian1D(-1)), TEST_TOLERANCE);
+        Assert.assertEquals(5.0, Cartesian1D.distanceInf(v1, v2), TEST_TOLERANCE);
+
+        Assert.assertEquals(v1.subtract(v2).getNormInf(), Cartesian1D.distanceInf(v1, v2), TEST_TOLERANCE);
     }
 
     @Test
-    public void testAdd() {
+    public void testDistanceSq() {
+        // arrange
         Cartesian1D v1 = new Cartesian1D(1);
-        Cartesian1D v2 = new Cartesian1D(-3);
-        v1 = v1.add(v2);
-        checkVector(v1, -2);
+        Cartesian1D v2 = new Cartesian1D(-4);
 
-        checkVector(v2.add(v1), -5);
-        checkVector(v2.add(3, v1), -9);
+        // act/assert
+        Assert.assertEquals(0.0, new Cartesian1D(-1).distanceSq(new Cartesian1D(-1)), TEST_TOLERANCE);
+        Assert.assertEquals(25.0, v1.distanceSq(v2), TEST_TOLERANCE);
+
+        Assert.assertEquals(Cartesian1D.distance(v1, v2) * Cartesian1D.distance(v1, v2),
+                            v1.distanceSq(v2), TEST_TOLERANCE);
     }
 
     @Test
-    public void testScalarProduct() {
-        Cartesian1D v = new Cartesian1D(1);
-        v = v.scalarMultiply(3);
-        checkVector(v, 3);
+    public void testDistanceSq_static() {
+        // arrange
+        Cartesian1D v1 = new Cartesian1D(1);
+        Cartesian1D v2 = new Cartesian1D(-4);
+
+        // act/assert
+        Assert.assertEquals(0.0, Cartesian1D.distanceSq(new Cartesian1D(-1), new Cartesian1D(-1)), TEST_TOLERANCE);
+        Assert.assertEquals(25.0, Cartesian1D.distanceSq(v1, v2), TEST_TOLERANCE);
 
-        checkVector(v.scalarMultiply(0.5), 1.5);
+        Assert.assertEquals(Cartesian1D.distance(v1, v2) * Cartesian1D.distance(v1, v2),
+                            Cartesian1D.distanceSq(v1, v2), TEST_TOLERANCE);
     }
 
     @Test
-    public void testNormalize() throws MathArithmeticException {
-        Assert.assertEquals(1.0, new Cartesian1D(5).normalize().getNorm(), 1.0e-12);
-        try {
-            Cartesian1D.ZERO.normalize();
-            Assert.fail("an exception should have been thrown");
-        } catch (MathArithmeticException ae) {
-            // expected behavior
-        }
+    public void testDotProduct() {
+        // act/assert
+        Assert.assertEquals(6.0, new Cartesian1D(2).dotProduct(new Cartesian1D(3)), TEST_TOLERANCE);
+        Assert.assertEquals(-6.0, new Cartesian1D(2).dotProduct(new Cartesian1D(-3)), TEST_TOLERANCE);
     }
 
     @Test
-    public void testNegate() {
-        checkVector(new Cartesian1D(0.1).negate(), -0.1);
+    public void testEquals() {
+        // arrange
+        Cartesian1D u1 = new Cartesian1D(1);
+        Cartesian1D u2 = new Cartesian1D(1);
+
+        // act/assert
+        Assert.assertFalse(u1.equals(null));
+        Assert.assertFalse(u1.equals(new Object()));
+
+        Assert.assertTrue(u1.equals(u1));
+        Assert.assertTrue(u1.equals(u2));
+
+        Assert.assertFalse(u1.equals(new Cartesian1D(-1)));
+        Assert.assertFalse(u1.equals(new Cartesian1D(1 + 10 * Precision.EPSILON)));
+
+        Assert.assertTrue(new Cartesian1D(Double.NaN).equals(new Cartesian1D(Double.NaN)));
+    }
+
+    @Test
+    public void testHash() {
+        // arrange
+        Cartesian1D u = new Cartesian1D(1);
+        Cartesian1D v = new Cartesian1D(1 + 10 * Precision.EPSILON);
+
+        // act/assert
+        Assert.assertTrue(u.hashCode() != v.hashCode());
+        Assert.assertEquals(new Cartesian1D(Double.NaN).hashCode(), new Cartesian1D(Double.NaN).hashCode());
+    }
+
+    @Test
+    public void testToString() {
+        // act/assert
+        Assert.assertEquals("{3}", new Cartesian1D(3).toString());
+        Assert.assertEquals("{-3}", new Cartesian1D(-3).toString());
+    }
+
+    @Test
+    public void testToString_numberFormat() {
+        // arrange
+        NumberFormat format = new DecimalFormat("0.000", new DecimalFormatSymbols(Locale.US));
+
+        // act/assert
+        Assert.assertEquals("{-1.000}", new Cartesian1D(-1).toString(format));
+        Assert.assertEquals("{3.142}", new Cartesian1D(FastMath.PI).toString(format));
     }
 
     private void checkVector(Cartesian1D v, double x) {
-        Assert.assertEquals(x, v.getX(), 1.0e-12);
+        Assert.assertEquals(x, v.getX(), TEST_TOLERANCE);
     }
 }

http://git-wip-us.apache.org/repos/asf/commons-math/blob/24d3dd8b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/IntervalTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/IntervalTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/IntervalTest.java
index e4a88d3..89e8590 100644
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/IntervalTest.java
+++ b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/IntervalTest.java
@@ -26,56 +26,158 @@ import org.junit.Test;
 
 public class IntervalTest {
 
+    private static final double TEST_TOLERANCE = 1e-10;
+
+    @Test
+    public void testBasicProperties() {
+        // arrange
+        Interval interval = new Interval(2.3, 5.7);
+
+        // act/assert
+        Assert.assertEquals(3.4, interval.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(4.0, interval.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(2.3, interval.getInf(), TEST_TOLERANCE);
+        Assert.assertEquals(5.7, interval.getSup(), TEST_TOLERANCE);
+    }
+
+    @Test
+    public void testBasicProperties_negativeValues() {
+        // arrange
+        Interval interval = new Interval(-5.7, -2.3);
+
+        // act/assert
+        Assert.assertEquals(3.4, interval.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(-4.0, interval.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(-5.7, interval.getInf(), TEST_TOLERANCE);
+        Assert.assertEquals(-2.3, interval.getSup(), TEST_TOLERANCE);
+    }
+
+    // MATH-1256
+    @Test(expected = NumberIsTooSmallException.class)
+    public void testStrictOrdering() {
+        new Interval(0, -1);
+    }
+
     @Test
-    public void testInterval() {
+    public void testCheckPoint() {
+        // arrange
         Interval interval = new Interval(2.3, 5.7);
-        Assert.assertEquals(3.4, interval.getSize(), 1.0e-10);
-        Assert.assertEquals(4.0, interval.getBarycenter(), 1.0e-10);
-        Assert.assertEquals(Region.Location.BOUNDARY, interval.checkPoint(2.3, 1.0e-10));
-        Assert.assertEquals(Region.Location.BOUNDARY, interval.checkPoint(5.7, 1.0e-10));
-        Assert.assertEquals(Region.Location.OUTSIDE,  interval.checkPoint(1.2, 1.0e-10));
-        Assert.assertEquals(Region.Location.OUTSIDE,  interval.checkPoint(8.7, 1.0e-10));
-        Assert.assertEquals(Region.Location.INSIDE,   interval.checkPoint(3.0, 1.0e-10));
-        Assert.assertEquals(2.3, interval.getInf(), 1.0e-10);
-        Assert.assertEquals(5.7, interval.getSup(), 1.0e-10);
+
+        // act/assert
+        Assert.assertEquals(Region.Location.OUTSIDE,  interval.checkPoint(1.2, TEST_TOLERANCE));
+
+        Assert.assertEquals(Region.Location.OUTSIDE, interval.checkPoint(2.2, TEST_TOLERANCE));
+        Assert.assertEquals(Region.Location.BOUNDARY, interval.checkPoint(2.3, TEST_TOLERANCE));
+        Assert.assertEquals(Region.Location.INSIDE, interval.checkPoint(2.4, TEST_TOLERANCE));
+
+        Assert.assertEquals(Region.Location.INSIDE,   interval.checkPoint(3.0, TEST_TOLERANCE));
+
+        Assert.assertEquals(Region.Location.INSIDE, interval.checkPoint(5.6, TEST_TOLERANCE));
+        Assert.assertEquals(Region.Location.BOUNDARY, interval.checkPoint(5.7, TEST_TOLERANCE));
+        Assert.assertEquals(Region.Location.OUTSIDE, interval.checkPoint(5.8, TEST_TOLERANCE));
+
+        Assert.assertEquals(Region.Location.OUTSIDE,  interval.checkPoint(8.7, TEST_TOLERANCE));
+
+        Assert.assertEquals(Region.Location.OUTSIDE, interval.checkPoint(Double.NEGATIVE_INFINITY, TEST_TOLERANCE));
+        Assert.assertEquals(Region.Location.OUTSIDE, interval.checkPoint(Double.POSITIVE_INFINITY, TEST_TOLERANCE));
+        Assert.assertEquals(Region.Location.BOUNDARY, interval.checkPoint(Double.NaN, TEST_TOLERANCE));
     }
 
     @Test
-    public void testTolerance() {
+    public void testCheckPoint_tolerance() {
+        // arrange
         Interval interval = new Interval(2.3, 5.7);
-        Assert.assertEquals(Region.Location.OUTSIDE,  interval.checkPoint(1.2, 1.0));
-        Assert.assertEquals(Region.Location.BOUNDARY, interval.checkPoint(1.2, 1.2));
-        Assert.assertEquals(Region.Location.OUTSIDE,  interval.checkPoint(8.7, 2.9));
-        Assert.assertEquals(Region.Location.BOUNDARY, interval.checkPoint(8.7, 3.1));
-        Assert.assertEquals(Region.Location.INSIDE,   interval.checkPoint(3.0, 0.6));
-        Assert.assertEquals(Region.Location.BOUNDARY, interval.checkPoint(3.0, 0.8));
+
+        // act/assert
+        Assert.assertEquals(Region.Location.OUTSIDE, interval.checkPoint(2.29, 1e-3));
+        Assert.assertEquals(Region.Location.BOUNDARY, interval.checkPoint(2.29, 1e-2));
+        Assert.assertEquals(Region.Location.BOUNDARY, interval.checkPoint(2.29, 1e-1));
+        Assert.assertEquals(Region.Location.BOUNDARY, interval.checkPoint(2.29, 1));
+        Assert.assertEquals(Region.Location.BOUNDARY, interval.checkPoint(2.29, 2));
+
+        Assert.assertEquals(Region.Location.INSIDE, interval.checkPoint(4.0, 1e-3));
+        Assert.assertEquals(Region.Location.INSIDE, interval.checkPoint(4.0, 1e-2));
+        Assert.assertEquals(Region.Location.INSIDE, interval.checkPoint(4.0, 1e-1));
+        Assert.assertEquals(Region.Location.INSIDE, interval.checkPoint(4.0, 1));
+        Assert.assertEquals(Region.Location.BOUNDARY, interval.checkPoint(4.0, 2));
     }
 
     @Test
-    public void testInfinite() {
+    public void testInfinite_inf() {
+        // act
+        Interval interval = new Interval(Double.NEGATIVE_INFINITY, 9);
+
+        // assert
+        Assert.assertEquals(Region.Location.BOUNDARY, interval.checkPoint(9.0, TEST_TOLERANCE));
+        Assert.assertEquals(Region.Location.OUTSIDE,  interval.checkPoint(9.4, TEST_TOLERANCE));
+        for (double e = 1.0; e <= 6.0; e += 1.0) {
+            Assert.assertEquals(Region.Location.INSIDE,
+                                interval.checkPoint(-1 * FastMath.pow(10.0, e), TEST_TOLERANCE));
+        }
+        Assert.assertEquals(Double.POSITIVE_INFINITY, interval.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.NEGATIVE_INFINITY, interval.getInf(), TEST_TOLERANCE);
+        Assert.assertEquals(9.0, interval.getSup(), TEST_TOLERANCE);
+    }
+
+    @Test
+    public void testInfinite_sup() {
+        // act
         Interval interval = new Interval(9.0, Double.POSITIVE_INFINITY);
-        Assert.assertEquals(Region.Location.BOUNDARY, interval.checkPoint(9.0, 1.0e-10));
-        Assert.assertEquals(Region.Location.OUTSIDE,  interval.checkPoint(8.4, 1.0e-10));
+
+        // assert
+        Assert.assertEquals(Region.Location.BOUNDARY, interval.checkPoint(9.0, TEST_TOLERANCE));
+        Assert.assertEquals(Region.Location.OUTSIDE,  interval.checkPoint(8.4, TEST_TOLERANCE));
         for (double e = 1.0; e <= 6.0; e += 1.0) {
             Assert.assertEquals(Region.Location.INSIDE,
-                                interval.checkPoint(FastMath.pow(10.0, e), 1.0e-10));
+                                interval.checkPoint(FastMath.pow(10.0, e), TEST_TOLERANCE));
         }
-        Assert.assertTrue(Double.isInfinite(interval.getSize()));
-        Assert.assertEquals(9.0, interval.getInf(), 1.0e-10);
-        Assert.assertTrue(Double.isInfinite(interval.getSup()));
+        Assert.assertEquals(Double.POSITIVE_INFINITY, interval.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(9.0, interval.getInf(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, interval.getSup(), TEST_TOLERANCE);
+    }
+
+    @Test
+    public void testInfinite_infAndSup() {
+        // act
+        Interval interval = new Interval(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
 
+        // assert
+        for (double e = 1.0; e <= 6.0; e += 1.0) {
+            Assert.assertEquals(Region.Location.INSIDE,
+                                interval.checkPoint(FastMath.pow(10.0, e), TEST_TOLERANCE));
+        }
+        Assert.assertEquals(Double.POSITIVE_INFINITY, interval.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.NEGATIVE_INFINITY, interval.getInf(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, interval.getSup(), TEST_TOLERANCE);
     }
 
     @Test
     public void testSinglePoint() {
+        // act
         Interval interval = new Interval(1.0, 1.0);
+
+        // assert
         Assert.assertEquals(0.0, interval.getSize(), Precision.SAFE_MIN);
         Assert.assertEquals(1.0, interval.getBarycenter(), Precision.EPSILON);
     }
 
-    // MATH-1256
-    @Test(expected=NumberIsTooSmallException.class)
-    public void testStrictOrdering() {
-        new Interval(0, -1);
+    @Test
+    public void testSingleInfinitePoint_positive() {
+        // act
+        Interval interval = new Interval(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
+
+        // assert
+        Assert.assertEquals(Double.NaN, interval.getSize(), Precision.SAFE_MIN); // inf - inf = NaN according to floating point spec
+        Assert.assertEquals(Double.POSITIVE_INFINITY, interval.getBarycenter(), Precision.EPSILON);
+    }
+
+    @Test
+    public void testSingleInfinitePoint_negative() {
+        // act
+        Interval interval = new Interval(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
+
+        // assert
+        Assert.assertEquals(Double.NaN, interval.getSize(), Precision.SAFE_MIN); // inf - inf = NaN according to floating point spec
+        Assert.assertEquals(Double.NEGATIVE_INFINITY, interval.getBarycenter(), Precision.EPSILON);
     }
 }

http://git-wip-us.apache.org/repos/asf/commons-math/blob/24d3dd8b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/IntervalsSetTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/IntervalsSetTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/IntervalsSetTest.java
index 17b1ee3..20c8790 100644
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/IntervalsSetTest.java
+++ b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/IntervalsSetTest.java
@@ -16,10 +16,15 @@
  */
 package org.apache.commons.math4.geometry.euclidean.oned;
 
+import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.commons.math4.geometry.GeometryTestUtils;
+import org.apache.commons.math4.geometry.partitioning.BSPTree;
+import org.apache.commons.math4.geometry.partitioning.BoundaryProjection;
 import org.apache.commons.math4.geometry.partitioning.Region;
 import org.apache.commons.math4.geometry.partitioning.RegionFactory;
+import org.apache.commons.math4.geometry.partitioning.SubHyperplane;
 import org.apache.commons.math4.util.FastMath;
 import org.apache.commons.numbers.core.Precision;
 import org.junit.Assert;
@@ -27,6 +32,463 @@ import org.junit.Test;
 
 public class IntervalsSetTest {
 
+    private static final double TEST_TOLERANCE = 1e-15;
+
+    @Test
+    public void testInterval_wholeNumberLine() {
+        // act
+        IntervalsSet set = new IntervalsSet(TEST_TOLERANCE);
+
+        // assert
+        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertEquals(Double.NEGATIVE_INFINITY, set.getInf(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSup(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(Cartesian1D.NaN, (Cartesian1D) set.getBarycenter(), TEST_TOLERANCE);
+
+        BSPTree<Euclidean1D> tree = set.getTree(true);
+        Assert.assertEquals(Boolean.TRUE, tree.getAttribute());
+        Assert.assertNull(tree.getCut());
+        Assert.assertNull(tree.getMinus());
+        Assert.assertNull(tree.getPlus());
+
+        List<Interval> intervals = set.asList();
+        Assert.assertEquals(1, intervals.size());
+        assertInterval(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, intervals.get(0), TEST_TOLERANCE);
+
+        assertLocation(Region.Location.INSIDE, set, Double.NEGATIVE_INFINITY);
+        assertLocation(Region.Location.INSIDE, set, 0.0);
+        assertLocation(Region.Location.INSIDE, set, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testInterval_doubleOpenInterval() {
+        // act
+        IntervalsSet set = new IntervalsSet(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_TOLERANCE);
+
+        // assert
+        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertEquals(Double.NEGATIVE_INFINITY, set.getInf(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSup(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(Cartesian1D.NaN, (Cartesian1D) set.getBarycenter(), TEST_TOLERANCE);
+
+        BSPTree<Euclidean1D> tree = set.getTree(true);
+        Assert.assertEquals(Boolean.TRUE, tree.getAttribute());
+        Assert.assertNull(tree.getCut());
+        Assert.assertNull(tree.getMinus());
+        Assert.assertNull(tree.getPlus());
+
+        List<Interval> intervals = set.asList();
+        Assert.assertEquals(1, intervals.size());
+        assertInterval(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, intervals.get(0), TEST_TOLERANCE);
+
+        assertLocation(Region.Location.INSIDE, set, Double.NEGATIVE_INFINITY);
+        assertLocation(Region.Location.INSIDE, set, 0.0);
+        assertLocation(Region.Location.INSIDE, set, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testInterval_openInterval_positive() {
+        // act
+        IntervalsSet set = new IntervalsSet(9.0, Double.POSITIVE_INFINITY, TEST_TOLERANCE);
+
+        // assert
+        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertEquals(9.0, set.getInf(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSup(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(Cartesian1D.NaN, (Cartesian1D) set.getBarycenter(), TEST_TOLERANCE);
+
+        List<Interval> intervals = set.asList();
+        Assert.assertEquals(1, intervals.size());
+        assertInterval(9.0, Double.POSITIVE_INFINITY, intervals.get(0), TEST_TOLERANCE);
+
+        assertLocation(Region.Location.OUTSIDE, set, Double.NEGATIVE_INFINITY);
+        assertLocation(Region.Location.OUTSIDE, set, 0.0);
+        assertLocation(Region.Location.BOUNDARY, set, 9.0 - 1e-16);
+        assertLocation(Region.Location.BOUNDARY, set, 9.0 + 1e-16);
+        assertLocation(Region.Location.INSIDE, set, 10.0);
+        assertLocation(Region.Location.INSIDE, set, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testInterval_openInterval_negative() {
+        // act
+        IntervalsSet set = new IntervalsSet(Double.NEGATIVE_INFINITY, 9.0, TEST_TOLERANCE);
+
+        // assert
+        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertEquals(Double.NEGATIVE_INFINITY, set.getInf(), TEST_TOLERANCE);
+        Assert.assertEquals(9.0, set.getSup(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(Cartesian1D.NaN, (Cartesian1D) set.getBarycenter(), TEST_TOLERANCE);
+
+        List<Interval> intervals = set.asList();
+        Assert.assertEquals(1, intervals.size());
+        assertInterval(Double.NEGATIVE_INFINITY, 9.0, intervals.get(0), TEST_TOLERANCE);
+
+        assertLocation(Region.Location.INSIDE, set, Double.NEGATIVE_INFINITY);
+        assertLocation(Region.Location.INSIDE, set, 0.0);
+        assertLocation(Region.Location.BOUNDARY, set, 9.0 - 1e-16);
+        assertLocation(Region.Location.BOUNDARY, set, 9.0 + 1e-16);
+        assertLocation(Region.Location.OUTSIDE, set, 10.0);
+        assertLocation(Region.Location.OUTSIDE, set, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testInterval_singleClosedInterval() {
+        // act
+        IntervalsSet set = new IntervalsSet(-1.0, 9.0, TEST_TOLERANCE);
+
+        // 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);
+        GeometryTestUtils.assertVectorEquals(new Cartesian1D(4.0), (Cartesian1D) set.getBarycenter(), TEST_TOLERANCE);
+
+        List<Interval> intervals = set.asList();
+        Assert.assertEquals(1, intervals.size());
+        assertInterval(-1.0, 9.0, intervals.get(0), TEST_TOLERANCE);
+
+        assertLocation(Region.Location.OUTSIDE, set, Double.NEGATIVE_INFINITY);
+        assertLocation(Region.Location.OUTSIDE, set, -2.0);
+        assertLocation(Region.Location.INSIDE, set, 0.0);
+        assertLocation(Region.Location.BOUNDARY, set, 9.0 - 1e-16);
+        assertLocation(Region.Location.BOUNDARY, set, 9.0 + 1e-16);
+        assertLocation(Region.Location.OUTSIDE, set, 10.0);
+        assertLocation(Region.Location.OUTSIDE, set, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testInterval_singlePoint() {
+        // act
+        IntervalsSet set = new IntervalsSet(1.0, 1.0, TEST_TOLERANCE);
+
+        // 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);
+        GeometryTestUtils.assertVectorEquals(new Cartesian1D(1.0), (Cartesian1D) set.getBarycenter(), TEST_TOLERANCE);
+
+        List<Interval> intervals = set.asList();
+        Assert.assertEquals(1, intervals.size());
+        assertInterval(1.0, 1.0, intervals.get(0), TEST_TOLERANCE);
+
+        assertLocation(Region.Location.OUTSIDE, set, Double.NEGATIVE_INFINITY);
+        assertLocation(Region.Location.OUTSIDE, set, 0.0);
+        assertLocation(Region.Location.BOUNDARY, set, 1.0);
+        assertLocation(Region.Location.OUTSIDE, set, 2.0);
+        assertLocation(Region.Location.OUTSIDE, set, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testFromBoundaries_wholeNumberLine() {
+        // arrange
+        List<SubHyperplane<Euclidean1D>> boundaries = new ArrayList<>();
+
+        // act
+        IntervalsSet set = new IntervalsSet(boundaries, TEST_TOLERANCE);
+
+        // assert
+        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertEquals(Double.NEGATIVE_INFINITY, set.getInf(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSup(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(Cartesian1D.NaN, (Cartesian1D) set.getBarycenter(), TEST_TOLERANCE);
+
+        BSPTree<Euclidean1D> tree = set.getTree(true);
+        Assert.assertEquals(Boolean.TRUE, tree.getAttribute());
+        Assert.assertNull(tree.getCut());
+        Assert.assertNull(tree.getMinus());
+        Assert.assertNull(tree.getPlus());
+
+        List<Interval> intervals = set.asList();
+        Assert.assertEquals(1, intervals.size());
+        assertInterval(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, intervals.get(0), TEST_TOLERANCE);
+
+        assertLocation(Region.Location.INSIDE, set, Double.NEGATIVE_INFINITY);
+        assertLocation(Region.Location.INSIDE, set, 0.0);
+        assertLocation(Region.Location.INSIDE, set, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testFromBoundaries_openInterval_positive() {
+        // arrange
+        List<SubHyperplane<Euclidean1D>> boundaries = new ArrayList<>();
+        boundaries.add(subOrientedPoint(9.0, false));
+
+        // act
+        IntervalsSet set = new IntervalsSet(boundaries, TEST_TOLERANCE);
+
+        // assert
+        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertEquals(9.0, set.getInf(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSup(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(Cartesian1D.NaN, (Cartesian1D) set.getBarycenter(), TEST_TOLERANCE);
+
+        List<Interval> intervals = set.asList();
+        Assert.assertEquals(1, intervals.size());
+        assertInterval(9.0, Double.POSITIVE_INFINITY, intervals.get(0), TEST_TOLERANCE);
+
+        assertLocation(Region.Location.OUTSIDE, set, Double.NEGATIVE_INFINITY);
+        assertLocation(Region.Location.OUTSIDE, set, 0.0);
+        assertLocation(Region.Location.BOUNDARY, set, 9.0 - 1e-16);
+        assertLocation(Region.Location.BOUNDARY, set, 9.0 + 1e-16);
+        assertLocation(Region.Location.INSIDE, set, 10.0);
+        assertLocation(Region.Location.INSIDE, set, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testFromBoundaries_openInterval_negative() {
+        // arrange
+        List<SubHyperplane<Euclidean1D>> boundaries = new ArrayList<>();
+        boundaries.add(subOrientedPoint(9.0, true));
+
+        // act
+        IntervalsSet set = new IntervalsSet(boundaries, TEST_TOLERANCE);
+
+        // assert
+        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertEquals(Double.NEGATIVE_INFINITY, set.getInf(), TEST_TOLERANCE);
+        Assert.assertEquals(9.0, set.getSup(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(Cartesian1D.NaN, (Cartesian1D) set.getBarycenter(), TEST_TOLERANCE);
+
+        List<Interval> intervals = set.asList();
+        Assert.assertEquals(1, intervals.size());
+        assertInterval(Double.NEGATIVE_INFINITY, 9.0, intervals.get(0), TEST_TOLERANCE);
+
+        assertLocation(Region.Location.INSIDE, set, Double.NEGATIVE_INFINITY);
+        assertLocation(Region.Location.INSIDE, set, 0.0);
+        assertLocation(Region.Location.BOUNDARY, set, 9.0 - 1e-16);
+        assertLocation(Region.Location.BOUNDARY, set, 9.0 + 1e-16);
+        assertLocation(Region.Location.OUTSIDE, set, 10.0);
+        assertLocation(Region.Location.OUTSIDE, set, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testFromBoundaries_singleClosedInterval() {
+        // arrange
+        List<SubHyperplane<Euclidean1D>> boundaries = new ArrayList<>();
+        boundaries.add(subOrientedPoint(-1.0, false));
+        boundaries.add(subOrientedPoint(9.0, true));
+
+        // act
+        IntervalsSet set = new IntervalsSet(boundaries, TEST_TOLERANCE);
+
+        // 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);
+        GeometryTestUtils.assertVectorEquals(new Cartesian1D(4.0), (Cartesian1D) set.getBarycenter(), TEST_TOLERANCE);
+
+        List<Interval> intervals = set.asList();
+        Assert.assertEquals(1, intervals.size());
+        assertInterval(-1.0, 9.0, intervals.get(0), TEST_TOLERANCE);
+
+        assertLocation(Region.Location.OUTSIDE, set, Double.NEGATIVE_INFINITY);
+        assertLocation(Region.Location.OUTSIDE, set, -2.0);
+        assertLocation(Region.Location.INSIDE, set, 0.0);
+        assertLocation(Region.Location.BOUNDARY, set, 9.0 - 1e-16);
+        assertLocation(Region.Location.BOUNDARY, set, 9.0 + 1e-16);
+        assertLocation(Region.Location.OUTSIDE, set, 10.0);
+        assertLocation(Region.Location.OUTSIDE, set, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testFromBoundaries_multipleClosedIntervals() {
+        // arrange
+        List<SubHyperplane<Euclidean1D>> boundaries = new ArrayList<>();
+        boundaries.add(subOrientedPoint(-1.0, false));
+        boundaries.add(subOrientedPoint(2.0, true));
+        boundaries.add(subOrientedPoint(5.0, false));
+        boundaries.add(subOrientedPoint(9.0, true));
+
+        // act
+        IntervalsSet set = new IntervalsSet(boundaries, TEST_TOLERANCE);
+
+        // 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);
+        GeometryTestUtils.assertVectorEquals(new Cartesian1D(29.5 / 7.0), (Cartesian1D) set.getBarycenter(), TEST_TOLERANCE);
+
+        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);
+
+        assertLocation(Region.Location.OUTSIDE, set, Double.NEGATIVE_INFINITY);
+        assertLocation(Region.Location.OUTSIDE, set, -2.0);
+        assertLocation(Region.Location.INSIDE, set, 0.0);
+        assertLocation(Region.Location.OUTSIDE, set, 3.0);
+        assertLocation(Region.Location.INSIDE, set, 6.0);
+        assertLocation(Region.Location.BOUNDARY, set, 9.0 - 1e-16);
+        assertLocation(Region.Location.BOUNDARY, set, 9.0 + 1e-16);
+        assertLocation(Region.Location.OUTSIDE, set, 10.0);
+        assertLocation(Region.Location.OUTSIDE, set, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testFromBoundaries_mixedOpenAndClosedIntervals() {
+        // arrange
+        List<SubHyperplane<Euclidean1D>> boundaries = new ArrayList<>();
+        boundaries.add(subOrientedPoint(-2.0, true));
+        boundaries.add(subOrientedPoint(-1.0, false));
+        boundaries.add(subOrientedPoint(2.0, true));
+        boundaries.add(subOrientedPoint(5.0, false));
+        boundaries.add(subOrientedPoint(9.0, true));
+        boundaries.add(subOrientedPoint(10.0, false));
+
+        // act
+        IntervalsSet set = new IntervalsSet(boundaries, TEST_TOLERANCE);
+
+        // assert
+        Assert.assertEquals(TEST_TOLERANCE, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertEquals(Double.NEGATIVE_INFINITY, set.getInf(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSup(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(new Cartesian1D(Double.NaN), (Cartesian1D) set.getBarycenter(), TEST_TOLERANCE);
+
+        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);
+
+        assertLocation(Region.Location.INSIDE, set, Double.NEGATIVE_INFINITY);
+        assertLocation(Region.Location.INSIDE, set, -3);
+        assertLocation(Region.Location.OUTSIDE, set, -1.5);
+        assertLocation(Region.Location.INSIDE, set, 0.0);
+        assertLocation(Region.Location.OUTSIDE, set, 3.0);
+        assertLocation(Region.Location.INSIDE, set, 6.0);
+        assertLocation(Region.Location.BOUNDARY, set, 9.0 - 1e-16);
+        assertLocation(Region.Location.BOUNDARY, set, 9.0 + 1e-16);
+        assertLocation(Region.Location.OUTSIDE, set, 9.5);
+        assertLocation(Region.Location.INSIDE, set, 11.0);
+        assertLocation(Region.Location.INSIDE, set, Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testFromBoundaries_intervalEqualToTolerance_onlyFirstBoundaryUsed() {
+        // arrange
+        double tolerance = 1e-3;
+        double first = 1.0;
+        double second = 1.0 + tolerance;
+        List<SubHyperplane<Euclidean1D>> boundaries = new ArrayList<>();
+        boundaries.add(subOrientedPoint(first, true, tolerance));
+        boundaries.add(subOrientedPoint(second, false, tolerance));
+
+        // act
+        IntervalsSet set = new IntervalsSet(boundaries, tolerance);
+
+        // assert
+        Assert.assertEquals(tolerance, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertEquals(Double.NEGATIVE_INFINITY, set.getInf(), TEST_TOLERANCE);
+        Assert.assertEquals(first, set.getSup(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(Cartesian1D.NaN, (Cartesian1D) set.getBarycenter(), TEST_TOLERANCE);
+
+        List<Interval> intervals = set.asList();
+        Assert.assertEquals(1, intervals.size());
+        assertInterval(Double.NEGATIVE_INFINITY, first, intervals.get(0), TEST_TOLERANCE);
+
+        assertLocation(Region.Location.INSIDE, set, 0.0);
+        assertLocation(Region.Location.BOUNDARY, set, 1.0);
+        assertLocation(Region.Location.OUTSIDE, set, 2.0);
+    }
+
+    @Test
+    public void testFromBoundaries_intervalSmallerThanTolerance_onlyFirstBoundaryUsed() {
+        // arrange
+        double tolerance = 1e-3;
+        double first = 1.0;
+        double second = 1.0 - 1e-4;
+        List<SubHyperplane<Euclidean1D>> boundaries = new ArrayList<>();
+        boundaries.add(subOrientedPoint(first, false, tolerance));
+        boundaries.add(subOrientedPoint(second, true, tolerance));
+
+        // act
+        IntervalsSet set = new IntervalsSet(boundaries, tolerance);
+
+        // assert
+        Assert.assertEquals(tolerance, set.getTolerance(), Precision.SAFE_MIN);
+        Assert.assertEquals(first, set.getInf(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSup(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, set.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(Cartesian1D.NaN, (Cartesian1D) set.getBarycenter(), TEST_TOLERANCE);
+
+        List<Interval> intervals = set.asList();
+        Assert.assertEquals(1, intervals.size());
+        assertInterval(first, Double.POSITIVE_INFINITY, intervals.get(0), TEST_TOLERANCE);
+
+        assertLocation(Region.Location.OUTSIDE, set, 0.0);
+        assertLocation(Region.Location.BOUNDARY, set, 1.0);
+        assertLocation(Region.Location.INSIDE, set, 2.0);
+    }
+
+    @Test
+    public void testProjectToBoundary() {
+        // arrange
+        List<SubHyperplane<Euclidean1D>> boundaries = new ArrayList<>();
+        boundaries.add(subOrientedPoint(-2.0, true));
+        boundaries.add(subOrientedPoint(-1.0, false));
+        boundaries.add(subOrientedPoint(2.0, true));
+        boundaries.add(subOrientedPoint(5.0, false));
+        boundaries.add(subOrientedPoint(9.0, true));
+        boundaries.add(subOrientedPoint(10.0, false));
+
+        IntervalsSet set = new IntervalsSet(boundaries, TEST_TOLERANCE);
+
+        // act/assert
+        assertProjection(new Cartesian1D(-2), -1, set, new Cartesian1D(-3));
+        assertProjection(new Cartesian1D(-2), 0, set, new Cartesian1D(-2));
+        assertProjection(new Cartesian1D(-2), 0.1, set, new Cartesian1D(-1.9));
+
+        assertProjection(new Cartesian1D(-1), 0.5, set, new Cartesian1D(-1.5));
+        assertProjection(new Cartesian1D(-1), 0.1, set, new Cartesian1D(-1.1));
+        assertProjection(new Cartesian1D(-1), 0, set, new Cartesian1D(-1));
+        assertProjection(new Cartesian1D(-1), -1, set, new Cartesian1D(0));
+
+        assertProjection(new Cartesian1D(2), -1, set, new Cartesian1D(1));
+        assertProjection(new Cartesian1D(2), 0, set, new Cartesian1D(2));
+        assertProjection(new Cartesian1D(2), 1, set, new Cartesian1D(3));
+
+        assertProjection(new Cartesian1D(5), 1, set, new Cartesian1D(4));
+        assertProjection(new Cartesian1D(5), 0, set, new Cartesian1D(5));
+
+        assertProjection(new Cartesian1D(5), -1, set, new Cartesian1D(6));
+        assertProjection(new Cartesian1D(5), -2, set, new Cartesian1D(7));
+
+        assertProjection(new Cartesian1D(9), -1, set, new Cartesian1D(8));
+        assertProjection(new Cartesian1D(9), 0, set, new Cartesian1D(9));
+        assertProjection(new Cartesian1D(9), 0.1, set, new Cartesian1D(9.1));
+
+        assertProjection(new Cartesian1D(10), 0, set, new Cartesian1D(10));
+        assertProjection(new Cartesian1D(10), -1, set, new Cartesian1D(11));
+    }
+
     @Test
     public void testInterval() {
         IntervalsSet set = new IntervalsSet(2.3, 5.7, 1.0e-10);
@@ -61,44 +523,65 @@ public class IntervalsSetTest {
     }
 
     @Test
-    public void testMultiple() {
+    public void testBooleanOperations() {
+        // arrange
         RegionFactory<Euclidean1D> factory = new RegionFactory<>();
+
+        // act
         IntervalsSet set = (IntervalsSet)
-        factory.intersection(factory.union(factory.difference(new IntervalsSet(1.0, 6.0, 1.0e-10),
-                                                              new IntervalsSet(3.0, 5.0, 1.0e-10)),
-                                                              new IntervalsSet(9.0, Double.POSITIVE_INFINITY, 1.0e-10)),
-                                                              new IntervalsSet(Double.NEGATIVE_INFINITY, 11.0, 1.0e-10));
-        Assert.assertEquals(5.0, set.getSize(), 1.0e-10);
-        Assert.assertEquals(5.9, ((Cartesian1D) set.getBarycenter()).getX(), 1.0e-10);
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new Cartesian1D(0.0)));
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new Cartesian1D(4.0)));
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new Cartesian1D(8.0)));
-        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new Cartesian1D(12.0)));
-        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(new Cartesian1D(1.2)));
-        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(new Cartesian1D(5.9)));
-        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(new Cartesian1D(9.01)));
-        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Cartesian1D(5.0)));
-        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new Cartesian1D(11.0)));
-        Assert.assertEquals( 1.0, set.getInf(), 1.0e-10);
-        Assert.assertEquals(11.0, set.getSup(), 1.0e-10);
+        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));
+
+        // arrange
+        Assert.assertEquals(1.0, set.getInf(), TEST_TOLERANCE);
+        Assert.assertEquals(11.0, set.getSup(), TEST_TOLERANCE);
+
+        Assert.assertEquals(5.0, set.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(5.9, ((Cartesian1D) set.getBarycenter()).getX(), TEST_TOLERANCE);
+
+        assertLocation(Region.Location.OUTSIDE, set, 0.0);
+        assertLocation(Region.Location.OUTSIDE, set, 4.0);
+        assertLocation(Region.Location.OUTSIDE, set, 8.0);
+        assertLocation(Region.Location.OUTSIDE, set, 12.0);
+        assertLocation(Region.Location.INSIDE, set, 1.2);
+        assertLocation(Region.Location.INSIDE, set, 5.9);
+        assertLocation(Region.Location.INSIDE, set, 9.01);
+        assertLocation(Region.Location.BOUNDARY, set, 5.0);
+        assertLocation(Region.Location.BOUNDARY, set, 11.0);
 
         List<Interval> list = set.asList();
         Assert.assertEquals(3, list.size());
-        Assert.assertEquals( 1.0, 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( 6.0, list.get(1).getSup(), 1.0e-10);
-        Assert.assertEquals( 9.0, list.get(2).getInf(), 1.0e-10);
-        Assert.assertEquals(11.0, list.get(2).getSup(), 1.0e-10);
+        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);
+    }
 
+    private void assertLocation(Region.Location location, IntervalsSet set, double pt) {
+        Assert.assertEquals(location, set.checkPoint(new Cartesian1D(pt)));
     }
 
-    @Test
-    public void testSinglePoint() {
-        IntervalsSet set = new IntervalsSet(1.0, 1.0, 1.0e-10);
-        Assert.assertEquals(0.0, set.getSize(), Precision.SAFE_MIN);
-        Assert.assertEquals(0.0, set.getBoundarySize(), Precision.SAFE_MIN);
-        Assert.assertEquals(1.0, ((Cartesian1D) set.getBarycenter()).getX(), Precision.EPSILON);
+    private void assertInterval(double expectedInf, double expectedSup, Interval actual, double tolerance) {
+        Assert.assertEquals(expectedInf, actual.getInf(), tolerance);
+        Assert.assertEquals(expectedSup, actual.getSup(), tolerance);
+    }
+
+    private void assertProjection(Cartesian1D expectedProjection, double expectedOffset,
+            IntervalsSet set, Cartesian1D toProject) {
+        BoundaryProjection<Euclidean1D> proj = set.projectToBoundary(toProject);
+
+        GeometryTestUtils.assertVectorEquals(toProject, (Cartesian1D) proj.getOriginal(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(expectedProjection, (Cartesian1D) proj.getProjected(), TEST_TOLERANCE);
+        Assert.assertEquals(expectedOffset, proj.getOffset(), TEST_TOLERANCE);
     }
 
+    private SubOrientedPoint subOrientedPoint(double location, boolean direct) {
+        return subOrientedPoint(location, direct, TEST_TOLERANCE);
+    }
+
+    private SubOrientedPoint subOrientedPoint(double location, boolean direct, double tolerance) {
+        // the remaining region isn't necessary for creating 1D boundaries so we can set it to null here
+        return new SubOrientedPoint(new OrientedPoint(new Cartesian1D(location), direct, tolerance), null);
+    }
 }

http://git-wip-us.apache.org/repos/asf/commons-math/blob/24d3dd8b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/OrientedPointTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/OrientedPointTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/OrientedPointTest.java
new file mode 100644
index 0000000..4a07113
--- /dev/null
+++ b/src/test/java/org/apache/commons/math4/geometry/euclidean/oned/OrientedPointTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.math4.geometry.euclidean.oned;
+
+import org.junit.Test;
+import org.apache.commons.math3.util.Precision;
+import org.apache.commons.math4.geometry.Point;
+import org.apache.commons.math4.geometry.Vector;
+import org.junit.Assert;
+
+public class OrientedPointTest {
+
+    @Test
+    public void testConstructor() {
+        // act
+        OrientedPoint pt = new OrientedPoint(new Cartesian1D(2.0), true, 1e-5);
+
+        // assert
+        Assert.assertEquals(2.0, pt.getLocation().getX(), Precision.EPSILON);
+        Assert.assertEquals(true, pt.isDirect());
+        Assert.assertEquals(1e-5, pt.getTolerance(), Precision.EPSILON);
+    }
+
+    @Test
+    public void testCopySelf() {
+        // arrange
+        OrientedPoint orig = new OrientedPoint(new Cartesian1D(2.0), true, 1e-5);
+
+        // act
+        OrientedPoint copy = orig.copySelf();
+
+        // assert
+        Assert.assertSame(orig, copy);
+        Assert.assertEquals(2.0, copy.getLocation().getX(), Precision.EPSILON);
+        Assert.assertEquals(true, copy.isDirect());
+        Assert.assertEquals(1e-5, copy.getTolerance(), Precision.EPSILON);
+    }
+
+    @Test
+    public void testGetOffset_direct_point() {
+        // arrange
+        OrientedPoint pt = new OrientedPoint(new Cartesian1D(-1.0), true, 1e-5);
+
+        // act/assert
+        Assert.assertEquals(-99, pt.getOffset((Point<Euclidean1D>) new Cartesian1D(-100)), Precision.EPSILON);
+        Assert.assertEquals(-1, pt.getOffset((Point<Euclidean1D>) new Cartesian1D(-2)), Precision.EPSILON);
+        Assert.assertEquals(-0.01, pt.getOffset((Point<Euclidean1D>) new Cartesian1D(-1.01)), Precision.EPSILON);
+        Assert.assertEquals(0.0, pt.getOffset((Point<Euclidean1D>) new Cartesian1D(-1.0)), Precision.EPSILON);
+        Assert.assertEquals(0.01, pt.getOffset((Point<Euclidean1D>) new Cartesian1D(-0.99)), Precision.EPSILON);
+        Assert.assertEquals(1, pt.getOffset((Point<Euclidean1D>) new Cartesian1D(0)), Precision.EPSILON);
+        Assert.assertEquals(101, pt.getOffset((Point<Euclidean1D>) new Cartesian1D(100)), Precision.EPSILON);
+    }
+
+    @Test
+    public void testGetOffset_notDirect_point() {
+        // arrange
+        OrientedPoint pt = new OrientedPoint(new Cartesian1D(-1.0), false, 1e-5);
+
+        // act/assert
+        Assert.assertEquals(99, pt.getOffset((Point<Euclidean1D>) new Cartesian1D(-100)), Precision.EPSILON);
+        Assert.assertEquals(1, pt.getOffset((Point<Euclidean1D>) new Cartesian1D(-2)), Precision.EPSILON);
+        Assert.assertEquals(0.01, pt.getOffset((Point<Euclidean1D>) new Cartesian1D(-1.01)), Precision.EPSILON);
+        Assert.assertEquals(0.0, pt.getOffset((Point<Euclidean1D>) new Cartesian1D(-1.0)), Precision.EPSILON);
+        Assert.assertEquals(-0.01, pt.getOffset((Point<Euclidean1D>) new Cartesian1D(-0.99)), Precision.EPSILON);
+        Assert.assertEquals(-1, pt.getOffset((Point<Euclidean1D>) new Cartesian1D(0)), Precision.EPSILON);
+        Assert.assertEquals(-101, pt.getOffset((Point<Euclidean1D>) new Cartesian1D(100)), Precision.EPSILON);
+    }
+
+    @Test
+    public void testGetOffset_direct_vector() {
+        // arrange
+        OrientedPoint pt = new OrientedPoint(new Cartesian1D(-1.0), true, 1e-5);
+
+        // act/assert
+        Assert.assertEquals(-99, pt.getOffset((Vector<Euclidean1D>) new Cartesian1D(-100)), Precision.EPSILON);
+        Assert.assertEquals(-1, pt.getOffset((Vector<Euclidean1D>) new Cartesian1D(-2)), Precision.EPSILON);
+        Assert.assertEquals(-0.01, pt.getOffset((Vector<Euclidean1D>) new Cartesian1D(-1.01)), Precision.EPSILON);
+        Assert.assertEquals(-0.0, pt.getOffset((Vector<Euclidean1D>) new Cartesian1D(-1.0)), Precision.EPSILON);
+        Assert.assertEquals(0.01, pt.getOffset((Vector<Euclidean1D>) new Cartesian1D(-0.99)), Precision.EPSILON);
+        Assert.assertEquals(1, pt.getOffset((Vector<Euclidean1D>) new Cartesian1D(0)), Precision.EPSILON);
+        Assert.assertEquals(101, pt.getOffset((Vector<Euclidean1D>) new Cartesian1D(100)), Precision.EPSILON);
+    }
+
+    @Test
+    public void testGetOffset_notDirect_vector() {
+        // arrange
+        OrientedPoint pt = new OrientedPoint(new Cartesian1D(-1.0), false, 1e-5);
+
+        // act/assert
+        Assert.assertEquals(99, pt.getOffset((Vector<Euclidean1D>) new Cartesian1D(-100)), Precision.EPSILON);
+        Assert.assertEquals(1, pt.getOffset((Vector<Euclidean1D>) new Cartesian1D(-2)), Precision.EPSILON);
+        Assert.assertEquals(0.01, pt.getOffset((Vector<Euclidean1D>) new Cartesian1D(-1.01)), Precision.EPSILON);
+        Assert.assertEquals(0.0, pt.getOffset((Vector<Euclidean1D>) new Cartesian1D(-1.0)), Precision.EPSILON);
+        Assert.assertEquals(-0.01, pt.getOffset((Vector<Euclidean1D>) new Cartesian1D(-0.99)), Precision.EPSILON);
+        Assert.assertEquals(-1, pt.getOffset((Vector<Euclidean1D>) new Cartesian1D(0)), Precision.EPSILON);
+        Assert.assertEquals(-101, pt.getOffset((Vector<Euclidean1D>) new Cartesian1D(100)), Precision.EPSILON);
+    }
+
+    @Test
+    public void testWholeHyperplane() {
+        // arrange
+        OrientedPoint pt = new OrientedPoint(new Cartesian1D(1.0), false, 1e-5);
+
+        // act
+        SubOrientedPoint subPt = pt.wholeHyperplane();
+
+        // assert
+        Assert.assertSame(pt, subPt.getHyperplane());
+        Assert.assertNull(subPt.getRemainingRegion());
+    }
+
+    @Test
+    public void testWholeSpace() {
+        // arrange
+        OrientedPoint pt = new OrientedPoint(new Cartesian1D(1.0), false, 1e-5);
+
+        // act
+        IntervalsSet set = pt.wholeSpace();
+
+        // assert
+        Assert.assertEquals(Double.NEGATIVE_INFINITY, set.getInf(), Precision.EPSILON);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, set.getSup(), Precision.EPSILON);
+    }
+
+    @Test
+    public void testSameOrientationAs() {
+        // arrange
+        OrientedPoint notDirect1 = new OrientedPoint(new Cartesian1D(1.0), false, 1e-5);
+        OrientedPoint notDirect2 = new OrientedPoint(new Cartesian1D(1.0), false, 1e-5);
+        OrientedPoint direct1 = new OrientedPoint(new Cartesian1D(1.0), true, 1e-5);
+        OrientedPoint direct2 = new OrientedPoint(new Cartesian1D(1.0), true, 1e-5);
+
+        // act/assert
+        Assert.assertEquals(true, notDirect1.sameOrientationAs(notDirect1));
+        Assert.assertEquals(true, notDirect1.sameOrientationAs(notDirect2));
+        Assert.assertEquals(true, notDirect2.sameOrientationAs(notDirect1));
+
+        Assert.assertEquals(true, direct1.sameOrientationAs(direct1));
+        Assert.assertEquals(true, direct1.sameOrientationAs(direct2));
+        Assert.assertEquals(true, direct2.sameOrientationAs(direct1));
+
+        Assert.assertEquals(false, notDirect1.sameOrientationAs(direct1));
+        Assert.assertEquals(false, direct1.sameOrientationAs(notDirect1));
+    }
+
+    @Test
+    public void testProject() {
+        // arrange
+        OrientedPoint pt = new OrientedPoint(new Cartesian1D(1.0), true, 1e-5);
+
+        // act/assert
+        Assert.assertEquals(1.0, ((Cartesian1D) pt.project(new Cartesian1D(-1.0))).getX(), Precision.EPSILON);
+        Assert.assertEquals(1.0, ((Cartesian1D) pt.project(new Cartesian1D(0.0))).getX(), Precision.EPSILON);
+        Assert.assertEquals(1.0, ((Cartesian1D) pt.project(new Cartesian1D(1.0))).getX(), Precision.EPSILON);
+        Assert.assertEquals(1.0, ((Cartesian1D) pt.project(new Cartesian1D(100.0))).getX(), Precision.EPSILON);
+    }
+
+    @Test
+    public void testRevertSelf() {
+        // arrange
+        OrientedPoint pt = new OrientedPoint(new Cartesian1D(2.0), true, 1e-5);
+
+        // act
+        pt.revertSelf();
+
+        // assert
+        Assert.assertEquals(2.0, pt.getLocation().getX(), Precision.EPSILON);
+        Assert.assertEquals(false, pt.isDirect());
+        Assert.assertEquals(1e-5, pt.getTolerance(), Precision.EPSILON);
+
+        Assert.assertEquals(1, pt.getOffset((Vector<Euclidean1D>) new Cartesian1D(1.0)), Precision.EPSILON);
+        Assert.assertEquals(-1, pt.getOffset((Vector<Euclidean1D>) new Cartesian1D(3.0)), Precision.EPSILON);
+    }
+}


[2/7] [math] Merge branch 'master' into test-MATH-1437

Posted by er...@apache.org.
Merge branch 'master' into test-MATH-1437


Project: http://git-wip-us.apache.org/repos/asf/commons-math/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-math/commit/1b99b458
Tree: http://git-wip-us.apache.org/repos/asf/commons-math/tree/1b99b458
Diff: http://git-wip-us.apache.org/repos/asf/commons-math/diff/1b99b458

Branch: refs/heads/master
Commit: 1b99b4583c552e0ece96349b4cb56b3584ad2b42
Parents: cb4ad07 3ea4597
Author: darkma773r <ma...@hotmail.com>
Authored: Thu Jan 25 21:21:06 2018 -0500
Committer: darkma773r <ma...@hotmail.com>
Committed: Thu Jan 25 21:21:06 2018 -0500

----------------------------------------------------------------------
 pom.xml                                         |   6 +
 .../AbstractIntegerDistribution.java            |  11 +-
 .../distribution/AbstractRealDistribution.java  |  14 +-
 .../math4/distribution/BetaDistribution.java    | 245 -----------
 .../distribution/BinomialDistribution.java      | 178 --------
 .../math4/distribution/CauchyDistribution.java  | 206 ---------
 .../distribution/ChiSquaredDistribution.java    | 154 -------
 .../distribution/ConstantRealDistribution.java  | 123 ------
 .../distribution/EmpiricalDistribution.java     |  33 +-
 .../distribution/EnumeratedDistribution.java    |  26 +-
 .../EnumeratedIntegerDistribution.java          |   9 +-
 .../EnumeratedRealDistribution.java             |  15 +-
 .../distribution/ExponentialDistribution.java   | 235 -----------
 .../math4/distribution/FDistribution.java       | 267 ------------
 .../math4/distribution/GammaDistribution.java   | 397 ------------------
 .../distribution/GeometricDistribution.java     | 170 --------
 .../math4/distribution/GumbelDistribution.java  | 141 -------
 .../HypergeometricDistribution.java             | 325 --------------
 .../math4/distribution/IntegerDistribution.java | 148 +------
 .../math4/distribution/LaplaceDistribution.java | 135 ------
 .../math4/distribution/LevyDistribution.java    | 166 --------
 .../distribution/LogNormalDistribution.java     | 311 --------------
 .../distribution/LogisticDistribution.java      | 136 ------
 .../MultivariateNormalDistribution.java         |   4 +-
 .../distribution/NakagamiDistribution.java      | 157 -------
 .../math4/distribution/NormalDistribution.java  | 261 ------------
 .../math4/distribution/ParetoDistribution.java  | 269 ------------
 .../math4/distribution/PascalDistribution.java  | 228 ----------
 .../math4/distribution/PoissonDistribution.java | 259 ------------
 .../math4/distribution/RealDistribution.java    | 161 +------
 .../distribution/SaddlePointExpansion.java      | 206 ---------
 .../math4/distribution/TDistribution.java       | 218 ----------
 .../distribution/TriangularDistribution.java    | 253 -----------
 .../UniformIntegerDistribution.java             | 165 --------
 .../distribution/UniformRealDistribution.java   | 180 --------
 .../math4/distribution/WeibullDistribution.java | 297 -------------
 .../math4/distribution/ZipfDistribution.java    | 278 ------------
 .../math4/distribution/package-info.java        |   1 +
 .../euclidean/oned/SubOrientedPoint.java        |  10 +-
 .../euclidean/threed/PolyhedronsSet.java        | 106 +++--
 .../geometry/euclidean/twod/PolygonsSet.java    |  74 ++--
 .../geometry/partitioning/Characterization.java |  13 +-
 .../ml/neuralnet/FeatureInitializerFactory.java |   8 +-
 .../scalar/noderiv/CMAESOptimizer.java          |   8 +-
 .../stat/correlation/PearsonsCorrelation.java   |   2 +-
 .../math4/stat/inference/BinomialTest.java      |   2 +-
 .../math4/stat/inference/ChiSquareTest.java     |   2 +-
 .../commons/math4/stat/inference/GTest.java     |   2 +-
 .../stat/inference/InferenceTestUtils.java      |  18 +-
 .../stat/inference/KolmogorovSmirnovTest.java   |  14 +-
 .../math4/stat/inference/MannWhitneyUTest.java  |   2 +-
 .../math4/stat/inference/OneWayAnova.java       |  10 +-
 .../commons/math4/stat/inference/TTest.java     |   4 +-
 .../stat/inference/WilcoxonSignedRankTest.java  |   2 +-
 .../stat/interval/AgrestiCoullInterval.java     |   4 +-
 .../stat/interval/ClopperPearsonInterval.java   |   2 +-
 .../interval/NormalApproximationInterval.java   |   4 +-
 .../stat/interval/WilsonScoreInterval.java      |   4 +-
 .../math4/stat/regression/SimpleRegression.java |   2 +-
 .../AkimaSplineInterpolatorTest.java            |   8 +-
 .../BicubicInterpolatingFunctionTest.java       |   8 +-
 .../interpolation/BicubicInterpolatorTest.java  |   8 +-
 ...eBicubicSplineInterpolatingFunctionTest.java |   8 +-
 .../PiecewiseBicubicSplineInterpolatorTest.java |  12 +-
 .../TricubicInterpolatingFunctionTest.java      |  10 +-
 .../AbstractIntegerDistributionTest.java        |   4 +-
 .../AbstractRealDistributionTest.java           |  12 +-
 .../distribution/BetaDistributionTest.java      | 384 -----------------
 .../distribution/BinomialDistributionTest.java  | 175 --------
 .../distribution/CauchyDistributionTest.java    | 122 ------
 .../ChiSquaredDistributionTest.java             | 137 ------
 .../ConstantRealDistributionTest.java           |  94 -----
 .../distribution/EmpiricalDistributionTest.java |  30 +-
 .../EnumeratedIntegerDistributionTest.java      |  11 +-
 .../EnumeratedRealDistributionTest.java         |  11 +-
 .../ExponentialDistributionTest.java            | 135 ------
 .../math4/distribution/FDistributionTest.java   | 159 -------
 .../distribution/GammaDistributionTest.java     | 358 ----------------
 .../distribution/GeometricDistributionTest.java | 172 --------
 .../distribution/GumbelDistributionTest.java    |  72 ----
 .../HypergeometricDistributionTest.java         | 354 ----------------
 .../distribution/LaplaceDistributionTest.java   |  73 ----
 .../distribution/LevyDistributionTest.java      |  82 ----
 .../distribution/LogNormalDistributionTest.java | 254 -----------
 .../distribution/LogisticsDistributionTest.java |  73 ----
 .../MultivariateNormalDistributionTest.java     |   2 +-
 .../distribution/NakagamiDistributionTest.java  |  73 ----
 .../distribution/NormalDistributionTest.java    | 216 ----------
 .../distribution/ParetoDistributionTest.java    | 206 ---------
 .../distribution/PascalDistributionTest.java    | 135 ------
 .../distribution/PoissonDistributionTest.java   | 248 -----------
 .../RealDistributionAbstractTest.java           |   7 +-
 .../math4/distribution/TDistributionTest.java   | 173 --------
 .../TriangularDistributionTest.java             | 194 ---------
 .../UniformIntegerDistributionTest.java         | 142 -------
 .../UniformRealDistributionTest.java            | 125 ------
 .../distribution/WeibullDistributionTest.java   | 126 ------
 .../distribution/ZipfDistributionTest.java      | 197 ---------
 .../commons/math4/filter/KalmanFilterTest.java  |  10 +-
 .../fitting/PolynomialCurveFitterTest.java      |   8 +-
 .../math4/fitting/SimpleCurveFitterTest.java    |   8 +-
 .../LevenbergMarquardtOptimizerTest.java        |   2 +-
 .../RandomCirclePointGenerator.java             |  14 +-
 .../RandomStraightLinePointGenerator.java       |  12 +-
 .../euclidean/oned/IntervalsSetTest.java        |   1 +
 .../euclidean/oned/SubOrientedPointTest.java    | 170 ++++----
 .../euclidean/threed/PolyhedronsSetTest.java    | 117 ++++++
 .../euclidean/twod/PolygonsSetTest.java         |  30 +-
 .../partitioning/CharacterizationTest.java      | 420 +++++++++++++++++++
 .../math4/linear/EigenDecompositionTest.java    |   6 +-
 .../math4/linear/HessenbergTransformerTest.java |   6 +-
 .../math4/linear/SchurTransformerTest.java      |   6 +-
 .../sofm/TravellingSalesmanSolver.java          |   6 +-
 .../correlation/PearsonsCorrelationTest.java    |   2 +-
 .../AggregateSummaryStatisticsTest.java         |  20 +-
 .../UnivariateStatisticAbstractTest.java        |  16 +-
 .../descriptive/rank/PSquarePercentileTest.java |  10 +-
 .../stat/descriptive/rank/PercentileTest.java   |   6 +-
 .../stat/inference/InferenceTestUtilsTest.java  |   2 +-
 .../inference/KolmogorovSmirnovTestTest.java    |  10 +-
 .../GLSMultipleLinearRegressionTest.java        |   6 +-
 .../commons/math4/util/MathUtilsTest.java       |   8 +-
 .../math4/util/ResizableDoubleArrayTest.java    |  14 +-
 123 files changed, 1031 insertions(+), 11170 deletions(-)
----------------------------------------------------------------------



[3/7] [math] MATH-1437: adding additional unit tests and test utilities for o.a.c.m.geometry.euclidean.twod and o.a.c.m.geometry.euclidean.threed

Posted by er...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-math/blob/24d3dd8b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/PolyhedronsSetTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/PolyhedronsSetTest.java b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/PolyhedronsSetTest.java
index 1a64d2a..a76643c 100644
--- a/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/PolyhedronsSetTest.java
+++ b/src/test/java/org/apache/commons/math4/geometry/euclidean/threed/PolyhedronsSetTest.java
@@ -26,117 +26,362 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
+import org.apache.commons.math3.util.Precision;
 import org.apache.commons.math4.exception.MathArithmeticException;
 import org.apache.commons.math4.exception.MathIllegalArgumentException;
 import org.apache.commons.math4.exception.util.ExceptionContext;
 import org.apache.commons.math4.exception.util.Localizable;
 import org.apache.commons.math4.exception.util.LocalizedFormats;
-import org.apache.commons.math4.geometry.Vector;
-import org.apache.commons.math4.geometry.euclidean.threed.Euclidean3D;
-import org.apache.commons.math4.geometry.euclidean.threed.Plane;
-import org.apache.commons.math4.geometry.euclidean.threed.PolyhedronsSet;
-import org.apache.commons.math4.geometry.euclidean.threed.Rotation;
-import org.apache.commons.math4.geometry.euclidean.threed.SubPlane;
-import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
+import org.apache.commons.math4.geometry.GeometryTestUtils;
+import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
 import org.apache.commons.math4.geometry.euclidean.twod.Euclidean2D;
 import org.apache.commons.math4.geometry.euclidean.twod.PolygonsSet;
 import org.apache.commons.math4.geometry.euclidean.twod.SubLine;
-import org.apache.commons.math4.geometry.euclidean.twod.Cartesian2D;
 import org.apache.commons.math4.geometry.partitioning.BSPTree;
 import org.apache.commons.math4.geometry.partitioning.BSPTreeVisitor;
 import org.apache.commons.math4.geometry.partitioning.BoundaryAttribute;
+import org.apache.commons.math4.geometry.partitioning.BoundaryProjection;
 import org.apache.commons.math4.geometry.partitioning.Region;
 import org.apache.commons.math4.geometry.partitioning.RegionDumper;
 import org.apache.commons.math4.geometry.partitioning.RegionFactory;
 import org.apache.commons.math4.geometry.partitioning.RegionParser;
 import org.apache.commons.math4.geometry.partitioning.SubHyperplane;
+import org.apache.commons.math4.util.FastMath;
 import org.apache.commons.rng.UniformRandomProvider;
 import org.apache.commons.rng.simple.RandomSource;
-import org.apache.commons.math4.util.FastMath;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class PolyhedronsSetTest {
 
+    private static final double TEST_TOLERANCE = 1e-10;
+
     @Test
-    public void testFull() {
+    public void testWholeSpace() {
         // act
-        PolyhedronsSet tree = new PolyhedronsSet(1e-10);
+        PolyhedronsSet polySet = new PolyhedronsSet(TEST_TOLERANCE);
 
         // assert
-        Assert.assertEquals(Double.POSITIVE_INFINITY, tree.getSize(), 1.0e-10);
-        Assert.assertEquals(0.0, tree.getBoundarySize(), 1.0e-10);
-        Cartesian3D center = (Cartesian3D) tree.getBarycenter();
-        Assert.assertEquals(Double.NaN, center.getX(), 1e-10);
-        Assert.assertEquals(Double.NaN, center.getY(), 1e-10);
-        Assert.assertEquals(Double.NaN, center.getZ(), 1e-10);
-        Assert.assertEquals(true, tree.isFull());
-        Assert.assertEquals(false, tree.isEmpty());
+        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, polySet.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, polySet.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(Cartesian3D.NaN, (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(false, polySet.isEmpty());
+        Assert.assertEquals(true, polySet.isFull());
 
-        checkPoints(Region.Location.INSIDE, tree, new Cartesian3D[] {
-                new Cartesian3D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY),
-                Cartesian3D.ZERO,
-                new Cartesian3D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY)
-        });
+        checkPoints(Region.Location.INSIDE, polySet,
+                new Cartesian3D(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE),
+                new Cartesian3D(-100, -100, -100),
+                new Cartesian3D(0, 0, 0),
+                new Cartesian3D(100, 100, 100),
+                new Cartesian3D(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE));
     }
 
     @Test
-    public void testEmpty() {
+    public void testEmptyRegion() {
         // act
-        PolyhedronsSet tree = new PolyhedronsSet(new BSPTree<Euclidean3D>(Boolean.FALSE), 1e-10);
+        PolyhedronsSet polySet = new PolyhedronsSet(new BSPTree<Euclidean3D>(Boolean.FALSE), TEST_TOLERANCE);
 
         // assert
-        Assert.assertEquals(0.0, tree.getSize(), 1.0e-10);
-        Assert.assertEquals(0.0, tree.getBoundarySize(), 1.0e-10);
-        Cartesian3D center = (Cartesian3D) tree.getBarycenter();
-        Assert.assertEquals(Double.NaN, center.getX(), 1e-10);
-        Assert.assertEquals(Double.NaN, center.getY(), 1e-10);
-        Assert.assertEquals(Double.NaN, center.getZ(), 1e-10);
-        Assert.assertEquals(false, tree.isFull());
-        Assert.assertEquals(true, tree.isEmpty());
+        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
+        Assert.assertEquals(0.0, polySet.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, polySet.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(Cartesian3D.NaN, (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(true, polySet.isEmpty());
+        Assert.assertEquals(false, polySet.isFull());
 
-        checkPoints(Region.Location.OUTSIDE, tree, new Cartesian3D[] {
-                new Cartesian3D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY),
-                Cartesian3D.ZERO,
-                new Cartesian3D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY)
-        });
+        checkPoints(Region.Location.OUTSIDE, polySet,
+                new Cartesian3D(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE),
+                new Cartesian3D(-100, -100, -100),
+                new Cartesian3D(0, 0, 0),
+                new Cartesian3D(100, 100, 100),
+                new Cartesian3D(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE));
+    }
+
+    @Test
+    public void testHalfSpace() {
+        // arrange
+        List<SubHyperplane<Euclidean3D>> boundaries = new ArrayList<>();
+        boundaries.add(new SubPlane(new Plane(Cartesian3D.ZERO, Cartesian3D.PLUS_J, TEST_TOLERANCE),
+                new PolygonsSet(TEST_TOLERANCE)));
+
+        // act
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
+
+        // assert
+        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, polySet.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, polySet.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(Cartesian3D.NaN, (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(false, polySet.isEmpty());
+        Assert.assertEquals(false, polySet.isFull());
+
+        checkPoints(Region.Location.INSIDE, polySet,
+                new Cartesian3D(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE),
+                new Cartesian3D(-100, -100, -100));
+        checkPoints(Region.Location.BOUNDARY, polySet, new Cartesian3D(0, 0, 0));
+        checkPoints(Region.Location.OUTSIDE, polySet,
+                new Cartesian3D(100, 100, 100),
+                new Cartesian3D(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE));
     }
 
     @Test
-    public void testSingleInfiniteBoundary() {
+    public void testInvertedRegion() {
         // arrange
-        Plane plane = new Plane(Cartesian3D.ZERO, Cartesian3D.PLUS_K, 1e-10);
+        List<SubHyperplane<Euclidean3D>> boundaries = createBoxBoundaries(Cartesian3D.ZERO, 1.0, TEST_TOLERANCE);
+        PolyhedronsSet box = new PolyhedronsSet(boundaries, TEST_TOLERANCE);;
+
+        // act
+        PolyhedronsSet polySet = (PolyhedronsSet) new RegionFactory<Euclidean3D>().getComplement(box);
 
+        // assert
+        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, polySet.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(6, polySet.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(Cartesian3D.NaN, (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(false, polySet.isEmpty());
+        Assert.assertEquals(false, polySet.isFull());
+
+        checkPoints(Region.Location.INSIDE, polySet,
+                new Cartesian3D(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE),
+                new Cartesian3D(-100, -100, -100),
+                new Cartesian3D(100, 100, 100),
+                new Cartesian3D(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE));
+        checkPoints(Region.Location.OUTSIDE, polySet,
+                new Cartesian3D(0, 0, 0));
+    }
+
+    @Test
+    public void testCreateFromBoundaries_noBoundaries_treeRepresentsWholeSpace() {
+        // arrange
         List<SubHyperplane<Euclidean3D>> boundaries = new ArrayList<>();
-        boundaries.add(plane.wholeHyperplane());
 
         // act
-        PolyhedronsSet tree = new PolyhedronsSet(boundaries, 1e-10);
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
 
         // assert
-        Assert.assertEquals(Double.POSITIVE_INFINITY, tree.getSize(), 1.0e-10);
-        Assert.assertEquals(Double.POSITIVE_INFINITY, tree.getBoundarySize(), 1.0e-10);
-        Cartesian3D center = (Cartesian3D) tree.getBarycenter();
-        Assert.assertEquals(Double.NaN, center.getX(), 1e-10);
-        Assert.assertEquals(Double.NaN, center.getY(), 1e-10);
-        Assert.assertEquals(Double.NaN, center.getZ(), 1e-10);
-        Assert.assertEquals(false, tree.isFull());
-        Assert.assertEquals(false, tree.isEmpty());
+        Assert.assertEquals(TEST_TOLERANCE, polySet.getTolerance(), Precision.EPSILON);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, polySet.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, polySet.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(Cartesian3D.NaN, (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(false, polySet.isEmpty());
+        Assert.assertEquals(true, polySet.isFull());
+    }
 
-        checkPoints(Region.Location.BOUNDARY, tree, new Cartesian3D[] {
-                Cartesian3D.ZERO
-        });
+    @Test
+    public void testCreateFromBoundaries_unitBox() {
+        // arrange
+        List<SubHyperplane<Euclidean3D>> boundaries = createBoxBoundaries(Cartesian3D.ZERO, 1.0, TEST_TOLERANCE);
+
+        // act
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
+
+        // 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);
+        GeometryTestUtils.assertVectorEquals(Cartesian3D.ZERO, (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(false, polySet.isEmpty());
+        Assert.assertEquals(false, polySet.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, polySet,
+                new Cartesian3D(-1, 0, 0),
+                new Cartesian3D(1, 0, 0),
+                new Cartesian3D(0, -1, 0),
+                new Cartesian3D(0, 1, 0),
+                new Cartesian3D(0, 0, -1),
+                new Cartesian3D(0, 0, 1),
+
+                new Cartesian3D(1, 1, 1),
+                new Cartesian3D(1, 1, -1),
+                new Cartesian3D(1, -1, 1),
+                new Cartesian3D(1, -1, -1),
+                new Cartesian3D(-1, 1, 1),
+                new Cartesian3D(-1, 1, -1),
+                new Cartesian3D(-1, -1, 1),
+                new Cartesian3D(-1, -1, -1));
+
+        checkPoints(Region.Location.BOUNDARY, polySet,
+                new Cartesian3D(0.5, 0, 0),
+                new Cartesian3D(-0.5, 0, 0),
+                new Cartesian3D(0, 0.5, 0),
+                new Cartesian3D(0, -0.5, 0),
+                new Cartesian3D(0, 0, 0.5),
+                new Cartesian3D(0, 0, -0.5),
+
+                new Cartesian3D(0.5, 0.5, 0.5),
+                new Cartesian3D(0.5, 0.5, -0.5),
+                new Cartesian3D(0.5, -0.5, 0.5),
+                new Cartesian3D(0.5, -0.5, -0.5),
+                new Cartesian3D(-0.5, 0.5, 0.5),
+                new Cartesian3D(-0.5, 0.5, -0.5),
+                new Cartesian3D(-0.5, -0.5, 0.5),
+                new Cartesian3D(-0.5, -0.5, -0.5));
+
+        checkPoints(Region.Location.INSIDE, polySet,
+                new Cartesian3D(0, 0, 0),
+
+                new Cartesian3D(0.4, 0.4, 0.4),
+                new Cartesian3D(0.4, 0.4, -0.4),
+                new Cartesian3D(0.4, -0.4, 0.4),
+                new Cartesian3D(0.4, -0.4, -0.4),
+                new Cartesian3D(-0.4, 0.4, 0.4),
+                new Cartesian3D(-0.4, 0.4, -0.4),
+                new Cartesian3D(-0.4, -0.4, 0.4),
+                new Cartesian3D(-0.4, -0.4, -0.4));
     }
 
     @Test
-    public void testBox() {
-        PolyhedronsSet tree = new PolyhedronsSet(0, 1, 0, 1, 0, 1, 1.0e-10);
-        Assert.assertEquals(1.0, tree.getSize(), 1.0e-10);
-        Assert.assertEquals(6.0, tree.getBoundarySize(), 1.0e-10);
-        Cartesian3D barycenter = (Cartesian3D) tree.getBarycenter();
-        Assert.assertEquals(0.5, barycenter.getX(), 1.0e-10);
-        Assert.assertEquals(0.5, barycenter.getY(), 1.0e-10);
-        Assert.assertEquals(0.5, barycenter.getZ(), 1.0e-10);
+    public void testCreateFromBoundaries_twoBoxes_disjoint() {
+        // arrange
+        List<SubHyperplane<Euclidean3D>> boundaries = new ArrayList<>();
+        boundaries.addAll(createBoxBoundaries(Cartesian3D.ZERO, 1.0, TEST_TOLERANCE));
+        boundaries.addAll(createBoxBoundaries(new Cartesian3D(2, 0, 0), 1.0, TEST_TOLERANCE));
+
+        // act
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
+
+        // 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);
+        GeometryTestUtils.assertVectorEquals(new Cartesian3D(1, 0, 0), (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(false, polySet.isEmpty());
+        Assert.assertEquals(false, polySet.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, polySet,
+                new Cartesian3D(-1, 0, 0),
+                new Cartesian3D(1, 0, 0),
+                new Cartesian3D(3, 0, 0));
+
+        checkPoints(Region.Location.INSIDE, polySet,
+                new Cartesian3D(0, 0, 0),
+                new Cartesian3D(2, 0, 0));
+    }
+
+    @Test
+    public void testCreateFromBoundaries_twoBoxes_sharedSide() {
+        // arrange
+        List<SubHyperplane<Euclidean3D>> boundaries = new ArrayList<>();
+        boundaries.addAll(createBoxBoundaries(new Cartesian3D(0, 0, 0), 1.0, TEST_TOLERANCE));
+        boundaries.addAll(createBoxBoundaries(new Cartesian3D(1, 0, 0), 1.0, TEST_TOLERANCE));
+
+        // act
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
+
+        // 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);
+        GeometryTestUtils.assertVectorEquals(new Cartesian3D(0.5, 0, 0), (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(false, polySet.isEmpty());
+        Assert.assertEquals(false, polySet.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, polySet,
+                new Cartesian3D(-1, 0, 0),
+                new Cartesian3D(2, 0, 0));
+
+        checkPoints(Region.Location.INSIDE, polySet,
+                new Cartesian3D(0, 0, 0),
+                new Cartesian3D(1, 0, 0));
+    }
+
+    @Test
+    public void testCreateFromBoundaries_twoBoxes_separationLessThanTolerance() {
+        // arrange
+        double tolerance = 1e-6;
+        List<SubHyperplane<Euclidean3D>> boundaries = new ArrayList<>();
+        boundaries.addAll(createBoxBoundaries(new Cartesian3D(0, 0, 0), 1.0, tolerance));
+        boundaries.addAll(createBoxBoundaries(new Cartesian3D(1 + 1e-7, 0, 0), 1.0, tolerance));
+
+        // act
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, tolerance);
+
+        // assert
+        Assert.assertEquals(tolerance, polySet.getTolerance(), Precision.EPSILON);
+        Assert.assertEquals(2.0, polySet.getSize(), tolerance);
+        Assert.assertEquals(10.0, polySet.getBoundarySize(), tolerance);
+        GeometryTestUtils.assertVectorEquals(new Cartesian3D(0.5 + 5e-8, 0, 0), (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(false, polySet.isEmpty());
+        Assert.assertEquals(false, polySet.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, polySet,
+                new Cartesian3D(-1, 0, 0),
+                new Cartesian3D(2, 0, 0));
+
+        checkPoints(Region.Location.INSIDE, polySet,
+                new Cartesian3D(0, 0, 0),
+                new Cartesian3D(1, 0, 0));
+    }
+
+    @Test
+    public void testCreateFromBoundaries_twoBoxes_sharedEdge() {
+        // arrange
+        List<SubHyperplane<Euclidean3D>> boundaries = new ArrayList<>();
+        boundaries.addAll(createBoxBoundaries(new Cartesian3D(0, 0, 0), 1.0, TEST_TOLERANCE));
+        boundaries.addAll(createBoxBoundaries(new Cartesian3D(1, 1, 0), 1.0, TEST_TOLERANCE));
+
+        // act
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
+
+        // 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);
+        GeometryTestUtils.assertVectorEquals(new Cartesian3D(0.5, 0.5, 0), (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(false, polySet.isEmpty());
+        Assert.assertEquals(false, polySet.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, polySet,
+                new Cartesian3D(-1, 0, 0),
+                new Cartesian3D(1, 0, 0),
+                new Cartesian3D(0, 1, 0),
+                new Cartesian3D(2, 1, 0));
+
+        checkPoints(Region.Location.INSIDE, polySet,
+                new Cartesian3D(0, 0, 0),
+                new Cartesian3D(1, 1, 0));
+    }
+
+    @Test
+    public void testCreateFromBoundaries_twoBoxes_sharedPoint() {
+        // arrange
+        List<SubHyperplane<Euclidean3D>> boundaries = new ArrayList<>();
+        boundaries.addAll(createBoxBoundaries(new Cartesian3D(0, 0, 0), 1.0, TEST_TOLERANCE));
+        boundaries.addAll(createBoxBoundaries(new Cartesian3D(1, 1, 1), 1.0, TEST_TOLERANCE));
+
+        // act
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
+
+        // 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);
+        GeometryTestUtils.assertVectorEquals(new Cartesian3D(0.5, 0.5, 0.5), (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(false, polySet.isEmpty());
+        Assert.assertEquals(false, polySet.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, polySet,
+                new Cartesian3D(-1, 0, 0),
+                new Cartesian3D(1, 0, 0),
+                new Cartesian3D(0, 1, 1),
+                new Cartesian3D(2, 1, 1));
+
+        checkPoints(Region.Location.INSIDE, polySet,
+                new Cartesian3D(0, 0, 0),
+                new Cartesian3D(1, 1, 1));
+    }
+
+    @Test
+    public void testCreateBox() {
+        // act
+        PolyhedronsSet tree = new PolyhedronsSet(0, 1, 0, 1, 0, 1, TEST_TOLERANCE);
+
+        // assert
+        Assert.assertEquals(1.0, tree.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(6.0, tree.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(new Cartesian3D(0.5, 0.5, 0.5), (Cartesian3D) tree.getBarycenter(), TEST_TOLERANCE);
+
         for (double x = -0.25; x < 1.25; x += 0.1) {
             boolean xOK = (x >= 0.0) && (x <= 1.0);
             for (double y = -0.25; y < 1.25; y += 0.1) {
@@ -216,22 +461,25 @@ public class PolyhedronsSetTest {
 
     @Test
     public void testTetrahedron() throws MathArithmeticException {
+        // arrange
         Cartesian3D vertex1 = new Cartesian3D(1, 2, 3);
         Cartesian3D vertex2 = new Cartesian3D(2, 2, 4);
         Cartesian3D vertex3 = new Cartesian3D(2, 3, 3);
         Cartesian3D vertex4 = new Cartesian3D(1, 3, 4);
+
+        // act
         PolyhedronsSet tree =
             (PolyhedronsSet) new RegionFactory<Euclidean3D>().buildConvex(
-                new Plane(vertex3, vertex2, vertex1, 1.0e-10),
-                new Plane(vertex2, vertex3, vertex4, 1.0e-10),
-                new Plane(vertex4, vertex3, vertex1, 1.0e-10),
-                new Plane(vertex1, vertex2, vertex4, 1.0e-10));
-        Assert.assertEquals(1.0 / 3.0, tree.getSize(), 1.0e-10);
-        Assert.assertEquals(2.0 * FastMath.sqrt(3.0), tree.getBoundarySize(), 1.0e-10);
-        Cartesian3D barycenter = (Cartesian3D) tree.getBarycenter();
-        Assert.assertEquals(1.5, barycenter.getX(), 1.0e-10);
-        Assert.assertEquals(2.5, barycenter.getY(), 1.0e-10);
-        Assert.assertEquals(3.5, barycenter.getZ(), 1.0e-10);
+                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));
+
+        // assert
+        Assert.assertEquals(1.0 / 3.0, tree.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(2.0 * FastMath.sqrt(3.0), tree.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(new Cartesian3D(1.5, 2.5, 3.5), (Cartesian3D) tree.getBarycenter(), TEST_TOLERANCE);
+
         double third = 1.0 / 3.0;
         checkPoints(Region.Location.BOUNDARY, tree, new Cartesian3D[] {
             vertex1, vertex2, vertex3, vertex4,
@@ -249,17 +497,59 @@ public class PolyhedronsSetTest {
     }
 
     @Test
+    public void testSphere() {
+        // arrange
+        // (use a high tolerance value here since the sphere is only an approximation)
+        double approximationTolerance = 0.2;
+        double radius = 1.0;
+
+        // act
+        PolyhedronsSet polySet = createSphere(new Cartesian3D(1, 2, 3), radius, 8, 16);
+
+        // assert
+        Assert.assertEquals(sphereVolume(radius), polySet.getSize(), approximationTolerance);
+        Assert.assertEquals(sphereSurface(radius), polySet.getBoundarySize(), approximationTolerance);
+        GeometryTestUtils.assertVectorEquals(new Cartesian3D(1, 2, 3), (Cartesian3D) polySet.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(false, polySet.isEmpty());
+        Assert.assertEquals(false, polySet.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, polySet,
+                new Cartesian3D(-0.1, 2, 3),
+                new Cartesian3D(2.1, 2, 3),
+                new Cartesian3D(1, 0.9, 3),
+                new Cartesian3D(1, 3.1, 3),
+                new Cartesian3D(1, 2, 1.9),
+                new Cartesian3D(1, 2, 4.1),
+                new Cartesian3D(1.6, 2.6, 3.6));
+
+        checkPoints(Region.Location.INSIDE, polySet,
+                new Cartesian3D(1, 2, 3),
+                new Cartesian3D(0.1, 2, 3),
+                new Cartesian3D(1.9, 2, 3),
+                new Cartesian3D(1, 2.1, 3),
+                new Cartesian3D(1, 2.9, 3),
+                new Cartesian3D(1, 2, 2.1),
+                new Cartesian3D(1, 2, 3.9),
+                new Cartesian3D(1.5, 2.5, 3.5));
+    }
+
+    @Test
     public void testIsometry() throws MathArithmeticException, MathIllegalArgumentException {
+        // arrange
         Cartesian3D vertex1 = new Cartesian3D(1.1, 2.2, 3.3);
         Cartesian3D vertex2 = new Cartesian3D(2.0, 2.4, 4.2);
         Cartesian3D vertex3 = new Cartesian3D(2.8, 3.3, 3.7);
         Cartesian3D vertex4 = new Cartesian3D(1.0, 3.6, 4.5);
+
+        // act
         PolyhedronsSet tree =
             (PolyhedronsSet) new RegionFactory<Euclidean3D>().buildConvex(
-                new Plane(vertex3, vertex2, vertex1, 1.0e-10),
-                new Plane(vertex2, vertex3, vertex4, 1.0e-10),
-                new Plane(vertex4, vertex3, vertex1, 1.0e-10),
-                new Plane(vertex1, vertex2, vertex4, 1.0e-10));
+                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));
+
+        // assert
         Cartesian3D barycenter = (Cartesian3D) tree.getBarycenter();
         Cartesian3D s = new Cartesian3D(10.2, 4.3, -6.7);
         Cartesian3D c = new Cartesian3D(-0.2, 2.1, -3.2);
@@ -272,8 +562,8 @@ public class PolyhedronsSetTest {
                          1.0, c,
                          1.0, r.applyTo(barycenter.subtract(c)));
         Assert.assertEquals(0.0,
-                            newB.subtract((Vector<Euclidean3D>) tree.getBarycenter()).getNorm(),
-                            1.0e-10);
+                            newB.subtract((Cartesian3D) tree.getBarycenter()).getNorm(),
+                            TEST_TOLERANCE);
 
         final Cartesian3D[] expectedV = new Cartesian3D[] {
             new Cartesian3D(1.0, s,
@@ -324,7 +614,7 @@ public class PolyhedronsSetTest {
                     for (int k = 0; k < expectedV.length; ++k) {
                         d = FastMath.min(d, v.subtract(expectedV[k]).getNorm());
                     }
-                    Assert.assertEquals(0, d, 1.0e-10);
+                    Assert.assertEquals(0, d, TEST_TOLERANCE);
                 }
             }
 
@@ -334,49 +624,53 @@ public class PolyhedronsSetTest {
 
     @Test
     public void testBuildBox() {
+        // arrange
         double x = 1.0;
         double y = 2.0;
         double z = 3.0;
         double w = 0.1;
         double l = 1.0;
+
+        // act
         PolyhedronsSet tree =
-            new PolyhedronsSet(x - l, x + l, y - w, y + w, z - w, z + w, 1.0e-10);
-        Cartesian3D barycenter = (Cartesian3D) tree.getBarycenter();
-        Assert.assertEquals(x, barycenter.getX(), 1.0e-10);
-        Assert.assertEquals(y, barycenter.getY(), 1.0e-10);
-        Assert.assertEquals(z, barycenter.getZ(), 1.0e-10);
-        Assert.assertEquals(8 * l * w * w, tree.getSize(), 1.0e-10);
-        Assert.assertEquals(8 * w * (2 * l + w), tree.getBoundarySize(), 1.0e-10);
+            new PolyhedronsSet(x - l, x + l, y - w, y + w, z - w, z + w, TEST_TOLERANCE);
+
+        // assert
+        GeometryTestUtils.assertVectorEquals(new Cartesian3D(x, y, z), (Cartesian3D) 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);
     }
 
     @Test
     public void testCross() {
-
+        // arrange
         double x = 1.0;
         double y = 2.0;
         double z = 3.0;
         double w = 0.1;
         double l = 1.0;
         PolyhedronsSet xBeam =
-            new PolyhedronsSet(x - l, x + l, y - w, y + w, z - w, z + w, 1.0e-10);
+            new PolyhedronsSet(x - l, x + l, y - w, y + w, z - w, z + w, TEST_TOLERANCE);
         PolyhedronsSet yBeam =
-            new PolyhedronsSet(x - w, x + w, y - l, y + l, z - w, z + w, 1.0e-10);
+            new PolyhedronsSet(x - w, x + w, y - l, y + l, z - w, z + w, TEST_TOLERANCE);
         PolyhedronsSet zBeam =
-            new PolyhedronsSet(x - w, x + w, y - w, y + w, z - l, z + l, 1.0e-10);
+            new PolyhedronsSet(x - w, x + w, y - w, y + w, z - l, z + l, TEST_TOLERANCE);
         RegionFactory<Euclidean3D> factory = new RegionFactory<>();
-        PolyhedronsSet tree = (PolyhedronsSet) factory.union(xBeam, factory.union(yBeam, zBeam));
-        Cartesian3D barycenter = (Cartesian3D) tree.getBarycenter();
 
-        Assert.assertEquals(x, barycenter.getX(), 1.0e-10);
-        Assert.assertEquals(y, barycenter.getY(), 1.0e-10);
-        Assert.assertEquals(z, barycenter.getZ(), 1.0e-10);
-        Assert.assertEquals(8 * w * w * (3 * l - 2 * w), tree.getSize(), 1.0e-10);
-        Assert.assertEquals(24 * w * (2 * l - w), tree.getBoundarySize(), 1.0e-10);
+        // act
+        PolyhedronsSet tree = (PolyhedronsSet) factory.union(xBeam, factory.union(yBeam, zBeam));
 
+        // assert
+        GeometryTestUtils.assertVectorEquals(new Cartesian3D(x, y, z), (Cartesian3D) 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);
     }
 
+    // Issue MATH-780
+    // See https://issues.apache.org/jira/browse/MATH-780
     @Test
-    public void testIssue780() throws MathArithmeticException {
+    public void testCreateFromBoundaries_handlesSmallBoundariesCreatedDuringConstruction() throws MathArithmeticException {
+        // arrange
         float[] coords = {
             1.000000f, -1.000000f, -1.000000f,
             1.000000f, -1.000000f, 1.000000f,
@@ -402,7 +696,7 @@ public class PolyhedronsSetTest {
             Cartesian3D v_2 = new Cartesian3D(coords[idxB], coords[idxB + 1], coords[idxB + 2]);
             Cartesian3D v_3 = new Cartesian3D(coords[idxC], coords[idxC + 1], coords[idxC + 2]);
             Cartesian3D[] vertices = {v_1, v_2, v_3};
-            Plane polyPlane = new Plane(v_1, v_2, v_3, 1.0e-10);
+            Plane polyPlane = new Plane(v_1, v_2, v_3, TEST_TOLERANCE);
             ArrayList<SubHyperplane<Euclidean2D>> lines = new ArrayList<>();
 
             Cartesian2D[] projPts = new Cartesian2D[vertices.length];
@@ -412,23 +706,29 @@ public class PolyhedronsSetTest {
 
             SubLine lineInPlane = null;
             for (int ptIdx = 0; ptIdx < projPts.length; ptIdx++) {
-                lineInPlane = new SubLine(projPts[ptIdx], projPts[(ptIdx + 1) % projPts.length], 1.0e-10);
+                lineInPlane = new SubLine(projPts[ptIdx], projPts[(ptIdx + 1) % projPts.length], TEST_TOLERANCE);
                 lines.add(lineInPlane);
             }
-            Region<Euclidean2D> polyRegion = new PolygonsSet(lines, 1.0e-10);
+            Region<Euclidean2D> polyRegion = new PolygonsSet(lines, TEST_TOLERANCE);
             SubPlane polygon = new SubPlane(polyPlane, polyRegion);
             subHyperplaneList.add(polygon);
         }
-        PolyhedronsSet polyhedronsSet = new PolyhedronsSet(subHyperplaneList, 1.0e-10);
-        Assert.assertEquals( 8.0, polyhedronsSet.getSize(), 3.0e-6);
+
+        // act
+        PolyhedronsSet polyhedronsSet = new PolyhedronsSet(subHyperplaneList, TEST_TOLERANCE);
+
+        // assert
+        Assert.assertEquals(8.0, polyhedronsSet.getSize(), 3.0e-6);
         Assert.assertEquals(24.0, polyhedronsSet.getBoundarySize(), 5.0e-6);
     }
 
     @Test
     public void testTooThinBox() {
-        Assert.assertEquals(0.0,
-                            new PolyhedronsSet(0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0e-10).getSize(),
-                            1.0e-10);
+        // act
+        PolyhedronsSet polyhedronsSet = new PolyhedronsSet(0.0, 0.0, 0.0, 1.0, 0.0, 1.0, TEST_TOLERANCE);
+
+        // assert
+        Assert.assertEquals(0.0, polyhedronsSet.getSize(), TEST_TOLERANCE);
     }
 
     @Test
@@ -436,7 +736,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<Euclidean3D>(), 1.0e-10);
+        PolyhedronsSet ps = new PolyhedronsSet(new BSPTree<Euclidean3D>(), TEST_TOLERANCE);
         Assert.assertNotNull(ps);
         try {
             ps.checkPoint(Cartesian3D.ZERO);
@@ -448,86 +748,91 @@ public class PolyhedronsSetTest {
 
     @Test
     public void testDumpParse() throws IOException, ParseException {
+        // arrange
         double tol=1e-8;
 
-            Cartesian3D[] verts=new Cartesian3D[8];
-            double xmin=-1,xmax=1;
-            double ymin=-1,ymax=1;
-            double zmin=-1,zmax=1;
-            verts[0]=new Cartesian3D(xmin,ymin,zmin);
-            verts[1]=new Cartesian3D(xmax,ymin,zmin);
-            verts[2]=new Cartesian3D(xmax,ymax,zmin);
-            verts[3]=new Cartesian3D(xmin,ymax,zmin);
-            verts[4]=new Cartesian3D(xmin,ymin,zmax);
-            verts[5]=new Cartesian3D(xmax,ymin,zmax);
-            verts[6]=new Cartesian3D(xmax,ymax,zmax);
-            verts[7]=new Cartesian3D(xmin,ymax,zmax);
-            //
-            int[][] faces=new int[12][];
-            faces[0]=new int[]{3,1,0};  // bottom (-z)
-            faces[1]=new int[]{1,3,2};  // bottom (-z)
-            faces[2]=new int[]{5,7,4};  // top (+z)
-            faces[3]=new int[]{7,5,6};  // top (+z)
-            faces[4]=new int[]{2,5,1};  // right (+x)
-            faces[5]=new int[]{5,2,6};  // right (+x)
-            faces[6]=new int[]{4,3,0};  // left (-x)
-            faces[7]=new int[]{3,4,7};  // left (-x)
-            faces[8]=new int[]{4,1,5};  // front (-y)
-            faces[9]=new int[]{1,4,0};  // front (-y)
-            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);
-            Assert.assertEquals(8.0, polyset.getSize(), 1.0e-10);
-            Assert.assertEquals(24.0, polyset.getBoundarySize(), 1.0e-10);
-            String dump = RegionDumper.dump(polyset);
-            PolyhedronsSet parsed = RegionParser.parsePolyhedronsSet(dump);
-            Assert.assertEquals(8.0, parsed.getSize(), 1.0e-10);
-            Assert.assertEquals(24.0, parsed.getBoundarySize(), 1.0e-10);
-            Assert.assertTrue(new RegionFactory<Euclidean3D>().difference(polyset, parsed).isEmpty());
-    }
-
-    @Test
-    public void testConnectedFacets() throws IOException, ParseException {
+        Cartesian3D[] verts=new Cartesian3D[8];
+        double xmin=-1,xmax=1;
+        double ymin=-1,ymax=1;
+        double zmin=-1,zmax=1;
+        verts[0]=new Cartesian3D(xmin,ymin,zmin);
+        verts[1]=new Cartesian3D(xmax,ymin,zmin);
+        verts[2]=new Cartesian3D(xmax,ymax,zmin);
+        verts[3]=new Cartesian3D(xmin,ymax,zmin);
+        verts[4]=new Cartesian3D(xmin,ymin,zmax);
+        verts[5]=new Cartesian3D(xmax,ymin,zmax);
+        verts[6]=new Cartesian3D(xmax,ymax,zmax);
+        verts[7]=new Cartesian3D(xmin,ymax,zmax);
+        //
+        int[][] faces=new int[12][];
+        faces[0]=new int[]{3,1,0};  // bottom (-z)
+        faces[1]=new int[]{1,3,2};  // bottom (-z)
+        faces[2]=new int[]{5,7,4};  // top (+z)
+        faces[3]=new int[]{7,5,6};  // top (+z)
+        faces[4]=new int[]{2,5,1};  // right (+x)
+        faces[5]=new int[]{5,2,6};  // right (+x)
+        faces[6]=new int[]{4,3,0};  // left (-x)
+        faces[7]=new int[]{3,4,7};  // left (-x)
+        faces[8]=new int[]{4,1,5};  // front (-y)
+        faces[9]=new int[]{1,4,0};  // front (-y)
+        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);
+
+        // act
+        String dump = RegionDumper.dump(polyset);
+        PolyhedronsSet parsed = RegionParser.parsePolyhedronsSet(dump);
+
+        // assert
+        Assert.assertEquals(8.0, polyset.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(24.0, polyset.getBoundarySize(), TEST_TOLERANCE);
+
+        Assert.assertEquals(8.0, parsed.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(24.0, parsed.getBoundarySize(), TEST_TOLERANCE);
+        Assert.assertTrue(new RegionFactory<Euclidean3D>().difference(polyset, parsed).isEmpty());
+    }
+
+    @Test
+    public void testCreateFromBRep_connectedFacets() throws IOException, ParseException {
         InputStream stream = getClass().getResourceAsStream("pentomino-N.ply");
         PLYParser   parser = new PLYParser(stream);
         stream.close();
-        PolyhedronsSet polyhedron = new PolyhedronsSet(parser.getVertices(), parser.getFaces(), 1.0e-10);
-        Assert.assertEquals( 5.0, polyhedron.getSize(), 1.0e-10);
-        Assert.assertEquals(22.0, polyhedron.getBoundarySize(), 1.0e-10);
+        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);
     }
 
     @Test
-    public void testTooClose() throws IOException, ParseException {
+    public void testCreateFromBRep_verticesTooClose() throws IOException, ParseException {
         checkError("pentomino-N-too-close.ply", LocalizedFormats.CLOSE_VERTICES);
     }
 
     @Test
-    public void testHole() throws IOException, ParseException {
+    public void testCreateFromBRep_hole() throws IOException, ParseException {
         checkError("pentomino-N-hole.ply", LocalizedFormats.EDGE_CONNECTED_TO_ONE_FACET);
     }
 
     @Test
-    public void testNonPlanar() throws IOException, ParseException {
+    public void testCreateFromBRep_nonPlanar() throws IOException, ParseException {
         checkError("pentomino-N-out-of-plane.ply", LocalizedFormats.OUT_OF_PLANE);
     }
 
     @Test
-    public void testOrientation() throws IOException, ParseException {
+    public void testCreateFromBRep_badOrientation() throws IOException, ParseException {
         checkError("pentomino-N-bad-orientation.ply", LocalizedFormats.FACET_ORIENTATION_MISMATCH);
     }
 
     @Test
-    public void testFacet2Vertices() throws IOException, ParseException {
+    public void testCreateFromBRep_wrongNumberOfPoints() throws IOException, ParseException {
         checkError(Arrays.asList(Cartesian3D.ZERO, Cartesian3D.PLUS_I, Cartesian3D.PLUS_J, Cartesian3D.PLUS_K),
                    Arrays.asList(new int[] { 0, 1, 2 }, new int[] {2, 3}),
                    LocalizedFormats.WRONG_NUMBER_OF_POINTS);
     }
 
     private void checkError(final String resourceName, final LocalizedFormats expected) {
-        try {
-            InputStream stream = getClass().getResourceAsStream(resourceName);
+        try (InputStream stream = getClass().getResourceAsStream(resourceName)) {
             PLYParser   parser = new PLYParser(stream);
-            stream.close();
             checkError(parser.getVertices(), parser.getFaces(), expected);
         } catch (IOException ioe) {
             Assert.fail(ioe.getLocalizedMessage());
@@ -539,7 +844,7 @@ public class PolyhedronsSetTest {
     private void checkError(final List<Cartesian3D> vertices, final List<int[]> facets,
                             final LocalizedFormats expected) {
         try {
-            new PolyhedronsSet(vertices, facets, 1.0e-10);
+            new PolyhedronsSet(vertices, facets, TEST_TOLERANCE);
             Assert.fail("an exception should have been thrown");
         } catch (MathIllegalArgumentException miae) {
             try {
@@ -557,10 +862,61 @@ public class PolyhedronsSetTest {
     }
 
     @Test
-    public void testIssue1211() throws IOException, ParseException {
+    public void testFirstIntersection() {
+        // arrange
+        List<SubHyperplane<Euclidean3D>> boundaries = createBoxBoundaries(Cartesian3D.ZERO, 2.0, TEST_TOLERANCE);
+        PolyhedronsSet polySet = new PolyhedronsSet(boundaries, TEST_TOLERANCE);
+
+        Line xPlus = new Line(Cartesian3D.ZERO, Cartesian3D.PLUS_I, TEST_TOLERANCE);
+        Line xMinus = new Line(Cartesian3D.ZERO, Cartesian3D.MINUS_I, TEST_TOLERANCE);
 
+        Line yPlus = new Line(Cartesian3D.ZERO, Cartesian3D.PLUS_J, TEST_TOLERANCE);
+        Line yMinus = new Line(Cartesian3D.ZERO, Cartesian3D.MINUS_J, TEST_TOLERANCE);
+
+        Line zPlus = new Line(Cartesian3D.ZERO, Cartesian3D.PLUS_K, TEST_TOLERANCE);
+        Line zMinus = new Line(Cartesian3D.ZERO, Cartesian3D.MINUS_K, TEST_TOLERANCE);
+
+        // act/assert
+        assertSubPlaneNormal(new Cartesian3D(-1, 0, 0), polySet.firstIntersection(new Cartesian3D(-1.1, 0, 0), xPlus));
+        assertSubPlaneNormal(new Cartesian3D(-1, 0, 0), polySet.firstIntersection(new Cartesian3D(-1, 0, 0), xPlus));
+        assertSubPlaneNormal(new Cartesian3D(1, 0, 0), polySet.firstIntersection(new Cartesian3D(-0.9, 0, 0), xPlus));
+        Assert.assertEquals(null, polySet.firstIntersection(new Cartesian3D(1.1, 0, 0), xPlus));
+
+        assertSubPlaneNormal(new Cartesian3D(1, 0, 0), polySet.firstIntersection(new Cartesian3D(1.1, 0, 0), xMinus));
+        assertSubPlaneNormal(new Cartesian3D(1, 0, 0), polySet.firstIntersection(new Cartesian3D(1, 0, 0), xMinus));
+        assertSubPlaneNormal(new Cartesian3D(-1, 0, 0), polySet.firstIntersection(new Cartesian3D(0.9, 0, 0), xMinus));
+        Assert.assertEquals(null, polySet.firstIntersection(new Cartesian3D(-1.1, 0, 0), xMinus));
+
+        assertSubPlaneNormal(new Cartesian3D(0, -1, 0), polySet.firstIntersection(new Cartesian3D(0, -1.1, 0), yPlus));
+        assertSubPlaneNormal(new Cartesian3D(0, -1, 0), polySet.firstIntersection(new Cartesian3D(0, -1, 0), yPlus));
+        assertSubPlaneNormal(new Cartesian3D(0, 1, 0), polySet.firstIntersection(new Cartesian3D(0, -0.9, 0), yPlus));
+        Assert.assertEquals(null, polySet.firstIntersection(new Cartesian3D(0, 1.1, 0), yPlus));
+
+        assertSubPlaneNormal(new Cartesian3D(0, 1, 0), polySet.firstIntersection(new Cartesian3D(0, 1.1, 0), yMinus));
+        assertSubPlaneNormal(new Cartesian3D(0, 1, 0), polySet.firstIntersection(new Cartesian3D(0, 1, 0), yMinus));
+        assertSubPlaneNormal(new Cartesian3D(0, -1, 0), polySet.firstIntersection(new Cartesian3D(0, 0.9, 0), yMinus));
+        Assert.assertEquals(null, polySet.firstIntersection(new Cartesian3D(0, -1.1, 0), yMinus));
+
+        assertSubPlaneNormal(new Cartesian3D(0, 0, -1), polySet.firstIntersection(new Cartesian3D(0, 0, -1.1), zPlus));
+        assertSubPlaneNormal(new Cartesian3D(0, 0, -1), polySet.firstIntersection(new Cartesian3D(0, 0, -1), zPlus));
+        assertSubPlaneNormal(new Cartesian3D(0, 0, 1), polySet.firstIntersection(new Cartesian3D(0, 0, -0.9), zPlus));
+        Assert.assertEquals(null, polySet.firstIntersection(new Cartesian3D(0, 0, 1.1), zPlus));
+
+        assertSubPlaneNormal(new Cartesian3D(0, 0, 1), polySet.firstIntersection(new Cartesian3D(0, 0, 1.1), zMinus));
+        assertSubPlaneNormal(new Cartesian3D(0, 0, 1), polySet.firstIntersection(new Cartesian3D(0, 0, 1), zMinus));
+        assertSubPlaneNormal(new Cartesian3D(0, 0, -1), polySet.firstIntersection(new Cartesian3D(0, 0, 0.9), zMinus));
+        Assert.assertEquals(null, polySet.firstIntersection(new Cartesian3D(0, 0, -1.1), zMinus));
+    }
+
+    // Issue 1211
+    // See https://issues.apache.org/jira/browse/MATH-1211
+    @Test
+    public void testFirstIntersection_onlyReturnsPointsInDirectionOfRay() throws IOException, ParseException {
+        // arrange
         PolyhedronsSet polyset = RegionParser.parsePolyhedronsSet(loadTestData("issue-1211.bsp"));
         UniformRandomProvider random = RandomSource.create(RandomSource.WELL_1024_A, 0xb97c9d1ade21e40al);
+
+        // act/assert
         int nrays = 1000;
         for (int i = 0; i < nrays; i++) {
             Cartesian3D origin    = Cartesian3D.ZERO;
@@ -577,21 +933,579 @@ public class PolyhedronsSetTest {
         }
     }
 
+    @Test
+    public void testBoolean_union() throws IOException {
+        // arrange
+        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 sphere = createSphere(new Cartesian3D(size * 0.5, size * 0.5, size), radius, 8, 16);
+
+        // act
+        PolyhedronsSet result = (PolyhedronsSet) new RegionFactory<Euclidean3D>().union(box, sphere);
+
+        // OBJWriter.write("union.obj", result);
+
+        // assert
+        Assert.assertEquals(cubeVolume(size) + (sphereVolume(radius) * 0.5),
+                result.getSize(), tolerance);
+        Assert.assertEquals(cubeSurface(size) - circleSurface(radius) + (0.5 * sphereSurface(radius)),
+                result.getBoundarySize(), tolerance);
+        Assert.assertEquals(false, result.isEmpty());
+        Assert.assertEquals(false, result.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, result,
+                new Cartesian3D(-0.1, 0.5, 0.5),
+                new Cartesian3D(1.1, 0.5, 0.5),
+                new Cartesian3D(0.5, -0.1, 0.5),
+                new Cartesian3D(0.5, 1.1, 0.5),
+                new Cartesian3D(0.5, 0.5, -0.1),
+                new Cartesian3D(0.5, 0.5, 1.6));
+
+        checkPoints(Region.Location.INSIDE, result,
+                new Cartesian3D(0.1, 0.5, 0.5),
+                new Cartesian3D(0.9, 0.5, 0.5),
+                new Cartesian3D(0.5, 0.1, 0.5),
+                new Cartesian3D(0.5, 0.9, 0.5),
+                new Cartesian3D(0.5, 0.5, 0.1),
+                new Cartesian3D(0.5, 0.5, 1.4));
+    }
+
+    @Test
+    public void testUnion_self() {
+        // arrange
+        double tolerance = 0.2;
+        double radius = 1.0;
+
+        PolyhedronsSet sphere = createSphere(Cartesian3D.ZERO, radius, 8, 16);
+
+        // act
+        PolyhedronsSet result = (PolyhedronsSet) new RegionFactory<Euclidean3D>().union(sphere, sphere.copySelf());
+
+        // assert
+        Assert.assertEquals(sphereVolume(radius), result.getSize(), tolerance);
+        Assert.assertEquals(sphereSurface(radius), result.getBoundarySize(), tolerance);
+        GeometryTestUtils.assertVectorEquals(Cartesian3D.ZERO, (Cartesian3D) result.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(false, result.isEmpty());
+        Assert.assertEquals(false, result.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, result,
+                new Cartesian3D(-1.1, 0, 0),
+                new Cartesian3D(1.1, 0, 0),
+                new Cartesian3D(0, -1.1, 0),
+                new Cartesian3D(0, 1.1, 0),
+                new Cartesian3D(0, 0, -1.1),
+                new Cartesian3D(0, 0, 1.1));
+
+        checkPoints(Region.Location.INSIDE, result,
+                new Cartesian3D(-0.9, 0, 0),
+                new Cartesian3D(0.9, 0, 0),
+                new Cartesian3D(0, -0.9, 0),
+                new Cartesian3D(0, 0.9, 0),
+                new Cartesian3D(0, 0, -0.9),
+                new Cartesian3D(0, 0, 0.9),
+                Cartesian3D.ZERO);
+    }
+
+    @Test
+    public void testBoolean_intersection() throws IOException {
+        // arrange
+        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 sphere = createSphere(new Cartesian3D(size * 0.5, size * 0.5, size), radius, 8, 16);
+
+        // act
+        PolyhedronsSet result = (PolyhedronsSet) new RegionFactory<Euclidean3D>().intersection(box, sphere);
+
+        // OBJWriter.write("intersection.obj", result);
+
+        // assert
+        Assert.assertEquals((sphereVolume(radius) * 0.5), result.getSize(), tolerance);
+        Assert.assertEquals(circleSurface(radius) + (0.5 * sphereSurface(radius)),
+                result.getBoundarySize(), tolerance);
+        Assert.assertEquals(false, result.isEmpty());
+        Assert.assertEquals(false, result.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, result,
+                new Cartesian3D(-0.1, 0.5, 1.0),
+                new Cartesian3D(1.1, 0.5, 1.0),
+                new Cartesian3D(0.5, -0.1, 1.0),
+                new Cartesian3D(0.5, 1.1, 1.0),
+                new Cartesian3D(0.5, 0.5, 0.4),
+                new Cartesian3D(0.5, 0.5, 1.1));
+
+        checkPoints(Region.Location.INSIDE, result,
+                new Cartesian3D(0.1, 0.5, 0.9),
+                new Cartesian3D(0.9, 0.5, 0.9),
+                new Cartesian3D(0.5, 0.1, 0.9),
+                new Cartesian3D(0.5, 0.9, 0.9),
+                new Cartesian3D(0.5, 0.5, 0.6),
+                new Cartesian3D(0.5, 0.5, 0.9));
+    }
+
+    @Test
+    public void testIntersection_self() {
+        // arrange
+        double tolerance = 0.2;
+        double radius = 1.0;
+
+        PolyhedronsSet sphere = createSphere(Cartesian3D.ZERO, radius, 8, 16);
+
+        // act
+        PolyhedronsSet result = (PolyhedronsSet) new RegionFactory<Euclidean3D>().intersection(sphere, sphere.copySelf());
+
+        // assert
+        Assert.assertEquals(sphereVolume(radius), result.getSize(), tolerance);
+        Assert.assertEquals(sphereSurface(radius), result.getBoundarySize(), tolerance);
+        GeometryTestUtils.assertVectorEquals(Cartesian3D.ZERO, (Cartesian3D) result.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(false, result.isEmpty());
+        Assert.assertEquals(false, result.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, result,
+                new Cartesian3D(-1.1, 0, 0),
+                new Cartesian3D(1.1, 0, 0),
+                new Cartesian3D(0, -1.1, 0),
+                new Cartesian3D(0, 1.1, 0),
+                new Cartesian3D(0, 0, -1.1),
+                new Cartesian3D(0, 0, 1.1));
+
+        checkPoints(Region.Location.INSIDE, result,
+                new Cartesian3D(-0.9, 0, 0),
+                new Cartesian3D(0.9, 0, 0),
+                new Cartesian3D(0, -0.9, 0),
+                new Cartesian3D(0, 0.9, 0),
+                new Cartesian3D(0, 0, -0.9),
+                new Cartesian3D(0, 0, 0.9),
+                Cartesian3D.ZERO);
+    }
+
+    @Test
+    public void testBoolean_xor_twoCubes() throws IOException {
+        // arrange
+        double size = 1.0;
+        PolyhedronsSet box1 = new PolyhedronsSet(
+                0, size,
+                0, size,
+                0, size, TEST_TOLERANCE);
+        PolyhedronsSet box2 = new PolyhedronsSet(
+                0.5, size + 0.5,
+                0.5, size + 0.5,
+                0.5, size + 0.5, TEST_TOLERANCE);
+
+        // act
+        PolyhedronsSet result = (PolyhedronsSet) new RegionFactory<Euclidean3D>().xor(box1, box2);
+
+        // OBJWriter.write("xor_twoCubes.obj", result);
+
+        Assert.assertEquals((2 * cubeVolume(size)) - (2 * cubeVolume(size * 0.5)), result.getSize(), TEST_TOLERANCE);
+
+        // assert
+        Assert.assertEquals(2 * cubeSurface(size), result.getBoundarySize(), TEST_TOLERANCE);
+        Assert.assertEquals(false, result.isEmpty());
+        Assert.assertEquals(false, result.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, result,
+                new Cartesian3D(-0.1, -0.1, -0.1),
+                new Cartesian3D(0.75, 0.75, 0.75),
+                new Cartesian3D(1.6, 1.6, 1.6));
+
+        checkPoints(Region.Location.BOUNDARY, result,
+                new Cartesian3D(0, 0, 0),
+                new Cartesian3D(0.5, 0.5, 0.5),
+                new Cartesian3D(1, 1, 1),
+                new Cartesian3D(1.5, 1.5, 1.5));
+
+        checkPoints(Region.Location.INSIDE, result,
+                new Cartesian3D(0.1, 0.1, 0.1),
+                new Cartesian3D(0.4, 0.4, 0.4),
+                new Cartesian3D(1.1, 1.1, 1.1),
+                new Cartesian3D(1.4, 1.4, 1.4));
+    }
+
+    @Test
+    public void testBoolean_xor_cubeAndSphere() throws IOException {
+        // arrange
+        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 sphere = createSphere(new Cartesian3D(size * 0.5, size * 0.5, size), radius, 8, 16);
+
+        // act
+        PolyhedronsSet result = (PolyhedronsSet) new RegionFactory<Euclidean3D>().xor(box, sphere);
+
+        // OBJWriter.write("xor_cubeAndSphere.obj", result);
+
+        Assert.assertEquals(cubeVolume(size), result.getSize(), tolerance);
+
+        // assert
+        Assert.assertEquals(cubeSurface(size) + (sphereSurface(radius)),
+                result.getBoundarySize(), tolerance);
+        Assert.assertEquals(false, result.isEmpty());
+        Assert.assertEquals(false, result.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, result,
+                new Cartesian3D(-0.1, 0.5, 0.5),
+                new Cartesian3D(1.1, 0.5, 0.5),
+                new Cartesian3D(0.5, -0.1, 0.5),
+                new Cartesian3D(0.5, 1.1, 0.5),
+                new Cartesian3D(0.5, 0.5, -0.1),
+                new Cartesian3D(0.5, 0.5, 1.6),
+                new Cartesian3D(0.5, 0.5, 0.9));
+
+        checkPoints(Region.Location.INSIDE, result,
+                new Cartesian3D(0.1, 0.5, 0.5),
+                new Cartesian3D(0.9, 0.5, 0.5),
+                new Cartesian3D(0.5, 0.1, 0.5),
+                new Cartesian3D(0.5, 0.9, 0.5),
+                new Cartesian3D(0.5, 0.5, 0.1),
+                new Cartesian3D(0.5, 0.5, 1.4));
+    }
+
+    @Test
+    public void testXor_self() {
+        // arrange
+        double radius = 1.0;
+
+        PolyhedronsSet sphere = createSphere(Cartesian3D.ZERO, radius, 8, 16);
+
+        // act
+        PolyhedronsSet result = (PolyhedronsSet) new RegionFactory<Euclidean3D>().xor(sphere, sphere.copySelf());
+
+        // assert
+        Assert.assertEquals(0.0, result.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, result.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(Cartesian3D.NaN, (Cartesian3D) result.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(true, result.isEmpty());
+        Assert.assertEquals(false, result.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, result,
+                new Cartesian3D(-1.1, 0, 0),
+                new Cartesian3D(1.1, 0, 0),
+                new Cartesian3D(0, -1.1, 0),
+                new Cartesian3D(0, 1.1, 0),
+                new Cartesian3D(0, 0, -1.1),
+                new Cartesian3D(0, 0, 1.1),
+                new Cartesian3D(-0.9, 0, 0),
+                new Cartesian3D(0.9, 0, 0),
+                new Cartesian3D(0, -0.9, 0),
+                new Cartesian3D(0, 0.9, 0),
+                new Cartesian3D(0, 0, -0.9),
+                new Cartesian3D(0, 0, 0.9),
+                Cartesian3D.ZERO);
+    }
+
+    @Test
+    public void testBoolean_difference() throws IOException {
+        // arrange
+        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 sphere = createSphere(new Cartesian3D(size * 0.5, size * 0.5, size), radius, 8, 16);
+
+        // act
+        PolyhedronsSet result = (PolyhedronsSet) new RegionFactory<Euclidean3D>().difference(box, sphere);
+
+        // OBJWriter.write("difference.obj", result);
+
+        // assert
+        Assert.assertEquals(cubeVolume(size) - (sphereVolume(radius) * 0.5), result.getSize(), tolerance);
+        Assert.assertEquals(cubeSurface(size) - circleSurface(radius) + (0.5 * sphereSurface(radius)),
+                result.getBoundarySize(), tolerance);
+        Assert.assertEquals(false, result.isEmpty());
+        Assert.assertEquals(false, result.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, result,
+                new Cartesian3D(-0.1, 0.5, 1.0),
+                new Cartesian3D(1.1, 0.5, 1.0),
+                new Cartesian3D(0.5, -0.1, 1.0),
+                new Cartesian3D(0.5, 1.1, 1.0),
+                new Cartesian3D(0.5, 0.5, -0.1),
+                new Cartesian3D(0.5, 0.5, 0.6));
+
+        checkPoints(Region.Location.INSIDE, result,
+                new Cartesian3D(0.1, 0.5, 0.4),
+                new Cartesian3D(0.9, 0.5, 0.4),
+                new Cartesian3D(0.5, 0.1, 0.4),
+                new Cartesian3D(0.5, 0.9, 0.4),
+                new Cartesian3D(0.5, 0.5, 0.1),
+                new Cartesian3D(0.5, 0.5, 0.4));
+    }
+
+    @Test
+    public void testDifference_self() {
+        // arrange
+        double radius = 1.0;
+
+        PolyhedronsSet sphere = createSphere(Cartesian3D.ZERO, radius, 8, 16);
+
+        // act
+        PolyhedronsSet result = (PolyhedronsSet) new RegionFactory<Euclidean3D>().difference(sphere, sphere.copySelf());
+
+        // assert
+        Assert.assertEquals(0.0, result.getSize(), TEST_TOLERANCE);
+        Assert.assertEquals(0.0, result.getBoundarySize(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(Cartesian3D.NaN, (Cartesian3D) result.getBarycenter(), TEST_TOLERANCE);
+        Assert.assertEquals(true, result.isEmpty());
+        Assert.assertEquals(false, result.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, result,
+                new Cartesian3D(-1.1, 0, 0),
+                new Cartesian3D(1.1, 0, 0),
+                new Cartesian3D(0, -1.1, 0),
+                new Cartesian3D(0, 1.1, 0),
+                new Cartesian3D(0, 0, -1.1),
+                new Cartesian3D(0, 0, 1.1),
+                new Cartesian3D(-0.9, 0, 0),
+                new Cartesian3D(0.9, 0, 0),
+                new Cartesian3D(0, -0.9, 0),
+                new Cartesian3D(0, 0.9, 0),
+                new Cartesian3D(0, 0, -0.9),
+                new Cartesian3D(0, 0, 0.9),
+                Cartesian3D.ZERO);
+    }
+
+    @Test
+    public void testBoolean_multiple() throws IOException {
+        // arrange
+        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 sphereToAdd = createSphere(new Cartesian3D(size * 0.5, size * 0.5, size), radius, 8, 16);
+        PolyhedronsSet sphereToRemove1 = createSphere(new Cartesian3D(size * 0.5, 0, size * 0.5), radius, 8, 16);
+        PolyhedronsSet sphereToRemove2 = createSphere(new Cartesian3D(size * 0.5, 1, size * 0.5), radius, 8, 16);
+
+        RegionFactory<Euclidean3D> factory = new RegionFactory<Euclidean3D>();
+
+        // act
+        PolyhedronsSet result = (PolyhedronsSet) factory.union(box, sphereToAdd);
+        result = (PolyhedronsSet) factory.difference(result, sphereToRemove1);
+        result = (PolyhedronsSet) factory.difference(result, sphereToRemove2);
+
+        // OBJWriter.write("multiple.obj", result);
+
+        // assert
+        Assert.assertEquals(cubeVolume(size) - (sphereVolume(radius) * 0.5),
+                result.getSize(), tolerance);
+        Assert.assertEquals(cubeSurface(size) - (3.0 * circleSurface(radius)) + (1.5 * sphereSurface(radius)),
+                result.getBoundarySize(), tolerance);
+        Assert.assertEquals(false, result.isEmpty());
+        Assert.assertEquals(false, result.isFull());
+
+        checkPoints(Region.Location.OUTSIDE, result,
+                new Cartesian3D(-0.1, 0.5, 0.5),
+                new Cartesian3D(1.1, 0.5, 0.5),
+                new Cartesian3D(0.5, 0.4, 0.5),
+                new Cartesian3D(0.5, 0.6, 0.5),
+                new Cartesian3D(0.5, 0.5, -0.1),
+                new Cartesian3D(0.5, 0.5, 1.6));
+
+        checkPoints(Region.Location.INSIDE, result,
+                new Cartesian3D(0.1, 0.5, 0.1),
+                new Cartesian3D(0.9, 0.5, 0.1),
+                new Cartesian3D(0.5, 0.4, 0.1),
+                new Cartesian3D(0.5, 0.6, 0.1),
+                new Cartesian3D(0.5, 0.5, 0.1),
+                new Cartesian3D(0.5, 0.5, 1.4));
+    }
+
+    @Test
+    public void testProjectToBoundary() {
+        // arrange
+        PolyhedronsSet polySet = new PolyhedronsSet(0, 1, 0, 1, 0, 1, TEST_TOLERANCE);
+
+        // act/assert
+        checkProjectToBoundary(polySet, new Cartesian3D(0.4, 0.5, 0.5),
+                new Cartesian3D(0, 0.5, 0.5), -0.4);
+        checkProjectToBoundary(polySet, new Cartesian3D(1.5, 0.5, 0.5),
+                new Cartesian3D(1, 0.5, 0.5), 0.5);
+        checkProjectToBoundary(polySet, new Cartesian3D(2, 2, 2),
+                new Cartesian3D(1, 1, 1), FastMath.sqrt(3));
+    }
+
+    @Test
+    public void testProjectToBoundary_invertedRegion() {
+        // arrange
+        PolyhedronsSet polySet = new PolyhedronsSet(0, 1, 0, 1, 0, 1, TEST_TOLERANCE);
+        polySet = (PolyhedronsSet) new RegionFactory<Euclidean3D>().getComplement(polySet);
+
+        // act/assert
+        checkProjectToBoundary(polySet, new Cartesian3D(0.4, 0.5, 0.5),
+                new Cartesian3D(0, 0.5, 0.5), 0.4);
+        checkProjectToBoundary(polySet, new Cartesian3D(1.5, 0.5, 0.5),
+                new Cartesian3D(1, 0.5, 0.5), -0.5);
+        checkProjectToBoundary(polySet, new Cartesian3D(2, 2, 2),
+                new Cartesian3D(1, 1, 1), -FastMath.sqrt(3));
+    }
+
+    private void checkProjectToBoundary(PolyhedronsSet poly, Cartesian3D toProject,
+            Cartesian3D expectedPoint, double expectedOffset) {
+        BoundaryProjection<Euclidean3D> proj = poly.projectToBoundary(toProject);
+
+        GeometryTestUtils.assertVectorEquals(toProject, (Cartesian3D) proj.getOriginal(), TEST_TOLERANCE);
+        GeometryTestUtils.assertVectorEquals(expectedPoint, (Cartesian3D) proj.getProjected(), TEST_TOLERANCE);
+        Assert.assertEquals(expectedOffset, proj.getOffset(), TEST_TOLERANCE);
+    }
+
     private String loadTestData(final String resourceName)
             throws IOException {
-            InputStream stream = getClass().getResourceAsStream(resourceName);
-            Reader reader = new InputStreamReader(stream, "UTF-8");
+        try (Reader reader = new InputStreamReader(getClass().getResourceAsStream(resourceName), "UTF-8")) {
             StringBuilder builder = new StringBuilder();
             for (int c = reader.read(); c >= 0; c = reader.read()) {
                 builder.append((char) c);
             }
             return builder.toString();
         }
+    }
 
-    private void checkPoints(Region.Location expected, PolyhedronsSet tree, Cartesian3D[] points) {
+    private void checkPoints(Region.Location expected, PolyhedronsSet poly, Cartesian3D ... points) {
         for (int i = 0; i < points.length; ++i) {
-            Assert.assertEquals(expected, tree.checkPoint(points[i]));
+            Assert.assertEquals("Incorrect location for " + points[i], expected, poly.checkPoint(points[i]));
+        }
+    }
+
+    private List<SubHyperplane<Euclidean3D>> createBoxBoundaries(Cartesian3D center, double size, double tolerance) {
+        List<SubHyperplane<Euclidean3D>> boundaries = new ArrayList<>();
+
+        double offset = size * 0.5;
+
+        Plane xMinus = new Plane(center.add(new Cartesian3D(-offset, 0, 0)), Cartesian3D.MINUS_I, tolerance);
+        Plane xPlus = new Plane(center.add(new Cartesian3D(offset, 0, 0)), Cartesian3D.PLUS_I, tolerance);
+        Plane yPlus = new Plane(center.add(new Cartesian3D(0, offset, 0)), Cartesian3D.PLUS_J, tolerance);
+        Plane yMinus = new Plane(center.add(new Cartesian3D(0, -offset, 0)), Cartesian3D.MINUS_J, tolerance);
+        Plane zPlus = new Plane(center.add(new Cartesian3D(0, 0, offset)), Cartesian3D.PLUS_K, tolerance);
+        Plane zMinus = new Plane(center.add(new Cartesian3D(0, 0, -offset)), Cartesian3D.MINUS_K, tolerance);
+
+        // +x
+        boundaries.add(createSubPlane(xPlus,
+                        center.add(new Cartesian3D(offset, offset, offset)),
+                        center.add(new Cartesian3D(offset, -offset, offset)),
+                        center.add(new Cartesian3D(offset, -offset, -offset)),
+                        center.add(new Cartesian3D(offset, offset, -offset))));
+
+        // -x
+        boundaries.add(createSubPlane(xMinus,
+                        center.add(new Cartesian3D(-offset, -offset, offset)),
+                        center.add(new Cartesian3D(-offset, offset, offset)),
+                        center.add(new Cartesian3D(-offset, offset, -offset)),
+                        center.add(new Cartesian3D(-offset, -offset, -offset))));
+
+        // +y
+        boundaries.add(createSubPlane(yPlus,
+                        center.add(new Cartesian3D(-offset, offset, offset)),
+                        center.add(new Cartesian3D(offset, offset, offset)),
+                        center.add(new Cartesian3D(offset, offset, -offset)),
+                        center.add(new Cartesian3D(-offset, offset, -offset))));
+
+        // -y
+        boundaries.add(createSubPlane(yMinus,
+                        center.add(new Cartesian3D(-offset, -offset, offset)),
+                        center.add(new Cartesian3D(-offset, -offset, -offset)),
+                        center.add(new Cartesian3D(offset, -offset, -offset)),
+                        center.add(new Cartesian3D(offset, -offset, offset))));
+
+        // +z
+        boundaries.add(createSubPlane(zPlus,
+                        center.add(new Cartesian3D(-offset, -offset, offset)),
+                        center.add(new Cartesian3D(offset, -offset, offset)),
+                        center.add(new Cartesian3D(offset, offset, offset)),
+                        center.add(new Cartesian3D(-offset, offset, offset))));
+
+        // -z
+        boundaries.add(createSubPlane(zMinus,
+                        center.add(new Cartesian3D(-offset, -offset, -offset)),
+                        center.add(new Cartesian3D(-offset, offset, -offset)),
+                        center.add(new Cartesian3D(offset, offset, -offset)),
+                        center.add(new Cartesian3D(offset, -offset, -offset))));
+
+        return boundaries;
+    }
+
+    private SubPlane createSubPlane(Plane plane, Cartesian3D...points) {
+        Cartesian2D[] points2d = new Cartesian2D[points.length];
+        for (int i=0; i<points.length; ++i) {
+            points2d[i] = plane.toSubSpace(points[i]);
         }
+
+        PolygonsSet polygon = new PolygonsSet(plane.getTolerance(), points2d);
+
+        return new SubPlane(plane, polygon);
     }
 
+    private PolyhedronsSet createSphere(Cartesian3D center, double radius, int stacks, int slices) {
+        List<Plane> planes = new ArrayList<>();
+
+        // add top and bottom planes (+/- z)
+        Cartesian3D topZ = new Cartesian3D(center.getX(), center.getY(), center.getZ() + radius);
+        Cartesian3D bottomZ = new Cartesian3D(center.getX(), center.getY(), center.getZ() - radius);
+
+        planes.add(new Plane(topZ, Cartesian3D.PLUS_K, TEST_TOLERANCE));
+        planes.add(new Plane(bottomZ, Cartesian3D.MINUS_K, TEST_TOLERANCE));
+
+        // add the side planes
+        double vDelta = FastMath.PI / stacks;
+        double hDelta = FastMath.PI * 2 / slices;
+
+        double adjustedRadius = (radius + (radius * FastMath.cos(vDelta * 0.5))) / 2.0;
+
+        double vAngle;
+        double hAngle;
+        double stackRadius;
+        double stackHeight;
+        double x, y;
+        Cartesian3D norm, pt;
+
+        vAngle = -0.5 * vDelta;
+        for (int v=0; v<stacks; ++v) {
+            vAngle += vDelta;
+
+            stackRadius = FastMath.sin(vAngle) * adjustedRadius;
+            stackHeight = FastMath.cos(vAngle) * adjustedRadius;
+
+            hAngle = -0.5 * hDelta;
+            for (int h=0; h<slices; ++h) {
+                hAngle += hDelta;
+
+                x = FastMath.cos(hAngle) * stackRadius;
+                y = FastMath.sin(hAngle) * stackRadius;
+
+                norm = new Cartesian3D(x, y, stackHeight).normalize();
+                pt = norm.scalarMultiply(adjustedRadius).add(center);
+
+                planes.add(new Plane(pt, norm, TEST_TOLERANCE));
+            }
+        }
+
+        return (PolyhedronsSet) new RegionFactory<Euclidean3D>().buildConvex(planes.toArray(new Plane[0]));
+    }
+
+    private void assertSubPlaneNormal(Cartesian3D expectedNormal, SubHyperplane<Euclidean3D> sub) {
+        Cartesian3D norm = ((Plane) sub.getHyperplane()).getNormal();
+        GeometryTestUtils.assertVectorEquals(expectedNormal, norm, TEST_TOLERANCE);
+    }
+
+    private double cubeVolume(double size) {
+        return size * size * size;
+    }
+
+    private double cubeSurface(double size) {
+        return 6.0 * size * size;
+    }
+
+    private double sphereVolume(double radius) {
+        return 4.0 * FastMath.PI * radius * radius * radius / 3.0;
+    }
+
+    private double sphereSurface(double radius) {
+        return 4.0 * FastMath.PI * radius * radius;
+    }
+
+    private double circleSurface(double radius) {
+        return FastMath.PI * radius * radius;
+    }
 }